41 lines
1.6 KiB
TypeScript
41 lines
1.6 KiB
TypeScript
// Ports the pattern list of upstream skills/misc/git-guardrails-claude-code (block-dangerous-git.sh)
|
|
// to an OpenCode v2 tool hook. Opt-in via plugin options { guardrails: true }.
|
|
|
|
export type Options = { guardrails: boolean }
|
|
|
|
export function resolveOptions(options: Record<string, unknown> | undefined): Options {
|
|
const opts = options ?? {}
|
|
const guardrails = opts.guardrails ?? false
|
|
if (typeof guardrails !== "boolean") {
|
|
throw new Error(`pocock: option guardrails must be a boolean, got ${JSON.stringify(guardrails)}`)
|
|
}
|
|
return { guardrails }
|
|
}
|
|
|
|
// Same patterns as the upstream hook script (grep -E semantics), in order.
|
|
const DANGEROUS: ReadonlyArray<readonly [string, RegExp]> = [
|
|
["git push", /git push/],
|
|
["git reset --hard", /git reset --hard/],
|
|
["git clean -fd", /git clean -fd/],
|
|
["git clean -f", /git clean -f/],
|
|
["git branch -D", /git branch -D/],
|
|
["git checkout .", /git checkout \./],
|
|
["git restore .", /git restore \./],
|
|
["push --force", /push --force/],
|
|
["reset --hard", /reset --hard/],
|
|
]
|
|
|
|
export function blockedPattern(command: string): string | undefined {
|
|
for (const [pattern, re] of DANGEROUS) if (re.test(command)) return pattern
|
|
return undefined
|
|
}
|
|
|
|
export function guardrailError(command: string, pattern: string): string {
|
|
return `BLOCKED: '${command}' matches dangerous pattern '${pattern}'. The user has prevented you from doing this.`
|
|
}
|
|
|
|
/** True when a tool-hook event targets the shell tool (v2 id may be "bash" or "shell"). */
|
|
export function isShellTool(tool: string): boolean {
|
|
return tool === "bash" || tool === "shell"
|
|
}
|