@webpieces/ai-hook-rules 0.4.621 → 0.4.623
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +29 -6
- package/package.json +2 -2
- package/src/adapters/hook-core.js +10 -3
- package/src/adapters/hook-core.js.map +1 -1
- package/src/bin/hook-registration.d.ts +60 -14
- package/src/bin/hook-registration.js +123 -22
- package/src/bin/hook-registration.js.map +1 -1
- package/src/bin/managed-env.d.ts +42 -0
- package/src/bin/managed-env.js +46 -0
- package/src/bin/managed-env.js.map +1 -0
- package/src/bin/setup.js +10 -0
- package/src/bin/setup.js.map +1 -1
- package/src/bin/shim-deny-reason.d.ts +6 -0
- package/src/bin/shim-deny-reason.js +80 -0
- package/src/bin/shim-deny-reason.js.map +1 -0
- package/src/bin/shim.d.ts +0 -1
- package/src/bin/shim.js +0 -54
- package/src/bin/shim.js.map +1 -1
- package/src/bin/upgrade-shim.d.ts +2 -2
- package/src/bin/upgrade-shim.js +95 -13
- package/src/bin/upgrade-shim.js.map +1 -1
- package/src/core/l0-matrix.js +14 -12
- package/src/core/l0-matrix.js.map +1 -1
- package/templates/claude-settings-hook.json +16 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hook-registration.js","sourceRoot":"","sources":["../../../../../../packages/tooling/ai-hook-rules/src/bin/hook-registration.ts"],"names":[],"mappings":"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","sourcesContent":["import * as fs from 'fs';\nimport * as path from 'path';\n\nimport { toError } from '../core/to-error';\nimport { SHIM_MARKER, committedShimStale } from './shim';\nimport { GUARANTEE_ROOT_MARKER, committedGuaranteeRootStale, guaranteeRootPath } from './guarantee-root';\n\n/**\n * THE INSTALLED HOOK SURFACE — three hooks, and the ONE place their spelling is defined.\n *\n * ─── Why three, and why two of them are RELATIVE ───────────────────────────────────────────────────\n * `.claude/settings.json` used to register two hooks, BOTH absolute via `$CLAUDE_PROJECT_DIR`. That\n * variable NEVER moves — proven from four separate worktrees' own logs, every line reading\n * `root=<worktree> projectDir=<primary>` — so every tree was governed by the PRIMARY's shim, the\n * PRIMARY's binary and the PRIMARY's pin, forever. A worktree could never be judged by the release its\n * own branch pins, and measuring one tree while running another's binary is the non-convergent\n * \"two-tree straddle\" recorded in shim.ts (an agent gave up after four cures).\n *\n * The hooks reference says \"the hook runs in the `cwd` value from the JSON input\", so a RELATIVE\n * command resolves against the tool call's own tree. Hence:\n *\n * H1 absolute sh \"$CLAUDE_PROJECT_DIR/.claude/webpieces/guarantee-root.sh\" matcher Bash\n * H2 relative sh \".claude/webpieces/ai-hook.sh\" wp-ai-guards-hook matcher Write|…|Read\n * H3 relative sh \".claude/webpieces/ai-hook.sh\" wp-ai-rules-hook matcher Write|Edit|MultiEdit\n *\n * H1 stays absolute because it is the one hook that must ALWAYS resolve: a relative hook that cannot\n * resolve exits 127, and per the same reference any non-2 non-zero exit is a NON-BLOCKING error — i.e.\n * a SILENT UNGUARDED ALLOW. H1 refuses any `cd` that would park the shell where H2/H3 cannot launch,\n * which is what makes the relative pair admissible at all. See guarantee-root.ts.\n *\n * H1 matches `Bash` alone because only Bash can move the shell — the same reason stated at the top of\n * guarantee-root.ts, and the reason the rendered guarantee-root.sh exits 0 immediately for every other\n * tool. Registering it wider would spawn a process per Write/Read to do nothing.\n *\n * ─── Why the registration is a DRIFT SURFACE, not just an install step ─────────────────────────────\n * Nothing used to validate `.claude/settings.json` at all, so a settings file left on the old\n * two-absolute-hook form silently reverted a repo to per-PRIMARY governance and disabled H1 — the one\n * component whose whole job is failing closed. The installed surface is therefore THREE things\n * (ai-hook.sh, guarantee-root.sh, the registration), all three are compared against this release, and\n * `wp-upgrade-shim` regenerates all three. A cure that fixes one of three is worse than no cure,\n * because it reports success.\n */\n\n/** One PreToolUse hook entry as webpieces registers it. Data-only → a class, per CLAUDE.md. */\nexport class HookRegistrationEntry {\n constructor(\n readonly matcher: string,\n readonly command: string,\n ) {}\n\n sameAs(other: HookRegistrationEntry): boolean {\n return this.matcher === other.matcher && this.command === other.command;\n }\n}\n\n// webpieces-disable no-any-unknown -- settings.json is opaque consumer JSON\nexport interface HookCommand { type: string; command: string; }\nexport interface HookEntry { matcher: string; hooks: HookCommand[]; }\nexport interface ClaudeSettings {\n hooks?: { PreToolUse?: HookEntry[] };\n // webpieces-disable no-any-unknown -- opaque settings bag; arbitrary keys allowed\n [key: string]: unknown;\n}\n\nexport const RULES_BIN = 'wp-ai-rules-hook';\nexport const GUARDS_BIN = 'wp-ai-guards-hook';\nexport const RULES_MATCHER = 'Write|Edit|MultiEdit';\n// Guards match Bash (git/PR guards), Write|Edit|MultiEdit (file-scoped guards) AND Read — Read carries\n// no guard, but the guards hook owns the per-invocation audit log, so matching Read records every file\n// the AI opens (log-and-allow fast path in hook-core.ts; a Read is never blocked).\nexport const GUARDS_MATCHER = 'Write|Edit|MultiEdit|Bash|Read';\n// Only Bash can move the shell, and moving the shell is the only thing H1 judges.\nexport const GUARANTEE_ROOT_MATCHER = 'Bash';\n\n/**\n * The RELATIVE guard-hook command — `sh \".claude/webpieces/ai-hook.sh\" <bin>`.\n *\n * Relative, NOT `$CLAUDE_PROJECT_DIR/…`: that is the whole point (see the header). Invoked via `sh\n * <file>` rather than executed directly so a missing executable bit on the checked-in shim (fresh\n * clone, a filesystem that drops the bit, git core.fileMode quirks) can never break the hook with a raw\n * `Permission denied` on every tool call. Quoted to survive spaces in the path.\n */\n// webpieces-disable no-function-outside-class -- this module must load on a tree too broken to build a DI container (upgrade-shim.ts depends on that), so it is module-scope like its siblings shim.ts / guarantee-root.ts\nexport function shimCommand(bin: string): string {\n return `sh \"${SHIM_MARKER}\" ${bin}`;\n}\n\n/** H1's command. ABSOLUTE on purpose — it must resolve from ANY cwd or it cannot fail closed. */\nexport const GUARANTEE_ROOT_COMMAND = `sh \"$CLAUDE_PROJECT_DIR/${GUARANTEE_ROOT_MARKER}\"`;\n\nexport const GUARANTEE_ROOT_ENTRY = new HookRegistrationEntry(GUARANTEE_ROOT_MATCHER, GUARANTEE_ROOT_COMMAND);\n\n/** The registration entry for one guard bin. */\n// webpieces-disable no-function-outside-class -- module-scope for the same dependency-free reason as shimCommand above\nexport function guardHookEntry(bin: string): HookRegistrationEntry {\n return new HookRegistrationEntry(bin === RULES_BIN ? RULES_MATCHER : GUARDS_MATCHER, shimCommand(bin));\n}\n\n/** True when this PreToolUse command is one webpieces owns (either .sh file, in any spelling). */\n// webpieces-disable no-function-outside-class -- module-scope for the same dependency-free reason as shimCommand above\nexport function isManagedCommand(command: string): boolean {\n return command.includes(SHIM_MARKER) || command.includes(GUARANTEE_ROOT_MARKER);\n}\n\n// webpieces-disable no-function-outside-class -- module-scope for the same dependency-free reason as shimCommand above\nfunction preToolUse(settings: ClaudeSettings): readonly HookEntry[] {\n return settings.hooks?.PreToolUse ?? [];\n}\n\n/** Every webpieces-managed entry of one settings file, flattened to matcher + command pairs. */\n// webpieces-disable no-function-outside-class -- module-scope for the same dependency-free reason as shimCommand above\nexport function managedEntries(settings: ClaudeSettings): readonly HookRegistrationEntry[] {\n const found: HookRegistrationEntry[] = [];\n for (const entry of preToolUse(settings)) {\n for (const hook of entry.hooks) {\n if (isManagedCommand(hook.command)) found.push(new HookRegistrationEntry(entry.matcher, hook.command));\n }\n }\n return found;\n}\n\n/**\n * Which guard bins this settings file registers, in installer order. A file registering NEITHER is not\n * a project (relative) install and is therefore never judged — a global/absolute install names the bin\n * path directly and carries no shim marker at all.\n */\n// webpieces-disable no-function-outside-class -- module-scope for the same dependency-free reason as shimCommand above\nexport function registeredBins(settings: ClaudeSettings): readonly string[] {\n const commands = managedEntries(settings).map((e: HookRegistrationEntry): string => e.command);\n return [GUARDS_BIN, RULES_BIN].filter((bin: string): boolean => commands.some((c: string): boolean => c.includes(bin)));\n}\n\n/**\n * The exact set of entries THIS RELEASE expects in a settings file that registers `bins`.\n *\n * H1 rides with the GUARDS hook, not the rules hook: H1 judges Bash, and `Bash` is in the guards\n * matcher. A file carrying only the rules hook (the supported split install, where a team ships the\n * guards and a developer keeps the code-style rules local) gets no H1 and needs none.\n */\n// webpieces-disable no-function-outside-class -- module-scope for the same dependency-free reason as shimCommand above\nexport function expectedEntries(bins: readonly string[]): readonly HookRegistrationEntry[] {\n const wanted: HookRegistrationEntry[] = [];\n if (bins.includes(GUARDS_BIN)) wanted.push(GUARANTEE_ROOT_ENTRY);\n for (const bin of bins) wanted.push(guardHookEntry(bin));\n return wanted;\n}\n\n/**\n * True when a settings file registers webpieces hooks in a shape this release does not expect — the\n * old two-absolute-hook form, a missing guarantee-root entry, a stray duplicate, a wrong matcher.\n *\n * Compared as a SET, not a sequence: Claude Code runs all matching hooks in parallel, so array order\n * carries no meaning and reordering must not read as drift.\n */\n// webpieces-disable no-function-outside-class -- module-scope for the same dependency-free reason as shimCommand above\nexport function registrationStale(settings: ClaudeSettings): boolean {\n const bins = registeredBins(settings);\n if (bins.length === 0) return false;\n const have = managedEntries(settings);\n const want = expectedEntries(bins);\n if (have.length !== want.length) return true;\n return want.some((w: HookRegistrationEntry): boolean => !have.some((h: HookRegistrationEntry): boolean => h.sameAs(w)));\n}\n\n/** Drop every webpieces-managed PreToolUse command; returns true if anything was removed. */\n// webpieces-disable no-function-outside-class -- module-scope for the same dependency-free reason as shimCommand above\nexport function dropManagedEntries(settings: ClaudeSettings): boolean {\n const entries = settings.hooks?.PreToolUse;\n if (!entries) return false;\n let changed = false;\n const kept: HookEntry[] = [];\n for (const entry of entries) {\n const hooks = entry.hooks.filter((h: HookCommand): boolean => !isManagedCommand(h.command));\n if (hooks.length !== entry.hooks.length) changed = true;\n if (hooks.length > 0) kept.push({ matcher: entry.matcher, hooks });\n }\n if (changed) settings.hooks!.PreToolUse = kept;\n return changed;\n}\n\n/** Append one PreToolUse entry. */\n// webpieces-disable no-function-outside-class -- module-scope for the same dependency-free reason as shimCommand above\nexport function addHookEntry(settings: ClaudeSettings, entry: HookRegistrationEntry): void {\n if (!settings.hooks) settings.hooks = {};\n if (!Array.isArray(settings.hooks.PreToolUse)) settings.hooks.PreToolUse = [];\n settings.hooks.PreToolUse.push({ matcher: entry.matcher, hooks: [{ type: 'command', command: entry.command }] });\n}\n\n/**\n * Bring one settings object to the three-hook form IN PLACE. Returns true when it changed.\n *\n * REMOVE-then-ADD, never add-beside: two spellings of one registration is exactly the compatibility\n * shim the backwards-compat reviewer rejects, and leaving the `$CLAUDE_PROJECT_DIR/`-prefixed entry\n * beside the relative one would run the PRIMARY's binary alongside the tree's own — the straddle this\n * whole change exists to delete.\n */\n// webpieces-disable no-function-outside-class -- module-scope for the same dependency-free reason as shimCommand above\nexport function repairRegistration(settings: ClaudeSettings): boolean {\n const bins = registeredBins(settings);\n if (bins.length === 0 || !registrationStale(settings)) return false;\n dropManagedEntries(settings);\n for (const entry of expectedEntries(bins)) addHookEntry(settings, entry);\n return true;\n}\n\n/** The two project settings files the installer can write. */\n// webpieces-disable no-function-outside-class -- module-scope for the same dependency-free reason as shimCommand above\nexport function projectSettingsPaths(projectRoot: string): readonly string[] {\n return [\n path.join(projectRoot, '.claude', 'settings.json'),\n path.join(projectRoot, '.claude', 'settings.local.json'),\n ];\n}\n\n// webpieces-disable no-function-outside-class -- module-scope for the same dependency-free reason as shimCommand above\nexport function readSettings(settingsPath: string): ClaudeSettings {\n if (!fs.existsSync(settingsPath)) return {};\n const raw = fs.readFileSync(settingsPath, 'utf8');\n if (raw.trim() === '') return {};\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n return JSON.parse(raw) as ClaudeSettings;\n } catch (err: unknown) {\n const error = toError(err);\n throw new Error(`${settingsPath} has invalid JSON — fix it, then retry: ${error.message}`, { cause: error });\n }\n}\n\n// webpieces-disable no-function-outside-class -- module-scope for the same dependency-free reason as shimCommand above\nexport function writeSettings(settingsPath: string, settings: ClaudeSettings): void {\n fs.mkdirSync(path.dirname(settingsPath), { recursive: true });\n fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 4) + '\\n');\n}\n\n/** True when either project settings file under `root` carries a stale registration. */\n// webpieces-disable no-function-outside-class -- module-scope for the same dependency-free reason as shimCommand above\nexport function registrationStaleAt(root: string | null): boolean {\n if (root === null) return false;\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n return projectSettingsPaths(root).some((p: string): boolean => registrationStale(readSettings(p)));\n } catch (err: unknown) {\n const error = toError(err);\n void error; // best-effort: unreadable/invalid settings counts as \"not stale\" so it never wedges a call\n return false;\n }\n}\n\n/** Rewrite every stale project settings file under `root`; returns the paths actually changed. */\n// webpieces-disable no-function-outside-class -- module-scope for the same dependency-free reason as shimCommand above\nexport function repairRegistrationAt(root: string): readonly string[] {\n const changed: string[] = [];\n for (const settingsPath of projectSettingsPaths(root)) {\n if (!fs.existsSync(settingsPath)) continue;\n const settings = readSettings(settingsPath);\n if (!repairRegistration(settings)) continue;\n writeSettings(settingsPath, settings);\n changed.push(settingsPath);\n }\n return changed;\n}\n\n/** The three names the drift check reports, so a deny can say WHICH of them moved. */\nexport const SHIM_SURFACE = SHIM_MARKER;\nexport const GUARANTEE_ROOT_SURFACE = GUARANTEE_ROOT_MARKER;\nexport const REGISTRATION_SURFACE = '.claude/settings.json hook registration';\n\n/**\n * WHICH of the three managed surfaces disagree with this release — the input to fault S.\n *\n * All three are checked against the SAME root, resolved from the RUNNING MODULE (governingShimRoot),\n * never from cwd and never from `$CLAUDE_PROJECT_DIR`: the files we compare and the renderers we\n * compare them TO must come from one install, or the check straddles two trees and can never converge.\n */\n// webpieces-disable no-function-outside-class -- module-scope for the same dependency-free reason as shimCommand above\nexport function managedSurfaceDrift(root: string | null): readonly string[] {\n const drifted: string[] = [];\n if (committedShimStale(root)) drifted.push(SHIM_SURFACE);\n if (committedGuaranteeRootStale(root) || guaranteeRootRegisteredButMissing(root)) drifted.push(GUARANTEE_ROOT_SURFACE);\n if (registrationStaleAt(root)) drifted.push(REGISTRATION_SURFACE);\n return drifted;\n}\n\n/**\n * The L-1 hook is REGISTERED but its file is gone.\n *\n * `committedGuaranteeRootStale()` answers false for a missing file on purpose — a repo that has not\n * adopted L-1 yet is not \"stale\", it is simply still on the old registration, and that case is already\n * reported by `registrationStaleAt()`. But a settings file that REGISTERS the hook while the file is\n * absent is the worst case of all: the hook cannot launch, exit 127 is a NON-BLOCKING error, and per\n * the hooks reference the tool call proceeds — every `cd` unjudged, with nothing surfaced. The\n * registration is what distinguishes \"not adopted\" from \"adopted and broken\", so it is what is asked.\n */\n// webpieces-disable no-function-outside-class -- module-scope for the same dependency-free reason as shimCommand above\nfunction guaranteeRootRegisteredButMissing(root: string | null): boolean {\n if (root === null) return false;\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n const registered = projectSettingsPaths(root).some((p: string): boolean =>\n managedEntries(readSettings(p)).some((e: HookRegistrationEntry): boolean => e.command === GUARANTEE_ROOT_COMMAND));\n return registered && !fs.existsSync(guaranteeRootPath(root));\n } catch (err: unknown) {\n const error = toError(err);\n void error; // best-effort: unreadable settings counts as \"not drifted\" so it never wedges a call\n return false;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"hook-registration.js","sourceRoot":"","sources":["../../../../../../packages/tooling/ai-hook-rules/src/bin/hook-registration.ts"],"names":[],"mappings":"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","sourcesContent":["import * as fs from 'fs';\nimport * as path from 'path';\n\nimport { toError } from '../core/to-error';\nimport { SHIM_MARKER, committedShimStale } from './shim';\nimport { GUARANTEE_ROOT_MARKER, committedGuaranteeRootStale, guaranteeRootPath } from './guarantee-root';\nimport { BASH_CWD_ENV_KEY, BASH_CWD_ENV_VALUE } from './managed-env';\n\n/**\n * THE INSTALLED HOOK SURFACE — three hooks, and the ONE place their spelling is defined.\n *\n * ─── Why three, and why two of them are RELATIVE ───────────────────────────────────────────────────\n * `.claude/settings.json` used to register two hooks, BOTH absolute via `$CLAUDE_PROJECT_DIR`. That\n * variable NEVER moves — proven from four separate worktrees' own logs, every line reading\n * `root=<worktree> projectDir=<primary>` — so every tree was governed by the PRIMARY's shim, the\n * PRIMARY's binary and the PRIMARY's pin, forever. A worktree could never be judged by the release its\n * own branch pins, and measuring one tree while running another's binary is the non-convergent\n * \"two-tree straddle\" recorded in shim.ts (an agent gave up after four cures).\n *\n * The hooks reference says \"the hook runs in the `cwd` value from the JSON input\", so a RELATIVE\n * command resolves against the tool call's own tree. Hence:\n *\n * H1 absolute sh \"$CLAUDE_PROJECT_DIR/.claude/webpieces/guarantee-root.sh\" matcher Bash\n * H2 relative sh \".claude/webpieces/ai-hook.sh\" wp-ai-guards-hook matcher Write|…|Read\n * H3 relative sh \".claude/webpieces/ai-hook.sh\" wp-ai-rules-hook matcher Write|Edit|MultiEdit\n *\n * H1 stays absolute because it is the one hook that must ALWAYS resolve: a relative hook that cannot\n * resolve exits 127, and per the same reference any non-2 non-zero exit is a NON-BLOCKING error — i.e.\n * a SILENT UNGUARDED ALLOW. H1 refuses any `cd` that would park the shell where H2/H3 cannot launch,\n * which is what makes the relative pair admissible at all. See guarantee-root.ts.\n *\n * H1 matches `Bash` alone because only Bash can move the shell — the same reason stated at the top of\n * guarantee-root.ts, and the reason the rendered guarantee-root.sh exits 0 immediately for every other\n * tool. Registering it wider would spawn a process per Write/Read to do nothing.\n *\n * ─── Why the registration is a DRIFT SURFACE, not just an install step ─────────────────────────────\n * Nothing used to validate `.claude/settings.json` at all, so a settings file left on the old\n * two-absolute-hook form silently reverted a repo to per-PRIMARY governance and disabled H1 — the one\n * component whose whole job is failing closed. The installed surface is therefore FOUR things\n * (ai-hook.sh, guarantee-root.sh, the registration, and the managed `env` entry — see managed-env.ts for\n * what that fourth one is and why it is guard integrity rather than ergonomics), all four are compared\n * against this release, and `wp-upgrade-shim` regenerates all four. A cure that fixes three of four is\n * worse than no cure, because it reports success.\n */\n\n/** One PreToolUse hook entry as webpieces registers it. Data-only → a class, per CLAUDE.md. */\nexport class HookRegistrationEntry {\n constructor(\n readonly matcher: string,\n readonly command: string,\n ) {}\n\n sameAs(other: HookRegistrationEntry): boolean {\n return this.matcher === other.matcher && this.command === other.command;\n }\n}\n\n// webpieces-disable no-any-unknown -- settings.json is opaque consumer JSON\nexport interface HookCommand { type: string; command: string; }\nexport interface HookEntry { matcher: string; hooks: HookCommand[]; }\nexport interface ClaudeSettings {\n hooks?: { PreToolUse?: HookEntry[] };\n // Claude Code's settings `env` block: every key is exported into the environment of the session AND\n // of every subagent it spawns. That inheritance is precisely why webpieces pins its managed entry\n // here rather than in a shell profile — see managed-env.ts.\n env?: Record<string, string>;\n // webpieces-disable no-any-unknown -- opaque settings bag; arbitrary keys allowed\n [key: string]: unknown;\n}\n\nexport const RULES_BIN = 'wp-ai-rules-hook';\nexport const GUARDS_BIN = 'wp-ai-guards-hook';\nexport const RULES_MATCHER = 'Write|Edit|MultiEdit';\n// Guards match Bash (git/PR guards), Write|Edit|MultiEdit (file-scoped guards) AND Read — Read carries\n// no guard, but the guards hook owns the per-invocation audit log, so matching Read records every file\n// the AI opens (log-and-allow fast path in hook-core.ts; a Read is never blocked).\nexport const GUARDS_MATCHER = 'Write|Edit|MultiEdit|Bash|Read';\n// Only Bash can move the shell, and moving the shell is the only thing H1 judges.\nexport const GUARANTEE_ROOT_MATCHER = 'Bash';\n\n/**\n * The RELATIVE guard-hook command — `sh \".claude/webpieces/ai-hook.sh\" <bin>`.\n *\n * Relative, NOT `$CLAUDE_PROJECT_DIR/…`: that is the whole point (see the header). Invoked via `sh\n * <file>` rather than executed directly so a missing executable bit on the checked-in shim (fresh\n * clone, a filesystem that drops the bit, git core.fileMode quirks) can never break the hook with a raw\n * `Permission denied` on every tool call. Quoted to survive spaces in the path.\n */\n// webpieces-disable no-function-outside-class -- this module must load on a tree too broken to build a DI container (upgrade-shim.ts depends on that), so it is module-scope like its siblings shim.ts / guarantee-root.ts\nexport function shimCommand(bin: string): string {\n return `sh \"${SHIM_MARKER}\" ${bin}`;\n}\n\n/** H1's command. ABSOLUTE on purpose — it must resolve from ANY cwd or it cannot fail closed. */\nexport const GUARANTEE_ROOT_COMMAND = `sh \"$CLAUDE_PROJECT_DIR/${GUARANTEE_ROOT_MARKER}\"`;\n\nexport const GUARANTEE_ROOT_ENTRY = new HookRegistrationEntry(GUARANTEE_ROOT_MATCHER, GUARANTEE_ROOT_COMMAND);\n\n/** The registration entry for one guard bin. */\n// webpieces-disable no-function-outside-class -- module-scope for the same dependency-free reason as shimCommand above\nexport function guardHookEntry(bin: string): HookRegistrationEntry {\n return new HookRegistrationEntry(bin === RULES_BIN ? RULES_MATCHER : GUARDS_MATCHER, shimCommand(bin));\n}\n\n/** True when this PreToolUse command is one webpieces owns (either .sh file, in any spelling). */\n// webpieces-disable no-function-outside-class -- module-scope for the same dependency-free reason as shimCommand above\nexport function isManagedCommand(command: string): boolean {\n return command.includes(SHIM_MARKER) || command.includes(GUARANTEE_ROOT_MARKER);\n}\n\n// webpieces-disable no-function-outside-class -- module-scope for the same dependency-free reason as shimCommand above\nfunction preToolUse(settings: ClaudeSettings): readonly HookEntry[] {\n return settings.hooks?.PreToolUse ?? [];\n}\n\n/** Every webpieces-managed entry of one settings file, flattened to matcher + command pairs. */\n// webpieces-disable no-function-outside-class -- module-scope for the same dependency-free reason as shimCommand above\nexport function managedEntries(settings: ClaudeSettings): readonly HookRegistrationEntry[] {\n const found: HookRegistrationEntry[] = [];\n for (const entry of preToolUse(settings)) {\n for (const hook of entry.hooks) {\n if (isManagedCommand(hook.command)) found.push(new HookRegistrationEntry(entry.matcher, hook.command));\n }\n }\n return found;\n}\n\n/**\n * Which guard bins this settings file registers, in installer order. A file registering NEITHER is not\n * a project (relative) install and is therefore never judged — a global/absolute install names the bin\n * path directly and carries no shim marker at all.\n */\n// webpieces-disable no-function-outside-class -- module-scope for the same dependency-free reason as shimCommand above\nexport function registeredBins(settings: ClaudeSettings): readonly string[] {\n const commands = managedEntries(settings).map((e: HookRegistrationEntry): string => e.command);\n return [GUARDS_BIN, RULES_BIN].filter((bin: string): boolean => commands.some((c: string): boolean => c.includes(bin)));\n}\n\n/**\n * The exact set of entries THIS RELEASE expects in a settings file that registers `bins`.\n *\n * H1 rides with the GUARDS hook, not the rules hook: H1 judges Bash, and `Bash` is in the guards\n * matcher. A file carrying only the rules hook (the supported split install, where a team ships the\n * guards and a developer keeps the code-style rules local) gets no H1 and needs none.\n */\n// webpieces-disable no-function-outside-class -- module-scope for the same dependency-free reason as shimCommand above\nexport function expectedEntries(bins: readonly string[]): readonly HookRegistrationEntry[] {\n const wanted: HookRegistrationEntry[] = [];\n if (bins.includes(GUARDS_BIN)) wanted.push(GUARANTEE_ROOT_ENTRY);\n for (const bin of bins) wanted.push(guardHookEntry(bin));\n return wanted;\n}\n\n/**\n * True when a settings file registers webpieces hooks in a shape this release does not expect — the\n * old two-absolute-hook form, a missing guarantee-root entry, a stray duplicate, a wrong matcher.\n *\n * Compared as a SET, not a sequence: Claude Code runs all matching hooks in parallel, so array order\n * carries no meaning and reordering must not read as drift.\n */\n// webpieces-disable no-function-outside-class -- module-scope for the same dependency-free reason as shimCommand above\nexport function registrationStale(settings: ClaudeSettings): boolean {\n const bins = registeredBins(settings);\n if (bins.length === 0) return false;\n const have = managedEntries(settings);\n const want = expectedEntries(bins);\n if (have.length !== want.length) return true;\n return want.some((w: HookRegistrationEntry): boolean => !have.some((h: HookRegistrationEntry): boolean => h.sameAs(w)));\n}\n\n/** Drop every webpieces-managed PreToolUse command; returns true if anything was removed. */\n// webpieces-disable no-function-outside-class -- module-scope for the same dependency-free reason as shimCommand above\nexport function dropManagedEntries(settings: ClaudeSettings): boolean {\n const entries = settings.hooks?.PreToolUse;\n if (!entries) return false;\n let changed = false;\n const kept: HookEntry[] = [];\n for (const entry of entries) {\n const hooks = entry.hooks.filter((h: HookCommand): boolean => !isManagedCommand(h.command));\n if (hooks.length !== entry.hooks.length) changed = true;\n if (hooks.length > 0) kept.push({ matcher: entry.matcher, hooks });\n }\n if (changed) settings.hooks!.PreToolUse = kept;\n return changed;\n}\n\n/** Append one PreToolUse entry. */\n// webpieces-disable no-function-outside-class -- module-scope for the same dependency-free reason as shimCommand above\nexport function addHookEntry(settings: ClaudeSettings, entry: HookRegistrationEntry): void {\n if (!settings.hooks) settings.hooks = {};\n if (!Array.isArray(settings.hooks.PreToolUse)) settings.hooks.PreToolUse = [];\n settings.hooks.PreToolUse.push({ matcher: entry.matcher, hooks: [{ type: 'command', command: entry.command }] });\n}\n\n/** The settings `env` block, or null when the file carries none (or carries junk in its place). */\n// webpieces-disable no-function-outside-class -- module-scope for the same dependency-free reason as shimCommand above\nfunction settingsEnv(settings: ClaudeSettings): Record<string, string> | null {\n // webpieces-disable no-any-unknown -- settings.json is opaque consumer JSON; `env` is only typed after this check\n const env: unknown = settings.env;\n if (typeof env !== 'object' || env === null || Array.isArray(env)) return null;\n return env as Record<string, string>;\n}\n\n/**\n * True when a settings file that registers webpieces hooks is missing the managed `env` entry, or\n * carries any value other than the one required one.\n *\n * Gated on `registeredBins()` for the SAME reason `registrationStale()` is: a settings file that\n * registers no webpieces hooks is not a project install and is never judged. A global (absolute)\n * install names the bin path directly and has no relative resolution to protect, so an `env` entry\n * there is nothing this release governs.\n */\n// webpieces-disable no-function-outside-class -- module-scope for the same dependency-free reason as shimCommand above\nexport function envStale(settings: ClaudeSettings): boolean {\n if (registeredBins(settings).length === 0) return false;\n const env = settingsEnv(settings);\n return env === null || env[BASH_CWD_ENV_KEY] !== BASH_CWD_ENV_VALUE;\n}\n\n/**\n * Set the managed `env` entry IN PLACE, whatever was there before. Returns true when it changed.\n *\n * A user-set `\"0\"` is BROUGHT TO `\"1\"`, not honoured: this is a managed surface, and \"webpieces sets it\n * unless you disagreed\" would be a second, invisible spelling of the decision. Turning it off means\n * uninstalling the hooks, exactly as it does for every other managed thing.\n *\n * UNGATED on purpose — the installer calls it for the file it is writing hooks into, and the gate lives\n * at the caller (repairRegistration / applyHook), so a file with no webpieces hooks is never touched.\n */\n// webpieces-disable no-function-outside-class -- module-scope for the same dependency-free reason as shimCommand above\nexport function applyManagedEnv(settings: ClaudeSettings): boolean {\n const existing = settingsEnv(settings);\n if (existing !== null && existing[BASH_CWD_ENV_KEY] === BASH_CWD_ENV_VALUE) return false;\n const env = existing ?? {};\n env[BASH_CWD_ENV_KEY] = BASH_CWD_ENV_VALUE;\n settings.env = env;\n return true;\n}\n\n/**\n * Bring one settings object to the three-hook form AND the managed `env` entry IN PLACE. Returns true\n * when it changed anything.\n *\n * REMOVE-then-ADD for the hooks, never add-beside: two spellings of one registration is exactly the\n * compatibility shim the backwards-compat reviewer rejects, and leaving the `$CLAUDE_PROJECT_DIR/`-\n * prefixed entry beside the relative one would run the PRIMARY's binary alongside the tree's own — the\n * straddle this whole change exists to delete.\n *\n * THE TWO REPAIRS ARE EVALUATED INDEPENDENTLY, and that is load-bearing rather than tidy: this used to\n * early-return on `!registrationStale(settings)`, so a repo whose hooks are already current but whose\n * `env` entry is missing — the state EVERY existing consumer is in the moment this release lands — would\n * have been reported as drifted by fault S and then left unrepaired by its own prescribed cure. A cure\n * that skips half the surface is the failure mode `upgrade-shim.ts`'s header exists to prevent.\n */\n// webpieces-disable no-function-outside-class -- module-scope for the same dependency-free reason as shimCommand above\nexport function repairRegistration(settings: ClaudeSettings): boolean {\n const bins = registeredBins(settings);\n if (bins.length === 0) return false;\n let changed = false;\n if (registrationStale(settings)) {\n dropManagedEntries(settings);\n for (const entry of expectedEntries(bins)) addHookEntry(settings, entry);\n changed = true;\n }\n if (applyManagedEnv(settings)) changed = true;\n return changed;\n}\n\n/** The two project settings files the installer can write. */\n// webpieces-disable no-function-outside-class -- module-scope for the same dependency-free reason as shimCommand above\nexport function projectSettingsPaths(projectRoot: string): readonly string[] {\n return [\n path.join(projectRoot, '.claude', 'settings.json'),\n path.join(projectRoot, '.claude', 'settings.local.json'),\n ];\n}\n\n// webpieces-disable no-function-outside-class -- module-scope for the same dependency-free reason as shimCommand above\nexport function readSettings(settingsPath: string): ClaudeSettings {\n if (!fs.existsSync(settingsPath)) return {};\n const raw = fs.readFileSync(settingsPath, 'utf8');\n if (raw.trim() === '') return {};\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n return JSON.parse(raw) as ClaudeSettings;\n } catch (err: unknown) {\n const error = toError(err);\n throw new Error(`${settingsPath} has invalid JSON — fix it, then retry: ${error.message}`, { cause: error });\n }\n}\n\n// webpieces-disable no-function-outside-class -- module-scope for the same dependency-free reason as shimCommand above\nexport function writeSettings(settingsPath: string, settings: ClaudeSettings): void {\n fs.mkdirSync(path.dirname(settingsPath), { recursive: true });\n fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 4) + '\\n');\n}\n\n/** True when either project settings file under `root` carries a stale registration. */\n// webpieces-disable no-function-outside-class -- module-scope for the same dependency-free reason as shimCommand above\nexport function registrationStaleAt(root: string | null): boolean {\n if (root === null) return false;\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n return projectSettingsPaths(root).some((p: string): boolean => registrationStale(readSettings(p)));\n } catch (err: unknown) {\n const error = toError(err);\n void error; // best-effort: unreadable/invalid settings counts as \"not stale\" so it never wedges a call\n return false;\n }\n}\n\n/** True when either project settings file under `root` is missing the managed `env` entry. */\n// webpieces-disable no-function-outside-class -- module-scope for the same dependency-free reason as shimCommand above\nexport function envStaleAt(root: string | null): boolean {\n if (root === null) return false;\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n return projectSettingsPaths(root).some((p: string): boolean => envStale(readSettings(p)));\n } catch (err: unknown) {\n const error = toError(err);\n void error; // best-effort: unreadable/invalid settings counts as \"not stale\" so it never wedges a call\n return false;\n }\n}\n\n/**\n * WHAT was rewritten in ONE settings file. Data-only → a class, per CLAUDE.md.\n *\n * Two independent flags rather than one path, because the cure has to be able to SAY which repair it\n * made: \"rewrote the hook registration\" printed for a file whose registration was already current and\n * whose `env` entry was the only thing missing is a cure lying about its own work.\n */\nexport class SettingsRepair {\n constructor(\n readonly settingsPath: string,\n readonly registration: boolean,\n readonly env: boolean,\n ) {}\n}\n\n/** Rewrite every stale project settings file under `root`; returns what changed, per file. */\n// webpieces-disable no-function-outside-class -- module-scope for the same dependency-free reason as shimCommand above\nexport function repairRegistrationAt(root: string): readonly SettingsRepair[] {\n const repairs: SettingsRepair[] = [];\n for (const settingsPath of projectSettingsPaths(root)) {\n if (!fs.existsSync(settingsPath)) continue;\n const settings = readSettings(settingsPath);\n const neededRegistration = registrationStale(settings);\n const neededEnv = envStale(settings);\n if (!repairRegistration(settings)) continue;\n writeSettings(settingsPath, settings);\n repairs.push(new SettingsRepair(settingsPath, neededRegistration, neededEnv));\n }\n return repairs;\n}\n\n/** The four names the drift check reports, so a deny can say WHICH of them moved. */\nexport const SHIM_SURFACE = SHIM_MARKER;\nexport const GUARANTEE_ROOT_SURFACE = GUARANTEE_ROOT_MARKER;\nexport const REGISTRATION_SURFACE = '.claude/settings.json hook registration';\nexport const ENV_SURFACE = `.claude/settings.json env.${BASH_CWD_ENV_KEY}`;\n\n/**\n * WHICH of the four managed surfaces disagree with this release — the input to fault S.\n *\n * All four are checked against the SAME root, resolved from the RUNNING MODULE (governingShimRoot),\n * never from cwd and never from `$CLAUDE_PROJECT_DIR`: the files we compare and the renderers we\n * compare them TO must come from one install, or the check straddles two trees and can never converge.\n */\n// webpieces-disable no-function-outside-class -- module-scope for the same dependency-free reason as shimCommand above\nexport function managedSurfaceDrift(root: string | null): readonly string[] {\n const drifted: string[] = [];\n if (committedShimStale(root)) drifted.push(SHIM_SURFACE);\n if (committedGuaranteeRootStale(root) || guaranteeRootRegisteredButMissing(root)) drifted.push(GUARANTEE_ROOT_SURFACE);\n if (registrationStaleAt(root)) drifted.push(REGISTRATION_SURFACE);\n if (envStaleAt(root)) drifted.push(ENV_SURFACE);\n return drifted;\n}\n\n/**\n * The L-1 hook is REGISTERED but its file is gone.\n *\n * `committedGuaranteeRootStale()` answers false for a missing file on purpose — a repo that has not\n * adopted L-1 yet is not \"stale\", it is simply still on the old registration, and that case is already\n * reported by `registrationStaleAt()`. But a settings file that REGISTERS the hook while the file is\n * absent is the worst case of all: the hook cannot launch, exit 127 is a NON-BLOCKING error, and per\n * the hooks reference the tool call proceeds — every `cd` unjudged, with nothing surfaced. The\n * registration is what distinguishes \"not adopted\" from \"adopted and broken\", so it is what is asked.\n */\n// webpieces-disable no-function-outside-class -- module-scope for the same dependency-free reason as shimCommand above\nfunction guaranteeRootRegisteredButMissing(root: string | null): boolean {\n if (root === null) return false;\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n const registered = projectSettingsPaths(root).some((p: string): boolean =>\n managedEntries(readSettings(p)).some((e: HookRegistrationEntry): boolean => e.command === GUARANTEE_ROOT_COMMAND));\n return registered && !fs.existsSync(guaranteeRootPath(root));\n } catch (err: unknown) {\n const error = toError(err);\n void error; // best-effort: unreadable settings counts as \"not drifted\" so it never wedges a call\n return false;\n }\n}\n"]}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* THE MANAGED `env` ENTRY — `CLAUDE_BASH_MAINTAIN_PROJECT_WORKING_DIR=1`, the FOURTH managed surface.
|
|
3
|
+
*
|
|
4
|
+
* Claude Code reads this variable once per Bash tool call and, when it is truthy, resets the shell's
|
|
5
|
+
* cwd back to the project directory after EVERY call. With it unset, the reset is CONDITIONAL (only
|
|
6
|
+
* when the cwd drifted to a dir that is not an allowed one) and prints a visible "Shell cwd was reset
|
|
7
|
+
* to …" notice, so an ordinary `cd` persists from one Bash call to the next. Verified against the
|
|
8
|
+
* 2.1.226 binary, where the variable also appears in the settings-`env` allowlist beside
|
|
9
|
+
* `BASH_DEFAULT_TIMEOUT_MS` — which is what makes `.claude/settings.json` → `env` a supported home for
|
|
10
|
+
* it rather than a guess.
|
|
11
|
+
*
|
|
12
|
+
* WHY WEBPIECES MANAGES IT — it is guard integrity, not ergonomics:
|
|
13
|
+
*
|
|
14
|
+
* 1. H2/H3 are registered RELATIVE on purpose (`sh ".claude/webpieces/ai-hook.sh" <bin>`, see the
|
|
15
|
+
* header of hook-registration.ts), so each git worktree runs its own release, binary and pin. A
|
|
16
|
+
* relative hook resolves against the tool call's cwd — and a relative hook that cannot resolve
|
|
17
|
+
* exits 127, which per the Claude Code hooks reference is a NON-BLOCKING error, i.e. a SILENT
|
|
18
|
+
* UNGUARDED ALLOW. Pinning the cwd to the project root means the relative pair always resolves.
|
|
19
|
+
* H1 (guarantee-root.sh) already refuses a `cd` that would park the shell where H2/H3 cannot
|
|
20
|
+
* launch — but that is a cure AFTER the fact; this PREVENTS the drift instead.
|
|
21
|
+
* 2. Settings `env` is INHERITED, so the main agent and every subagent it spawns get the SAME cwd,
|
|
22
|
+
* hence the same relative-hook resolution, hence the same guard verdict — instead of a verdict
|
|
23
|
+
* that depends on whatever `cd` happened earlier in the session. Consistency is the point.
|
|
24
|
+
* 3. It mechanically enforces the long-standing "never `cd` into a sub-package in Bash, it persists
|
|
25
|
+
* and blocks the global hook" rule, rather than relying on an agent remembering it.
|
|
26
|
+
*
|
|
27
|
+
* THE TRADE, said out loud: with the flag ON the cwd reset is SILENT and UNCONDITIONAL, where without
|
|
28
|
+
* it the reset is conditional and prints a notice. A deliberate `cd` therefore no longer persists
|
|
29
|
+
* across Bash calls. That is the intended cost of (1) and (2), not an oversight — chain into the
|
|
30
|
+
* directory you need (`cd <dir> && <cmd>`) instead of relying on a sticky cwd.
|
|
31
|
+
*
|
|
32
|
+
* ONE spelling, one required value: the entry is either exactly `1` or it is drift. There is no
|
|
33
|
+
* "accepted alternative truthy value" and no legacy key — `envStale()` in hook-registration.ts is the
|
|
34
|
+
* whole contract, and `applyManagedEnv()` brings any other value (including a user-set `0`) to `1`.
|
|
35
|
+
*
|
|
36
|
+
* WHY THESE TWO CONSTANTS LIVE IN THEIR OWN MODULE: `shim.ts` names them in the fault-S deny text and
|
|
37
|
+
* `hook-registration.ts` owns the predicate that reads them, and hook-registration already imports
|
|
38
|
+
* shim. Defining them here — a leaf with no imports at all — keeps that graph acyclic while leaving
|
|
39
|
+
* exactly one definition of each, in the same way SHIM_MARKER lives in shim.ts.
|
|
40
|
+
*/
|
|
41
|
+
export declare const BASH_CWD_ENV_KEY = "CLAUDE_BASH_MAINTAIN_PROJECT_WORKING_DIR";
|
|
42
|
+
export declare const BASH_CWD_ENV_VALUE = "1";
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.BASH_CWD_ENV_VALUE = exports.BASH_CWD_ENV_KEY = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* THE MANAGED `env` ENTRY — `CLAUDE_BASH_MAINTAIN_PROJECT_WORKING_DIR=1`, the FOURTH managed surface.
|
|
6
|
+
*
|
|
7
|
+
* Claude Code reads this variable once per Bash tool call and, when it is truthy, resets the shell's
|
|
8
|
+
* cwd back to the project directory after EVERY call. With it unset, the reset is CONDITIONAL (only
|
|
9
|
+
* when the cwd drifted to a dir that is not an allowed one) and prints a visible "Shell cwd was reset
|
|
10
|
+
* to …" notice, so an ordinary `cd` persists from one Bash call to the next. Verified against the
|
|
11
|
+
* 2.1.226 binary, where the variable also appears in the settings-`env` allowlist beside
|
|
12
|
+
* `BASH_DEFAULT_TIMEOUT_MS` — which is what makes `.claude/settings.json` → `env` a supported home for
|
|
13
|
+
* it rather than a guess.
|
|
14
|
+
*
|
|
15
|
+
* WHY WEBPIECES MANAGES IT — it is guard integrity, not ergonomics:
|
|
16
|
+
*
|
|
17
|
+
* 1. H2/H3 are registered RELATIVE on purpose (`sh ".claude/webpieces/ai-hook.sh" <bin>`, see the
|
|
18
|
+
* header of hook-registration.ts), so each git worktree runs its own release, binary and pin. A
|
|
19
|
+
* relative hook resolves against the tool call's cwd — and a relative hook that cannot resolve
|
|
20
|
+
* exits 127, which per the Claude Code hooks reference is a NON-BLOCKING error, i.e. a SILENT
|
|
21
|
+
* UNGUARDED ALLOW. Pinning the cwd to the project root means the relative pair always resolves.
|
|
22
|
+
* H1 (guarantee-root.sh) already refuses a `cd` that would park the shell where H2/H3 cannot
|
|
23
|
+
* launch — but that is a cure AFTER the fact; this PREVENTS the drift instead.
|
|
24
|
+
* 2. Settings `env` is INHERITED, so the main agent and every subagent it spawns get the SAME cwd,
|
|
25
|
+
* hence the same relative-hook resolution, hence the same guard verdict — instead of a verdict
|
|
26
|
+
* that depends on whatever `cd` happened earlier in the session. Consistency is the point.
|
|
27
|
+
* 3. It mechanically enforces the long-standing "never `cd` into a sub-package in Bash, it persists
|
|
28
|
+
* and blocks the global hook" rule, rather than relying on an agent remembering it.
|
|
29
|
+
*
|
|
30
|
+
* THE TRADE, said out loud: with the flag ON the cwd reset is SILENT and UNCONDITIONAL, where without
|
|
31
|
+
* it the reset is conditional and prints a notice. A deliberate `cd` therefore no longer persists
|
|
32
|
+
* across Bash calls. That is the intended cost of (1) and (2), not an oversight — chain into the
|
|
33
|
+
* directory you need (`cd <dir> && <cmd>`) instead of relying on a sticky cwd.
|
|
34
|
+
*
|
|
35
|
+
* ONE spelling, one required value: the entry is either exactly `1` or it is drift. There is no
|
|
36
|
+
* "accepted alternative truthy value" and no legacy key — `envStale()` in hook-registration.ts is the
|
|
37
|
+
* whole contract, and `applyManagedEnv()` brings any other value (including a user-set `0`) to `1`.
|
|
38
|
+
*
|
|
39
|
+
* WHY THESE TWO CONSTANTS LIVE IN THEIR OWN MODULE: `shim.ts` names them in the fault-S deny text and
|
|
40
|
+
* `hook-registration.ts` owns the predicate that reads them, and hook-registration already imports
|
|
41
|
+
* shim. Defining them here — a leaf with no imports at all — keeps that graph acyclic while leaving
|
|
42
|
+
* exactly one definition of each, in the same way SHIM_MARKER lives in shim.ts.
|
|
43
|
+
*/
|
|
44
|
+
exports.BASH_CWD_ENV_KEY = 'CLAUDE_BASH_MAINTAIN_PROJECT_WORKING_DIR';
|
|
45
|
+
exports.BASH_CWD_ENV_VALUE = '1';
|
|
46
|
+
//# sourceMappingURL=managed-env.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"managed-env.js","sourceRoot":"","sources":["../../../../../../packages/tooling/ai-hook-rules/src/bin/managed-env.ts"],"names":[],"mappings":";;;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACU,QAAA,gBAAgB,GAAG,0CAA0C,CAAC;AAC9D,QAAA,kBAAkB,GAAG,GAAG,CAAC","sourcesContent":["/**\n * THE MANAGED `env` ENTRY — `CLAUDE_BASH_MAINTAIN_PROJECT_WORKING_DIR=1`, the FOURTH managed surface.\n *\n * Claude Code reads this variable once per Bash tool call and, when it is truthy, resets the shell's\n * cwd back to the project directory after EVERY call. With it unset, the reset is CONDITIONAL (only\n * when the cwd drifted to a dir that is not an allowed one) and prints a visible \"Shell cwd was reset\n * to …\" notice, so an ordinary `cd` persists from one Bash call to the next. Verified against the\n * 2.1.226 binary, where the variable also appears in the settings-`env` allowlist beside\n * `BASH_DEFAULT_TIMEOUT_MS` — which is what makes `.claude/settings.json` → `env` a supported home for\n * it rather than a guess.\n *\n * WHY WEBPIECES MANAGES IT — it is guard integrity, not ergonomics:\n *\n * 1. H2/H3 are registered RELATIVE on purpose (`sh \".claude/webpieces/ai-hook.sh\" <bin>`, see the\n * header of hook-registration.ts), so each git worktree runs its own release, binary and pin. A\n * relative hook resolves against the tool call's cwd — and a relative hook that cannot resolve\n * exits 127, which per the Claude Code hooks reference is a NON-BLOCKING error, i.e. a SILENT\n * UNGUARDED ALLOW. Pinning the cwd to the project root means the relative pair always resolves.\n * H1 (guarantee-root.sh) already refuses a `cd` that would park the shell where H2/H3 cannot\n * launch — but that is a cure AFTER the fact; this PREVENTS the drift instead.\n * 2. Settings `env` is INHERITED, so the main agent and every subagent it spawns get the SAME cwd,\n * hence the same relative-hook resolution, hence the same guard verdict — instead of a verdict\n * that depends on whatever `cd` happened earlier in the session. Consistency is the point.\n * 3. It mechanically enforces the long-standing \"never `cd` into a sub-package in Bash, it persists\n * and blocks the global hook\" rule, rather than relying on an agent remembering it.\n *\n * THE TRADE, said out loud: with the flag ON the cwd reset is SILENT and UNCONDITIONAL, where without\n * it the reset is conditional and prints a notice. A deliberate `cd` therefore no longer persists\n * across Bash calls. That is the intended cost of (1) and (2), not an oversight — chain into the\n * directory you need (`cd <dir> && <cmd>`) instead of relying on a sticky cwd.\n *\n * ONE spelling, one required value: the entry is either exactly `1` or it is drift. There is no\n * \"accepted alternative truthy value\" and no legacy key — `envStale()` in hook-registration.ts is the\n * whole contract, and `applyManagedEnv()` brings any other value (including a user-set `0`) to `1`.\n *\n * WHY THESE TWO CONSTANTS LIVE IN THEIR OWN MODULE: `shim.ts` names them in the fault-S deny text and\n * `hook-registration.ts` owns the predicate that reads them, and hook-registration already imports\n * shim. Defining them here — a leaf with no imports at all — keeps that graph acyclic while leaving\n * exactly one definition of each, in the same way SHIM_MARKER lives in shim.ts.\n */\nexport const BASH_CWD_ENV_KEY = 'CLAUDE_BASH_MAINTAIN_PROJECT_WORKING_DIR';\nexport const BASH_CWD_ENV_VALUE = '1';\n"]}
|
package/src/bin/setup.js
CHANGED
|
@@ -19,6 +19,7 @@ const shim_1 = require("./shim");
|
|
|
19
19
|
Object.defineProperty(exports, "renderShim", { enumerable: true, get: function () { return shim_1.renderShim; } });
|
|
20
20
|
const guarantee_root_1 = require("./guarantee-root");
|
|
21
21
|
const hook_registration_1 = require("./hook-registration");
|
|
22
|
+
const managed_env_1 = require("./managed-env");
|
|
22
23
|
const CONFIG_FILENAME = 'webpieces.config.json';
|
|
23
24
|
// The seeded buildCommand comes from @webpieces/rules-config, NOT from a copy here. This file used to
|
|
24
25
|
// hold its own — with `--base=origin/main`, a DIFFERENT base from the one the gate documents — so a
|
|
@@ -444,6 +445,15 @@ function applyHook(hook, chosen, targets, projectRoot) {
|
|
|
444
445
|
const isChosen = chosen !== null && chosen.settingsPath === target.settingsPath;
|
|
445
446
|
if (isChosen) {
|
|
446
447
|
(0, hook_registration_1.addHookEntry)(settings, new hook_registration_1.HookRegistrationEntry(hook.matcher, hook.commandFor(target, projectRoot)));
|
|
448
|
+
// The managed `env` entry goes into the SAME file the hooks go into, on every path that
|
|
449
|
+
// writes hooks — interactive or `--target=`. It pins the Bash cwd to the project root, which
|
|
450
|
+
// is what keeps the RELATIVE guard hooks resolvable (an unresolvable hook exits 127, and per
|
|
451
|
+
// the hooks reference that is a SILENT UNGUARDED ALLOW), and settings `env` is inherited, so
|
|
452
|
+
// every subagent gets the identical cwd and therefore the identical guard verdict. See
|
|
453
|
+
// hook-registration.ts for the full argument; `wp-upgrade-shim` self-heals it afterwards.
|
|
454
|
+
if ((0, hook_registration_1.applyManagedEnv)(settings)) {
|
|
455
|
+
console.log(` ✅ env.${managed_env_1.BASH_CWD_ENV_KEY}=${managed_env_1.BASH_CWD_ENV_VALUE} → ${target.label} (pins the Bash cwd to the project root, for this session and every subagent)`);
|
|
456
|
+
}
|
|
447
457
|
(0, hook_registration_1.writeSettings)(target.settingsPath, settings);
|
|
448
458
|
console.log(` ✅ ${hook.label} → ${target.label}`);
|
|
449
459
|
}
|
package/src/bin/setup.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"setup.js","sourceRoot":"","sources":["../../../../../../packages/tooling/ai-hook-rules/src/bin/setup.ts"],"names":[],"mappings":"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","sourcesContent":["import * as fs from 'fs';\nimport * as path from 'path';\nimport { homedir } from 'os';\nimport { createInterface } from 'readline';\n\nimport { allRuleNames, seedEntryForRule, sectionForRule, isHookGuard, DEFAULT_MATCH_RULES, DEFAULT_BUILD_COMMAND, RETIRED_CONFIG_KEYS, RETIRED_SCOPE_RULE, RepoRootFinder, writeTemplate, writeTemplateIfMissing, CONFIG_POLICY_DOC } from '@webpieces/rules-config';\n\nimport { toError } from '../core/to-error';\nimport { SHIM_MARKER, shimPath, renderShim } from './shim';\nimport { GUARANTEE_ROOT_MARKER, guaranteeRootPath, writeGuaranteeRoot } from './guarantee-root';\nimport {\n ClaudeSettings, HookCommand, HookEntry, HookRegistrationEntry, GUARANTEE_ROOT_ENTRY, GUARDS_BIN,\n GUARDS_MATCHER, RULES_BIN, RULES_MATCHER, addHookEntry, readSettings, shimCommand, writeSettings,\n} from './hook-registration';\n\n// Re-exported for back-compat (setup.spec.ts + external callers). The shim body + path now live in\n// ./shim (shared with the runtime self-heal in hook-core). See shim.ts for the single source of truth.\nexport { renderShim };\n\nconst CONFIG_FILENAME = 'webpieces.config.json';\n// The seeded buildCommand comes from @webpieces/rules-config, NOT from a copy here. This file used to\n// hold its own — with `--base=origin/main`, a DIFFERENT base from the one the gate documents — so a\n// freshly set-up repo was seeded with a command that rebuilds projects touched by other people's\n// merged PRs, and whole-repo-build-guard then quoted that command back in its refusals.\nconst DEFAULT_UPSERT_PR = 'pnpm wp-start-upsert-pr';\nconst DEFAULT_MERGE_COMPLETE = 'pnpm wp-finish-upsert-pr';\n\n// ---------------------------------------------------------------------------\n// The two independently-installable GUARD hooks. Each can land in a different settings file (see\n// InstallTarget) so a team can ship the guards while a developer keeps the code-style rules local\n// while iterating. The L-1 hook is a third registration but is NOT independently installable — it\n// rides with the guards hook (applyGuaranteeRoot), because it exists to protect the RELATIVE\n// resolution of these two and is meaningless without them.\n// ---------------------------------------------------------------------------\nclass HookSpec {\n constructor(\n readonly key: string,\n readonly label: string,\n readonly matcher: string,\n readonly bin: string,\n ) {}\n\n // Absolute targets (global) need the exact path to this repo's bin — no ~/.webpieces bridge.\n // Project targets get the RELATIVE shim command (see hook-registration.ts for why relative is the\n // whole point), and the L-1 hook registered beside them is what keeps a relative path from ever\n // failing to resolve — which per the hooks reference would be a SILENT UNGUARDED ALLOW, not a block.\n commandFor(target: InstallTarget, projectRoot: string): string {\n if (target.absolute) {\n return `node ${path.join(projectRoot, 'node_modules', '.bin', this.bin)}`;\n }\n return shimCommand(this.bin);\n }\n}\n\n// Idempotent: re-running the installer overwrites the managed shim in place.\nfunction writeShim(projectRoot: string): void {\n const target = shimPath(projectRoot);\n fs.mkdirSync(path.dirname(target), { recursive: true });\n fs.writeFileSync(target, renderShim(), { mode: 0o755 });\n // writeFileSync's mode is only applied when creating the file; force it on overwrite too.\n fs.chmodSync(target, 0o755);\n}\n\nfunction removeShim(projectRoot: string): void {\n const target = shimPath(projectRoot);\n if (fs.existsSync(target)) fs.rmSync(target);\n}\n\n// A managed .sh is shared by the project hooks — only safe to delete once no project settings file\n// references it anymore (i.e. the other hook was moved to global or uninstalled too).\n// webpieces-disable no-function-outside-class -- setup.ts is deliberately DI-free (it must run on a half-written node_modules; see install-entry.ts), so every function here is module-scope\nfunction markerReferenced(targets: InstallTarget[], marker: string): boolean {\n return targets.some((t: InstallTarget) => {\n const entries = readSettings(t.settingsPath).hooks?.PreToolUse ?? [];\n return entries.some((e: HookEntry) => e.hooks.some((h: HookCommand) => h.command.includes(marker)));\n });\n}\n\n// webpieces-disable no-function-outside-class -- setup.ts is deliberately DI-free (it must run on a half-written node_modules; see install-entry.ts), so every function here is module-scope\nfunction removeGuaranteeRootFile(projectRoot: string): void {\n const target = guaranteeRootPath(projectRoot);\n if (fs.existsSync(target)) fs.rmSync(target);\n}\n\n// Drop every PreToolUse command referencing the L-1 hook; returns true if anything was removed.\n// webpieces-disable no-function-outside-class -- setup.ts is deliberately DI-free (it must run on a half-written node_modules; see install-entry.ts), so every function here is module-scope\nfunction removeGuaranteeRootHook(settings: ClaudeSettings): boolean {\n return removeHookByMarker(settings, GUARANTEE_ROOT_MARKER);\n}\n\n/**\n * Install / move / uninstall the L-1 hook (guarantee-root.sh) alongside the GUARDS hook.\n *\n * It rides with the guards hook and not the rules hook because it judges `cd`, `cd` arrives on Bash,\n * and `Bash` is in the guards matcher. It is registered ABSOLUTE while the guard hooks are RELATIVE —\n * that asymmetry is the design, not an oversight (hook-registration.ts states it once).\n *\n * A GLOBAL (absolute) install gets none: those hooks name the bin path directly, so there is no\n * relative path that could fail to resolve, which is the only thing L-1 protects against.\n */\n// webpieces-disable no-function-outside-class -- setup.ts is deliberately DI-free (it must run on a half-written node_modules; see install-entry.ts), so every function here is module-scope\nfunction applyGuaranteeRoot(chosen: InstallTarget | null, targets: InstallTarget[], projectRoot: string): void {\n const relative = chosen !== null && !chosen.absolute;\n for (const target of targets) {\n const settings = readSettings(target.settingsPath);\n const removed = removeGuaranteeRootHook(settings);\n if (relative && chosen.settingsPath === target.settingsPath) {\n addHookEntry(settings, GUARANTEE_ROOT_ENTRY);\n writeSettings(target.settingsPath, settings);\n console.log(` ✅ L-1 guarantee-root hook (keeps the shell where the relative guard hooks can launch) → ${target.label}`);\n } else if (removed) {\n writeSettings(target.settingsPath, settings);\n }\n }\n if (relative) writeGuaranteeRoot(projectRoot);\n else if (!markerReferenced(targets, GUARANTEE_ROOT_MARKER)) removeGuaranteeRootFile(projectRoot);\n}\n\nexport class InstallTarget {\n constructor(\n readonly choice: string,\n readonly label: string,\n readonly settingsPath: string,\n readonly absolute: boolean,\n ) {}\n}\n\n// The matchers and bin names come from ./hook-registration, which is also what the drift check and\n// wp-upgrade-shim compare against — one spelling of the registration, or the installer and the\n// validator can disagree about what \"installed\" means.\nexport const RULES_HOOK = new HookSpec('rules', 'Rules hook (code-style validation)', RULES_MATCHER, RULES_BIN);\nexport const GUARDS_HOOK = new HookSpec('guards', 'Guards hook (git/PR/branch protection)', GUARDS_MATCHER, GUARDS_BIN);\n\n// `homeDir` is injectable so tests can point the global target at a temp dir instead of the real\n// ~/.claude/settings.json (a unit test must never write the user's actual global settings).\nexport function installTargets(projectRoot: string, homeDir: string = homedir()): InstallTarget[] {\n return [\n new InstallTarget('1', 'project (.claude/settings.json — committed, for the team)',\n path.join(projectRoot, '.claude', 'settings.json'), false),\n new InstallTarget('2', 'project for you (.claude/settings.local.json — personal)',\n path.join(projectRoot, '.claude', 'settings.local.json'), false),\n new InstallTarget('3', 'global (~/.claude/settings.json — exact path, this repo only)',\n path.join(homeDir, '.claude', 'settings.json'), true),\n ];\n}\n\n// ---------------------------------------------------------------------------\n// webpieces.config.json seeding + migration to the rules / hookGuards / commands layout.\n// ---------------------------------------------------------------------------\n// webpieces-disable no-any-unknown -- webpieces.config.json / settings.json are opaque consumer JSON\ntype Json = Record<string, unknown>;\ntype RuleEntry = Json;\ntype Section = Record<string, RuleEntry>;\n\ninterface ConfigFile {\n extends?: string;\n rules: Section;\n hookGuards: Section;\n commands: Json;\n excludePaths: string[];\n 'match-rules': Json[];\n rulesDir: string[];\n}\n\ninterface MigrateResult {\n config: ConfigFile;\n changes: string[];\n}\n\n// webpieces-disable no-function-outside-class -- sibling of the other seed* helpers; this module is config-shape builders by design\nfunction seedRule(ruleName: string): RuleEntry {\n // Both escape hatches are seeded (and REQUIRED) so every rule block shows them: 0 = active,\n // null = no branch scoping. A human/AI edits these to time-box or branch-scope a rule off.\n //\n // The ENTIRE entry comes from rules-config's seedEntryForRule() — the same module that owns the\n // schema the loader validates against, so the installer can never emit an entry the loader\n // rejects. It supplies: the recommended mode (the SAME recommendation the validator prints in its\n // copy-paste snippet, so seed and advice cannot disagree), both hatches, and a default for every\n // other schema-REQUIRED field. Seeding used to be a flat 'OFF' plus the two hatches, which was\n // wrong twice over: adopters got nothing enforced, AND the entry was missing required fields\n // (e.g. branch-creation-guard.autoReapMergedBranches), so the config failed to load on first run.\n return seedEntryForRule(ruleName);\n}\n\n// The guard-hint command strings live under `guardHints`. The flat `upsertPr`/`mergeComplete` keys this\n// used to seed are RETIRED and now fail validation — seeding them meant every freshly installed repo was\n// born on a shape the validator rejects.\nfunction seedCommands(): Json {\n return {\n 'pr-gate': { mode: 'OFF', buildCommand: DEFAULT_BUILD_COMMAND, gates: [] },\n guardHints: { prCreationOrPush: DEFAULT_UPSERT_PR, mergeInProgress: DEFAULT_MERGE_COMPLETE },\n };\n}\n\n// Required excludePaths block: ONE glob list suppressing hook enforcement per file path. Seeded empty\n// (enforce everywhere) — a client adds paths (e.g. \"repositories/**\") to exempt vendored trees.\n// webpieces-disable no-function-outside-class -- sibling of the other seed* helpers; this module is config-shape builders by design\nfunction seedExcludePaths(): string[] {\n return [];\n}\n\n// Bring an existing `excludePaths` forward to the single-list shape. Already a list → untouched.\n// Legacy `{ rules, guards }` → unioned (order preserved, duplicates dropped) and recorded as a change\n// so `wp-install-ai-hooks` is the migration path rather than a hand-edit. Anything else → seeded [].\n// webpieces-disable no-any-unknown -- `raw` is opaque consumer JSON until narrowed here\n// webpieces-disable no-function-outside-class -- sibling of the other seed*/migrate* helpers; this module is config-shape builders by design\nfunction migrateExcludePaths(raw: unknown, changes: string[]): string[] {\n if (Array.isArray(raw)) return (raw as string[]).filter(p => typeof p === 'string');\n if (typeof raw === 'object' && raw !== null) {\n // webpieces-disable no-any-unknown -- narrowing the opaque legacy block from consumer JSON\n const legacy = raw as Record<string, unknown>;\n const rules = Array.isArray(legacy['rules']) ? (legacy['rules'] as string[]) : [];\n const guards = Array.isArray(legacy['guards']) ? (legacy['guards'] as string[]) : [];\n const merged = [...new Set([...rules, ...guards].filter(p => typeof p === 'string'))];\n changes.push(`migrated excludePaths {rules,guards} -> one list (${merged.length} path(s))`);\n return merged;\n }\n changes.push('added excludePaths ([])');\n return [];\n}\n\n/** One retired flat command string and the guardHints field it becomes. Data-only (per CLAUDE.md). */\nclass GuardHintMove {\n retiredKey: string;\n hintKey: string;\n fallback: string;\n\n constructor(retiredKey: string, hintKey: string, fallback: string) {\n this.retiredKey = retiredKey;\n this.hintKey = hintKey;\n this.fallback = fallback;\n }\n}\n\n/**\n * Bring `commands` forward to the `guardHints` shape, moving the RETIRED flat `upsertPr`/`mergeComplete`\n * strings and DELETING them. Deleting is the point: the validator now rejects them, so leaving them behind\n * would keep the config failing after a \"successful\" sync.\n *\n * The consumer's own value wins over the default — a repo that renamed its gated command keeps that name.\n */\n// webpieces-disable no-function-outside-class -- sibling of the other seed*/migrate* helpers; this module is config-shape builders by design\nfunction migrateGuardHints(commands: Json, changes: string[]): void {\n const hints: Json = (typeof commands['guardHints'] === 'object' && commands['guardHints'] !== null)\n ? (commands['guardHints'] as Json) : {};\n const moves: readonly GuardHintMove[] = [\n new GuardHintMove('upsertPr', 'prCreationOrPush', DEFAULT_UPSERT_PR),\n new GuardHintMove('mergeComplete', 'mergeInProgress', DEFAULT_MERGE_COMPLETE),\n ];\n for (const move of moves) {\n const retiredKey = move.retiredKey;\n const hintKey = move.hintKey;\n const fallback = move.fallback;\n const carried = commands[retiredKey];\n if (carried !== undefined) {\n delete commands[retiredKey];\n if (hints[hintKey] === undefined) hints[hintKey] = carried;\n changes.push(`moved retired commands.${retiredKey} -> commands.guardHints.${hintKey}`);\n }\n if (hints[hintKey] === undefined) {\n hints[hintKey] = fallback;\n changes.push(`added commands.guardHints.${hintKey}`);\n }\n }\n commands['guardHints'] = hints;\n}\n\n/**\n * Apply the RETIRED rule/guard retirements in place. These used to be rewritten silently at load time, so\n * a consumer's file kept the dead name forever; the loader now rejects it, which makes this the one\n * command that can fix the file. Skips a rename when the new name is already configured, so an explicit\n * entry is never clobbered by a stale one.\n *\n * NOT EVERY RETIREMENT IS A RENAME, and treating them all as one produced garbage. `whole-repo-build-guard`\n * moved OUT of webpieces.config.json entirely — its `movedTo` is the PROSE destination\n * `~/.webpieces/config.json → experimental.whole-repo-build-guard`, not a sibling key — so the rename\n * branch below would have created a hookGuards entry literally named that whole sentence, which no\n * validator knows and which the next run reports as another unknown rule. `prunable` is the discriminator:\n * when the entry says deleting is the whole fix, DELETE it, exactly as `ConfigPruner` does.\n */\n// webpieces-disable no-function-outside-class -- sibling of the other seed*/migrate* helpers; this module is config-shape builders by design\nfunction migrateRetiredRuleNames(section: Section, changes: string[]): void {\n for (const entry of RETIRED_CONFIG_KEYS) {\n if (entry.scope !== RETIRED_SCOPE_RULE) continue;\n if (!(entry.key in section)) continue;\n if (entry.prunable) {\n delete section[entry.key];\n changes.push(`deleted retired \"${entry.key}\" (it moved to ${entry.movedTo})`);\n continue;\n }\n if (entry.movedTo in section) {\n delete section[entry.key];\n changes.push(`dropped retired \"${entry.key}\" (\"${entry.movedTo}\" is already configured)`);\n continue;\n }\n section[entry.movedTo] = section[entry.key];\n delete section[entry.key];\n changes.push(`renamed retired \"${entry.key}\" -> \"${entry.movedTo}\"`);\n }\n}\n\n// Deep-copy the framework's default match-rules (the no-fetch guard) into plain JSON for the config\n// file. Round-tripping through JSON turns the MatchRuleConfig instances into plain objects.\nfunction seedMatchRules(): Json[] {\n return JSON.parse(JSON.stringify(DEFAULT_MATCH_RULES)) as Json[];\n}\n\nfunction buildSeedConfig(): ConfigFile {\n const rules: Section = {};\n const hookGuards: Section = {};\n for (const name of allRuleNames()) {\n if (sectionForRule(name) === 'hookGuards') hookGuards[name] = seedRule(name);\n else rules[name] = seedRule(name);\n }\n return {\n rules, hookGuards, commands: seedCommands(), excludePaths: seedExcludePaths(),\n // Seed the required match-rules array with the framework's default no-fetch guard. A fresh\n // project gets contract-first enforcement out of the box; clients edit it and add more entries.\n 'match-rules': seedMatchRules(),\n rulesDir: [],\n };\n}\n\nfunction writeConfig(configPath: string, config: ConfigFile): void {\n fs.writeFileSync(configPath, JSON.stringify(config, null, 4) + '\\n');\n}\n\nfunction readConfig(configPath: string): Json {\n const raw = fs.readFileSync(configPath, 'utf8');\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n return JSON.parse(raw) as Json;\n } catch (err: unknown) {\n const error = toError(err);\n throw new Error(`${CONFIG_FILENAME} has invalid JSON — fix it, then retry: ${error.message}`, { cause: error });\n }\n}\n\nfunction asSection(value: Json[string]): Section {\n return (typeof value === 'object' && value !== null && !Array.isArray(value)) ? (value as Section) : {};\n}\n\n// Migrate an existing config to the rules / hookGuards / commands layout and add any missing rules.\n// Returns a human-readable list of what changed (empty = already up to date).\nexport function migrate(existing: Json): MigrateResult {\n const changes: string[] = [];\n const rules: Section = asSection(existing['rules']);\n const hookGuards: Section = asSection(existing['hookGuards']);\n const commands: Json = (typeof existing['commands'] === 'object' && existing['commands'] !== null)\n ? (existing['commands'] as Json) : {};\n\n // Move a deprecated top-level pr-gate block under commands.\n if (existing['pr-gate'] !== undefined && commands['pr-gate'] === undefined) {\n commands['pr-gate'] = existing['pr-gate'];\n changes.push('moved top-level \"pr-gate\" → commands[\"pr-gate\"]');\n }\n // Apply retired RENAMES first, so a renamed guard is placed and presence-checked under its new name\n // rather than being treated as unknown and re-added alongside its own stale entry.\n migrateRetiredRuleNames(rules, changes);\n migrateRetiredRuleNames(hookGuards, changes);\n\n // Move guards mistakenly left in rules into hookGuards.\n for (const name of Object.keys(rules)) {\n if (isHookGuard(name)) {\n hookGuards[name] = rules[name];\n delete rules[name];\n changes.push(`moved \"${name}\" from rules → hookGuards`);\n }\n }\n // Move code rules mistakenly placed in hookGuards back into rules.\n for (const name of Object.keys(hookGuards)) {\n if (!isHookGuard(name) && allRuleNames().includes(name)) {\n rules[name] = hookGuards[name];\n delete hookGuards[name];\n changes.push(`moved \"${name}\" from hookGuards → rules`);\n }\n }\n // Add any missing built-in into its correct section, ENFORCING at its recommended mode (not OFF).\n for (const name of allRuleNames()) {\n const target = sectionForRule(name) === 'hookGuards' ? hookGuards : rules;\n if (!(name in target)) {\n const entry = seedRule(name);\n target[name] = entry;\n changes.push(`added \"${name}\" (${String(entry['mode'])}) to ${sectionForRule(name)}`);\n }\n }\n // Fill command defaults.\n if (commands['pr-gate'] === undefined) {\n commands['pr-gate'] = { mode: 'OFF', buildCommand: DEFAULT_BUILD_COMMAND, gates: [] };\n changes.push('added commands[\"pr-gate\"] (OFF)');\n }\n migrateGuardHints(commands, changes);\n\n // Seed the now-required excludePaths list (empty = enforce everywhere) if the config predates it,\n // and MIGRATE the legacy `{ rules: [], guards: [] }` object to the single list by unioning them.\n // The union is behaviour-preserving for every config we have seen (both lists set identically), and\n // widening is the safe direction anyway: a path either side excluded stays excluded.\n const excludePaths: string[] = migrateExcludePaths(existing['excludePaths'], changes);\n\n // Seed the now-required match-rules array (with the default no-fetch guard) if the config predates\n // it. A client that has already customized it keeps their array untouched.\n let matchRules: Json[];\n if (Array.isArray(existing['match-rules'])) {\n matchRules = existing['match-rules'] as Json[];\n } else {\n matchRules = seedMatchRules();\n changes.push('added \"match-rules\" (seeded with the no-fetch guard)');\n }\n\n const rulesDir: string[] = Array.isArray(existing['rulesDir']) ? (existing['rulesDir'] as string[]) : [];\n const config: ConfigFile = { rules, hookGuards, commands, excludePaths, 'match-rules': matchRules, rulesDir };\n if (typeof existing['extends'] === 'string') config.extends = existing['extends'];\n return { config, changes };\n}\n\n// Seed the config when it is missing, migrate it when it is not. ONE behaviour, always — there is no\n// \"migrate but stop here\" mode any more. The flag that used to select it was never NECESSARY (the validator prints\n// the exact edit for every error at once, and editing webpieces.config.json is always allowed through the\n// guard — the documented primary cure), it REFUSED to act when the config was missing (useless in the one\n// case automation would have helped), and it gave deny messages a second competing path when they are\n// supposed to end in exactly one action. Readers also mistook it for the shim-repair command, which it\n// never was — `wp-upgrade-shim` is that.\n// webpieces-disable no-function-outside-class -- setup.ts is deliberately DI-free (it must run on a half-written node_modules; see install-entry.ts), so every function here is module-scope\nfunction seedOrSyncConfig(projectRoot: string): void {\n const configPath = path.join(projectRoot, CONFIG_FILENAME);\n if (!fs.existsSync(configPath)) {\n writeConfig(configPath, buildSeedConfig());\n console.log(` [ai-hooks] Created ${CONFIG_FILENAME} (rules / hookGuards / commands); each rule seeded at its recommended mode — gradual where supported, so only code you change is enforced.`);\n console.log(' Enable the ones you want by changing \"mode\".');\n return;\n }\n const result = migrate(readConfig(configPath));\n if (result.changes.length === 0) {\n console.log(` [ai-hooks] ${CONFIG_FILENAME} already uses the rules / hookGuards / commands layout — no changes.`);\n return;\n }\n writeConfig(configPath, result.config);\n console.log(` [ai-hooks] Migrated ${CONFIG_FILENAME}:`);\n for (const change of result.changes) console.log(` - ${change}`);\n}\n\n// ---------------------------------------------------------------------------\n// Claude Code settings.json hook wiring.\n// ---------------------------------------------------------------------------\nexport function hasHook(settings: ClaudeSettings, bin: string): boolean {\n const entries = settings.hooks?.PreToolUse ?? [];\n return entries.some((e: HookEntry) => e.hooks.some((h: HookCommand) => h.command.includes(bin)));\n}\n\n// Drop every PreToolUse command containing `marker` (a bin name, or a managed .sh path); returns true\n// if anything was removed. REMOVE-then-ADD is what keeps an upgrade from leaving the old absolute\n// spelling beside the new relative one — two spellings of one registration.\n// webpieces-disable no-function-outside-class -- setup.ts is deliberately DI-free (it must run on a half-written node_modules; see install-entry.ts), so every function here is module-scope\nfunction removeHookByMarker(settings: ClaudeSettings, marker: string): boolean {\n const entries = settings.hooks?.PreToolUse;\n if (!entries) return false;\n let changed = false;\n const kept: HookEntry[] = [];\n for (const entry of entries) {\n const hooks = entry.hooks.filter((h: HookCommand) => !h.command.includes(marker));\n if (hooks.length !== entry.hooks.length) changed = true;\n if (hooks.length > 0) kept.push({ matcher: entry.matcher, hooks });\n }\n if (changed) settings.hooks!.PreToolUse = kept;\n return changed;\n}\n\n// Apply the chosen install for one hook: remove it from every target file, then add it back to the\n// chosen one (or nowhere, for uninstall). Writes only the files that changed.\nexport function applyHook(hook: HookSpec, chosen: InstallTarget | null, targets: InstallTarget[], projectRoot: string): void {\n for (const target of targets) {\n const settings = readSettings(target.settingsPath);\n const removed = removeHookByMarker(settings, hook.bin);\n const isChosen = chosen !== null && chosen.settingsPath === target.settingsPath;\n if (isChosen) {\n addHookEntry(settings, new HookRegistrationEntry(hook.matcher, hook.commandFor(target, projectRoot)));\n writeSettings(target.settingsPath, settings);\n console.log(` ✅ ${hook.label} → ${target.label}`);\n } else if (removed) {\n writeSettings(target.settingsPath, settings);\n }\n }\n // Manage the shared checked-in shim: (re)write it whenever a project (relative) install exists,\n // otherwise clean it up once neither hook references it anymore.\n if (chosen !== null && !chosen.absolute) {\n writeShim(projectRoot);\n } else if (!markerReferenced(targets, SHIM_MARKER)) {\n removeShim(projectRoot);\n }\n // The L-1 hook rides with the GUARDS hook (it judges `cd`, which arrives on Bash). Doing it here\n // rather than at a separate call site means every existing caller of applyHook — the installer's\n // interactive and --target paths, and every test — gets the three-hook form with no second step.\n if (hook.bin === GUARDS_BIN) applyGuaranteeRoot(chosen, targets, projectRoot);\n if (chosen === null) console.log(` ⛔ ${hook.label} not installed (removed from all locations).`);\n}\n\nfunction currentLocation(hook: HookSpec, targets: InstallTarget[]): string {\n const here = targets.filter((t: InstallTarget) => hasHook(readSettings(t.settingsPath), hook.bin));\n return here.length === 0 ? 'none' : here.map((t: InstallTarget) => t.label.split(' (')[0]).join(', ');\n}\n\nfunction prompt(question: string): Promise<string> {\n return new Promise((resolve: (answer: string) => void) => {\n const rl = createInterface({ input: process.stdin, output: process.stdout });\n rl.question(question, (answer: string) => { rl.close(); resolve(answer.trim()); });\n });\n}\n\n// Map a friendly `--target` name to an InstallTarget choice id (see installTargets). Returns null\n// for an unknown name so the caller can error out. Kept separate + exported for unit testing.\nexport function resolveTargetChoice(name: string): string | null {\n switch (name) {\n case 'project': return '1';\n case 'project-personal':\n case 'projectpersonal':\n case 'local': return '2';\n case 'global': return '3';\n case 'none':\n case 'uninstall': return '4';\n default: return null;\n }\n}\n\n// Extract the value of `--target=<name>` from argv (null if the flag is absent).\nexport function parseTargetArg(args: string[]): string | null {\n const flag = args.find((a: string): boolean => a.startsWith('--target='));\n return flag ? flag.slice('--target='.length) : null;\n}\n\nasync function wireHook(hook: HookSpec, targets: InstallTarget[], projectRoot: string): Promise<void> {\n console.log('');\n console.log(`${hook.label} [matcher: ${hook.matcher}]`);\n console.log(` currently installed in: ${currentLocation(hook, targets)}`);\n for (const target of targets) console.log(` ${target.choice}) ${target.label}`);\n console.log(' 4) none / uninstall');\n const answer = await prompt(' Where should it live? [1/2/3/4, default 4]: ');\n const chosen = targets.find((t: InstallTarget) => t.choice === answer) ?? null;\n applyHook(hook, chosen, targets, projectRoot);\n}\n\n/**\n * Scaffold the SERVER-SIDE PR gate: the CI workflow plus the doc explaining how to turn it on.\n *\n * This lives in the installer, not the PR flow. `wp-start-upsert-pr` used to do it — printing\n * copy-to-`.github` and branch-protection instructions on EVERY run, at an agent doing feature work\n * that could not act on them anyway (marking a check required needs a repo admin). Setup is a\n * one-time, admin-shaped act, so it belongs with the other one-time setup.\n *\n * Written UNCONDITIONALLY, unlike the old version which required a `gateSalt` to already be set: the\n * whole point of the doc is to tell you to set one, so gating it on the thing it teaches meant the\n * instructions only appeared to repos that no longer needed them.\n *\n * Both land in gitignored `.webpieces/instruct-ai/`, never `.github/` directly — writing there would\n * dirty the tree, and copying it is the human's decision. `IfMissing` for the yml so a repo that has\n * customized its workflow never gets it clobbered; the doc itself is refreshed so it cannot go stale.\n */\n// webpieces-disable no-function-outside-class -- setup.ts is deliberately DI-free (it must run on a half-written node_modules; see install-entry.ts), so every function here is module-scope\nfunction scaffoldCiGate(projectRoot: string): void {\n writeTemplateIfMissing(projectRoot, 'webpieces-pr-gate.yml');\n writeTemplate(projectRoot, 'webpieces.ci-gate-setup.md');\n console.log('');\n console.log('ℹ️ Optional: server-side PR gate (stops an UNHOOKED teammate opening a PR in the web UI).');\n console.log(' It is OFF until you set a gateSalt. Three steps, one of which needs a repo admin:');\n console.log(' .webpieces/instruct-ai/webpieces.ci-gate-setup.md');\n}\n\nexport async function main(): Promise<void> {\n const args = process.argv.slice(2);\n // Anchor the install at the repo root (git toplevel — webpieces.config.json may not exist yet on\n // a first install), never a subdir cwd, so `.webpieces`/hooks/config all land at the root.\n const projectRoot = new RepoRootFinder().resolveRepoRoot(process.cwd());\n\n seedOrSyncConfig(projectRoot);\n // Always refreshed: it explains why a retired key is rejected rather than accepted, and what to do\n // about it — which is exactly what an agent needs on the run where a migration just moved keys out\n // from under its config.\n writeTemplate(projectRoot, CONFIG_POLICY_DOC);\n\n scaffoldCiGate(projectRoot);\n\n const targets = installTargets(projectRoot);\n\n // Non-interactive: `--target=project|project-personal|global|none` installs BOTH hooks at that\n // location without prompting, so an agent or CI can run the installer unattended (e.g. after a\n // @webpieces upgrade that changed the hook entry). Omit the flag for the interactive per-hook chooser.\n const targetName = parseTargetArg(args);\n if (targetName !== null) {\n const choice = resolveTargetChoice(targetName);\n if (choice === null) {\n console.error(`❌ Unknown --target '${targetName}'. Use one of: project | project-personal | global | none`);\n process.exitCode = 1;\n return;\n }\n const chosen = targets.find((t: InstallTarget): boolean => t.choice === choice) ?? null;\n applyHook(RULES_HOOK, chosen, targets, projectRoot);\n applyHook(GUARDS_HOOK, chosen, targets, projectRoot);\n console.log(`\\nDone. Both hooks set to: ${targetName}.`);\n return;\n }\n\n console.log('');\n console.log('Two webpieces hooks can be installed independently — choose a location for each:');\n await wireHook(RULES_HOOK, targets, projectRoot);\n await wireHook(GUARDS_HOOK, targets, projectRoot);\n console.log('');\n console.log('Done. Re-run `pnpm wp-install-ai-hooks` anytime to move or uninstall a hook.');\n console.log('(Non-interactive: pnpm wp-install-ai-hooks --target=project|project-personal|global|none)');\n}\n\nif (require.main === module) {\n void main();\n}\n"]}
|
|
1
|
+
{"version":3,"file":"setup.js","sourceRoot":"","sources":["../../../../../../packages/tooling/ai-hook-rules/src/bin/setup.ts"],"names":[],"mappings":"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","sourcesContent":["import * as fs from 'fs';\nimport * as path from 'path';\nimport { homedir } from 'os';\nimport { createInterface } from 'readline';\n\nimport { allRuleNames, seedEntryForRule, sectionForRule, isHookGuard, DEFAULT_MATCH_RULES, DEFAULT_BUILD_COMMAND, RETIRED_CONFIG_KEYS, RETIRED_SCOPE_RULE, RepoRootFinder, writeTemplate, writeTemplateIfMissing, CONFIG_POLICY_DOC } from '@webpieces/rules-config';\n\nimport { toError } from '../core/to-error';\nimport { SHIM_MARKER, shimPath, renderShim } from './shim';\nimport { GUARANTEE_ROOT_MARKER, guaranteeRootPath, writeGuaranteeRoot } from './guarantee-root';\nimport {\n ClaudeSettings, HookCommand, HookEntry, HookRegistrationEntry, GUARANTEE_ROOT_ENTRY, GUARDS_BIN,\n GUARDS_MATCHER, RULES_BIN, RULES_MATCHER, addHookEntry, applyManagedEnv, readSettings, shimCommand,\n writeSettings,\n} from './hook-registration';\nimport { BASH_CWD_ENV_KEY, BASH_CWD_ENV_VALUE } from './managed-env';\n\n// Re-exported for back-compat (setup.spec.ts + external callers). The shim body + path now live in\n// ./shim (shared with the runtime self-heal in hook-core). See shim.ts for the single source of truth.\nexport { renderShim };\n\nconst CONFIG_FILENAME = 'webpieces.config.json';\n// The seeded buildCommand comes from @webpieces/rules-config, NOT from a copy here. This file used to\n// hold its own — with `--base=origin/main`, a DIFFERENT base from the one the gate documents — so a\n// freshly set-up repo was seeded with a command that rebuilds projects touched by other people's\n// merged PRs, and whole-repo-build-guard then quoted that command back in its refusals.\nconst DEFAULT_UPSERT_PR = 'pnpm wp-start-upsert-pr';\nconst DEFAULT_MERGE_COMPLETE = 'pnpm wp-finish-upsert-pr';\n\n// ---------------------------------------------------------------------------\n// The two independently-installable GUARD hooks. Each can land in a different settings file (see\n// InstallTarget) so a team can ship the guards while a developer keeps the code-style rules local\n// while iterating. The L-1 hook is a third registration but is NOT independently installable — it\n// rides with the guards hook (applyGuaranteeRoot), because it exists to protect the RELATIVE\n// resolution of these two and is meaningless without them.\n// ---------------------------------------------------------------------------\nclass HookSpec {\n constructor(\n readonly key: string,\n readonly label: string,\n readonly matcher: string,\n readonly bin: string,\n ) {}\n\n // Absolute targets (global) need the exact path to this repo's bin — no ~/.webpieces bridge.\n // Project targets get the RELATIVE shim command (see hook-registration.ts for why relative is the\n // whole point), and the L-1 hook registered beside them is what keeps a relative path from ever\n // failing to resolve — which per the hooks reference would be a SILENT UNGUARDED ALLOW, not a block.\n commandFor(target: InstallTarget, projectRoot: string): string {\n if (target.absolute) {\n return `node ${path.join(projectRoot, 'node_modules', '.bin', this.bin)}`;\n }\n return shimCommand(this.bin);\n }\n}\n\n// Idempotent: re-running the installer overwrites the managed shim in place.\nfunction writeShim(projectRoot: string): void {\n const target = shimPath(projectRoot);\n fs.mkdirSync(path.dirname(target), { recursive: true });\n fs.writeFileSync(target, renderShim(), { mode: 0o755 });\n // writeFileSync's mode is only applied when creating the file; force it on overwrite too.\n fs.chmodSync(target, 0o755);\n}\n\nfunction removeShim(projectRoot: string): void {\n const target = shimPath(projectRoot);\n if (fs.existsSync(target)) fs.rmSync(target);\n}\n\n// A managed .sh is shared by the project hooks — only safe to delete once no project settings file\n// references it anymore (i.e. the other hook was moved to global or uninstalled too).\n// webpieces-disable no-function-outside-class -- setup.ts is deliberately DI-free (it must run on a half-written node_modules; see install-entry.ts), so every function here is module-scope\nfunction markerReferenced(targets: InstallTarget[], marker: string): boolean {\n return targets.some((t: InstallTarget) => {\n const entries = readSettings(t.settingsPath).hooks?.PreToolUse ?? [];\n return entries.some((e: HookEntry) => e.hooks.some((h: HookCommand) => h.command.includes(marker)));\n });\n}\n\n// webpieces-disable no-function-outside-class -- setup.ts is deliberately DI-free (it must run on a half-written node_modules; see install-entry.ts), so every function here is module-scope\nfunction removeGuaranteeRootFile(projectRoot: string): void {\n const target = guaranteeRootPath(projectRoot);\n if (fs.existsSync(target)) fs.rmSync(target);\n}\n\n// Drop every PreToolUse command referencing the L-1 hook; returns true if anything was removed.\n// webpieces-disable no-function-outside-class -- setup.ts is deliberately DI-free (it must run on a half-written node_modules; see install-entry.ts), so every function here is module-scope\nfunction removeGuaranteeRootHook(settings: ClaudeSettings): boolean {\n return removeHookByMarker(settings, GUARANTEE_ROOT_MARKER);\n}\n\n/**\n * Install / move / uninstall the L-1 hook (guarantee-root.sh) alongside the GUARDS hook.\n *\n * It rides with the guards hook and not the rules hook because it judges `cd`, `cd` arrives on Bash,\n * and `Bash` is in the guards matcher. It is registered ABSOLUTE while the guard hooks are RELATIVE —\n * that asymmetry is the design, not an oversight (hook-registration.ts states it once).\n *\n * A GLOBAL (absolute) install gets none: those hooks name the bin path directly, so there is no\n * relative path that could fail to resolve, which is the only thing L-1 protects against.\n */\n// webpieces-disable no-function-outside-class -- setup.ts is deliberately DI-free (it must run on a half-written node_modules; see install-entry.ts), so every function here is module-scope\nfunction applyGuaranteeRoot(chosen: InstallTarget | null, targets: InstallTarget[], projectRoot: string): void {\n const relative = chosen !== null && !chosen.absolute;\n for (const target of targets) {\n const settings = readSettings(target.settingsPath);\n const removed = removeGuaranteeRootHook(settings);\n if (relative && chosen.settingsPath === target.settingsPath) {\n addHookEntry(settings, GUARANTEE_ROOT_ENTRY);\n writeSettings(target.settingsPath, settings);\n console.log(` ✅ L-1 guarantee-root hook (keeps the shell where the relative guard hooks can launch) → ${target.label}`);\n } else if (removed) {\n writeSettings(target.settingsPath, settings);\n }\n }\n if (relative) writeGuaranteeRoot(projectRoot);\n else if (!markerReferenced(targets, GUARANTEE_ROOT_MARKER)) removeGuaranteeRootFile(projectRoot);\n}\n\nexport class InstallTarget {\n constructor(\n readonly choice: string,\n readonly label: string,\n readonly settingsPath: string,\n readonly absolute: boolean,\n ) {}\n}\n\n// The matchers and bin names come from ./hook-registration, which is also what the drift check and\n// wp-upgrade-shim compare against — one spelling of the registration, or the installer and the\n// validator can disagree about what \"installed\" means.\nexport const RULES_HOOK = new HookSpec('rules', 'Rules hook (code-style validation)', RULES_MATCHER, RULES_BIN);\nexport const GUARDS_HOOK = new HookSpec('guards', 'Guards hook (git/PR/branch protection)', GUARDS_MATCHER, GUARDS_BIN);\n\n// `homeDir` is injectable so tests can point the global target at a temp dir instead of the real\n// ~/.claude/settings.json (a unit test must never write the user's actual global settings).\nexport function installTargets(projectRoot: string, homeDir: string = homedir()): InstallTarget[] {\n return [\n new InstallTarget('1', 'project (.claude/settings.json — committed, for the team)',\n path.join(projectRoot, '.claude', 'settings.json'), false),\n new InstallTarget('2', 'project for you (.claude/settings.local.json — personal)',\n path.join(projectRoot, '.claude', 'settings.local.json'), false),\n new InstallTarget('3', 'global (~/.claude/settings.json — exact path, this repo only)',\n path.join(homeDir, '.claude', 'settings.json'), true),\n ];\n}\n\n// ---------------------------------------------------------------------------\n// webpieces.config.json seeding + migration to the rules / hookGuards / commands layout.\n// ---------------------------------------------------------------------------\n// webpieces-disable no-any-unknown -- webpieces.config.json / settings.json are opaque consumer JSON\ntype Json = Record<string, unknown>;\ntype RuleEntry = Json;\ntype Section = Record<string, RuleEntry>;\n\ninterface ConfigFile {\n extends?: string;\n rules: Section;\n hookGuards: Section;\n commands: Json;\n excludePaths: string[];\n 'match-rules': Json[];\n rulesDir: string[];\n}\n\ninterface MigrateResult {\n config: ConfigFile;\n changes: string[];\n}\n\n// webpieces-disable no-function-outside-class -- sibling of the other seed* helpers; this module is config-shape builders by design\nfunction seedRule(ruleName: string): RuleEntry {\n // Both escape hatches are seeded (and REQUIRED) so every rule block shows them: 0 = active,\n // null = no branch scoping. A human/AI edits these to time-box or branch-scope a rule off.\n //\n // The ENTIRE entry comes from rules-config's seedEntryForRule() — the same module that owns the\n // schema the loader validates against, so the installer can never emit an entry the loader\n // rejects. It supplies: the recommended mode (the SAME recommendation the validator prints in its\n // copy-paste snippet, so seed and advice cannot disagree), both hatches, and a default for every\n // other schema-REQUIRED field. Seeding used to be a flat 'OFF' plus the two hatches, which was\n // wrong twice over: adopters got nothing enforced, AND the entry was missing required fields\n // (e.g. branch-creation-guard.autoReapMergedBranches), so the config failed to load on first run.\n return seedEntryForRule(ruleName);\n}\n\n// The guard-hint command strings live under `guardHints`. The flat `upsertPr`/`mergeComplete` keys this\n// used to seed are RETIRED and now fail validation — seeding them meant every freshly installed repo was\n// born on a shape the validator rejects.\nfunction seedCommands(): Json {\n return {\n 'pr-gate': { mode: 'OFF', buildCommand: DEFAULT_BUILD_COMMAND, gates: [] },\n guardHints: { prCreationOrPush: DEFAULT_UPSERT_PR, mergeInProgress: DEFAULT_MERGE_COMPLETE },\n };\n}\n\n// Required excludePaths block: ONE glob list suppressing hook enforcement per file path. Seeded empty\n// (enforce everywhere) — a client adds paths (e.g. \"repositories/**\") to exempt vendored trees.\n// webpieces-disable no-function-outside-class -- sibling of the other seed* helpers; this module is config-shape builders by design\nfunction seedExcludePaths(): string[] {\n return [];\n}\n\n// Bring an existing `excludePaths` forward to the single-list shape. Already a list → untouched.\n// Legacy `{ rules, guards }` → unioned (order preserved, duplicates dropped) and recorded as a change\n// so `wp-install-ai-hooks` is the migration path rather than a hand-edit. Anything else → seeded [].\n// webpieces-disable no-any-unknown -- `raw` is opaque consumer JSON until narrowed here\n// webpieces-disable no-function-outside-class -- sibling of the other seed*/migrate* helpers; this module is config-shape builders by design\nfunction migrateExcludePaths(raw: unknown, changes: string[]): string[] {\n if (Array.isArray(raw)) return (raw as string[]).filter(p => typeof p === 'string');\n if (typeof raw === 'object' && raw !== null) {\n // webpieces-disable no-any-unknown -- narrowing the opaque legacy block from consumer JSON\n const legacy = raw as Record<string, unknown>;\n const rules = Array.isArray(legacy['rules']) ? (legacy['rules'] as string[]) : [];\n const guards = Array.isArray(legacy['guards']) ? (legacy['guards'] as string[]) : [];\n const merged = [...new Set([...rules, ...guards].filter(p => typeof p === 'string'))];\n changes.push(`migrated excludePaths {rules,guards} -> one list (${merged.length} path(s))`);\n return merged;\n }\n changes.push('added excludePaths ([])');\n return [];\n}\n\n/** One retired flat command string and the guardHints field it becomes. Data-only (per CLAUDE.md). */\nclass GuardHintMove {\n retiredKey: string;\n hintKey: string;\n fallback: string;\n\n constructor(retiredKey: string, hintKey: string, fallback: string) {\n this.retiredKey = retiredKey;\n this.hintKey = hintKey;\n this.fallback = fallback;\n }\n}\n\n/**\n * Bring `commands` forward to the `guardHints` shape, moving the RETIRED flat `upsertPr`/`mergeComplete`\n * strings and DELETING them. Deleting is the point: the validator now rejects them, so leaving them behind\n * would keep the config failing after a \"successful\" sync.\n *\n * The consumer's own value wins over the default — a repo that renamed its gated command keeps that name.\n */\n// webpieces-disable no-function-outside-class -- sibling of the other seed*/migrate* helpers; this module is config-shape builders by design\nfunction migrateGuardHints(commands: Json, changes: string[]): void {\n const hints: Json = (typeof commands['guardHints'] === 'object' && commands['guardHints'] !== null)\n ? (commands['guardHints'] as Json) : {};\n const moves: readonly GuardHintMove[] = [\n new GuardHintMove('upsertPr', 'prCreationOrPush', DEFAULT_UPSERT_PR),\n new GuardHintMove('mergeComplete', 'mergeInProgress', DEFAULT_MERGE_COMPLETE),\n ];\n for (const move of moves) {\n const retiredKey = move.retiredKey;\n const hintKey = move.hintKey;\n const fallback = move.fallback;\n const carried = commands[retiredKey];\n if (carried !== undefined) {\n delete commands[retiredKey];\n if (hints[hintKey] === undefined) hints[hintKey] = carried;\n changes.push(`moved retired commands.${retiredKey} -> commands.guardHints.${hintKey}`);\n }\n if (hints[hintKey] === undefined) {\n hints[hintKey] = fallback;\n changes.push(`added commands.guardHints.${hintKey}`);\n }\n }\n commands['guardHints'] = hints;\n}\n\n/**\n * Apply the RETIRED rule/guard retirements in place. These used to be rewritten silently at load time, so\n * a consumer's file kept the dead name forever; the loader now rejects it, which makes this the one\n * command that can fix the file. Skips a rename when the new name is already configured, so an explicit\n * entry is never clobbered by a stale one.\n *\n * NOT EVERY RETIREMENT IS A RENAME, and treating them all as one produced garbage. `whole-repo-build-guard`\n * moved OUT of webpieces.config.json entirely — its `movedTo` is the PROSE destination\n * `~/.webpieces/config.json → experimental.whole-repo-build-guard`, not a sibling key — so the rename\n * branch below would have created a hookGuards entry literally named that whole sentence, which no\n * validator knows and which the next run reports as another unknown rule. `prunable` is the discriminator:\n * when the entry says deleting is the whole fix, DELETE it, exactly as `ConfigPruner` does.\n */\n// webpieces-disable no-function-outside-class -- sibling of the other seed*/migrate* helpers; this module is config-shape builders by design\nfunction migrateRetiredRuleNames(section: Section, changes: string[]): void {\n for (const entry of RETIRED_CONFIG_KEYS) {\n if (entry.scope !== RETIRED_SCOPE_RULE) continue;\n if (!(entry.key in section)) continue;\n if (entry.prunable) {\n delete section[entry.key];\n changes.push(`deleted retired \"${entry.key}\" (it moved to ${entry.movedTo})`);\n continue;\n }\n if (entry.movedTo in section) {\n delete section[entry.key];\n changes.push(`dropped retired \"${entry.key}\" (\"${entry.movedTo}\" is already configured)`);\n continue;\n }\n section[entry.movedTo] = section[entry.key];\n delete section[entry.key];\n changes.push(`renamed retired \"${entry.key}\" -> \"${entry.movedTo}\"`);\n }\n}\n\n// Deep-copy the framework's default match-rules (the no-fetch guard) into plain JSON for the config\n// file. Round-tripping through JSON turns the MatchRuleConfig instances into plain objects.\nfunction seedMatchRules(): Json[] {\n return JSON.parse(JSON.stringify(DEFAULT_MATCH_RULES)) as Json[];\n}\n\nfunction buildSeedConfig(): ConfigFile {\n const rules: Section = {};\n const hookGuards: Section = {};\n for (const name of allRuleNames()) {\n if (sectionForRule(name) === 'hookGuards') hookGuards[name] = seedRule(name);\n else rules[name] = seedRule(name);\n }\n return {\n rules, hookGuards, commands: seedCommands(), excludePaths: seedExcludePaths(),\n // Seed the required match-rules array with the framework's default no-fetch guard. A fresh\n // project gets contract-first enforcement out of the box; clients edit it and add more entries.\n 'match-rules': seedMatchRules(),\n rulesDir: [],\n };\n}\n\nfunction writeConfig(configPath: string, config: ConfigFile): void {\n fs.writeFileSync(configPath, JSON.stringify(config, null, 4) + '\\n');\n}\n\nfunction readConfig(configPath: string): Json {\n const raw = fs.readFileSync(configPath, 'utf8');\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n return JSON.parse(raw) as Json;\n } catch (err: unknown) {\n const error = toError(err);\n throw new Error(`${CONFIG_FILENAME} has invalid JSON — fix it, then retry: ${error.message}`, { cause: error });\n }\n}\n\nfunction asSection(value: Json[string]): Section {\n return (typeof value === 'object' && value !== null && !Array.isArray(value)) ? (value as Section) : {};\n}\n\n// Migrate an existing config to the rules / hookGuards / commands layout and add any missing rules.\n// Returns a human-readable list of what changed (empty = already up to date).\nexport function migrate(existing: Json): MigrateResult {\n const changes: string[] = [];\n const rules: Section = asSection(existing['rules']);\n const hookGuards: Section = asSection(existing['hookGuards']);\n const commands: Json = (typeof existing['commands'] === 'object' && existing['commands'] !== null)\n ? (existing['commands'] as Json) : {};\n\n // Move a deprecated top-level pr-gate block under commands.\n if (existing['pr-gate'] !== undefined && commands['pr-gate'] === undefined) {\n commands['pr-gate'] = existing['pr-gate'];\n changes.push('moved top-level \"pr-gate\" → commands[\"pr-gate\"]');\n }\n // Apply retired RENAMES first, so a renamed guard is placed and presence-checked under its new name\n // rather than being treated as unknown and re-added alongside its own stale entry.\n migrateRetiredRuleNames(rules, changes);\n migrateRetiredRuleNames(hookGuards, changes);\n\n // Move guards mistakenly left in rules into hookGuards.\n for (const name of Object.keys(rules)) {\n if (isHookGuard(name)) {\n hookGuards[name] = rules[name];\n delete rules[name];\n changes.push(`moved \"${name}\" from rules → hookGuards`);\n }\n }\n // Move code rules mistakenly placed in hookGuards back into rules.\n for (const name of Object.keys(hookGuards)) {\n if (!isHookGuard(name) && allRuleNames().includes(name)) {\n rules[name] = hookGuards[name];\n delete hookGuards[name];\n changes.push(`moved \"${name}\" from hookGuards → rules`);\n }\n }\n // Add any missing built-in into its correct section, ENFORCING at its recommended mode (not OFF).\n for (const name of allRuleNames()) {\n const target = sectionForRule(name) === 'hookGuards' ? hookGuards : rules;\n if (!(name in target)) {\n const entry = seedRule(name);\n target[name] = entry;\n changes.push(`added \"${name}\" (${String(entry['mode'])}) to ${sectionForRule(name)}`);\n }\n }\n // Fill command defaults.\n if (commands['pr-gate'] === undefined) {\n commands['pr-gate'] = { mode: 'OFF', buildCommand: DEFAULT_BUILD_COMMAND, gates: [] };\n changes.push('added commands[\"pr-gate\"] (OFF)');\n }\n migrateGuardHints(commands, changes);\n\n // Seed the now-required excludePaths list (empty = enforce everywhere) if the config predates it,\n // and MIGRATE the legacy `{ rules: [], guards: [] }` object to the single list by unioning them.\n // The union is behaviour-preserving for every config we have seen (both lists set identically), and\n // widening is the safe direction anyway: a path either side excluded stays excluded.\n const excludePaths: string[] = migrateExcludePaths(existing['excludePaths'], changes);\n\n // Seed the now-required match-rules array (with the default no-fetch guard) if the config predates\n // it. A client that has already customized it keeps their array untouched.\n let matchRules: Json[];\n if (Array.isArray(existing['match-rules'])) {\n matchRules = existing['match-rules'] as Json[];\n } else {\n matchRules = seedMatchRules();\n changes.push('added \"match-rules\" (seeded with the no-fetch guard)');\n }\n\n const rulesDir: string[] = Array.isArray(existing['rulesDir']) ? (existing['rulesDir'] as string[]) : [];\n const config: ConfigFile = { rules, hookGuards, commands, excludePaths, 'match-rules': matchRules, rulesDir };\n if (typeof existing['extends'] === 'string') config.extends = existing['extends'];\n return { config, changes };\n}\n\n// Seed the config when it is missing, migrate it when it is not. ONE behaviour, always — there is no\n// \"migrate but stop here\" mode any more. The flag that used to select it was never NECESSARY (the validator prints\n// the exact edit for every error at once, and editing webpieces.config.json is always allowed through the\n// guard — the documented primary cure), it REFUSED to act when the config was missing (useless in the one\n// case automation would have helped), and it gave deny messages a second competing path when they are\n// supposed to end in exactly one action. Readers also mistook it for the shim-repair command, which it\n// never was — `wp-upgrade-shim` is that.\n// webpieces-disable no-function-outside-class -- setup.ts is deliberately DI-free (it must run on a half-written node_modules; see install-entry.ts), so every function here is module-scope\nfunction seedOrSyncConfig(projectRoot: string): void {\n const configPath = path.join(projectRoot, CONFIG_FILENAME);\n if (!fs.existsSync(configPath)) {\n writeConfig(configPath, buildSeedConfig());\n console.log(` [ai-hooks] Created ${CONFIG_FILENAME} (rules / hookGuards / commands); each rule seeded at its recommended mode — gradual where supported, so only code you change is enforced.`);\n console.log(' Enable the ones you want by changing \"mode\".');\n return;\n }\n const result = migrate(readConfig(configPath));\n if (result.changes.length === 0) {\n console.log(` [ai-hooks] ${CONFIG_FILENAME} already uses the rules / hookGuards / commands layout — no changes.`);\n return;\n }\n writeConfig(configPath, result.config);\n console.log(` [ai-hooks] Migrated ${CONFIG_FILENAME}:`);\n for (const change of result.changes) console.log(` - ${change}`);\n}\n\n// ---------------------------------------------------------------------------\n// Claude Code settings.json hook wiring.\n// ---------------------------------------------------------------------------\nexport function hasHook(settings: ClaudeSettings, bin: string): boolean {\n const entries = settings.hooks?.PreToolUse ?? [];\n return entries.some((e: HookEntry) => e.hooks.some((h: HookCommand) => h.command.includes(bin)));\n}\n\n// Drop every PreToolUse command containing `marker` (a bin name, or a managed .sh path); returns true\n// if anything was removed. REMOVE-then-ADD is what keeps an upgrade from leaving the old absolute\n// spelling beside the new relative one — two spellings of one registration.\n// webpieces-disable no-function-outside-class -- setup.ts is deliberately DI-free (it must run on a half-written node_modules; see install-entry.ts), so every function here is module-scope\nfunction removeHookByMarker(settings: ClaudeSettings, marker: string): boolean {\n const entries = settings.hooks?.PreToolUse;\n if (!entries) return false;\n let changed = false;\n const kept: HookEntry[] = [];\n for (const entry of entries) {\n const hooks = entry.hooks.filter((h: HookCommand) => !h.command.includes(marker));\n if (hooks.length !== entry.hooks.length) changed = true;\n if (hooks.length > 0) kept.push({ matcher: entry.matcher, hooks });\n }\n if (changed) settings.hooks!.PreToolUse = kept;\n return changed;\n}\n\n// Apply the chosen install for one hook: remove it from every target file, then add it back to the\n// chosen one (or nowhere, for uninstall). Writes only the files that changed.\nexport function applyHook(hook: HookSpec, chosen: InstallTarget | null, targets: InstallTarget[], projectRoot: string): void {\n for (const target of targets) {\n const settings = readSettings(target.settingsPath);\n const removed = removeHookByMarker(settings, hook.bin);\n const isChosen = chosen !== null && chosen.settingsPath === target.settingsPath;\n if (isChosen) {\n addHookEntry(settings, new HookRegistrationEntry(hook.matcher, hook.commandFor(target, projectRoot)));\n // The managed `env` entry goes into the SAME file the hooks go into, on every path that\n // writes hooks — interactive or `--target=`. It pins the Bash cwd to the project root, which\n // is what keeps the RELATIVE guard hooks resolvable (an unresolvable hook exits 127, and per\n // the hooks reference that is a SILENT UNGUARDED ALLOW), and settings `env` is inherited, so\n // every subagent gets the identical cwd and therefore the identical guard verdict. See\n // hook-registration.ts for the full argument; `wp-upgrade-shim` self-heals it afterwards.\n if (applyManagedEnv(settings)) {\n console.log(` ✅ env.${BASH_CWD_ENV_KEY}=${BASH_CWD_ENV_VALUE} → ${target.label} (pins the Bash cwd to the project root, for this session and every subagent)`);\n }\n writeSettings(target.settingsPath, settings);\n console.log(` ✅ ${hook.label} → ${target.label}`);\n } else if (removed) {\n writeSettings(target.settingsPath, settings);\n }\n }\n // Manage the shared checked-in shim: (re)write it whenever a project (relative) install exists,\n // otherwise clean it up once neither hook references it anymore.\n if (chosen !== null && !chosen.absolute) {\n writeShim(projectRoot);\n } else if (!markerReferenced(targets, SHIM_MARKER)) {\n removeShim(projectRoot);\n }\n // The L-1 hook rides with the GUARDS hook (it judges `cd`, which arrives on Bash). Doing it here\n // rather than at a separate call site means every existing caller of applyHook — the installer's\n // interactive and --target paths, and every test — gets the three-hook form with no second step.\n if (hook.bin === GUARDS_BIN) applyGuaranteeRoot(chosen, targets, projectRoot);\n if (chosen === null) console.log(` ⛔ ${hook.label} not installed (removed from all locations).`);\n}\n\nfunction currentLocation(hook: HookSpec, targets: InstallTarget[]): string {\n const here = targets.filter((t: InstallTarget) => hasHook(readSettings(t.settingsPath), hook.bin));\n return here.length === 0 ? 'none' : here.map((t: InstallTarget) => t.label.split(' (')[0]).join(', ');\n}\n\nfunction prompt(question: string): Promise<string> {\n return new Promise((resolve: (answer: string) => void) => {\n const rl = createInterface({ input: process.stdin, output: process.stdout });\n rl.question(question, (answer: string) => { rl.close(); resolve(answer.trim()); });\n });\n}\n\n// Map a friendly `--target` name to an InstallTarget choice id (see installTargets). Returns null\n// for an unknown name so the caller can error out. Kept separate + exported for unit testing.\nexport function resolveTargetChoice(name: string): string | null {\n switch (name) {\n case 'project': return '1';\n case 'project-personal':\n case 'projectpersonal':\n case 'local': return '2';\n case 'global': return '3';\n case 'none':\n case 'uninstall': return '4';\n default: return null;\n }\n}\n\n// Extract the value of `--target=<name>` from argv (null if the flag is absent).\nexport function parseTargetArg(args: string[]): string | null {\n const flag = args.find((a: string): boolean => a.startsWith('--target='));\n return flag ? flag.slice('--target='.length) : null;\n}\n\nasync function wireHook(hook: HookSpec, targets: InstallTarget[], projectRoot: string): Promise<void> {\n console.log('');\n console.log(`${hook.label} [matcher: ${hook.matcher}]`);\n console.log(` currently installed in: ${currentLocation(hook, targets)}`);\n for (const target of targets) console.log(` ${target.choice}) ${target.label}`);\n console.log(' 4) none / uninstall');\n const answer = await prompt(' Where should it live? [1/2/3/4, default 4]: ');\n const chosen = targets.find((t: InstallTarget) => t.choice === answer) ?? null;\n applyHook(hook, chosen, targets, projectRoot);\n}\n\n/**\n * Scaffold the SERVER-SIDE PR gate: the CI workflow plus the doc explaining how to turn it on.\n *\n * This lives in the installer, not the PR flow. `wp-start-upsert-pr` used to do it — printing\n * copy-to-`.github` and branch-protection instructions on EVERY run, at an agent doing feature work\n * that could not act on them anyway (marking a check required needs a repo admin). Setup is a\n * one-time, admin-shaped act, so it belongs with the other one-time setup.\n *\n * Written UNCONDITIONALLY, unlike the old version which required a `gateSalt` to already be set: the\n * whole point of the doc is to tell you to set one, so gating it on the thing it teaches meant the\n * instructions only appeared to repos that no longer needed them.\n *\n * Both land in gitignored `.webpieces/instruct-ai/`, never `.github/` directly — writing there would\n * dirty the tree, and copying it is the human's decision. `IfMissing` for the yml so a repo that has\n * customized its workflow never gets it clobbered; the doc itself is refreshed so it cannot go stale.\n */\n// webpieces-disable no-function-outside-class -- setup.ts is deliberately DI-free (it must run on a half-written node_modules; see install-entry.ts), so every function here is module-scope\nfunction scaffoldCiGate(projectRoot: string): void {\n writeTemplateIfMissing(projectRoot, 'webpieces-pr-gate.yml');\n writeTemplate(projectRoot, 'webpieces.ci-gate-setup.md');\n console.log('');\n console.log('ℹ️ Optional: server-side PR gate (stops an UNHOOKED teammate opening a PR in the web UI).');\n console.log(' It is OFF until you set a gateSalt. Three steps, one of which needs a repo admin:');\n console.log(' .webpieces/instruct-ai/webpieces.ci-gate-setup.md');\n}\n\nexport async function main(): Promise<void> {\n const args = process.argv.slice(2);\n // Anchor the install at the repo root (git toplevel — webpieces.config.json may not exist yet on\n // a first install), never a subdir cwd, so `.webpieces`/hooks/config all land at the root.\n const projectRoot = new RepoRootFinder().resolveRepoRoot(process.cwd());\n\n seedOrSyncConfig(projectRoot);\n // Always refreshed: it explains why a retired key is rejected rather than accepted, and what to do\n // about it — which is exactly what an agent needs on the run where a migration just moved keys out\n // from under its config.\n writeTemplate(projectRoot, CONFIG_POLICY_DOC);\n\n scaffoldCiGate(projectRoot);\n\n const targets = installTargets(projectRoot);\n\n // Non-interactive: `--target=project|project-personal|global|none` installs BOTH hooks at that\n // location without prompting, so an agent or CI can run the installer unattended (e.g. after a\n // @webpieces upgrade that changed the hook entry). Omit the flag for the interactive per-hook chooser.\n const targetName = parseTargetArg(args);\n if (targetName !== null) {\n const choice = resolveTargetChoice(targetName);\n if (choice === null) {\n console.error(`❌ Unknown --target '${targetName}'. Use one of: project | project-personal | global | none`);\n process.exitCode = 1;\n return;\n }\n const chosen = targets.find((t: InstallTarget): boolean => t.choice === choice) ?? null;\n applyHook(RULES_HOOK, chosen, targets, projectRoot);\n applyHook(GUARDS_HOOK, chosen, targets, projectRoot);\n console.log(`\\nDone. Both hooks set to: ${targetName}.`);\n return;\n }\n\n console.log('');\n console.log('Two webpieces hooks can be installed independently — choose a location for each:');\n await wireHook(RULES_HOOK, targets, projectRoot);\n await wireHook(GUARDS_HOOK, targets, projectRoot);\n console.log('');\n console.log('Done. Re-run `pnpm wp-install-ai-hooks` anytime to move or uninstall a hook.');\n console.log('(Non-interactive: pnpm wp-install-ai-hooks --target=project|project-personal|global|none)');\n}\n\nif (require.main === module) {\n void main();\n}\n"]}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* THE FAIL-CLOSED DENY TEXT for a drifted managed hook surface (L0 fault S) — its own module because
|
|
3
|
+
* shim.ts is at its line cap and this is one cohesive unit: the words a blocked agent reads, and
|
|
4
|
+
* nothing else. It imports FROM shim.ts and is never imported BY it, so the graph stays acyclic.
|
|
5
|
+
*/
|
|
6
|
+
export declare function shimStaleDenyReason(installedVersion: string, root: string, drifted: readonly string[], inSubagent: boolean): string;
|