skills-experimental/dangerous-files-auto-edit-protection/SKILL.md
# Dangerous Files Auto-Edit Protection Skill Dangerous Files Auto-Edit Protection - DANGEROUS_FILES .gitconfig/.bashrc/.zshrc/.claude.json + DANGEROUS_DIRECTORIES .git/.vscode/.idea/.claude + normalizeCaseForComparison lowercase + getClaudeSkillScope skill directory + .claude/worktrees/ exception + isDangerousFilePathToAutoEdit UNC/dangerous check + isClaudeConfigFilePath + isSessionPlanFile + isScratchpadPath + isSessionMemoryPath + isProjectDirPath。 ## 功能概述 从Claude Code的utils/permissions/fi
npx skillsauth add bianhaifeng789-hue/openclaw-config skills-experimental/dangerous-files-auto-edit-protectionInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Dangerous Files Auto-Edit Protection - DANGEROUS_FILES .gitconfig/.bashrc/.zshrc/.claude.json + DANGEROUS_DIRECTORIES .git/.vscode/.idea/.claude + normalizeCaseForComparison lowercase + getClaudeSkillScope skill directory + .claude/worktrees/ exception + isDangerousFilePathToAutoEdit UNC/dangerous check + isClaudeConfigFilePath + isSessionPlanFile + isScratchpadPath + isSessionMemoryPath + isProjectDirPath。
从Claude Code的utils/permissions/filesystem.ts提取的Dangerous files auto-edit protection模式,用于OpenClaw的危险文件自动编辑保护。
export const DANGEROUS_FILES = [
'.gitconfig',
'.gitmodules',
'.bashrc',
'.bash_profile',
'.zshrc',
'.zprofile',
'.profile',
'.ripgreprc',
'.mcp.json',
'.claude.json',
] as const
// DANGEROUS_FILES
# Shell config files
# Git config files
# MCP config
# Claude settings
# Code execution vectors
export const DANGEROUS_DIRECTORIES = [
'.git',
'.vscode',
'.idea',
'.claude',
] as const
// DANGEROUS_DIRECTORIES
# Git metadata
# IDE settings
# Claude config
# Sensitive configuration
export function normalizeCaseForComparison(path: string): string {
return path.toLowerCase()
}
// SECURITY: Normalize for case-insensitive comparison to prevent bypassing security
// with paths like .cLauDe/Settings.locaL.json
// normalizeCaseForComparison
# Always lowercase
# Prevent case bypass
# .cLauDe → .claude
export function getClaudeSkillScope(
filePath: string,
): { skillName: string; pattern: string } | null {
const absolutePath = expandPath(filePath)
const absolutePathLower = normalizeCaseForComparison(absolutePath)
const bases = [
{ dir: expandPath(join(getOriginalCwd(), '.claude', 'skills')), prefix: '/.claude/skills/' },
{ dir: expandPath(join(homedir(), '.claude', 'skills')), prefix: '~/.claude/skills/' },
]
for (const { dir, prefix } of bases) {
const dirLower = normalizeCaseForComparison(dir)
for (const s of [sep, '/']) {
if (absolutePathLower.startsWith(dirLower + s.toLowerCase())) {
const rest = absolutePath.slice(dir.length + s.length)
const cut = Math.min(rest.indexOf('/'), sep === '\\' ? rest.indexOf('\\') : -1)
if (cut <= 0) return null // File must be INSIDE skill dir
const skillName = rest.slice(0, cut)
if (!skillName || skillName === '.' || skillName.includes('..')) return null
if (/[*?[\]]/.test(skillName)) return null // Reject glob metacharacters
return { skillName, pattern: prefix + skillName + '/**' }
}
}
}
return null
}
// getClaudeSkillScope
# skill name extraction
# pattern: /.claude/skills/{name}/**
# Glob metachar reject
# Traversal reject
// Special case: .claude/worktrees/ is a structural path (where Claude stores
// git worktrees), not a user-created dangerous directory. Skip the .claude
// segment when it's followed by 'worktrees'. Any nested .claude directories
// within the worktree (not followed by 'worktrees') are still blocked.
if (dir === '.claude') {
const nextSegment = pathSegments[i + 1]
if (nextSegment && normalizeCaseForComparison(nextSegment) === 'worktrees') {
break // Skip this .claude, continue checking other segments
}
}
// .claude/worktrees/ exception
# Structural path
# Not dangerous
# Skip .claude when followed by worktrees
function isDangerousFilePathToAutoEdit(path: string): boolean {
const absolutePath = expandPath(path)
const pathSegments = absolutePath.split(sep)
const fileName = pathSegments.at(-1)
// Block UNC paths
if (path.startsWith('\\\\') || path.startsWith('//')) return true
// Check dangerous directories (case-insensitive)
for (let i = 0; i < pathSegments.length; i++) {
const segment = pathSegments[i]!
const normalizedSegment = normalizeCaseForComparison(segment)
for (const dir of DANGEROUS_DIRECTORIES) {
if (normalizedSegment !== normalizeCaseForComparison(dir)) continue
// Special case: .claude/worktrees/ exception
if (dir === '.claude') {
const nextSegment = pathSegments[i + 1]
if (nextSegment && normalizeCaseForComparison(nextSegment) === 'worktrees') break
}
return true
}
}
// Check dangerous configuration files (case-insensitive)
if (fileName) {
const normalizedFileName = normalizeCaseForComparison(fileName)
if ((DANGEROUS_FILES as readonly string[]).some(
dangerousFile => normalizeCaseForComparison(dangerousFile) === normalizedFileName,
)) return true
}
return false
}
// isDangerousFilePathToAutoEdit
# UNC paths → true
# Dangerous directories → true
# Dangerous files → true
# Case-insensitive
function isClaudeConfigFilePath(filePath: string): boolean {
if (isClaudeSettingsPath(filePath)) return true
const commandsDir = join(getOriginalCwd(), '.claude', 'commands')
const agentsDir = join(getOriginalCwd(), '.claude', 'agents')
const skillsDir = join(getOriginalCwd(), '.claude', 'skills')
return (
pathInWorkingPath(filePath, commandsDir) ||
pathInWorkingPath(filePath, agentsDir) ||
pathInWorkingPath(filePath, skillsDir)
)
}
// isClaudeConfigFilePath
# settings.json
# commands/agents/skills dirs
# Always ask for Claude config
function isSessionPlanFile(absolutePath: string): boolean {
const expectedPrefix = join(getPlansDirectory(), getPlanSlug())
const normalizedPath = normalize(absolutePath)
return normalizedPath.startsWith(expectedPrefix) && normalizedPath.endsWith('.md')
}
// isSessionPlanFile
# {plansDir}/{planSlug}.md
# {plansDir}/{planSlug}-agent-{agentId}.md
# Internal editable
function isScratchpadPath(absolutePath: string): boolean {
if (!isScratchpadEnabled()) return false
const scratchpadDir = getScratchpadDir()
const normalizedPath = normalize(absolutePath)
return normalizedPath === scratchpadDir || normalizedPath.startsWith(scratchpadDir + sep)
}
// isScratchpadPath
# /tmp/claude-{uid}/{cwd}/{session}/scratchpad/
# Internal editable
# Statsig gate enabled
function isSessionMemoryPath(absolutePath: string): boolean {
const normalizedPath = normalize(absolutePath)
return normalizedPath.startsWith(getSessionMemoryDir())
}
export function getSessionMemoryDir(): string {
return join(getProjectDir(getCwd()), getSessionId(), 'session-memory') + sep
}
// isSessionMemoryPath
# {projectDir}/{sessionId}/session-memory/
# Internal readable
function isProjectDirPath(absolutePath: string): boolean {
const projectDir = getProjectDir(getCwd())
const normalizedPath = normalize(absolutePath)
return normalizedPath === projectDir || normalizedPath.startsWith(projectDir + sep)
}
// isProjectDirPath
# ~/.claude/projects/{sanitized-cwd}/
# Internal readable
{
"path": ".gitconfig",
"dangerous": true,
"reason": "DANGEROUS_FILES",
"caseNormalized": ".gitconfig"
}
.gitconfig + .bashrc + .zshrc + .mcp.json + .claude.json → code execution → DANGEROUS_FILES → auto-edit protection → shell config vector
# shell config code execution vector
# shell startup scripts
# git hooks/config
# MCP/claude settings
normalizeCaseForComparison(path) → lowercase → .cLauDe → .claude → prevent bypass → case-insensitive always lowercase
# case-insensitive lowercase always
# prevent case bypass
# always lowercase
.claude followed by worktrees → exception → structural path → not dangerous → skip .claude → worktrees exception
# .claude/worktrees structural exception
# git worktree storage
# not dangerous
skillName.includes('*?[]') → reject → prevent pattern match all skills → glob metachar reject → security guard
# skill scope glob metachar reject
# prevent pattern matching all
# reject *, ?, [, ]
session plan + scratchpad + session memory + project dir → internal paths → auto-edit allowed → internal editable → session scratchpad memory
# internal paths session scratchpad memory
# auto-edit allowed
# internal editable/readable
utils/permissions/filesystem.ts (1278+ lines)business
IAA 日报飞书输出能力。 支持把固定 CSV 模板一键转换成: - 中文运营结论 - 飞书卡片 JSON - 飞书发送载荷 Use when: - 需要把 IAA 日报直接发到飞书 - 需要从 CSV 一键生成运营日报
data-ai
IAA日报分析模型 功能: - 渠道日报自动分析 - 小时级+日级ROI联动判断 - 按地区输出加量/降量/停投建议 - 按产品类型输出阈值 - 自动识别利润区/观察区/止损区 Use when: - 分析每天投放数据 - 生成运营日报结论 - 判断是否加量/降量/停投 - 对比美加澳/日韩表现 Keywords: - 日报模型, 投放日报, 加量, 降量, 停投, ROI日报, 分地区分析
data-ai
IAA固定日报分析模板 功能: - 固定字段模板(可直接贴每天数据) - 自动输出总盘结论 - 自动输出美加澳/日韩结论 - 自动给出加量/降量/停投建议 - 适配文件修复/清理两类产品 Use when: - 需要固定日报格式 - 每天复盘渠道表现 - 给运营团队出统一结论 Keywords: - 固定模板, 日报模板, ROI模板, IAA日报, 运营模板
development
# HyperlinkPool Pattern Skill HyperlinkPool Pattern - HyperlinkPool class + strings array + stringMap + Index 0 no hyperlink + intern(hyperlink) + get(id) + undefined handling + 5-minute reset + OSC8 hyperlink interning。 ## 功能概述 从Claude Code的ink/screen.ts提取的HyperlinkPool模式,用于OpenClaw的OSC8超链接池管理。 ## 核心机制 ### HyperlinkPool Class ```typescript export class HyperlinkPool { private strings: string[] = [''] // Index 0 = no hyperlink private stringMap = new Map<string, number>() // strings