cleargate 0.1.0-alpha.1 → 0.2.1

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.
Files changed (67) hide show
  1. package/README.md +41 -2
  2. package/dist/MANIFEST.json +160 -0
  3. package/dist/cli.cjs +4383 -16
  4. package/dist/cli.cjs.map +1 -1
  5. package/dist/cli.js +4367 -4
  6. package/dist/cli.js.map +1 -1
  7. package/dist/templates/cleargate-planning/.claude/agents/architect.md +57 -0
  8. package/dist/templates/cleargate-planning/.claude/agents/cleargate-wiki-ingest.md +145 -0
  9. package/dist/templates/cleargate-planning/.claude/agents/cleargate-wiki-lint.md +256 -0
  10. package/dist/templates/cleargate-planning/.claude/agents/cleargate-wiki-query.md +143 -0
  11. package/dist/templates/cleargate-planning/.claude/agents/developer.md +58 -0
  12. package/dist/templates/cleargate-planning/.claude/agents/qa.md +57 -0
  13. package/dist/templates/cleargate-planning/.claude/agents/reporter.md +129 -0
  14. package/dist/templates/cleargate-planning/.claude/hooks/session-start.sh +4 -0
  15. package/dist/templates/cleargate-planning/.claude/hooks/stamp-and-gate.sh +18 -0
  16. package/dist/templates/cleargate-planning/.claude/hooks/token-ledger.sh +174 -0
  17. package/dist/templates/cleargate-planning/.claude/settings.json +35 -0
  18. package/dist/templates/cleargate-planning/.claude/skills/flashcard/SKILL.md +92 -0
  19. package/dist/templates/cleargate-planning/.cleargate/FLASHCARD.md +7 -0
  20. package/dist/templates/cleargate-planning/.cleargate/delivery/archive/.gitkeep +0 -0
  21. package/dist/templates/cleargate-planning/.cleargate/delivery/pending-sync/.gitkeep +0 -0
  22. package/dist/templates/cleargate-planning/.cleargate/knowledge/cleargate-protocol.md +508 -0
  23. package/dist/templates/cleargate-planning/.cleargate/knowledge/readiness-gates.md +133 -0
  24. package/dist/templates/cleargate-planning/.cleargate/templates/Bug.md +82 -0
  25. package/dist/templates/cleargate-planning/.cleargate/templates/CR.md +77 -0
  26. package/dist/templates/cleargate-planning/.cleargate/templates/Sprint Plan Template.md +63 -0
  27. package/dist/templates/cleargate-planning/.cleargate/templates/epic.md +120 -0
  28. package/dist/templates/cleargate-planning/.cleargate/templates/initiative.md +53 -0
  29. package/dist/templates/cleargate-planning/.cleargate/templates/proposal.md +52 -0
  30. package/dist/templates/cleargate-planning/.cleargate/templates/story.md +135 -0
  31. package/dist/templates/cleargate-planning/CLAUDE.md +42 -0
  32. package/dist/templates/cleargate-planning/MANIFEST.json +160 -0
  33. package/dist/templates/synthesis/active-sprint.md +30 -0
  34. package/dist/templates/synthesis/open-gates.md +38 -0
  35. package/dist/templates/synthesis/product-state.md +32 -0
  36. package/dist/templates/synthesis/roadmap.md +63 -0
  37. package/package.json +9 -2
  38. package/templates/cleargate-planning/.claude/agents/architect.md +57 -0
  39. package/templates/cleargate-planning/.claude/agents/cleargate-wiki-ingest.md +145 -0
  40. package/templates/cleargate-planning/.claude/agents/cleargate-wiki-lint.md +256 -0
  41. package/templates/cleargate-planning/.claude/agents/cleargate-wiki-query.md +143 -0
  42. package/templates/cleargate-planning/.claude/agents/developer.md +58 -0
  43. package/templates/cleargate-planning/.claude/agents/qa.md +57 -0
  44. package/templates/cleargate-planning/.claude/agents/reporter.md +129 -0
  45. package/templates/cleargate-planning/.claude/hooks/session-start.sh +4 -0
  46. package/templates/cleargate-planning/.claude/hooks/stamp-and-gate.sh +18 -0
  47. package/templates/cleargate-planning/.claude/hooks/token-ledger.sh +174 -0
  48. package/templates/cleargate-planning/.claude/settings.json +35 -0
  49. package/templates/cleargate-planning/.claude/skills/flashcard/SKILL.md +92 -0
  50. package/templates/cleargate-planning/.cleargate/FLASHCARD.md +7 -0
  51. package/templates/cleargate-planning/.cleargate/delivery/archive/.gitkeep +0 -0
  52. package/templates/cleargate-planning/.cleargate/delivery/pending-sync/.gitkeep +0 -0
  53. package/templates/cleargate-planning/.cleargate/knowledge/cleargate-protocol.md +508 -0
  54. package/templates/cleargate-planning/.cleargate/knowledge/readiness-gates.md +133 -0
  55. package/templates/cleargate-planning/.cleargate/templates/Bug.md +82 -0
  56. package/templates/cleargate-planning/.cleargate/templates/CR.md +77 -0
  57. package/templates/cleargate-planning/.cleargate/templates/Sprint Plan Template.md +63 -0
  58. package/templates/cleargate-planning/.cleargate/templates/epic.md +120 -0
  59. package/templates/cleargate-planning/.cleargate/templates/initiative.md +53 -0
  60. package/templates/cleargate-planning/.cleargate/templates/proposal.md +52 -0
  61. package/templates/cleargate-planning/.cleargate/templates/story.md +135 -0
  62. package/templates/cleargate-planning/CLAUDE.md +42 -0
  63. package/templates/cleargate-planning/MANIFEST.json +160 -0
  64. package/templates/synthesis/active-sprint.md +30 -0
  65. package/templates/synthesis/open-gates.md +38 -0
  66. package/templates/synthesis/product-state.md +32 -0
  67. package/templates/synthesis/roadmap.md +63 -0
package/dist/cli.cjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cli.ts","../package.json","../src/commands/_stub.ts","../src/commands/join.ts","../src/config.ts","../src/auth/factory.ts","../src/auth/keychain-store.ts","../src/auth/file-store.ts"],"sourcesContent":["import { Command } from 'commander';\nimport pkg from '../package.json' with { type: 'json' };\nimport { stubHandler } from './commands/_stub.js';\nimport { joinHandler } from './commands/join.js';\n\nconst program = new Command();\n\nprogram\n .name('cleargate')\n .description('ClearGate CLI — connects AI agent teams to the ClearGate MCP server')\n .version(pkg.version, '-V, --version')\n .option('--profile <name>', 'configuration profile to use', 'default')\n .option('--mcp-url <url>', 'MCP server URL (overrides config file and env)')\n .showHelpAfterError('(use `cleargate --help`)');\n\nprogram\n .command('join <invite-url>')\n .description('join a ClearGate workspace using an invite URL')\n .action(async (inviteUrl: string, _opts: Record<string, unknown>, command: Command) => {\n const globals = command.parent!.opts<{ profile: string; mcpUrl?: string }>();\n await joinHandler({\n inviteUrl,\n profile: globals.profile,\n mcpUrlFlag: globals.mcpUrl,\n });\n });\n\nprogram\n .command('whoami')\n .description('print the currently authenticated agent identity')\n .action(stubHandler('whoami'));\n\nprogram\n .command('stamp')\n .description('stamp a delivery artifact into the MCP server')\n .action(stubHandler('stamp'));\n\nprogram\n .command('wiki')\n .description('query or update the workspace wiki')\n .action(stubHandler('wiki'));\n\nprogram\n .command('admin')\n .description('administrative operations (create-project, invite, issue-token, revoke-token)')\n .action(stubHandler('admin'));\n\nvoid program.parseAsync(process.argv);\n","{\n \"name\": \"cleargate\",\n \"version\": \"0.1.0-alpha.1\",\n \"private\": false,\n \"type\": \"module\",\n \"description\": \"ClearGate CLI — connects AI agent teams to the ClearGate MCP server\",\n \"bin\": {\n \"cleargate\": \"dist/cli.js\"\n },\n \"main\": \"./dist/cli.cjs\",\n \"module\": \"./dist/cli.js\",\n \"exports\": {\n \".\": {\n \"types\": \"./dist/cli.d.ts\",\n \"import\": \"./dist/cli.js\",\n \"require\": \"./dist/cli.cjs\"\n },\n \"./admin-api\": {\n \"types\": \"./dist/admin-api/index.d.ts\",\n \"import\": \"./dist/admin-api/index.js\",\n \"require\": \"./dist/admin-api/index.cjs\"\n }\n },\n \"files\": [\n \"dist\",\n \"README.md\"\n ],\n \"engines\": {\n \"node\": \">=24.0.0\"\n },\n \"scripts\": {\n \"build\": \"tsup\",\n \"dev\": \"tsup --watch\",\n \"typecheck\": \"tsc --noEmit\",\n \"pretest\": \"npm run build\",\n \"test\": \"vitest run\",\n \"test:watch\": \"vitest\"\n },\n \"dependencies\": {\n \"@napi-rs/keyring\": \"^1.2.0\",\n \"commander\": \"^12\",\n \"zod\": \"^4.3.0\"\n },\n \"devDependencies\": {\n \"@types/node\": \"^24.0.0\",\n \"tsup\": \"^8\",\n \"typescript\": \"^5.8.0\",\n \"vitest\": \"^2.1.0\"\n }\n}\n","/**\n * Shared stub handler for all not-yet-implemented subcommands.\n * Writes \"<name>: not yet implemented\" to stderr and exits 1.\n */\nexport function stubHandler(name: string): () => never {\n return (): never => {\n process.stderr.write(`${name}: not yet implemented\\n`);\n process.exit(1);\n };\n}\n","import * as os from 'node:os';\nimport { loadConfig } from '../config.js';\nimport { createTokenStore } from '../auth/factory.js';\n\nconst UUID_V4_RE =\n /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;\n\nexport interface JoinOptions {\n inviteUrl: string;\n profile: string;\n mcpUrlFlag?: string;\n /** Test seam: replaces globalThis.fetch */\n fetch?: typeof globalThis.fetch;\n /** Test seam: replaces createTokenStore */\n createStore?: typeof createTokenStore;\n /** Test seam: replaces os.hostname() */\n hostname?: () => string;\n /** Test seam: replaces process.stdout.write */\n stdout?: (s: string) => void;\n /** Test seam: replaces process.stderr.write */\n stderr?: (s: string) => void;\n /** Test seam: replaces process.exit */\n exit?: (code: number) => never;\n}\n\nexport async function joinHandler(opts: JoinOptions): Promise<void> {\n const fetchFn = opts.fetch ?? globalThis.fetch;\n const stdout = opts.stdout ?? ((s) => process.stdout.write(s));\n const stderr = opts.stderr ?? ((s) => process.stderr.write(s));\n const exit = opts.exit ?? ((c: number): never => process.exit(c));\n const hostname = opts.hostname ?? (() => os.hostname());\n\n // ── Parse inviteUrl → { token, baseUrl } ──────────────────────────────────\n let token: string;\n let baseUrl: string;\n\n try {\n if (UUID_V4_RE.test(opts.inviteUrl)) {\n // Bare UUID form — requires mcpUrl from config\n token = opts.inviteUrl;\n const cfg = loadConfig({\n flags: { profile: opts.profile, mcpUrl: opts.mcpUrlFlag },\n });\n if (!cfg.mcpUrl) {\n stderr(\n 'cleargate: bare invite token requires mcpUrl. Pass --mcp-url <url> or set CLEARGATE_MCP_URL.\\n',\n );\n exit(5);\n return; // unreachable — satisfies TypeScript after mock exit\n }\n baseUrl = cfg.mcpUrl;\n } else {\n // Full URL form: https://host/join/<uuid>\n const url = new URL(opts.inviteUrl);\n const m = url.pathname.match(/^\\/join\\/([0-9a-f-]{36})$/i);\n if (!m || !UUID_V4_RE.test(m[1]!)) {\n throw new Error('bad path');\n }\n token = m[1]!;\n baseUrl = url.origin;\n }\n } catch {\n stderr('cleargate: invalid invite URL or token format.\\n');\n exit(5);\n return; // unreachable\n }\n\n // ── POST /join/:token ──────────────────────────────────────────────────────\n let response: Response;\n try {\n response = await fetchFn(`${baseUrl}/join/${token}`, { method: 'POST' });\n } catch (err) {\n stderr(\n `cleargate: cannot reach ${baseUrl} (${err instanceof Error ? err.message : String(err)}).\\n`,\n );\n exit(2);\n return; // unreachable\n }\n\n // ── Error status handling ──────────────────────────────────────────────────\n if (response.status === 410) {\n const body = (await response.json().catch(() => ({}))) as {\n error?: string;\n };\n if (body.error === 'invite_expired') {\n stderr('cleargate: invite expired. Request a new invite.\\n');\n } else {\n stderr('cleargate: invite already consumed. Request a new invite.\\n');\n }\n exit(3);\n return;\n }\n\n if (response.status === 404) {\n stderr('cleargate: invite not found.\\n');\n exit(4);\n return;\n }\n\n if (response.status === 429) {\n const retry = response.headers.get('retry-after') ?? '900';\n stderr(`cleargate: too many requests. Retry after ${retry}s.\\n`);\n exit(8);\n return;\n }\n\n if (response.status >= 500) {\n stderr(`cleargate: server error ${response.status}.\\n`);\n exit(6);\n return;\n }\n\n if (!response.ok) {\n stderr(`cleargate: unexpected status ${response.status}.\\n`);\n exit(7);\n return;\n }\n\n // ── 200 — extract with named field access (NEVER spread) ──────────────────\n let rawBody: unknown;\n try {\n rawBody = await response.json();\n } catch {\n stderr('cleargate: server returned non-JSON response.\\n');\n exit(7);\n return;\n }\n\n const b = rawBody as {\n refresh_token?: unknown;\n project_name?: unknown;\n member_role?: unknown;\n };\n\n if (typeof b.refresh_token !== 'string' || typeof b.project_name !== 'string') {\n stderr('cleargate: server returned unexpected response shape.\\n');\n exit(7);\n return;\n }\n\n // ── Seat the refresh token ─────────────────────────────────────────────────\n // Named field access — b.refresh_token is a bare string, never logged\n const refreshToken: string = b.refresh_token;\n const projectName: string = b.project_name;\n\n try {\n const store = await (opts.createStore ?? createTokenStore)();\n await store.save(opts.profile, refreshToken);\n\n // ── Success output (D10) ─────────────────────────────────────────────────\n stdout(`joined project '${projectName}' as '${hostname()}'\\n`);\n stdout(`refresh token saved to ${store.backend}.\\n`);\n } catch (err) {\n stderr(\n `cleargate: internal error: ${err instanceof Error ? err.message : String(err)}\\n`,\n );\n exit(99);\n }\n}\n","import * as fs from 'node:fs';\nimport * as os from 'node:os';\nimport * as path from 'node:path';\nimport { z } from 'zod';\n\nexport const ConfigSchema = z\n .object({\n mcpUrl: z.string().url().optional(),\n profile: z.string().min(1).default('default'),\n logLevel: z.enum(['debug', 'info', 'warn', 'error']).default('info'),\n })\n .strict();\n\nexport type Config = z.infer<typeof ConfigSchema>;\n\n/** Partial raw config used for each layer before merge */\ntype RawConfig = Partial<{\n mcpUrl: string | undefined;\n profile: string | undefined;\n logLevel: string | undefined;\n}>;\n\nexport interface LoadConfigOptions {\n flags?: RawConfig;\n env?: NodeJS.ProcessEnv;\n configPath?: string;\n}\n\n/**\n * Synchronously loads and merges config from all layers:\n * flags > env > config file > zod defaults\n */\nexport function loadConfig(opts: LoadConfigOptions = {}): Config {\n const {\n flags = {},\n env = process.env,\n configPath,\n } = opts;\n\n // Resolve config file path\n const resolvedConfigPath =\n configPath ??\n (() => {\n const home = os.homedir();\n if (!home) return null;\n return path.join(home, '.cleargate', 'config.json');\n })();\n\n // Layer: file\n let fileLayer: RawConfig = {};\n if (resolvedConfigPath) {\n try {\n const raw = fs.readFileSync(resolvedConfigPath, 'utf8');\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch {\n throw new Error(\n `Failed to parse config file at ${resolvedConfigPath}: invalid JSON`,\n );\n }\n // Validate file contents strictly (unknown keys will throw here)\n const fileResult = ConfigSchema.safeParse(parsed);\n if (!fileResult.success) {\n throw new Error(\n `Invalid config file at ${resolvedConfigPath}: ${fileResult.error.message}`,\n );\n }\n fileLayer = fileResult.data;\n } catch (err) {\n // Re-throw parse/validation errors; silently skip only ENOENT\n if (\n err instanceof Error &&\n 'code' in err &&\n (err as NodeJS.ErrnoException).code === 'ENOENT'\n ) {\n // file doesn't exist — skip silently\n } else {\n throw err;\n }\n }\n }\n\n // Layer: env\n const envLayer: RawConfig = {};\n if (env['CLEARGATE_MCP_URL']) {\n envLayer.mcpUrl = env['CLEARGATE_MCP_URL'];\n }\n if (env['CLEARGATE_PROFILE']) {\n envLayer.profile = env['CLEARGATE_PROFILE'];\n }\n if (env['CLEARGATE_LOG_LEVEL']) {\n envLayer.logLevel = env['CLEARGATE_LOG_LEVEL'];\n }\n\n // Merge: flags > env > file (start from {} so zod defaults fill in missing fields)\n const merged: Record<string, unknown> = {\n ...fileLayer,\n ...envLayer,\n ...(flags.mcpUrl !== undefined ? { mcpUrl: flags.mcpUrl } : {}),\n ...(flags.profile !== undefined ? { profile: flags.profile } : {}),\n ...(flags.logLevel !== undefined ? { logLevel: flags.logLevel } : {}),\n };\n\n // Remove undefined values so zod defaults apply properly\n for (const key of Object.keys(merged)) {\n if (merged[key] === undefined) {\n delete merged[key];\n }\n }\n\n const result = ConfigSchema.safeParse(merged);\n if (!result.success) {\n throw new Error(`Config validation failed: ${result.error.message}`);\n }\n\n return result.data;\n}\n\n/**\n * Asserts mcpUrl is present, throws a user-friendly error if not.\n */\nexport function requireMcpUrl(cfg: Config): string {\n if (cfg.mcpUrl === undefined) {\n throw new Error(\n 'mcpUrl not configured. Run `cleargate join <invite-url>` first.',\n );\n }\n return cfg.mcpUrl;\n}\n","import * as os from 'node:os';\nimport * as path from 'node:path';\nimport { KeychainTokenStore } from './keychain-store.js';\nimport { FileTokenStore } from './file-store.js';\nimport type { TokenStore, TokenStoreFactoryOptions } from './token-store.js';\n\nconst DEFAULT_KEYCHAIN_SERVICE = 'cleargate';\n\nfunction resolveFilePath(opts: TokenStoreFactoryOptions): string {\n if (opts.filePath) return opts.filePath;\n const home = os.homedir();\n if (!home) {\n throw new Error(\n 'Cannot determine home directory. Set opts.filePath explicitly or ensure os.homedir() returns a non-empty string.',\n );\n }\n return path.join(home, '.cleargate', 'auth.json');\n}\n\nfunction defaultWarn(msg: string): void {\n process.stderr.write(msg + '\\n');\n}\n\n/**\n * Creates a TokenStore, selecting the keychain backend when available and\n * falling back to file storage with a stderr warning when the OS keychain\n * cannot be accessed.\n */\nexport async function createTokenStore(\n opts: TokenStoreFactoryOptions = {},\n): Promise<TokenStore> {\n const filePath = resolveFilePath(opts);\n const service = opts.keychainService ?? DEFAULT_KEYCHAIN_SERVICE;\n const warn = opts.warn ?? defaultWarn;\n\n // Short-circuit if backend is forced (test seam, skips probe)\n if (opts.forceBackend === 'file') {\n return new FileTokenStore(filePath);\n }\n if (opts.forceBackend === 'keychain') {\n return new KeychainTokenStore(service);\n }\n\n // Probe the keychain to determine availability\n try {\n const { Entry } = await import('@napi-rs/keyring');\n new Entry(service, '__cleargate_probe__').getPassword();\n // Probe succeeded (returned string | null cleanly) — use keychain\n return new KeychainTokenStore(service);\n } catch {\n // Constructor threw (native module load failed, libsecret missing on Linux)\n // OR getPassword() threw (dbus not running, prompt cancelled)\n // Either way, keychain is unavailable for this CLI invocation\n warn(\n `cleargate: OS keychain unavailable, falling back to file storage at ${filePath}. Run with --log-level=debug for details.`,\n );\n return new FileTokenStore(filePath);\n }\n}\n","import { Entry } from '@napi-rs/keyring';\nimport type { TokenStore } from './token-store.js';\n\nexport class KeychainTokenStore implements TokenStore {\n readonly backend = 'keychain' as const;\n\n constructor(private readonly service: string) {}\n\n async save(profile: string, token: string): Promise<void> {\n new Entry(this.service, profile).setPassword(token);\n }\n\n async load(profile: string): Promise<string | null> {\n try {\n const result = new Entry(this.service, profile).getPassword();\n // getPassword() returns string | null per @napi-rs/keyring@1.2.0 index.d.ts:124\n // Despite the docstring claiming it throws NoEntry, the return type wins.\n // Handle both: null return AND potential thrown NoEntry (platform-specific).\n return result ?? null;\n } catch {\n // NoEntry or other keychain error — treat as absent\n return null;\n }\n }\n\n async remove(profile: string): Promise<void> {\n try {\n new Entry(this.service, profile).deletePassword();\n } catch {\n // Entry didn't exist or other keychain error — idempotent, swallow\n }\n }\n}\n","import * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport { z } from 'zod';\nimport type { TokenStore } from './token-store.js';\n\nconst ProfileEntrySchema = z.object({ refreshToken: z.string().min(1) }).strict();\n\nexport const AuthFileSchema = z\n .object({\n version: z.literal(1),\n profiles: z.record(z.string().min(1), ProfileEntrySchema),\n })\n .strict();\n\ntype AuthFile = z.infer<typeof AuthFileSchema>;\n\nconst EMPTY_AUTH_FILE: AuthFile = { version: 1, profiles: {} };\n\nexport class FileTokenStore implements TokenStore {\n readonly backend = 'file' as const;\n\n constructor(private readonly filePath: string) {}\n\n async save(profile: string, token: string): Promise<void> {\n const current = await this.readFile();\n const updated: AuthFile = {\n ...current,\n profiles: {\n ...current.profiles,\n [profile]: { refreshToken: token },\n },\n };\n await this.writeFile(updated);\n }\n\n async load(profile: string): Promise<string | null> {\n const data = await this.readFile();\n return data.profiles[profile]?.refreshToken ?? null;\n }\n\n async remove(profile: string): Promise<void> {\n let current: AuthFile;\n try {\n current = await this.readFile();\n } catch {\n // File doesn't exist or unreadable — no-op since there's nothing to remove\n return;\n }\n if (!(profile in current.profiles)) {\n return; // Profile doesn't exist — idempotent\n }\n const { [profile]: _removed, ...rest } = current.profiles;\n const updated: AuthFile = { ...current, profiles: rest };\n await this.writeFile(updated);\n }\n\n private async readFile(): Promise<AuthFile> {\n let raw: string;\n try {\n raw = await fs.readFile(this.filePath, 'utf8');\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') {\n return EMPTY_AUTH_FILE;\n }\n throw err;\n }\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch {\n throw new Error(\n `Failed to parse auth file at ${this.filePath}: invalid JSON`,\n );\n }\n\n const result = AuthFileSchema.safeParse(parsed);\n if (!result.success) {\n // Check for version mismatch specifically\n const versionCheck = (parsed as Record<string, unknown>)?.['version'];\n if (versionCheck !== 1) {\n throw new Error(\n `Invalid auth file at ${this.filePath}: unsupported version ${String(versionCheck)}. Please upgrade \\`cleargate\\` to read this file.`,\n );\n }\n throw new Error(\n `Invalid auth file at ${this.filePath}: ${result.error.message}`,\n );\n }\n\n return result.data;\n }\n\n private async writeFile(data: AuthFile): Promise<void> {\n const dir = path.dirname(this.filePath);\n await fs.mkdir(dir, { recursive: true, mode: 0o700 });\n // Explicit chmod after mkdir — mkdir only sets mode on newly created dirs\n await fs.chmod(dir, 0o700).catch(() => {\n // If chmod fails on existing dir, that's acceptable — we don't want to\n // surprise users who have set custom modes on ~/.cleargate/\n });\n\n const json = JSON.stringify(data, null, 2);\n const tmpPath = path.join(dir, '.auth.json.tmp');\n\n // Atomic write: write to tmp then rename to avoid partial-write corruption\n await fs.writeFile(tmpPath, json, { mode: 0o600 });\n // Explicit chmod after writeFile — writeFile only sets mode on file creation\n await fs.chmod(tmpPath, 0o600);\n await fs.rename(tmpPath, this.filePath);\n // After rename, chmod the final path to ensure it stays 0600\n await fs.chmod(this.filePath, 0o600);\n }\n}\n"],"mappings":"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","names":["os","os","path","fs","path","import_zod","Entry","hostname"]}
1
+ {"version":3,"sources":["../node_modules/tsup/assets/cjs_shims.js","../src/cli.ts","../package.json","../src/commands/_stub.ts","../src/commands/join.ts","../src/config.ts","../src/auth/factory.ts","../src/auth/keychain-store.ts","../src/auth/file-store.ts","../src/commands/stamp.ts","../src/lib/codebase-version.ts","../src/lib/stamp-frontmatter.ts","../src/wiki/parse-frontmatter.ts","../src/lib/frontmatter-yaml.ts","../src/commands/init.ts","../src/init/copy-payload.ts","../src/init/merge-settings.ts","../src/init/inject-claude-md.ts","../src/commands/wiki-build.ts","../src/wiki/scan.ts","../src/wiki/derive-bucket.ts","../src/wiki/derive-repo.ts","../src/wiki/git-sha.ts","../src/wiki/page-schema.ts","../src/wiki/synthesis/active-sprint.ts","../src/wiki/synthesis/render.ts","../src/wiki/synthesis/open-gates.ts","../src/wiki/synthesis/product-state.ts","../src/wiki/synthesis/roadmap.ts","../src/lib/manifest.ts","../src/lib/sha256.ts","../src/lib/prompts.ts","../src/commands/wiki-ingest.ts","../src/commands/wiki-lint.ts","../src/wiki/load-wiki.ts","../src/wiki/lint-checks.ts","../src/lib/work-item-type.ts","../src/commands/wiki-query.ts","../src/commands/doctor.ts","../src/lib/pricing.ts","../src/commands/gate.ts","../src/lib/readiness-predicates.ts","../src/lib/frontmatter-cache.ts","../src/commands/stamp-tokens.ts","../src/lib/ledger-reader.ts","../src/commands/upgrade.ts","../src/lib/claude-md-surgery.ts","../src/lib/settings-json-surgery.ts","../src/lib/merge-ui.ts","../src/lib/editor.ts","../src/commands/uninstall.ts"],"sourcesContent":["// Shim globals in cjs bundle\n// There's a weird bug that esbuild will always inject importMetaUrl\n// if we export it as `const importMetaUrl = ... __filename ...`\n// But using a function will not cause this issue\n\nconst getImportMetaUrl = () => \n typeof document === \"undefined\" \n ? new URL(`file:${__filename}`).href \n : (document.currentScript && document.currentScript.tagName.toUpperCase() === 'SCRIPT') \n ? document.currentScript.src \n : new URL(\"main.js\", document.baseURI).href;\n\nexport const importMetaUrl = /* @__PURE__ */ getImportMetaUrl()\n","import { Command } from 'commander';\nimport pkg from '../package.json' with { type: 'json' };\nimport { stubHandler } from './commands/_stub.js';\nimport { joinHandler } from './commands/join.js';\nimport { stampHandler } from './commands/stamp.js';\nimport { initHandler } from './commands/init.js';\nimport { wikiBuildHandler } from './commands/wiki-build.js';\nimport { wikiIngestHandler } from './commands/wiki-ingest.js';\nimport { wikiLintHandler } from './commands/wiki-lint.js';\nimport { wikiQueryHandler } from './commands/wiki-query.js';\nimport { doctorHandler } from './commands/doctor.js';\nimport { gateCheckHandler, gateExplainHandler } from './commands/gate.js';\nimport { stampTokensHandler } from './commands/stamp-tokens.js';\nimport { upgradeHandler } from './commands/upgrade.js';\nimport { uninstallHandler } from './commands/uninstall.js';\n\nconst program = new Command();\n\nprogram\n .name('cleargate')\n .description('ClearGate CLI — connects AI agent teams to the ClearGate MCP server')\n .version(pkg.version, '-V, --version')\n .option('--profile <name>', 'configuration profile to use', 'default')\n .option('--mcp-url <url>', 'MCP server URL (overrides config file and env)')\n .showHelpAfterError('(use `cleargate --help`)');\n\nprogram\n .command('join <invite-url>')\n .description('join a ClearGate workspace using an invite URL')\n .action(async (inviteUrl: string, _opts: Record<string, unknown>, command: Command) => {\n const globals = command.parent!.opts<{ profile: string; mcpUrl?: string }>();\n await joinHandler({\n inviteUrl,\n profile: globals.profile,\n mcpUrlFlag: globals.mcpUrl,\n });\n });\n\nprogram\n .command('init')\n .description('initialise a repo with ClearGate scaffold (CLAUDE.md block, hook config, agents, templates)')\n .option('--force', 'overwrite existing files that differ from the bundled payload')\n .action(async (opts: { force?: boolean }) => {\n await initHandler({ force: opts.force ?? false });\n });\n\nprogram\n .command('whoami')\n .description('print the currently authenticated agent identity')\n .action(stubHandler('whoami'));\n\nprogram\n .command('stamp <file>')\n .description('stamp ClearGate metadata fields into a file\\'s frontmatter')\n .option('--dry-run', 'print planned changes without writing')\n .action(async (file: string, opts: { dryRun?: boolean }) => {\n await stampHandler(file, { dryRun: opts.dryRun });\n });\n\nconst wiki = program\n .command('wiki')\n .description('query or update the workspace wiki');\n\nwiki\n .command('build')\n .description('full rebuild of .cleargate/wiki/ from raw delivery items')\n .action(async () => {\n await wikiBuildHandler();\n });\n\nwiki\n .command('ingest <file>')\n .description('ingest a single raw delivery file into the wiki')\n .action(async (file: string) => {\n await wikiIngestHandler({ rawPath: file });\n });\n\nwiki\n .command('lint')\n .description('check wiki pages for drift vs raw sources')\n .option('--suggest', 'advisory mode — exit 0, emit suggestions only')\n .helpOption('--help', [\n 'Usage: cleargate wiki lint [--suggest]',\n '',\n 'Enforcement mode (default): exits 1 on any finding.',\n 'Suggest mode (--suggest): exits 0, prefixes findings with [advisory],',\n ' and emits Karpathy cross-ref discovery candidates.',\n ].join('\\n'))\n .action(async (_opts: Record<string, unknown>, command: Command) => {\n const cmdOpts = command.opts<{ suggest?: boolean }>();\n await wikiLintHandler({\n mode: cmdOpts.suggest ? 'suggest' : 'enforce',\n });\n });\n\nwiki\n .command('query <terms...>')\n .description('search the wiki index for matching work items')\n .option('--persist', 'write result as a topic page under wiki/topics/')\n .addHelpText('after', [\n '',\n 'NOTE: CLI synthesis is grep-and-list. For NL synthesis with the',\n 'cleargate-wiki-query subagent, invoke from a Claude Code session.',\n 'This diverges from PROPOSAL-002 §2.2 intentionally for testability',\n 'and offline/scripted use.',\n ].join('\\n'))\n .action(async (terms: string[], opts: { persist?: boolean }) => {\n await wikiQueryHandler({\n query: terms.join(' '),\n persist: opts.persist ?? false,\n });\n });\n\nconst gate = program\n .command('gate')\n .description('evaluate readiness gates for a ClearGate work-item file');\n\ngate\n .command('check <file>')\n .description('evaluate readiness criteria and write result to frontmatter')\n .option('-v, --verbose', 'show full expected-vs-actual detail per criterion')\n .option('--transition <name>', 'override auto-detected transition name')\n .action(async (file: string, opts: { verbose?: boolean; transition?: string }) => {\n await gateCheckHandler(file, { verbose: opts.verbose, transition: opts.transition });\n });\n\ngate\n .command('explain <file>')\n .description('render cached gate result in ≤50 agent tokens (read-only)')\n .action(async (file: string) => {\n await gateExplainHandler(file);\n });\n\nprogram\n .command('stamp-tokens <file>')\n .description('stamp draft_tokens from token-ledger into a work-item file (hook-invoked)')\n .option('--dry-run', 'print planned changes without writing')\n .action(async (file: string, opts: { dryRun?: boolean }) => {\n await stampTokensHandler(file, { dryRun: opts.dryRun });\n });\n\nprogram\n .command('admin')\n .description('administrative operations (create-project, invite, issue-token, revoke-token)')\n .action(stubHandler('admin'));\n\nprogram\n .command('doctor')\n .description('diagnose scaffold drift, hook health, blocked items, and token cost')\n .option('--check-scaffold', 'check scaffold files for drift against install snapshot')\n .option('--session-start-mode', 'hidden: enables daily throttle (used by session-start hook)', false)\n .option('--session-start', 'emit blocked pending-sync items summary (used by SessionStart hook)')\n .option('--pricing <file>', 'compute USD cost estimate from a work item\\'s draft_tokens')\n .option('-v, --verbose', 'show per-file drift detail')\n .addHelpText('after', [\n '',\n 'Modes (mutually exclusive):',\n ' --check-scaffold Compute drift for all tracked scaffold files.',\n ' Writes .cleargate/.drift-state.json.',\n ' --session-start List blocked pending-sync items (≤10, ≤100 tokens).',\n ' --pricing <file> Compute USD estimate from a work item\\'s draft_tokens.',\n ' (default) Print a minimal hook-config health report.',\n ].join('\\n'))\n .action(async (opts: { checkScaffold?: boolean; sessionStartMode?: boolean; sessionStart?: boolean; pricing?: string; verbose?: boolean }) => {\n await doctorHandler({\n checkScaffold: opts.checkScaffold,\n sessionStartMode: opts.sessionStartMode,\n sessionStart: opts.sessionStart,\n pricing: !!opts.pricing,\n pricingFile: opts.pricing,\n verbose: opts.verbose,\n });\n });\n\nprogram\n .command('upgrade')\n .description('three-way merge scaffold files with upstream changes')\n .option('--dry-run', 'print plan without making any changes')\n .option('--yes', 'auto-accept \"take theirs\" for all merge-3way files (non-interactive)')\n .option('--only <tier>', 'restrict to a specific scaffold tier (protocol/template/agent/hook/skill/cli-config)')\n .addHelpText('after', [\n '',\n 'Overwrite policies:',\n ' always — silent overwrite with package content',\n ' never — silent skip',\n ' preserve — silent skip',\n ' merge-3way — interactive: [k]eep mine / [t]ake theirs / [e]dit in $EDITOR',\n '',\n '--yes auto-accepts [t]ake theirs for all merge-3way files.',\n ].join('\\n'))\n .action(async (opts: { dryRun?: boolean; yes?: boolean; only?: string }) => {\n await upgradeHandler({ dryRun: opts.dryRun, yes: opts.yes, only: opts.only });\n });\n\nprogram\n .command('uninstall')\n .description('remove ClearGate scaffold from a project (preservation-first)')\n .option('--dry-run', 'preview planned actions without making any changes (CI-safe)')\n .option('--preserve <tiers>', 'comma-separated tier ids to force-preserve (default: user-artifact)')\n .option('--remove <tiers>', 'comma-separated tier ids to force-remove; use \"all\" to remove everything including user artifacts (DANGEROUS)')\n .option('--yes', 'skip typed project-name confirmation (dangerous — use in scripts/CI)')\n .option('--path <dir>', 'target directory (must contain .cleargate/.install-manifest.json); defaults to cwd')\n .option('--force', 'bypass uncommitted-changes safety check (not applicable for non-git targets)')\n .addHelpText('after', [\n '',\n 'Preservation defaults:',\n ' user-artifact tier → kept (FLASHCARD.md, archive, pending-sync, sprint REPORT.md)',\n ' framework tiers → removed (protocol, template, agent, hook, skill, cli-config)',\n '',\n 'Always removed (no prompt): .claude/agents/*.md, ClearGate hooks,',\n ' .claude/skills/flashcard/, CLAUDE.md CLEARGATE block,',\n ' @cleargate/cli from package.json, .install-manifest.json, .drift-state.json.',\n '',\n 'Non-git targets: uncommitted-changes check is skipped silently.',\n ].join('\\n'))\n .action(async (opts: {\n dryRun?: boolean;\n preserve?: string;\n remove?: string;\n yes?: boolean;\n path?: string;\n force?: boolean;\n }) => {\n await uninstallHandler({\n dryRun: opts.dryRun,\n preserve: opts.preserve ? opts.preserve.split(',').map((s) => s.trim()) : undefined,\n remove: opts.remove ? opts.remove.split(',').map((s) => s.trim()) : undefined,\n yes: opts.yes,\n path: opts.path,\n force: opts.force,\n });\n });\n\nvoid program.parseAsync(process.argv);\n","{\n \"name\": \"cleargate\",\n \"version\": \"0.2.1\",\n \"private\": false,\n \"type\": \"module\",\n \"description\": \"Planning framework for Claude Code agents — sprint/epic/story protocol, four-agent loop (architect/developer/qa/reporter), Karpathy-style awareness wiki.\",\n \"bin\": {\n \"cleargate\": \"dist/cli.js\"\n },\n \"main\": \"./dist/cli.cjs\",\n \"module\": \"./dist/cli.js\",\n \"exports\": {\n \".\": {\n \"types\": \"./dist/cli.d.ts\",\n \"import\": \"./dist/cli.js\",\n \"require\": \"./dist/cli.cjs\"\n },\n \"./admin-api\": {\n \"types\": \"./dist/admin-api/index.d.ts\",\n \"import\": \"./dist/admin-api/index.js\",\n \"require\": \"./dist/admin-api/index.cjs\"\n }\n },\n \"files\": [\n \"dist\",\n \"templates\",\n \"README.md\"\n ],\n \"engines\": {\n \"node\": \">=24.0.0\"\n },\n \"scripts\": {\n \"prebuild\": \"tsx scripts/build-manifest.ts && node scripts/copy-planning-payload.mjs\",\n \"build\": \"tsup\",\n \"dev\": \"tsup --watch\",\n \"typecheck\": \"tsc --noEmit\",\n \"pretest\": \"npm run build\",\n \"test\": \"vitest run\",\n \"test:watch\": \"vitest\"\n },\n \"dependencies\": {\n \"@napi-rs/keyring\": \"^1.2.0\",\n \"commander\": \"^12\",\n \"diff\": \"^5.2.2\",\n \"js-yaml\": \"^4.1.0\",\n \"zod\": \"^4.3.0\"\n },\n \"devDependencies\": {\n \"@types/diff\": \"^5.2.3\",\n \"@types/js-yaml\": \"^4.0.9\",\n \"@types/node\": \"^24.0.0\",\n \"tsup\": \"^8\",\n \"tsx\": \"^4.21.0\",\n \"typescript\": \"^5.8.0\",\n \"vitest\": \"^2.1.0\"\n }\n}\n","/**\n * Shared stub handler for all not-yet-implemented subcommands.\n * Writes \"<name>: not yet implemented\" to stderr and exits 1.\n */\nexport function stubHandler(name: string): () => never {\n return (): never => {\n process.stderr.write(`${name}: not yet implemented\\n`);\n process.exit(1);\n };\n}\n","import * as os from 'node:os';\nimport { loadConfig } from '../config.js';\nimport { createTokenStore } from '../auth/factory.js';\n\nconst UUID_V4_RE =\n /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;\n\nexport interface JoinOptions {\n inviteUrl: string;\n profile: string;\n mcpUrlFlag?: string;\n /** Test seam: replaces globalThis.fetch */\n fetch?: typeof globalThis.fetch;\n /** Test seam: replaces createTokenStore */\n createStore?: typeof createTokenStore;\n /** Test seam: replaces os.hostname() */\n hostname?: () => string;\n /** Test seam: replaces process.stdout.write */\n stdout?: (s: string) => void;\n /** Test seam: replaces process.stderr.write */\n stderr?: (s: string) => void;\n /** Test seam: replaces process.exit */\n exit?: (code: number) => never;\n}\n\nexport async function joinHandler(opts: JoinOptions): Promise<void> {\n const fetchFn = opts.fetch ?? globalThis.fetch;\n const stdout = opts.stdout ?? ((s) => process.stdout.write(s));\n const stderr = opts.stderr ?? ((s) => process.stderr.write(s));\n const exit = opts.exit ?? ((c: number): never => process.exit(c));\n const hostname = opts.hostname ?? (() => os.hostname());\n\n // ── Parse inviteUrl → { token, baseUrl } ──────────────────────────────────\n let token: string;\n let baseUrl: string;\n\n try {\n if (UUID_V4_RE.test(opts.inviteUrl)) {\n // Bare UUID form — requires mcpUrl from config\n token = opts.inviteUrl;\n const cfg = loadConfig({\n flags: { profile: opts.profile, mcpUrl: opts.mcpUrlFlag },\n });\n if (!cfg.mcpUrl) {\n stderr(\n 'cleargate: bare invite token requires mcpUrl. Pass --mcp-url <url> or set CLEARGATE_MCP_URL.\\n',\n );\n exit(5);\n return; // unreachable — satisfies TypeScript after mock exit\n }\n baseUrl = cfg.mcpUrl;\n } else {\n // Full URL form: https://host/join/<uuid>\n const url = new URL(opts.inviteUrl);\n const m = url.pathname.match(/^\\/join\\/([0-9a-f-]{36})$/i);\n if (!m || !UUID_V4_RE.test(m[1]!)) {\n throw new Error('bad path');\n }\n token = m[1]!;\n baseUrl = url.origin;\n }\n } catch {\n stderr('cleargate: invalid invite URL or token format.\\n');\n exit(5);\n return; // unreachable\n }\n\n // ── POST /join/:token ──────────────────────────────────────────────────────\n let response: Response;\n try {\n response = await fetchFn(`${baseUrl}/join/${token}`, { method: 'POST' });\n } catch (err) {\n stderr(\n `cleargate: cannot reach ${baseUrl} (${err instanceof Error ? err.message : String(err)}).\\n`,\n );\n exit(2);\n return; // unreachable\n }\n\n // ── Error status handling ──────────────────────────────────────────────────\n if (response.status === 410) {\n const body = (await response.json().catch(() => ({}))) as {\n error?: string;\n };\n if (body.error === 'invite_expired') {\n stderr('cleargate: invite expired. Request a new invite.\\n');\n } else {\n stderr('cleargate: invite already consumed. Request a new invite.\\n');\n }\n exit(3);\n return;\n }\n\n if (response.status === 404) {\n stderr('cleargate: invite not found.\\n');\n exit(4);\n return;\n }\n\n if (response.status === 429) {\n const retry = response.headers.get('retry-after') ?? '900';\n stderr(`cleargate: too many requests. Retry after ${retry}s.\\n`);\n exit(8);\n return;\n }\n\n if (response.status >= 500) {\n stderr(`cleargate: server error ${response.status}.\\n`);\n exit(6);\n return;\n }\n\n if (!response.ok) {\n stderr(`cleargate: unexpected status ${response.status}.\\n`);\n exit(7);\n return;\n }\n\n // ── 200 — extract with named field access (NEVER spread) ──────────────────\n let rawBody: unknown;\n try {\n rawBody = await response.json();\n } catch {\n stderr('cleargate: server returned non-JSON response.\\n');\n exit(7);\n return;\n }\n\n const b = rawBody as {\n refresh_token?: unknown;\n project_name?: unknown;\n member_role?: unknown;\n };\n\n if (typeof b.refresh_token !== 'string' || typeof b.project_name !== 'string') {\n stderr('cleargate: server returned unexpected response shape.\\n');\n exit(7);\n return;\n }\n\n // ── Seat the refresh token ─────────────────────────────────────────────────\n // Named field access — b.refresh_token is a bare string, never logged\n const refreshToken: string = b.refresh_token;\n const projectName: string = b.project_name;\n\n try {\n const store = await (opts.createStore ?? createTokenStore)();\n await store.save(opts.profile, refreshToken);\n\n // ── Success output (D10) ─────────────────────────────────────────────────\n stdout(`joined project '${projectName}' as '${hostname()}'\\n`);\n stdout(`refresh token saved to ${store.backend}.\\n`);\n } catch (err) {\n stderr(\n `cleargate: internal error: ${err instanceof Error ? err.message : String(err)}\\n`,\n );\n exit(99);\n }\n}\n","import * as fs from 'node:fs';\nimport * as os from 'node:os';\nimport * as path from 'node:path';\nimport { z } from 'zod';\n\nexport const ConfigSchema = z\n .object({\n mcpUrl: z.string().url().optional(),\n profile: z.string().min(1).default('default'),\n logLevel: z.enum(['debug', 'info', 'warn', 'error']).default('info'),\n })\n .strict();\n\nexport type Config = z.infer<typeof ConfigSchema>;\n\n/** Partial raw config used for each layer before merge */\ntype RawConfig = Partial<{\n mcpUrl: string | undefined;\n profile: string | undefined;\n logLevel: string | undefined;\n}>;\n\nexport interface LoadConfigOptions {\n flags?: RawConfig;\n env?: NodeJS.ProcessEnv;\n configPath?: string;\n}\n\n/**\n * Synchronously loads and merges config from all layers:\n * flags > env > config file > zod defaults\n */\nexport function loadConfig(opts: LoadConfigOptions = {}): Config {\n const {\n flags = {},\n env = process.env,\n configPath,\n } = opts;\n\n // Resolve config file path\n const resolvedConfigPath =\n configPath ??\n (() => {\n const home = os.homedir();\n if (!home) return null;\n return path.join(home, '.cleargate', 'config.json');\n })();\n\n // Layer: file\n let fileLayer: RawConfig = {};\n if (resolvedConfigPath) {\n try {\n const raw = fs.readFileSync(resolvedConfigPath, 'utf8');\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch {\n throw new Error(\n `Failed to parse config file at ${resolvedConfigPath}: invalid JSON`,\n );\n }\n // Validate file contents strictly (unknown keys will throw here)\n const fileResult = ConfigSchema.safeParse(parsed);\n if (!fileResult.success) {\n throw new Error(\n `Invalid config file at ${resolvedConfigPath}: ${fileResult.error.message}`,\n );\n }\n fileLayer = fileResult.data;\n } catch (err) {\n // Re-throw parse/validation errors; silently skip only ENOENT\n if (\n err instanceof Error &&\n 'code' in err &&\n (err as NodeJS.ErrnoException).code === 'ENOENT'\n ) {\n // file doesn't exist — skip silently\n } else {\n throw err;\n }\n }\n }\n\n // Layer: env\n const envLayer: RawConfig = {};\n if (env['CLEARGATE_MCP_URL']) {\n envLayer.mcpUrl = env['CLEARGATE_MCP_URL'];\n }\n if (env['CLEARGATE_PROFILE']) {\n envLayer.profile = env['CLEARGATE_PROFILE'];\n }\n if (env['CLEARGATE_LOG_LEVEL']) {\n envLayer.logLevel = env['CLEARGATE_LOG_LEVEL'];\n }\n\n // Merge: flags > env > file (start from {} so zod defaults fill in missing fields)\n const merged: Record<string, unknown> = {\n ...fileLayer,\n ...envLayer,\n ...(flags.mcpUrl !== undefined ? { mcpUrl: flags.mcpUrl } : {}),\n ...(flags.profile !== undefined ? { profile: flags.profile } : {}),\n ...(flags.logLevel !== undefined ? { logLevel: flags.logLevel } : {}),\n };\n\n // Remove undefined values so zod defaults apply properly\n for (const key of Object.keys(merged)) {\n if (merged[key] === undefined) {\n delete merged[key];\n }\n }\n\n const result = ConfigSchema.safeParse(merged);\n if (!result.success) {\n throw new Error(`Config validation failed: ${result.error.message}`);\n }\n\n return result.data;\n}\n\n/**\n * Asserts mcpUrl is present, throws a user-friendly error if not.\n */\nexport function requireMcpUrl(cfg: Config): string {\n if (cfg.mcpUrl === undefined) {\n throw new Error(\n 'mcpUrl not configured. Run `cleargate join <invite-url>` first.',\n );\n }\n return cfg.mcpUrl;\n}\n","import * as os from 'node:os';\nimport * as path from 'node:path';\nimport { KeychainTokenStore } from './keychain-store.js';\nimport { FileTokenStore } from './file-store.js';\nimport type { TokenStore, TokenStoreFactoryOptions } from './token-store.js';\n\nconst DEFAULT_KEYCHAIN_SERVICE = 'cleargate';\n\nfunction resolveFilePath(opts: TokenStoreFactoryOptions): string {\n if (opts.filePath) return opts.filePath;\n const home = os.homedir();\n if (!home) {\n throw new Error(\n 'Cannot determine home directory. Set opts.filePath explicitly or ensure os.homedir() returns a non-empty string.',\n );\n }\n return path.join(home, '.cleargate', 'auth.json');\n}\n\nfunction defaultWarn(msg: string): void {\n process.stderr.write(msg + '\\n');\n}\n\n/**\n * Creates a TokenStore, selecting the keychain backend when available and\n * falling back to file storage with a stderr warning when the OS keychain\n * cannot be accessed.\n */\nexport async function createTokenStore(\n opts: TokenStoreFactoryOptions = {},\n): Promise<TokenStore> {\n const filePath = resolveFilePath(opts);\n const service = opts.keychainService ?? DEFAULT_KEYCHAIN_SERVICE;\n const warn = opts.warn ?? defaultWarn;\n\n // Short-circuit if backend is forced (test seam, skips probe)\n if (opts.forceBackend === 'file') {\n return new FileTokenStore(filePath);\n }\n if (opts.forceBackend === 'keychain') {\n return new KeychainTokenStore(service);\n }\n\n // Probe the keychain to determine availability\n try {\n const { Entry } = await import('@napi-rs/keyring');\n new Entry(service, '__cleargate_probe__').getPassword();\n // Probe succeeded (returned string | null cleanly) — use keychain\n return new KeychainTokenStore(service);\n } catch {\n // Constructor threw (native module load failed, libsecret missing on Linux)\n // OR getPassword() threw (dbus not running, prompt cancelled)\n // Either way, keychain is unavailable for this CLI invocation\n warn(\n `cleargate: OS keychain unavailable, falling back to file storage at ${filePath}. Run with --log-level=debug for details.`,\n );\n return new FileTokenStore(filePath);\n }\n}\n","import { Entry } from '@napi-rs/keyring';\nimport type { TokenStore } from './token-store.js';\n\nexport class KeychainTokenStore implements TokenStore {\n readonly backend = 'keychain' as const;\n\n constructor(private readonly service: string) {}\n\n async save(profile: string, token: string): Promise<void> {\n new Entry(this.service, profile).setPassword(token);\n }\n\n async load(profile: string): Promise<string | null> {\n try {\n const result = new Entry(this.service, profile).getPassword();\n // getPassword() returns string | null per @napi-rs/keyring@1.2.0 index.d.ts:124\n // Despite the docstring claiming it throws NoEntry, the return type wins.\n // Handle both: null return AND potential thrown NoEntry (platform-specific).\n return result ?? null;\n } catch {\n // NoEntry or other keychain error — treat as absent\n return null;\n }\n }\n\n async remove(profile: string): Promise<void> {\n try {\n new Entry(this.service, profile).deletePassword();\n } catch {\n // Entry didn't exist or other keychain error — idempotent, swallow\n }\n }\n}\n","import * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport { z } from 'zod';\nimport type { TokenStore } from './token-store.js';\n\nconst ProfileEntrySchema = z.object({ refreshToken: z.string().min(1) }).strict();\n\nexport const AuthFileSchema = z\n .object({\n version: z.literal(1),\n profiles: z.record(z.string().min(1), ProfileEntrySchema),\n })\n .strict();\n\ntype AuthFile = z.infer<typeof AuthFileSchema>;\n\nconst EMPTY_AUTH_FILE: AuthFile = { version: 1, profiles: {} };\n\nexport class FileTokenStore implements TokenStore {\n readonly backend = 'file' as const;\n\n constructor(private readonly filePath: string) {}\n\n async save(profile: string, token: string): Promise<void> {\n const current = await this.readFile();\n const updated: AuthFile = {\n ...current,\n profiles: {\n ...current.profiles,\n [profile]: { refreshToken: token },\n },\n };\n await this.writeFile(updated);\n }\n\n async load(profile: string): Promise<string | null> {\n const data = await this.readFile();\n return data.profiles[profile]?.refreshToken ?? null;\n }\n\n async remove(profile: string): Promise<void> {\n let current: AuthFile;\n try {\n current = await this.readFile();\n } catch {\n // File doesn't exist or unreadable — no-op since there's nothing to remove\n return;\n }\n if (!(profile in current.profiles)) {\n return; // Profile doesn't exist — idempotent\n }\n const { [profile]: _removed, ...rest } = current.profiles;\n const updated: AuthFile = { ...current, profiles: rest };\n await this.writeFile(updated);\n }\n\n private async readFile(): Promise<AuthFile> {\n let raw: string;\n try {\n raw = await fs.readFile(this.filePath, 'utf8');\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') {\n return EMPTY_AUTH_FILE;\n }\n throw err;\n }\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch {\n throw new Error(\n `Failed to parse auth file at ${this.filePath}: invalid JSON`,\n );\n }\n\n const result = AuthFileSchema.safeParse(parsed);\n if (!result.success) {\n // Check for version mismatch specifically\n const versionCheck = (parsed as Record<string, unknown>)?.['version'];\n if (versionCheck !== 1) {\n throw new Error(\n `Invalid auth file at ${this.filePath}: unsupported version ${String(versionCheck)}. Please upgrade \\`cleargate\\` to read this file.`,\n );\n }\n throw new Error(\n `Invalid auth file at ${this.filePath}: ${result.error.message}`,\n );\n }\n\n return result.data;\n }\n\n private async writeFile(data: AuthFile): Promise<void> {\n const dir = path.dirname(this.filePath);\n await fs.mkdir(dir, { recursive: true, mode: 0o700 });\n // Explicit chmod after mkdir — mkdir only sets mode on newly created dirs\n await fs.chmod(dir, 0o700).catch(() => {\n // If chmod fails on existing dir, that's acceptable — we don't want to\n // surprise users who have set custom modes on ~/.cleargate/\n });\n\n const json = JSON.stringify(data, null, 2);\n const tmpPath = path.join(dir, '.auth.json.tmp');\n\n // Atomic write: write to tmp then rename to avoid partial-write corruption\n await fs.writeFile(tmpPath, json, { mode: 0o600 });\n // Explicit chmod after writeFile — writeFile only sets mode on file creation\n await fs.chmod(tmpPath, 0o600);\n await fs.rename(tmpPath, this.filePath);\n // After rename, chmod the final path to ensure it stays 0600\n await fs.chmod(this.filePath, 0o600);\n }\n}\n","/**\n * stamp.ts — `cleargate stamp <file>` command handler\n *\n * Wraps M1 helpers: getCodebaseVersion + stampFrontmatter.\n * Do NOT hand-roll YAML or shell git — use the M1 helpers.\n *\n * FLASHCARD #cli #determinism #test-seam: thread `now`, `exit`, `stdout` seams.\n * FLASHCARD #tsup #cjs #esm: no top-level await.\n * FLASHCARD #cli #commander #optional-key: conditionally assign `now`/`version` opts.\n */\n\nimport * as fs from 'node:fs';\nimport * as os from 'node:os';\nimport * as path from 'node:path';\nimport { getCodebaseVersion, type CodebaseVersion } from '../lib/codebase-version.js';\nimport { stampFrontmatter, type StampOptions } from '../lib/stamp-frontmatter.js';\nimport { parseFrontmatter } from '../wiki/parse-frontmatter.js';\n\nexport interface StampCliOptions {\n cwd?: string;\n now?: () => Date;\n stdout?: (s: string) => void;\n exit?: (code: number) => never;\n /** Test seam: inject a fixed CodebaseVersion instead of calling getCodebaseVersion. */\n getVersion?: () => CodebaseVersion;\n}\n\n/**\n * Build a unified-diff-style preview of the frontmatter changes.\n * Prints context lines (unchanged) with a leading space,\n * removed lines with `-`, added lines with `+`.\n */\nfunction buildDiffPreview(\n filePath: string,\n before: Record<string, unknown>,\n after: Record<string, unknown>,\n): string {\n const lines: string[] = [`--- ${filePath}`, `+++ ${filePath} (after stamp)`];\n\n // Use insertion order of keys — include both before and after\n const seenKeys = new Set<string>();\n for (const key of [...Object.keys(before), ...Object.keys(after)]) {\n if (seenKeys.has(key)) continue;\n seenKeys.add(key);\n const bVal = before[key];\n const aVal = after[key];\n if (bVal === aVal) {\n lines.push(` ${key}: ${String(bVal)}`);\n } else {\n if (key in before) {\n lines.push(`-${key}: ${String(bVal)}`);\n }\n if (key in after) {\n lines.push(`+${key}: ${String(aVal)}`);\n }\n }\n }\n return lines.join('\\n');\n}\n\nexport async function stampHandler(\n file: string,\n opts: { dryRun?: boolean },\n cli?: StampCliOptions,\n): Promise<void> {\n const stdoutFn = cli?.stdout ?? ((s: string) => process.stdout.write(s + '\\n'));\n const exitFn: (code: number) => never =\n cli?.exit ?? ((code: number) => process.exit(code) as never);\n const cwd = cli?.cwd ?? process.cwd();\n\n // Resolve file to absolute path\n const absPath = path.isAbsolute(file) ? file : path.resolve(cwd, file);\n\n // Verify file exists before calling helpers\n if (!fs.existsSync(absPath)) {\n process.stderr.write(`[cleargate stamp] error: file not found: ${absPath}\\n`);\n return exitFn(1);\n }\n\n const version = cli?.getVersion ? cli.getVersion() : getCodebaseVersion({ cwd });\n\n if (opts.dryRun) {\n // For dry-run: operate on a temp file copy so the real file is never written.\n const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'cg-stamp-dry-'));\n try {\n const tmpFile = path.join(tmpDir, path.basename(absPath));\n fs.copyFileSync(absPath, tmpFile);\n\n // Read current frontmatter for the diff's before-side\n let before: Record<string, unknown> = {};\n try {\n const raw = fs.readFileSync(absPath, 'utf8');\n if (raw.trimStart().startsWith('---')) {\n ({ fm: before } = parseFrontmatter(raw));\n }\n } catch {\n // before stays empty if parse fails\n }\n\n // Build stamp options — conditionally assign now per FLASHCARD #cli #commander #optional-key\n const stampOpts: StampOptions = { version };\n if (cli?.now) {\n stampOpts.now = cli.now;\n }\n\n const result = await stampFrontmatter(tmpFile, stampOpts);\n\n const diff = buildDiffPreview(file, before, result.frontmatterAfter);\n stdoutFn(diff);\n if (result.reason === 'noop-archive' || result.reason === 'noop-unchanged') {\n stdoutFn(`[dry-run] no changes (${result.reason})`);\n }\n } finally {\n fs.rmSync(tmpDir, { recursive: true, force: true });\n }\n return;\n }\n\n // Real stamp — conditionally assign now per FLASHCARD #cli #commander #optional-key\n const stampOpts: StampOptions = { version };\n if (cli?.now) {\n stampOpts.now = cli.now;\n }\n\n const result = await stampFrontmatter(absPath, stampOpts);\n stdoutFn(`[stamped] ${file} (${result.reason})`);\n}\n","import { execSync } from 'child_process';\nimport * as fs from 'fs';\nimport * as path from 'path';\n\nexport interface CodebaseVersion {\n sha: string | null;\n dirty: boolean;\n tag: string | null;\n package_version: string | null;\n version_string: string; // e.g. \"a3f2e91\", \"a3f2e91-dirty\", \"1.4.2\", \"unknown\"\n}\n\nexport type ExecFn = (cmd: string, args: string[]) => { stdout: string; code: number };\n\nexport interface CodebaseVersionOpts {\n cwd?: string;\n exec?: ExecFn;\n}\n\nfunction makeDefaultExec(cwd: string): ExecFn {\n return (cmd: string, args: string[]): { stdout: string; code: number } => {\n try {\n const stdout = execSync([cmd, ...args].join(' '), {\n cwd,\n encoding: 'utf8',\n stdio: ['pipe', 'pipe', 'pipe'],\n });\n return { stdout: stdout.trim(), code: 0 };\n } catch (err: unknown) {\n const e = err as { stdout?: string | Buffer; status?: number };\n return {\n stdout: typeof e.stdout === 'string' ? e.stdout.trim() : '',\n code: typeof e.status === 'number' ? e.status : 1,\n };\n }\n };\n}\n\nfunction findPackageJson(startDir: string): string | null {\n let current = startDir;\n while (true) {\n const candidate = path.join(current, 'package.json');\n if (fs.existsSync(candidate)) {\n return candidate;\n }\n const parent = path.dirname(current);\n if (parent === current) {\n return null;\n }\n current = parent;\n }\n}\n\nexport function getCodebaseVersion(opts?: CodebaseVersionOpts): CodebaseVersion {\n const cwd = opts?.cwd ?? process.cwd();\n const execFn = opts?.exec ?? makeDefaultExec(cwd);\n\n // Try git SHA\n const shaResult = execFn('git', ['rev-parse', '--short', 'HEAD']);\n if (shaResult.code === 0 && shaResult.stdout.length > 0) {\n const sha = shaResult.stdout.trim();\n\n // Check dirty\n const statusResult = execFn('git', ['status', '--porcelain']);\n const dirty = statusResult.code === 0 && statusResult.stdout.trim().length > 0;\n\n const version_string = dirty ? `${sha}-dirty` : sha;\n\n return {\n sha,\n dirty,\n tag: null,\n package_version: null,\n version_string,\n };\n }\n\n // Fallback: find nearest package.json\n const pkgPath = findPackageJson(cwd);\n if (pkgPath !== null) {\n try {\n const raw = fs.readFileSync(pkgPath, 'utf8');\n const pkg = JSON.parse(raw) as { version?: string };\n const package_version = typeof pkg.version === 'string' ? pkg.version : null;\n if (package_version !== null) {\n return {\n sha: null,\n dirty: false,\n tag: null,\n package_version,\n version_string: package_version,\n };\n }\n } catch {\n // fall through to unknown\n }\n }\n\n // Unknown\n console.warn('[cleargate] codebase-version: could not determine version (no git, no package.json)');\n return {\n sha: null,\n dirty: false,\n tag: null,\n package_version: null,\n version_string: 'unknown',\n };\n}\n","import * as fs from 'fs/promises';\nimport type { CodebaseVersion } from './codebase-version.js';\nimport { parseFrontmatter } from '../wiki/parse-frontmatter.js';\nimport { serializeFrontmatter, toIsoSecond } from './frontmatter-yaml.js';\n\nexport interface StampOptions {\n now?: () => Date;\n version?: CodebaseVersion;\n /** Default: /\\/\\.cleargate\\/delivery\\/archive\\// */\n archivePathMatcher?: (absPath: string) => boolean;\n}\n\nexport interface StampResult {\n changed: boolean;\n frontmatterBefore: Record<string, unknown>;\n frontmatterAfter: Record<string, unknown>;\n reason: 'created' | 'updated' | 'noop-archive' | 'noop-unchanged';\n}\n\n/** Write-template marker keys (epic/story/bug/CR/proposal). */\nconst WRITE_TEMPLATE_KEYS = new Set([\n 'story_id',\n 'epic_id',\n 'proposal_id',\n 'cr_id',\n 'bug_id',\n]);\n\nconst DEFAULT_ARCHIVE_MATCHER = (absPath: string): boolean =>\n /\\/\\.cleargate\\/delivery\\/archive\\//.test(absPath);\n\nexport async function stampFrontmatter(absPath: string, opts?: StampOptions): Promise<StampResult> {\n const isArchive = (opts?.archivePathMatcher ?? DEFAULT_ARCHIVE_MATCHER)(absPath);\n if (isArchive) {\n // Read to get frontmatter for result shape, but do not write\n const raw = await fs.readFile(absPath, 'utf8');\n let fm: Record<string, unknown> = {};\n try {\n ({ fm } = parseFrontmatter(raw));\n } catch {\n // If parse fails, return empty frontmatter snapshot\n }\n return {\n changed: false,\n frontmatterBefore: fm,\n frontmatterAfter: fm,\n reason: 'noop-archive',\n };\n }\n\n const raw = await fs.readFile(absPath, 'utf8');\n\n // Determine if the file has frontmatter at all\n const hasFrontmatter = raw.trimStart().startsWith('---');\n\n let fm: Record<string, unknown> = {};\n let body = raw;\n\n if (hasFrontmatter) {\n const parsed = parseFrontmatter(raw);\n fm = parsed.fm;\n body = parsed.body;\n }\n\n const frontmatterBefore = { ...fm };\n\n const nowFn = opts?.now ?? (() => new Date());\n const now = nowFn();\n const nowIso = toIsoSecond(now);\n\n const version = opts?.version ?? { sha: null, dirty: false, tag: null, package_version: null, version_string: 'unknown' };\n const versionString = version.version_string;\n\n // Determine if this is a first stamp or re-stamp\n const hasCreatedAt = 'created_at' in fm && fm['created_at'] !== undefined && fm['created_at'] !== '' && fm['created_at'] !== null;\n\n // Determine if it's a write-template (needs server_pushed_at_version)\n const isWriteTemplate = WRITE_TEMPLATE_KEYS.has(Object.keys(fm).find((k) => WRITE_TEMPLATE_KEYS.has(k)) ?? '');\n\n // Build the new frontmatter:\n // 1. Preserve existing key order\n // 2. Append new keys in canonical order: created_at, updated_at, created_at_version, updated_at_version, server_pushed_at_version\n const newFm: Record<string, unknown> = {};\n\n // Copy all existing keys first (preserves order)\n for (const [k, v] of Object.entries(fm)) {\n newFm[k] = v;\n }\n\n if (!hasCreatedAt) {\n // First stamp: set all 4 fields\n // If the keys exist already (placeholder values), update them in-place order\n // If not, append at the end in canonical order\n newFm['created_at'] = nowIso;\n newFm['updated_at'] = nowIso;\n newFm['created_at_version'] = versionString;\n newFm['updated_at_version'] = versionString;\n\n if (isWriteTemplate && !('server_pushed_at_version' in newFm)) {\n newFm['server_pushed_at_version'] = null;\n }\n } else {\n // Re-stamp: preserve created_at + created_at_version, advance updated_at + updated_at_version\n // created_at stays\n newFm['updated_at'] = nowIso;\n // created_at_version stays\n newFm['updated_at_version'] = versionString;\n\n if (isWriteTemplate && !('server_pushed_at_version' in newFm)) {\n newFm['server_pushed_at_version'] = null;\n }\n }\n\n // Check noop-unchanged: if nothing changed, return early\n const unchanged =\n newFm['updated_at'] === fm['updated_at'] &&\n newFm['updated_at_version'] === fm['updated_at_version'] &&\n newFm['created_at'] === fm['created_at'] &&\n newFm['created_at_version'] === fm['created_at_version'];\n\n if (unchanged && hasCreatedAt) {\n return {\n changed: false,\n frontmatterBefore,\n frontmatterAfter: newFm,\n reason: 'noop-unchanged',\n };\n }\n\n // Serialize and write\n const fmBlock = serializeFrontmatter(newFm);\n // Reconstruct: frontmatter block + newline + body\n // body from parseFrontmatter does NOT have a leading blank line (it strips one)\n const newContent = body.length > 0 ? `${fmBlock}\\n\\n${body}` : `${fmBlock}\\n`;\n\n await fs.writeFile(absPath, newContent, 'utf8');\n\n return {\n changed: true,\n frontmatterBefore,\n frontmatterAfter: newFm,\n reason: hasCreatedAt ? 'updated' : 'created',\n };\n}\n","/**\n * YAML frontmatter parser backed by js-yaml with CORE_SCHEMA (YAML 1.2 core).\n *\n * Parses `---\\n<yaml>\\n---\\n<body>` into a typed frontmatter map + body string.\n * Preserves native types (null, boolean, number, string), nested maps, and\n * arrays. Uses CORE_SCHEMA so ISO-8601 timestamp strings are NOT coerced to\n * Date objects (YAML 1.1's quirk).\n *\n * Historical note: an earlier hand-rolled parser flattened indented nested\n * maps into top-level keys and stringified null/boolean scalars. See\n * BUG-001 and FLASHCARD entry `#yaml #frontmatter`.\n */\n\nimport yaml from 'js-yaml';\n\nexport function parseFrontmatter(raw: string): { fm: Record<string, unknown>; body: string } {\n const lines = raw.split('\\n');\n if (lines[0] !== '---') {\n throw new Error('parseFrontmatter: input does not start with ---');\n }\n let closeIdx = -1;\n for (let i = 1; i < lines.length; i++) {\n if (lines[i] === '---') { closeIdx = i; break; }\n }\n if (closeIdx === -1) {\n throw new Error('parseFrontmatter: missing closing ---');\n }\n\n const yamlText = lines.slice(1, closeIdx).join('\\n');\n const bodyLines = lines.slice(closeIdx + 1);\n // strip one leading blank line if present\n if (bodyLines[0] === '') bodyLines.shift();\n const body = bodyLines.join('\\n');\n\n if (yamlText.trim() === '') {\n return { fm: {}, body };\n }\n\n let parsed: unknown;\n try {\n parsed = yaml.load(yamlText, { schema: yaml.CORE_SCHEMA });\n } catch (err) {\n throw new Error(`parseFrontmatter: invalid YAML: ${(err as Error).message}`);\n }\n\n if (parsed === null || parsed === undefined) {\n return { fm: {}, body };\n }\n if (typeof parsed !== 'object' || Array.isArray(parsed)) {\n throw new Error('parseFrontmatter: frontmatter is not a YAML mapping');\n }\n\n return { fm: parsed as Record<string, unknown>, body };\n}\n","/**\n * Frontmatter YAML serializer backed by js-yaml with CORE_SCHEMA.\n *\n * Emits a `---\\n<yaml>\\n---` block. Preserves key insertion order (JS\n * objects iterate non-numeric keys in insertion order by spec, and js-yaml\n * follows Object.keys), nested maps, arrays, and native scalar types.\n *\n * Partner of parse-frontmatter.ts — the two round-trip losslessly.\n */\n\nimport yaml from 'js-yaml';\n\n/**\n * Serialize a frontmatter record to a YAML block (including the --- delimiters).\n * Key order is preserved as supplied.\n */\nexport function serializeFrontmatter(fm: Record<string, unknown>): string {\n // Empty object → emit a two-delimiter block with no body\n if (Object.keys(fm).length === 0) {\n return '---\\n---';\n }\n\n const yamlBody = yaml.dump(fm, {\n schema: yaml.CORE_SCHEMA,\n lineWidth: -1,\n noRefs: true,\n noCompatMode: true,\n quotingType: '\"',\n forceQuotes: false,\n });\n\n // js-yaml always ends with \\n; trim so we control the framing\n return `---\\n${yamlBody.replace(/\\n+$/, '')}\\n---`;\n}\n\n/**\n * Format a Date as ISO 8601 UTC with second precision: \"YYYY-MM-DDTHH:MM:SSZ\"\n */\nexport function toIsoSecond(d: Date): string {\n return d.toISOString().replace(/\\.\\d{3}Z$/, 'Z');\n}\n","/**\n * init.ts — `cleargate init` command handler\n *\n * Steps:\n * 1. Validate cwd exists and is writable\n * 2. Resolve payloadDir (bundled cleargate-planning/ templates)\n * 3. copyPayload: copy scaffold files to target cwd\n * 4. mergeSettings: merge PostToolUse hook into .claude/settings.json\n * 5. injectClaudeMd: bounded-block inject into CLAUDE.md\n * 6. Bootstrap pass: if delivery/ has items, run wiki build\n * 7. Print Done\n */\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { copyPayload } from '../init/copy-payload.js';\nimport { mergeSettings, type SettingsJson } from '../init/merge-settings.js';\nimport { injectClaudeMd, extractBlock } from '../init/inject-claude-md.js';\nimport { wikiBuildHandler, type WikiBuildOptions } from './wiki-build.js';\nimport { loadPackageManifest, type ManifestFile } from '../lib/manifest.js';\nimport { promptYesNo as defaultPromptYesNo } from '../lib/prompts.js';\n\n/**\n * The PostToolUse hook config to merge — updated in STORY-008-06 to use\n * stamp-and-gate.sh (replaces legacy SPRINT-04 inline wiki ingest command).\n * Uses ${CLAUDE_PROJECT_DIR} so the path is project-relative at runtime.\n * mergeSettings deduplicates by exact command string — safe to re-run.\n */\nconst HOOK_ADDITION: SettingsJson = {\n hooks: {\n PostToolUse: [\n {\n matcher: 'Edit|Write',\n hooks: [\n {\n type: 'command',\n command: '${CLAUDE_PROJECT_DIR}/.claude/hooks/stamp-and-gate.sh',\n },\n ],\n },\n ],\n },\n};\n\nexport interface InitOptions {\n /** Target working directory (the repo being initialised). Default: process.cwd() */\n cwd?: string;\n /** Overwrite files that differ from payload. Default: false */\n force?: boolean;\n /** Test seam: path to bundled cleargate-planning/ payload directory */\n payloadDir?: string;\n /** Test seam: frozen ISO timestamp */\n now?: () => string;\n /** Test seam: replaces process.stdout.write */\n stdout?: (s: string) => void;\n /** Test seam: replaces process.stderr.write */\n stderr?: (s: string) => void;\n /** Test seam: replaces process.exit */\n exit?: (code: number) => never;\n /** Test seam: runs wiki build (default: wikiBuildHandler) */\n runWikiBuild?: (opts: WikiBuildOptions) => Promise<void>;\n /**\n * Test seam: replaces the real Y/n prompt for restore flow.\n * STORY-009-03: injectable so integration tests don't block on stdin.\n */\n promptYesNo?: (question: string, defaultYes: boolean) => Promise<boolean>;\n /**\n * Test seam: replaces loadPackageManifest() call for snapshot step.\n * STORY-009-03: allows tests to supply a known ManifestFile without a real MANIFEST.json.\n */\n readInstallManifest?: () => ManifestFile;\n}\n\n/** Shape of the .cleargate/.uninstalled marker written by STORY-009-07 `uninstall`. */\ninterface UninstalledMarker {\n uninstalled_at: string;\n prior_version: string;\n preserved: string[];\n}\n\n/** Resolve default payloadDir from the installed package structure.\n *\n * tsup bundles all modules into dist/cli.js (single entry point).\n * As a result, import.meta.url inside ANY module resolves to dist/cli.js.\n * So dirname(import.meta.url) = dist/. One level up = package root.\n * See flashcard: #tsup #bundle #import-meta.\n */\nfunction resolveDefaultPayloadDir(): string {\n const thisFile = fileURLToPath(import.meta.url);\n // dist/cli.js → dirname = dist/ → one level up = package root\n const pkgRoot = path.resolve(path.dirname(thisFile), '..');\n return path.join(pkgRoot, 'templates', 'cleargate-planning');\n}\n\n/** Glob delivery dir for .md files, excluding .gitkeep */\nfunction countDeliveryItems(cwd: string): number {\n const pendingSync = path.join(cwd, '.cleargate', 'delivery', 'pending-sync');\n const archive = path.join(cwd, '.cleargate', 'delivery', 'archive');\n let count = 0;\n for (const dir of [pendingSync, archive]) {\n if (!fs.existsSync(dir)) continue;\n const entries = fs.readdirSync(dir);\n for (const f of entries) {\n if (f.endsWith('.md') && f !== '.gitkeep') count++;\n }\n }\n return count;\n}\n\n/** Write file atomically: write to tmp, then rename. */\nfunction writeAtomic(filePath: string, content: string): void {\n const tmpPath = filePath + '.tmp.' + Date.now();\n fs.writeFileSync(tmpPath, content, 'utf8');\n fs.renameSync(tmpPath, filePath);\n}\n\nexport async function initHandler(opts: InitOptions = {}): Promise<void> {\n const cwd = opts.cwd ?? process.cwd();\n const force = opts.force ?? false;\n const now = opts.now ?? (() => new Date().toISOString());\n const stdout = opts.stdout ?? ((s: string) => process.stdout.write(s));\n const stderr = opts.stderr ?? ((s: string) => process.stderr.write(s));\n const exit = opts.exit ?? ((c: number): never => process.exit(c));\n const runWikiBuild = opts.runWikiBuild ?? wikiBuildHandler;\n const promptYesNoFn = opts.promptYesNo ?? defaultPromptYesNo;\n\n // Step 1: Validate cwd\n if (!fs.existsSync(cwd)) {\n stderr(`[cleargate init] ERROR: target directory does not exist: ${cwd}\\n`);\n exit(1);\n return;\n }\n\n // Check writable by attempting to create a tmp file\n const testWritePath = path.join(cwd, `.cleargate-init-write-test-${Date.now()}`);\n try {\n fs.writeFileSync(testWritePath, '');\n fs.unlinkSync(testWritePath);\n } catch {\n stderr(`[cleargate init] ERROR: target directory is not writable: ${cwd}\\n`);\n exit(1);\n return;\n }\n\n stdout(`[cleargate init] Target: ${cwd}\\n`);\n\n // Step 2: Resolve payloadDir\n const payloadDir = opts.payloadDir ?? resolveDefaultPayloadDir();\n\n if (!fs.existsSync(payloadDir)) {\n stderr(`[cleargate init] ERROR: payload directory not found: ${payloadDir}\\n`);\n stderr(`[cleargate init] Run \\`npm run prebuild\\` to copy the payload first.\\n`);\n exit(1);\n return;\n }\n\n // Step 3: Copy scaffold payload\n // Step 3.5 (pre-copy): Detect .uninstalled marker and prompt restore.\n // Must run before any writes so the user sees the restore prompt first.\n const uninstalledMarkerPath = path.join(cwd, '.cleargate', '.uninstalled');\n let uninstalledMarker: UninstalledMarker | null = null;\n let userChoseRestore = false;\n\n if (fs.existsSync(uninstalledMarkerPath)) {\n try {\n const raw = fs.readFileSync(uninstalledMarkerPath, 'utf8');\n uninstalledMarker = JSON.parse(raw) as UninstalledMarker;\n } catch {\n stderr(`[cleargate init] WARNING: .uninstalled marker is malformed; ignoring it.\\n`);\n }\n\n if (uninstalledMarker !== null) {\n const { uninstalled_at, prior_version, preserved } = uninstalledMarker;\n const question =\n `[cleargate init] Detected previous ClearGate install` +\n ` (uninstalled ${uninstalled_at}, prior version ${prior_version}).` +\n ` Restore preserved items? [Y/n]`;\n userChoseRestore = await promptYesNoFn(question, true);\n\n if (userChoseRestore) {\n // Blind copy: just verify each preserved file still exists on disk\n // (it was preserved as intended). Log status; never touch content.\n for (const preservedPath of preserved) {\n const absPreserved = path.isAbsolute(preservedPath)\n ? preservedPath\n : path.join(cwd, preservedPath);\n if (fs.existsSync(absPreserved)) {\n stdout(`[cleargate init] [preserved] ${preservedPath}\\n`);\n } else {\n stdout(`[cleargate init] [warn] preserved path missing on disk: ${preservedPath}\\n`);\n }\n }\n } else {\n stdout(\n `[cleargate init] discarding preservation; preserved files untouched on disk\\n`,\n );\n }\n // Marker removal happens AFTER bootstrap (Step 6) completes — tracked below.\n }\n }\n\n const copyReport = copyPayload(payloadDir, cwd, { force });\n for (const action of copyReport.actions) {\n const verb =\n action.action === 'created'\n ? 'Created'\n : action.action === 'overwritten'\n ? 'Overwritten'\n : 'Skipped (exists)';\n stdout(`[cleargate init] ${verb} ${action.relPath}\\n`);\n }\n\n // Step 4: Merge PostToolUse hook into .claude/settings.json\n const settingsPath = path.join(cwd, '.claude', 'settings.json');\n let existingSettings: SettingsJson | null = null;\n if (fs.existsSync(settingsPath)) {\n try {\n existingSettings = JSON.parse(fs.readFileSync(settingsPath, 'utf8')) as SettingsJson;\n } catch {\n stderr(`[cleargate init] WARNING: could not parse ${settingsPath}; treating as empty.\\n`);\n }\n }\n\n const mergedSettings = mergeSettings(existingSettings, HOOK_ADDITION);\n fs.mkdirSync(path.dirname(settingsPath), { recursive: true });\n writeAtomic(settingsPath, JSON.stringify(mergedSettings, null, 2) + '\\n');\n stdout(`[cleargate init] Updated .claude/settings.json: merged PostToolUse hook\\n`);\n\n // Step 5: Inject bounded block into CLAUDE.md\n const claudeMdPath = path.join(cwd, 'CLAUDE.md');\n const claudeMdSrcPath = path.join(payloadDir, 'CLAUDE.md');\n\n let claudeMdBlock: string;\n try {\n const claudeMdSrc = fs.readFileSync(claudeMdSrcPath, 'utf8');\n claudeMdBlock = extractBlock(claudeMdSrc);\n } catch (e) {\n stderr(`[cleargate init] WARNING: could not read CLAUDE.md block from payload: ${String(e)}\\n`);\n claudeMdBlock = '<!-- CLEARGATE:START -->\\n<!-- CLEARGATE:END -->';\n }\n\n const existingClaudeMd = fs.existsSync(claudeMdPath)\n ? fs.readFileSync(claudeMdPath, 'utf8')\n : null;\n\n const newClaudeMd = injectClaudeMd(existingClaudeMd, claudeMdBlock);\n writeAtomic(claudeMdPath, newClaudeMd);\n\n if (existingClaudeMd === null) {\n stdout(`[cleargate init] Created CLAUDE.md (with bounded block)\\n`);\n } else if (existingClaudeMd !== newClaudeMd) {\n stdout(`[cleargate init] Updated CLAUDE.md (bounded block injected/replaced)\\n`);\n } else {\n stdout(`[cleargate init] CLAUDE.md unchanged (block already up to date)\\n`);\n }\n\n // Step 6: Bootstrap pass\n const itemCount = countDeliveryItems(cwd);\n if (itemCount > 0) {\n stdout(`[cleargate init] Bootstrap: running wiki build (${itemCount} items found)...\\n`);\n await runWikiBuild({ cwd, now });\n stdout(`[cleargate init] Bootstrap: ran wiki build (${itemCount} items ingested)\\n`);\n } else {\n stdout(`[cleargate init] Bootstrap: no items to ingest, skipping build\\n`);\n }\n\n // Step 7: Write install snapshot atomically to .cleargate/.install-manifest.json.\n // Must be the FINAL step after all scaffold files are written (blueprint §1.2).\n const cleargateDir = path.join(cwd, '.cleargate');\n fs.mkdirSync(cleargateDir, { recursive: true });\n\n const snapshotPath = path.join(cleargateDir, '.install-manifest.json');\n try {\n const readManifest = opts.readInstallManifest ?? (() => loadPackageManifest({ packageRoot: payloadDir }));\n const pkgManifest = readManifest();\n const snapshot: ManifestFile = {\n ...pkgManifest,\n installed_at: now(),\n };\n writeAtomic(snapshotPath, JSON.stringify(snapshot, null, 2) + '\\n');\n stdout(`[cleargate init] Wrote install snapshot: .cleargate/.install-manifest.json\\n`);\n } catch (e) {\n stderr(`[cleargate init] WARNING: could not write install snapshot: ${String(e)}\\n`);\n }\n\n // Remove .uninstalled marker AFTER bootstrap + snapshot complete (whether user chose Y or N).\n // This prevents repeated prompting on subsequent init runs.\n if (uninstalledMarker !== null && fs.existsSync(uninstalledMarkerPath)) {\n try {\n fs.unlinkSync(uninstalledMarkerPath);\n } catch (e) {\n stderr(`[cleargate init] WARNING: could not remove .uninstalled marker: ${String(e)}\\n`);\n }\n }\n\n // Step 8: Done\n stdout(\n `[cleargate init] Done. Read CLAUDE.md and .cleargate/knowledge/cleargate-protocol.md to learn the protocol.\\n`,\n );\n\n void now; // suppress unused warning if not used after this\n}\n","/**\n * copy-payload.ts — recursively copy cleargate-planning/ payload to target cwd.\n *\n * Handles overwrite policy:\n * - by default: skip files that already exist with identical content\n * - force=true: overwrite all\n *\n * Does NOT prompt interactively; skip-or-overwrite is determined by `force`.\n */\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\n\nexport interface CopyReport {\n created: number;\n skipped: number;\n overwritten: number;\n /** Per-file action lines for verbose printing */\n actions: Array<{ action: 'created' | 'skipped' | 'overwritten'; relPath: string }>;\n}\n\nexport interface CopyPayloadOptions {\n force: boolean;\n}\n\n/**\n * Recursively enumerate files under `dir`.\n * Returns paths relative to `dir`.\n */\nfunction listFilesRecursive(dir: string): string[] {\n const results: string[] = [];\n function walk(current: string, rel: string): void {\n const entries = fs.readdirSync(current, { withFileTypes: true });\n for (const entry of entries) {\n const entryRel = rel ? `${rel}/${entry.name}` : entry.name;\n const entryAbs = path.join(current, entry.name);\n if (entry.isDirectory()) {\n walk(entryAbs, entryRel);\n } else {\n results.push(entryRel);\n }\n }\n }\n walk(dir, '');\n return results;\n}\n\n/**\n * Copy all files from `payloadDir` to `targetCwd`, preserving directory structure.\n * Dotfiles and dot-directories (e.g. `.claude/`, `.cleargate/`) are preserved.\n */\nexport function copyPayload(\n payloadDir: string,\n targetCwd: string,\n opts: CopyPayloadOptions,\n): CopyReport {\n const report: CopyReport = { created: 0, skipped: 0, overwritten: 0, actions: [] };\n\n if (!fs.existsSync(payloadDir)) {\n throw new Error(`copyPayload: payloadDir does not exist: ${payloadDir}`);\n }\n\n const files = listFilesRecursive(payloadDir);\n\n for (const relPath of files) {\n const srcPath = path.join(payloadDir, relPath);\n const dstPath = path.join(targetCwd, relPath);\n\n // Ensure target directory exists\n fs.mkdirSync(path.dirname(dstPath), { recursive: true });\n\n const srcContent = fs.readFileSync(srcPath);\n\n if (fs.existsSync(dstPath)) {\n const dstContent = fs.readFileSync(dstPath);\n if (srcContent.equals(dstContent)) {\n // Identical — skip silently even with force (idempotent)\n report.skipped++;\n report.actions.push({ action: 'skipped', relPath });\n continue;\n }\n if (!opts.force) {\n // Different content, no force — skip\n report.skipped++;\n report.actions.push({ action: 'skipped', relPath });\n continue;\n }\n // Different + force — overwrite\n fs.writeFileSync(dstPath, srcContent);\n report.overwritten++;\n report.actions.push({ action: 'overwritten', relPath });\n } else {\n // New file\n fs.writeFileSync(dstPath, srcContent);\n report.created++;\n report.actions.push({ action: 'created', relPath });\n }\n }\n\n return report;\n}\n","/**\n * merge-settings.ts — JSON merge for .claude/settings.json\n *\n * Algorithm (from M4 blueprint):\n * - if existing is null: return addition\n * - otherwise deep-clone existing and merge addition.hooks into result.hooks\n * - For each event (e.g. PostToolUse):\n * - find matching entry by `matcher` field\n * - if absent: push entire new entry\n * - if present: de-dup merge inner hooks[] by exact `command` string match\n * - Preserves all other top-level keys (SubagentStop, permissions, etc.)\n */\n\nexport interface HookCommand {\n type: string;\n command: string;\n}\n\nexport interface HookEntry {\n matcher?: string;\n hooks?: HookCommand[];\n [key: string]: unknown;\n}\n\nexport interface HooksConfig {\n [event: string]: HookEntry[];\n}\n\nexport interface SettingsJson {\n hooks?: HooksConfig;\n [key: string]: unknown;\n}\n\n/**\n * Deep-clone a plain JSON-serializable object.\n */\nfunction deepClone<T>(obj: T): T {\n return JSON.parse(JSON.stringify(obj)) as T;\n}\n\n/**\n * Merge `addition` hook config into `existing` settings.\n * Returns a new merged object; does not mutate either argument.\n *\n * @param existing - parsed .claude/settings.json content, or null if file absent\n * @param addition - the hook config to merge in (must have `hooks` key)\n */\nexport function mergeSettings(\n existing: SettingsJson | null,\n addition: SettingsJson,\n): SettingsJson {\n if (existing === null) {\n return deepClone(addition);\n }\n\n const result: SettingsJson = deepClone(existing);\n\n // Ensure result.hooks exists\n if (!result.hooks) {\n result.hooks = {};\n }\n\n // Merge each event from addition\n for (const [eventName, eventArray] of Object.entries(addition.hooks ?? {})) {\n if (!result.hooks[eventName]) {\n result.hooks[eventName] = [];\n }\n\n for (const newEntry of eventArray) {\n const matchingIdx = result.hooks[eventName].findIndex(\n (e) => e.matcher === newEntry.matcher,\n );\n\n if (matchingIdx === -1) {\n // No matching entry — push entire new entry\n result.hooks[eventName].push(deepClone(newEntry));\n } else {\n // Matcher exists — merge inner hooks[] by de-dup on `command`\n const existingEntry = result.hooks[eventName][matchingIdx];\n const existingInner: HookCommand[] = Array.isArray(existingEntry.hooks)\n ? (existingEntry.hooks as HookCommand[])\n : [];\n\n for (const newInner of newEntry.hooks ?? []) {\n if (!existingInner.some((h) => h.command === newInner.command)) {\n existingInner.push(deepClone(newInner) as HookCommand);\n }\n }\n\n result.hooks[eventName][matchingIdx] = {\n ...existingEntry,\n hooks: existingInner,\n };\n }\n }\n }\n\n return result;\n}\n","/**\n * inject-claude-md.ts — bounded-block injection for CLAUDE.md\n *\n * Block format: <!-- CLEARGATE:START -->\\n<content>\\n<!-- CLEARGATE:END -->\n * Detection regex: /<!-- CLEARGATE:START -->[\\s\\S]*<!-- CLEARGATE:END -->/ (greedy, see below)\n *\n * Rules:\n * - If existing === null: create file with block as full content (+ trailing newline)\n * - If existing matches: replace the bounded block in place (idempotent)\n * - If existing no match: append block with 2 leading newlines (preserve user content above)\n */\n\n// Greedy match: from first <!-- CLEARGATE:START --> to LAST <!-- CLEARGATE:END -->.\n// Greedy is correct here because:\n// (a) cleargate-planning/CLAUDE.md body text mentions both markers inline as code references,\n// and non-greedy would stop at the inline END before the real one.\n// (b) We assume at most one cleargate block per file (idempotency requires it).\nconst BLOCK_REGEX = /<!-- CLEARGATE:START -->[\\s\\S]*<!-- CLEARGATE:END -->/;\n\n/**\n * Extract the bounded block from a source file (e.g. cleargate-planning/CLAUDE.md).\n * Returns the text from <!-- CLEARGATE:START --> to <!-- CLEARGATE:END --> inclusive.\n * Throws if the markers are not found.\n */\nexport function extractBlock(sourceContent: string): string {\n const match = BLOCK_REGEX.exec(sourceContent);\n if (!match) {\n throw new Error('inject-claude-md: CLEARGATE:START/END markers not found in source content');\n }\n return match[0];\n}\n\n/**\n * Inject or update the bounded block in an existing CLAUDE.md.\n *\n * @param existing - current content of CLAUDE.md, or null if file doesn't exist\n * @param block - the full block to inject, from <!-- CLEARGATE:START --> to <!-- CLEARGATE:END --> inclusive\n * @returns - new file content (ready to write)\n */\nexport function injectClaudeMd(existing: string | null, block: string): string {\n if (existing === null) {\n // Create new file with block as full content\n return block + '\\n';\n }\n\n if (BLOCK_REGEX.test(existing)) {\n // Replace existing block in place\n return existing.replace(BLOCK_REGEX, block);\n }\n\n // Append block with 2 leading newlines\n return existing.trimEnd() + '\\n\\n' + block + '\\n';\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { scanRawItems, type RawItem } from '../wiki/scan.js';\nimport { getGitSha, type GitRunner } from '../wiki/git-sha.js';\nimport { serializePage, type WikiPage } from '../wiki/page-schema.js';\nimport { compile as compileActiveSprint } from '../wiki/synthesis/active-sprint.js';\nimport { compile as compileOpenGates } from '../wiki/synthesis/open-gates.js';\nimport { compile as compileProductState } from '../wiki/synthesis/product-state.js';\nimport { compile as compileRoadmap } from '../wiki/synthesis/roadmap.js';\n\nexport interface WikiBuildOptions {\n /** Test seam: working directory (defaults to process.cwd()) */\n cwd?: string;\n /** Test seam: frozen ISO timestamp for last_ingest field (defaults to new Date().toISOString()) */\n now?: () => string;\n /** Test seam: replaces process.stdout.write */\n stdout?: (s: string) => void;\n /** Test seam: replaces process.stderr.write */\n stderr?: (s: string) => void;\n /** Test seam: replaces process.exit */\n exit?: (code: number) => never;\n /** Test seam: forwarded to getGitSha */\n gitRunner?: GitRunner;\n /** Test seam: override directory for synthesis templates (default resolved via import.meta.url) */\n templateDir?: string;\n}\n\nconst BUCKET_ORDER = ['epics', 'stories', 'sprints', 'proposals', 'crs', 'bugs', 'topics'] as const;\nconst BUCKET_LABELS: Record<string, string> = {\n epics: 'Epics',\n stories: 'Stories',\n sprints: 'Sprints',\n proposals: 'Proposals',\n crs: 'CRs',\n bugs: 'Bugs',\n topics: 'Topics',\n};\n\nexport async function wikiBuildHandler(opts: WikiBuildOptions = {}): Promise<void> {\n const cwd = opts.cwd ?? process.cwd();\n const now = opts.now ?? (() => new Date().toISOString());\n const stdout = opts.stdout ?? ((s) => process.stdout.write(s));\n const stderr = opts.stderr ?? ((s) => process.stderr.write(s));\n const exit = opts.exit ?? ((c: number): never => process.exit(c));\n const gitRunner = opts.gitRunner;\n const templateDir = opts.templateDir;\n\n const deliveryRoot = path.join(cwd, '.cleargate', 'delivery');\n const wikiRoot = path.join(cwd, '.cleargate', 'wiki');\n\n if (!fs.existsSync(deliveryRoot)) {\n stderr(`wiki build: .cleargate/delivery/ not found at ${deliveryRoot}\\n`);\n exit(1);\n return;\n }\n\n // Ensure wiki directory structure exists\n for (const bucket of BUCKET_ORDER) {\n fs.mkdirSync(path.join(wikiRoot, bucket), { recursive: true });\n }\n\n // Step 2: scan raw items\n const items = scanRawItems(deliveryRoot, cwd);\n\n // Step 3: write per-item wiki pages\n const timestamp = now();\n let pagesWritten = 0;\n\n for (const item of items) {\n const sha = getGitSha(item.rawPath, gitRunner) ?? '';\n\n const parent = buildParentRef(item.fm);\n const children = buildChildrenRefs(item.fm);\n\n const wikiPage: WikiPage = {\n type: item.type,\n id: item.id,\n parent,\n children,\n status: String(item.fm['status'] ?? ''),\n remote_id: String(item.fm['remote_id'] ?? ''),\n raw_path: item.rawPath,\n last_ingest: timestamp,\n last_ingest_commit: sha,\n repo: item.repo,\n };\n\n const body = buildPageBody(item, wikiPage);\n const content = serializePage(wikiPage, body);\n\n const pageDir = path.join(wikiRoot, item.bucket);\n fs.mkdirSync(pageDir, { recursive: true });\n fs.writeFileSync(path.join(pageDir, `${item.id}.md`), content, 'utf8');\n pagesWritten++;\n }\n\n // Step 4: build index.md\n const indexContent = buildIndex(items);\n fs.writeFileSync(path.join(wikiRoot, 'index.md'), indexContent, 'utf8');\n\n // Step 5: build log.md\n const logContent = buildLog(items, timestamp);\n fs.writeFileSync(path.join(wikiRoot, 'log.md'), logContent, 'utf8');\n\n // Step 6: write synthesis pages\n fs.writeFileSync(path.join(wikiRoot, 'active-sprint.md'), compileActiveSprint(items, templateDir), 'utf8');\n fs.writeFileSync(path.join(wikiRoot, 'open-gates.md'), compileOpenGates(items, templateDir), 'utf8');\n fs.writeFileSync(path.join(wikiRoot, 'product-state.md'), compileProductState(items, templateDir), 'utf8');\n fs.writeFileSync(path.join(wikiRoot, 'roadmap.md'), compileRoadmap(items, templateDir), 'utf8');\n\n // Step 7: report\n stdout(`wiki build: OK (${pagesWritten} pages written)\\n`);\n}\n\nfunction buildParentRef(fm: Record<string, unknown>): string {\n const raw = fm['parent_epic_ref'] ?? fm['parent'] ?? '';\n const s = String(raw);\n if (!s) return '';\n if (s.startsWith('[[') && s.endsWith(']]')) return s;\n return `[[${s}]]`;\n}\n\nfunction buildChildrenRefs(fm: Record<string, unknown>): string[] {\n const raw = fm['children'];\n if (!raw) return [];\n const arr = Array.isArray(raw) ? raw : [raw];\n return arr.map((c) => {\n const s = String(c);\n if (s.startsWith('[[') && s.endsWith(']]')) return s;\n return `[[${s}]]`;\n });\n}\n\nfunction buildPageBody(item: RawItem, page: WikiPage): string {\n const title = String(item.fm['title'] ?? item.id);\n const summary = String(item.fm['description'] ?? item.body.split('\\n')[0] ?? 'No summary available.').slice(0, 200);\n\n const blastParts: string[] = [];\n if (page.parent) blastParts.push(page.parent);\n for (const child of page.children) blastParts.push(child);\n\n const blastLine = blastParts.length > 0 ? blastParts.join(', ') : 'None.';\n\n return [\n `# ${item.id}: ${title}`,\n '',\n summary,\n '',\n '## Blast radius',\n `Affects: ${blastLine}`,\n '',\n '## Open questions',\n 'None.',\n '',\n ].join('\\n');\n}\n\nfunction buildIndex(items: RawItem[]): string {\n const lines: string[] = [\n '# Wiki Index',\n '',\n '> Auto-generated by `cleargate wiki build`. Do not edit manually.',\n '',\n '| ID | Type | Status | Raw Path |',\n '|---|---|---|---|',\n ];\n\n if (items.length === 0) {\n lines.push('| _(no items)_ | — | — | — |');\n lines.push('');\n } else {\n // Group by bucket in canonical order\n for (const bucket of BUCKET_ORDER) {\n const bucketItems = items.filter((i) => i.bucket === bucket);\n if (bucket === 'topics') continue; // topics written by query --persist only\n\n lines.push('', `## ${BUCKET_LABELS[bucket]}`, '');\n\n if (bucketItems.length === 0) {\n lines.push('_No items._');\n } else {\n for (const item of bucketItems) {\n const status = String(item.fm['status'] ?? '');\n lines.push(`| [[${item.id}]] | ${item.type} | ${status} | ${item.rawPath} |`);\n }\n }\n }\n lines.push('');\n }\n\n return lines.join('\\n');\n}\n\nfunction buildLog(items: RawItem[], timestamp: string): string {\n if (items.length === 0) {\n return '# Wiki Event Log\\n\\n';\n }\n\n const entries = items.map((item) =>\n [\n `- timestamp: \"${timestamp}\"`,\n ` actor: \"cleargate wiki build\"`,\n ` action: \"create\"`,\n ` target: \"${item.id}\"`,\n ` path: \"${item.rawPath}\"`,\n ].join('\\n'),\n );\n\n return ['# Wiki Event Log', '', ...entries, ''].join('\\n');\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { parseFrontmatter } from './parse-frontmatter.js';\nimport { deriveBucket } from './derive-bucket.js';\nimport { deriveRepo } from './derive-repo.js';\nimport type { WikiPageType, RepoTag } from './page-schema.js';\n\nexport interface RawItem {\n /** Absolute path on disk */\n absPath: string;\n /** Path relative to repo root */\n rawPath: string;\n id: string;\n bucket: string;\n type: WikiPageType;\n repo: RepoTag;\n fm: Record<string, unknown>;\n body: string;\n}\n\n/** Directories under .cleargate/ that are excluded from ingest per §10.3. */\nconst EXCLUDED_SUFFIXES = [\n '.cleargate/knowledge/',\n '.cleargate/templates/',\n '.cleargate/sprint-runs/',\n '.cleargate/hook-log/',\n '.cleargate/wiki/',\n];\n\n/**\n * Scan pending-sync/ + archive/ under deliveryRoot for markdown work items.\n * Returns a sorted (by id) list of parsed raw items.\n */\nexport function scanRawItems(deliveryRoot: string, repoRoot: string): RawItem[] {\n const results: RawItem[] = [];\n\n for (const subdir of ['pending-sync', 'archive']) {\n const dir = path.join(deliveryRoot, subdir);\n if (!fs.existsSync(dir)) continue;\n\n const entries = fs.readdirSync(dir, { recursive: true, encoding: 'utf8' }) as string[];\n for (const rel of entries) {\n if (!rel.endsWith('.md')) continue;\n if (rel.includes('~') || rel.startsWith('.')) continue;\n\n const absPath = path.join(dir, rel);\n const stat = fs.statSync(absPath);\n if (!stat.isFile()) continue;\n\n // Compute rawPath relative to repo root\n const rawPath = path.relative(repoRoot, absPath).replace(/\\\\/g, '/');\n\n // Check exclusions\n const isExcluded = EXCLUDED_SUFFIXES.some((excl) => rawPath.startsWith(excl));\n if (isExcluded) continue;\n\n // Derive bucket info from filename\n const filename = path.basename(absPath);\n let bucketInfo: ReturnType<typeof deriveBucket>;\n try {\n bucketInfo = deriveBucket(filename);\n } catch {\n // Not a recognized work-item filename — skip silently\n continue;\n }\n\n // Derive repo from path\n let repo: RepoTag;\n try {\n repo = deriveRepo(rawPath);\n } catch {\n continue;\n }\n\n // Parse frontmatter\n const raw = fs.readFileSync(absPath, 'utf8');\n let fm: Record<string, unknown>;\n let body: string;\n try {\n const parsed = parseFrontmatter(raw);\n fm = parsed.fm;\n body = parsed.body;\n } catch {\n // Malformed frontmatter — skip\n continue;\n }\n\n results.push({\n absPath,\n rawPath,\n id: bucketInfo.id,\n bucket: bucketInfo.bucket,\n type: bucketInfo.type,\n repo,\n fm,\n body,\n });\n }\n }\n\n // Sort deterministically by id (alphanumeric ascending)\n results.sort((a, b) => a.id.localeCompare(b.id));\n return results;\n}\n","import type { WikiPageType } from './page-schema.js';\n\nexport interface BucketInfo {\n type: WikiPageType;\n id: string;\n bucket: string;\n}\n\nconst PREFIX_MAP: Array<{ prefix: string; type: WikiPageType; bucket: string }> = [\n { prefix: 'EPIC-', type: 'epic', bucket: 'epics' },\n { prefix: 'STORY-', type: 'story', bucket: 'stories' },\n { prefix: 'SPRINT-', type: 'sprint', bucket: 'sprints' },\n { prefix: 'PROPOSAL-', type: 'proposal', bucket: 'proposals' },\n { prefix: 'CR-', type: 'cr', bucket: 'crs' },\n { prefix: 'BUG-', type: 'bug', bucket: 'bugs' },\n];\n\n/**\n * Derive bucket, type, and id from a filename stem.\n * Filename `STORY-042-01_name.md` → `{ type: 'story', id: 'STORY-042-01', bucket: 'stories' }`.\n */\nexport function deriveBucket(filename: string): BucketInfo {\n // Strip path if any\n const base = filename.includes('/') ? filename.split('/').pop()! : filename;\n // Remove .md suffix\n const stem = base.endsWith('.md') ? base.slice(0, -3) : base;\n // id = everything before the first `_`\n const underscoreIdx = stem.indexOf('_');\n const id = underscoreIdx === -1 ? stem : stem.slice(0, underscoreIdx);\n\n for (const { prefix, type, bucket } of PREFIX_MAP) {\n if (id.startsWith(prefix)) {\n return { type, id, bucket };\n }\n }\n\n throw new Error(`deriveBucket: cannot determine bucket for filename: ${filename}`);\n}\n","import type { RepoTag } from './page-schema.js';\n\n/**\n * A1 helper: derive the `repo` tag from a raw file path prefix.\n * Mapping is per §10.4 field notes.\n */\nexport function deriveRepo(rawPath: string): RepoTag {\n if (rawPath.startsWith('cleargate-cli/')) return 'cli';\n if (rawPath.startsWith('mcp/')) return 'mcp';\n if (rawPath.startsWith('.cleargate/') || rawPath.startsWith('cleargate-planning/')) return 'planning';\n throw new Error(`cannot derive repo for path: ${rawPath}`);\n}\n","import { spawnSync } from 'node:child_process';\n\nexport type GitRunner = (cmd: string, args: string[]) => string;\n\n/**\n * A2 helper: return the git SHA of the last commit touching rawPath.\n * Returns null when the file is untracked (empty stdout, exit 0).\n * Accepts an optional `runner` test seam.\n */\nexport function getGitSha(rawPath: string, runner?: GitRunner): string | null {\n const run = runner ?? defaultRunner;\n const out = run('git', ['log', '-1', '--format=%H', '--', rawPath]).trim();\n return out.length > 0 ? out : null;\n}\n\nfunction defaultRunner(cmd: string, args: string[]): string {\n const result = spawnSync(cmd, args, { encoding: 'utf8' });\n return result.stdout ?? '';\n}\n","/**\n * §10.4 Wiki Page Schema — exactly nine frontmatter fields.\n * Lint will flag any extra or missing fields.\n */\n\nexport type WikiPageType = 'epic' | 'story' | 'sprint' | 'proposal' | 'cr' | 'bug' | 'topic';\nexport type RepoTag = 'cli' | 'mcp' | 'planning';\n\n/** The nine-field frontmatter shape every wiki page must satisfy. */\nexport interface WikiPage {\n type: WikiPageType;\n id: string;\n parent: string; // \"[[EPIC-042]]\" or \"\" if none\n children: string[]; // [\"[[STORY-042-01]]\", ...]\n status: string;\n remote_id: string;\n raw_path: string;\n last_ingest: string; // ISO 8601 UTC\n last_ingest_commit: string; // git SHA or \"\"\n repo: RepoTag;\n}\n\n/** Serialise a WikiPage frontmatter + body into a markdown string. */\nexport function serializePage(page: WikiPage, body: string): string {\n const childrenYaml =\n page.children.length === 0\n ? '[]'\n : '\\n' + page.children.map((c) => ` - \"${c}\"`).join('\\n');\n\n const fm = [\n '---',\n `type: ${page.type}`,\n `id: \"${page.id}\"`,\n `parent: \"${page.parent}\"`,\n `children: ${childrenYaml}`,\n `status: \"${page.status}\"`,\n `remote_id: \"${page.remote_id}\"`,\n `raw_path: \"${page.raw_path}\"`,\n `last_ingest: \"${page.last_ingest}\"`,\n `last_ingest_commit: \"${page.last_ingest_commit}\"`,\n `repo: \"${page.repo}\"`,\n '---',\n ].join('\\n');\n\n return `${fm}\\n\\n${body}`;\n}\n\n/** Parse a serialised wiki page back into a WikiPage. Throws on schema violations. */\nexport function parsePage(raw: string): WikiPage {\n const { fm } = parseFmRaw(raw);\n\n const type = fm['type'] as WikiPageType;\n const id = String(fm['id'] ?? '');\n const parent = String(fm['parent'] ?? '');\n const rawChildren = fm['children'];\n const children: string[] = Array.isArray(rawChildren)\n ? (rawChildren as unknown[]).map(String)\n : [];\n const status = String(fm['status'] ?? '');\n const remote_id = String(fm['remote_id'] ?? '');\n const raw_path = String(fm['raw_path'] ?? '');\n const last_ingest = String(fm['last_ingest'] ?? '');\n const last_ingest_commit = String(fm['last_ingest_commit'] ?? '');\n const repo = fm['repo'] as RepoTag;\n\n return { type, id, parent, children, status, remote_id, raw_path, last_ingest, last_ingest_commit, repo };\n}\n\nfunction parseFmRaw(raw: string): { fm: Record<string, unknown>; body: string } {\n const lines = raw.split('\\n');\n if (lines[0] !== '---') throw new Error('parsePage: missing opening ---');\n let close = -1;\n for (let i = 1; i < lines.length; i++) {\n if (lines[i] === '---') { close = i; break; }\n }\n if (close === -1) throw new Error('parsePage: missing closing ---');\n const fmLines = lines.slice(1, close);\n const body = lines.slice(close + 1).join('\\n').replace(/^\\n/, '');\n const fm: Record<string, unknown> = {};\n for (const line of fmLines) {\n const colon = line.indexOf(':');\n if (colon === -1) continue;\n const key = line.slice(0, colon).trim();\n const val = line.slice(colon + 1).trim();\n if (val === '[]') { fm[key] = []; continue; }\n if (val === '') { fm[key] = []; continue; }\n // inline list check\n if (val.startsWith('[') && val.endsWith(']')) {\n const inner = val.slice(1, -1);\n fm[key] = inner.split(',').map((s) => s.trim().replace(/^[\"']|[\"']$/g, ''));\n continue;\n }\n fm[key] = val.replace(/^[\"']|[\"']$/g, '');\n }\n return { fm, body };\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport type { RawItem } from '../scan.js';\nimport { renderTemplate } from './render.js';\n\n/**\n * Compile the active-sprint synthesis page.\n * Loads template from templates/synthesis/active-sprint.md.\n * Partitions sprints by activated_at / completed_at frontmatter values.\n */\nexport function compile(state: RawItem[], templateDir?: string): string {\n const tplDir = templateDir ?? resolveDefaultTemplateDir();\n const tpl = fs.readFileSync(path.join(tplDir, 'active-sprint.md'), 'utf8');\n\n const sprints = state.filter((i) => i.bucket === 'sprints');\n\n // Partition sprints:\n // - active: activated_at is set (non-null, non-empty) AND completed_at is not set\n // - completed: completed_at is set\n // - planned: neither activated_at nor completed_at is set\n const active = sprints.filter((s) => isSet(s.fm['activated_at']) && !isSet(s.fm['completed_at']));\n const completed = sprints.filter((s) => isSet(s.fm['completed_at']));\n const planned = sprints.filter((s) => !isSet(s.fm['activated_at']) && !isSet(s.fm['completed_at']));\n\n const data: Record<string, unknown> = {\n active: active.map((s) => ({ id: s.id, status: String(s.fm['status'] ?? 'unknown') })),\n no_active: active.length === 0 ? [{}] : [],\n planned: planned.map((s) => ({ id: s.id, status: String(s.fm['status'] ?? 'unknown') })),\n no_planned: planned.length === 0 ? [{}] : [],\n completed: completed.slice(0, 3).map((s) => ({\n id: s.id,\n completed_at: String(s.fm['completed_at'] ?? ''),\n })),\n no_completed: completed.length === 0 ? [{}] : [],\n };\n\n return renderTemplate(tpl, data);\n}\n\nfunction isSet(val: unknown): boolean {\n if (val === null || val === undefined) return false;\n const s = String(val).trim();\n return s !== '' && s !== 'null';\n}\n\nfunction resolveDefaultTemplateDir(): string {\n // tsup bundles all modules into dist/cli.js.\n // When running the built bundle: import.meta.url = file://.../cleargate-cli/dist/cli.js\n // __dirname = cleargate-cli/dist/\n // ../templates/synthesis = cleargate-cli/templates/synthesis ✓ (source)\n // AND dist/templates/synthesis is also available (copied by onSuccess) ✓\n //\n // When vitest runs source (test seam): templateDir is always passed explicitly,\n // so this default is only used for the built/production case.\n //\n // Strategy: go one level up from the file containing this code (works for both\n // the dist/ bundle and npm-published dist/ layout), then into templates/synthesis.\n // For dist/cli.js: one up = package root → templates/synthesis. ✓\n const __dirname = path.dirname(fileURLToPath(import.meta.url));\n return path.resolve(__dirname, '..', 'templates', 'synthesis');\n}\n","/**\n * Tiny Mustache-lite template renderer.\n * Supports:\n * {{var}} — variable substitution (missing → empty string)\n * {{#section}}...{{/section}} — array iteration; inner {{field}} resolves\n * against the current array element\n *\n * Anything more complex throws an Error.\n * No external dependencies.\n */\n\n/** Render a template string with the given data context. */\nexport function renderTemplate(template: string, data: Record<string, unknown>): string {\n // Validate: no nested sections or unsupported tags\n // We only support {{var}}, {{#section}}...{{/section}}\n const tagRe = /\\{\\{([^}]+)\\}\\}/g;\n const matches = [...template.matchAll(tagRe)].map((m) => m[1].trim());\n for (const tag of matches) {\n if (tag.startsWith('^') || tag.startsWith('>') || tag.startsWith('!') || tag.startsWith('=')) {\n throw new Error(`renderTemplate: unsupported tag type: {{${tag}}}`);\n }\n }\n\n return renderSection(template, data);\n}\n\nfunction renderSection(template: string, ctx: Record<string, unknown>): string {\n // Process {{#section}}...{{/section}} blocks first\n const sectionRe = /\\{\\{#(\\w+)\\}\\}([\\s\\S]*?)\\{\\{\\/\\1\\}\\}/g;\n\n let result = template.replace(sectionRe, (_match, key: string, inner: string) => {\n const val = ctx[key];\n if (!Array.isArray(val)) {\n // Non-array truthy: render inner once with same ctx; falsy: skip\n if (!val) return '';\n return renderSection(inner, ctx);\n }\n if (val.length === 0) return '';\n return val\n .map((item: unknown) => {\n const itemCtx =\n item !== null && typeof item === 'object'\n ? (item as Record<string, unknown>)\n : { '.': item };\n return renderSection(inner, itemCtx);\n })\n .join('');\n });\n\n // Then substitute remaining {{var}} tokens\n result = result.replace(/\\{\\{(\\w+)\\}\\}/g, (_match, key: string) => {\n const val = ctx[key];\n if (val === undefined || val === null) return '';\n return String(val);\n });\n\n return result;\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport type { RawItem } from '../scan.js';\nimport { renderTemplate } from './render.js';\n\n/**\n * Compile the open-gates (blocked items) synthesis page.\n * Loads template from templates/synthesis/open-gates.md.\n *\n * Three gate buckets (matching real corpus textual statuses):\n * Gate 1 — proposals with approved: false OR status: \"Draft\" / \"Approved\" (not yet shipped)\n * Gate 2 — stories with ambiguity starting with 🟡 or 🔴\n * Gate 3 — any item with status: \"Ready\" AND remote_id empty / null\n *\n * NOTE: The previous implementation filtered on status.includes('🔴') which matched\n * zero items in the real corpus (actual statuses are textual: Draft, Ready, Planned,\n * Active, Completed, Approved). This is the corpus-shape fix for STORY-002-09.\n */\nexport function compile(state: RawItem[], templateDir?: string): string {\n const tplDir = templateDir ?? resolveDefaultTemplateDir();\n const tpl = fs.readFileSync(path.join(tplDir, 'open-gates.md'), 'utf8');\n\n // Gate 1: proposals pending approval\n const gate1 = state.filter((i) => {\n if (i.bucket !== 'proposals') return false;\n const status = String(i.fm['status'] ?? '');\n const approved = i.fm['approved'];\n // Proposals that are Draft or explicitly not approved\n return status === 'Draft' || approved === false || approved === 'false';\n });\n\n // Gate 2: stories with elevated ambiguity (🟡 Medium or 🔴 High)\n const gate2 = state.filter((i) => {\n if (i.bucket !== 'stories') return false;\n const ambiguity = String(i.fm['ambiguity'] ?? '');\n return ambiguity.startsWith('🟡') || ambiguity.startsWith('🔴');\n });\n\n // Gate 3: items that are Ready but not yet pushed (remote_id empty or null)\n const gate3 = state.filter((i) => {\n const status = String(i.fm['status'] ?? '');\n if (status !== 'Ready') return false;\n const remoteId = i.fm['remote_id'];\n return remoteId === null || remoteId === undefined || String(remoteId).trim() === '';\n });\n\n const data: Record<string, unknown> = {\n gate1: gate1.map((i) => ({ id: i.id, status: String(i.fm['status'] ?? '') })),\n no_gate1: gate1.length === 0 ? [{}] : [],\n gate2: gate2.map((i) => ({ id: i.id, ambiguity: String(i.fm['ambiguity'] ?? '') })),\n no_gate2: gate2.length === 0 ? [{}] : [],\n gate3: gate3.map((i) => ({ id: i.id, status: String(i.fm['status'] ?? '') })),\n no_gate3: gate3.length === 0 ? [{}] : [],\n };\n\n return renderTemplate(tpl, data);\n}\n\nfunction resolveDefaultTemplateDir(): string {\n // Bundle: dist/cli.js → __dirname = dist/, .. = package root → templates/synthesis ✓\n const __dirname = path.dirname(fileURLToPath(import.meta.url));\n return path.resolve(__dirname, '..', 'templates', 'synthesis');\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport type { RawItem } from '../scan.js';\nimport { renderTemplate } from './render.js';\n\n/**\n * Compile the product-state synthesis page.\n * Loads template from templates/synthesis/product-state.md.\n *\n * Shipped = items in archive/ subdir (rawPath contains '/archive/')\n * Active = status is Active, In Progress, or 🟢-prefixed\n */\nexport function compile(state: RawItem[], templateDir?: string): string {\n const tplDir = templateDir ?? resolveDefaultTemplateDir();\n const tpl = fs.readFileSync(path.join(tplDir, 'product-state.md'), 'utf8');\n\n function countBucket(bucket: string) {\n return state.filter((i) => i.bucket === bucket);\n }\n\n function isShipped(item: RawItem) {\n return item.rawPath.includes('/archive/');\n }\n\n function isActive(item: RawItem) {\n const status = String(item.fm['status'] ?? '');\n return (\n status === 'Active' ||\n status === 'In Progress' ||\n status.startsWith('🟢') ||\n status === '🟡 in-flight'\n );\n }\n\n const buckets = ['epics', 'stories', 'sprints', 'proposals', 'crs', 'bugs'];\n\n function countFor(bucket: string, predicate: (i: RawItem) => boolean): number {\n return countBucket(bucket).filter(predicate).length;\n }\n\n const epics = countBucket('epics');\n const activeEpicsList = epics.filter(isActive);\n const shippedItems = state.filter(isShipped);\n\n const data: Record<string, unknown> = {\n // Totals\n total_epics: epics.length,\n total_stories: countBucket('stories').length,\n total_sprints: countBucket('sprints').length,\n total_proposals: countBucket('proposals').length,\n total_crs: countBucket('crs').length,\n total_bugs: countBucket('bugs').length,\n\n // Active counts (per bucket)\n ...Object.fromEntries(buckets.map((b) => [`active_${b}`, countFor(b, isActive)])),\n\n // Shipped counts (per bucket)\n ...Object.fromEntries(buckets.map((b) => [`shipped_${b}`, countFor(b, isShipped)])),\n\n // Active epics list\n active_epics_list: activeEpicsList.map((i) => ({\n id: i.id,\n status: String(i.fm['status'] ?? ''),\n })),\n no_active_epics: activeEpicsList.length === 0 ? [{}] : [],\n\n // Shipped items list\n shipped_items: shippedItems.map((i) => ({\n id: i.id,\n bucket: i.bucket,\n status: String(i.fm['status'] ?? ''),\n })),\n no_shipped: shippedItems.length === 0 ? [{}] : [],\n };\n\n return renderTemplate(tpl, data);\n}\n\nfunction resolveDefaultTemplateDir(): string {\n // Bundle: dist/cli.js → __dirname = dist/, .. = package root → templates/synthesis ✓\n const __dirname = path.dirname(fileURLToPath(import.meta.url));\n return path.resolve(__dirname, '..', 'templates', 'synthesis');\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport type { RawItem } from '../scan.js';\nimport { renderTemplate } from './render.js';\n\n/**\n * Compile the roadmap synthesis page.\n * Loads template from templates/synthesis/roadmap.md.\n *\n * Sprint buckets (by activated_at / completed_at):\n * in-flight: activated_at set AND completed_at not set\n * planned: neither set\n * shipped: completed_at set\n *\n * Epic buckets (by status):\n * active: Active / In Progress / 🟢-prefixed\n * planned: Ready / Planned / Draft\n * shipped: Completed / Approved\n */\nexport function compile(state: RawItem[], templateDir?: string): string {\n const tplDir = templateDir ?? resolveDefaultTemplateDir();\n const tpl = fs.readFileSync(path.join(tplDir, 'roadmap.md'), 'utf8');\n\n const sprints = state.filter((i) => i.bucket === 'sprints');\n const epics = state.filter((i) => i.bucket === 'epics');\n\n // Sprint partitions\n const inFlightSprints = sprints.filter(\n (s) => isSet(s.fm['activated_at']) && !isSet(s.fm['completed_at']),\n );\n const plannedSprints = sprints.filter(\n (s) => !isSet(s.fm['activated_at']) && !isSet(s.fm['completed_at']),\n );\n const shippedSprints = sprints.filter((s) => isSet(s.fm['completed_at']));\n\n // Epic partitions\n const activeEpics = epics.filter((e) => isActiveStatus(String(e.fm['status'] ?? '')));\n const plannedEpics = epics.filter((e) => isPlannedStatus(String(e.fm['status'] ?? '')));\n const shippedEpics = epics.filter((e) => isShippedStatus(String(e.fm['status'] ?? '')));\n\n const data: Record<string, unknown> = {\n in_flight_sprints: inFlightSprints.map((s) => ({\n id: s.id,\n activated_at: String(s.fm['activated_at'] ?? ''),\n })),\n no_in_flight_sprints: inFlightSprints.length === 0 ? [{}] : [],\n\n planned_sprints: plannedSprints.map((s) => ({\n id: s.id,\n status: String(s.fm['status'] ?? ''),\n })),\n no_planned_sprints: plannedSprints.length === 0 ? [{}] : [],\n\n shipped_sprints: shippedSprints.map((s) => ({\n id: s.id,\n completed_at: String(s.fm['completed_at'] ?? ''),\n })),\n no_shipped_sprints: shippedSprints.length === 0 ? [{}] : [],\n\n active_epics: activeEpics.map((e) => ({ id: e.id, status: String(e.fm['status'] ?? '') })),\n no_active_epics: activeEpics.length === 0 ? [{}] : [],\n\n planned_epics: plannedEpics.map((e) => ({ id: e.id, status: String(e.fm['status'] ?? '') })),\n no_planned_epics: plannedEpics.length === 0 ? [{}] : [],\n\n shipped_epics: shippedEpics.map((e) => ({ id: e.id, status: String(e.fm['status'] ?? '') })),\n no_shipped_epics: shippedEpics.length === 0 ? [{}] : [],\n };\n\n return renderTemplate(tpl, data);\n}\n\nfunction isSet(val: unknown): boolean {\n if (val === null || val === undefined) return false;\n const s = String(val).trim();\n return s !== '' && s !== 'null';\n}\n\nfunction isActiveStatus(status: string): boolean {\n return (\n status === 'Active' ||\n status === 'In Progress' ||\n status.startsWith('🟢') ||\n status === '🟡 in-flight'\n );\n}\n\nfunction isPlannedStatus(status: string): boolean {\n return status === 'Ready' || status === 'Planned' || status === 'Draft';\n}\n\nfunction isShippedStatus(status: string): boolean {\n return status === 'Completed' || status === 'Approved';\n}\n\nfunction resolveDefaultTemplateDir(): string {\n // Bundle: dist/cli.js → __dirname = dist/, .. = package root → templates/synthesis ✓\n const __dirname = path.dirname(fileURLToPath(import.meta.url));\n return path.resolve(__dirname, '..', 'templates', 'synthesis');\n}\n","/**\n * manifest.ts — STORY-009-01\n *\n * Scaffold manifest loading, drift classification, and atomic drift-state writing.\n * Node built-ins only: fs/promises, path.\n *\n * MANIFEST.json does not exist until STORY-009-02 runs `npm run build`.\n * loadPackageManifest throws a clear error when the file is absent — not raw ENOENT.\n */\n\nimport { readFile, writeFile, rename, mkdir } from 'node:fs/promises';\nimport { existsSync, readFileSync } from 'node:fs';\nimport * as path from 'node:path';\nimport { hashNormalized } from './sha256.js';\n\n// ─── Public types ─────────────────────────────────────────────────────────────\n\nexport type Tier =\n | 'protocol'\n | 'template'\n | 'agent'\n | 'hook'\n | 'skill'\n | 'cli-config'\n | 'user-artifact'\n | 'derived';\n\nexport type DriftState =\n | 'clean'\n | 'user-modified'\n | 'upstream-changed'\n | 'both-changed'\n | 'untracked';\n\nexport interface ManifestEntry {\n path: string;\n sha256: string | null;\n tier: Tier;\n overwrite_policy: 'always' | 'merge-3way' | 'skip' | 'preserve';\n preserve_on_uninstall: boolean;\n}\n\nexport interface ManifestFile {\n cleargate_version: string;\n generated_at: string;\n files: ManifestEntry[];\n /**\n * Present only in `.cleargate/.install-manifest.json` (the install snapshot).\n * Stamped by `cleargate init` as the FINAL step (STORY-009-03).\n * Not present in the package-shipped MANIFEST.json.\n */\n installed_at?: string;\n}\n\nexport interface DriftMapEntry {\n state: DriftState;\n entry: ManifestEntry;\n install_sha: string | null;\n current_sha: string | null;\n package_sha: string | null;\n}\n\nexport interface DriftMap {\n [filePath: string]: DriftMapEntry;\n}\n\n/**\n * The on-disk shape of `.cleargate/.drift-state.json`.\n * Wraps the DriftMap with a `last_refreshed` timestamp so the daily-throttle\n * logic in `cleargate doctor --check-scaffold` can skip re-computation.\n */\nexport interface DriftStateFile {\n last_refreshed: string;\n drift: DriftMap;\n}\n\n// ─── Options ──────────────────────────────────────────────────────────────────\n\nexport interface LoadPackageManifestOpts {\n /**\n * Override the root directory where MANIFEST.json is resolved.\n * Default: resolved via import.meta.url (1 level up from dist/ in prod,\n * or cleargate-planning/ in dev).\n *\n * This seam is mandatory per FLASHCARD #tsup #bundle #import-meta — the\n * bundle collapses import.meta.url to the bundle file so default resolution\n * must never be relied upon in tests.\n */\n packageRoot?: string;\n}\n\n// ─── Internal helpers ─────────────────────────────────────────────────────────\n\nfunction resolveDefaultPackageRoot(): string {\n // In production (dist/cli.js), import.meta.url points to dist/cli.js.\n // MANIFEST.json is copied to dist/ by the build step — so 0 levels up.\n // In dev, import.meta.url is cleargate-cli/src/lib/manifest.ts — 3 levels up\n // to cleargate-cli/, then ../cleargate-planning/ for the fixture source.\n // Rather than guessing, we prefer the dist/ sibling first; fall back to the\n // source-tree dev path.\n const here = new URL('.', import.meta.url).pathname;\n\n // Try: same directory (dist/ scenario)\n const distCandidate = path.join(here, 'MANIFEST.json');\n if (existsSync(distCandidate)) {\n return here;\n }\n\n // Try: 1 level up (also dist/ scenario when emitted as dist/lib/manifest.js)\n const oneLevelUp = path.join(here, '..', 'MANIFEST.json');\n if (existsSync(oneLevelUp)) {\n return path.join(here, '..');\n }\n\n // Dev fallback: from src/lib walk up to repo root, then cleargate-planning/\n // src/lib → src → cleargate-cli → repo-root → cleargate-planning\n const devCandidate = path.join(here, '..', '..', '..', 'cleargate-planning', 'MANIFEST.json');\n if (existsSync(devCandidate)) {\n return path.join(here, '..', '..', '..', 'cleargate-planning');\n }\n\n // Cannot determine — caller will get a clear error from loadPackageManifest\n return here;\n}\n\n// ─── Public API ───────────────────────────────────────────────────────────────\n\n/**\n * Load MANIFEST.json from the installed package root.\n *\n * Uses `opts.packageRoot` (required in tests) or default resolution.\n * Throws a descriptive error when the file is absent rather than a raw ENOENT.\n */\nexport function loadPackageManifest(opts?: LoadPackageManifestOpts): ManifestFile {\n const packageRoot = opts?.packageRoot ?? resolveDefaultPackageRoot();\n const manifestPath = path.join(packageRoot, 'MANIFEST.json');\n\n if (!existsSync(manifestPath)) {\n throw new Error(\n `MANIFEST.json not found at ${manifestPath}; run 'npm run build' to generate it.`\n );\n }\n\n let raw: string;\n try {\n // Synchronous read — callers treat loadPackageManifest as synchronous (startup-time).\n raw = readFileSync(manifestPath, 'utf-8');\n } catch {\n throw new Error(\n `MANIFEST.json not found at ${manifestPath}; run 'npm run build' to generate it.`\n );\n }\n\n return JSON.parse(raw) as ManifestFile;\n}\n\n/**\n * Load the install-time snapshot from `<projectRoot>/.cleargate/.install-manifest.json`.\n * Returns null if the file does not exist (first install or pre-manifest era).\n */\nexport async function loadInstallSnapshot(projectRoot: string): Promise<ManifestFile | null> {\n const snapshotPath = path.join(projectRoot, '.cleargate', '.install-manifest.json');\n try {\n const raw = await readFile(snapshotPath, 'utf-8');\n return JSON.parse(raw) as ManifestFile;\n } catch {\n return null;\n }\n}\n\n/**\n * Compute the SHA256 of a tracked file in the current working tree.\n * Returns null when the file does not exist on disk.\n */\nexport async function computeCurrentSha(\n file: ManifestEntry,\n projectRoot: string\n): Promise<string | null> {\n const filePath = path.join(projectRoot, file.path);\n try {\n const raw = await readFile(filePath);\n return hashNormalized(raw);\n } catch {\n return null;\n }\n}\n\n/**\n * Classify the drift state of a single tracked file.\n *\n * Decision table (PROP-006 §2.4):\n *\n * | Tier | Result |\n * |---------------|-------------|\n * | user-artifact | untracked |\n *\n * | pkgSha | installSha | currentSha | Result |\n * |--------|------------|------------|-------------------|\n * | any | any | null | untracked |\n * | A | A | A | clean |\n * | A | A | B (≠A) | user-modified |\n * | B (≠A) | A | A | upstream-changed |\n * | all differ pairwise | both-changed |\n */\nexport function classify(\n pkgSha: string | null,\n installSha: string | null,\n currentSha: string | null,\n tier: Tier\n): DriftState {\n // user-artifact short-circuit (EPIC-009 §6 Q8)\n if (tier === 'user-artifact') {\n return 'untracked';\n }\n\n // Missing current file\n if (currentSha === null) {\n return 'untracked';\n }\n\n const installEqualsPackage = installSha === pkgSha;\n const currentEqualsInstall = currentSha === installSha;\n\n if (installEqualsPackage && currentEqualsInstall) {\n // install == current == package\n return 'clean';\n }\n\n if (installEqualsPackage && !currentEqualsInstall) {\n // install == package, current != install => user modified\n return 'user-modified';\n }\n\n if (!installEqualsPackage && currentEqualsInstall) {\n // install == current, package != install => upstream changed\n return 'upstream-changed';\n }\n\n // All three differ pairwise\n return 'both-changed';\n}\n\n/**\n * Options for writeDriftState.\n */\nexport interface WriteDriftStateOpts {\n /**\n * ISO-8601 timestamp to record as `last_refreshed` in the output file.\n * When omitted, the current time is used (new Date().toISOString()).\n * This seam is mandatory for deterministic tests.\n */\n lastRefreshed?: string;\n}\n\n/**\n * Atomically write the drift-state map to `<projectRoot>/.cleargate/.drift-state.json`.\n *\n * The on-disk format is wrapped: `{ last_refreshed: string, drift: DriftMap }`.\n * This allows the daily-throttle logic in `cleargate doctor --check-scaffold`\n * to read the timestamp without re-computing all SHAs.\n *\n * Uses write-temp-then-rename (atomic on POSIX; best-effort on Windows).\n * Ensures parent directory exists before writing.\n *\n * STORY-009-04 extended the signature from `(projectRoot, DriftMap)` to\n * `(projectRoot, DriftMap, opts?)` — callers passing only two args continue to work.\n */\nexport async function writeDriftState(\n projectRoot: string,\n state: DriftMap,\n opts?: WriteDriftStateOpts\n): Promise<void> {\n const cleargatDir = path.join(projectRoot, '.cleargate');\n const finalPath = path.join(cleargatDir, '.drift-state.json');\n const tmpPath = `${finalPath}.tmp`;\n\n const lastRefreshed = opts?.lastRefreshed ?? new Date().toISOString();\n const fileContent: DriftStateFile = { last_refreshed: lastRefreshed, drift: state };\n\n await mkdir(cleargatDir, { recursive: true });\n await writeFile(tmpPath, JSON.stringify(fileContent, null, 2) + '\\n', 'utf-8');\n await rename(tmpPath, finalPath);\n}\n\n/**\n * Read the drift-state file written by `writeDriftState`.\n * Returns null when the file does not exist or is malformed.\n */\nexport async function readDriftState(projectRoot: string): Promise<DriftStateFile | null> {\n const driftPath = path.join(projectRoot, '.cleargate', '.drift-state.json');\n try {\n const raw = await readFile(driftPath, 'utf-8');\n const parsed = JSON.parse(raw) as unknown;\n // Accept both the new wrapped format {last_refreshed, drift} and the old flat format\n if (\n typeof parsed === 'object' &&\n parsed !== null &&\n 'last_refreshed' in parsed &&\n 'drift' in parsed\n ) {\n return parsed as DriftStateFile;\n }\n return null;\n } catch {\n return null;\n }\n}\n","/**\n * sha256.ts — STORY-009-01\n *\n * Deterministic SHA256 hasher with cross-platform content normalization.\n * Node built-ins only: crypto, fs/promises, path.\n */\n\nimport { createHash } from 'node:crypto';\nimport { readFile } from 'node:fs/promises';\n\n// ─── Public API ───────────────────────────────────────────────────────────────\n\n/**\n * Hash normalized content (string or Buffer) — 64 hex chars.\n *\n * Normalization steps applied in order:\n * 1. Convert Buffer to UTF-8 string.\n * 2. Strip leading BOM (U+FEFF).\n * 3. Normalize CRLF → LF.\n * 4. Enforce trailing newline (append `\\n` if missing).\n */\nexport function hashNormalized(content: string | Buffer): string {\n let text: string =\n Buffer.isBuffer(content) ? content.toString('utf-8') : content;\n\n // 1. Strip leading BOM\n if (text.startsWith('\\ufeff')) {\n text = text.slice(1);\n }\n\n // 2. CRLF → LF\n text = text.replace(/\\r\\n/g, '\\n');\n\n // 3. Enforce trailing newline\n if (!text.endsWith('\\n')) {\n text += '\\n';\n }\n\n return createHash('sha256').update(text, 'utf-8').digest('hex');\n}\n\n/**\n * Read a file, normalize its content, and return the SHA256 hex digest.\n */\nexport async function hashFile(filePath: string): Promise<string> {\n const raw = await readFile(filePath);\n return hashNormalized(raw);\n}\n\n/**\n * Return the first 8 hex characters of a full SHA256 digest for human-readable output.\n */\nexport function shortHash(full: string): string {\n return full.slice(0, 8);\n}\n","/**\n * prompts.ts — minimal readline-based Y/n prompt helper\n *\n * STORY-009-03: created here (cited in story §3 as \"existing\"; verified absent).\n * Used by init.ts restore flow and future commands that need a binary yes/no prompt.\n */\nimport * as readline from 'node:readline';\n\nexport interface PromptOptions {\n /** Override stdin for testing */\n stdin?: NodeJS.ReadableStream;\n /** Override stdout write for testing */\n stdout?: (s: string) => void;\n}\n\n/**\n * Prompt the user with a yes/no question.\n *\n * @param question The question text to display (without [Y/n] suffix — caller includes it)\n * @param defaultYes Whether Enter with no input means yes\n * @param opts Test seams for stdin/stdout\n * @returns true for yes, false for no\n */\nexport async function promptYesNo(\n question: string,\n defaultYes: boolean,\n opts?: PromptOptions,\n): Promise<boolean> {\n const stdoutFn = opts?.stdout ?? ((s: string) => process.stdout.write(s));\n stdoutFn(question + '\\n');\n\n const inputStream = opts?.stdin ?? process.stdin;\n\n return new Promise<boolean>((resolve) => {\n const rl = readline.createInterface({\n input: inputStream,\n output: undefined, // we handle output ourselves\n terminal: false,\n });\n\n let answered = false;\n\n rl.once('line', (line: string) => {\n answered = true;\n rl.close();\n const trimmed = line.trim().toLowerCase();\n if (trimmed === '') {\n resolve(defaultYes);\n } else if (trimmed === 'y' || trimmed === 'yes') {\n resolve(true);\n } else {\n resolve(false);\n }\n });\n\n rl.once('close', () => {\n if (!answered) {\n // EOF without a line — treat as default\n resolve(defaultYes);\n }\n });\n });\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { spawnSync } from 'node:child_process';\nimport { parseFrontmatter } from '../wiki/parse-frontmatter.js';\nimport { deriveBucket } from '../wiki/derive-bucket.js';\nimport { deriveRepo } from '../wiki/derive-repo.js';\nimport { getGitSha, type GitRunner } from '../wiki/git-sha.js';\nimport { serializePage, parsePage, type WikiPage } from '../wiki/page-schema.js';\nimport { compile as compileActiveSprint } from '../wiki/synthesis/active-sprint.js';\nimport { compile as compileOpenGates } from '../wiki/synthesis/open-gates.js';\nimport { compile as compileProductState } from '../wiki/synthesis/product-state.js';\nimport { compile as compileRoadmap } from '../wiki/synthesis/roadmap.js';\nimport { scanRawItems, type RawItem } from '../wiki/scan.js';\n\nexport interface WikiIngestOptions {\n /** Absolute path to the raw delivery file to ingest */\n rawPath: string;\n /** Test seam: working directory (defaults to process.cwd()) */\n cwd?: string;\n /** Test seam: frozen ISO timestamp */\n now?: () => string;\n /** Test seam: replaces process.stdout.write */\n stdout?: (s: string) => void;\n /** Test seam: replaces process.stderr.write */\n stderr?: (s: string) => void;\n /** Test seam: replaces process.exit */\n exit?: (code: number) => never;\n /** Test seam: forwarded to getGitSha */\n gitRunner?: GitRunner;\n /** Test seam: replaces fs.rename (for atomic index.md write test) */\n rename?: (src: string, dst: string) => void;\n /** Test seam: override directory for synthesis templates (default resolved via import.meta.url) */\n templateDir?: string;\n}\n\n/** Directories under .cleargate/ that are excluded from ingest per §10.3. */\nconst EXCLUDED_SUFFIXES = [\n '.cleargate/knowledge/',\n '.cleargate/templates/',\n '.cleargate/sprint-runs/',\n '.cleargate/hook-log/',\n '.cleargate/wiki/',\n];\n\nconst BUCKET_ORDER = ['epics', 'stories', 'sprints', 'proposals', 'crs', 'bugs', 'topics'] as const;\nconst BUCKET_LABELS: Record<string, string> = {\n epics: 'Epics',\n stories: 'Stories',\n sprints: 'Sprints',\n proposals: 'Proposals',\n crs: 'CRs',\n bugs: 'Bugs',\n topics: 'Topics',\n};\n\nexport async function wikiIngestHandler(opts: WikiIngestOptions): Promise<void> {\n const cwd = opts.cwd ?? process.cwd();\n const now = opts.now ?? (() => new Date().toISOString());\n const stdout = opts.stdout ?? ((s) => process.stdout.write(s));\n const stderr = opts.stderr ?? ((s) => process.stderr.write(s));\n const exit = opts.exit ?? ((c: number): never => process.exit(c));\n const gitRunner = opts.gitRunner;\n const rename = opts.rename ?? fs.renameSync;\n const templateDir = opts.templateDir;\n\n const rawPath = opts.rawPath;\n\n // Resolve rawPath: if relative, resolve against cwd\n const absRawPath = path.isAbsolute(rawPath) ? rawPath : path.resolve(cwd, rawPath);\n // Compute relative path from cwd (repo root)\n const relRawPath = path.relative(cwd, absRawPath).replace(/\\\\/g, '/');\n\n // Step 1: Validate path resolves under <cwd>/.cleargate/delivery/\n const deliveryRoot = path.join(cwd, '.cleargate', 'delivery');\n const deliveryRootNorm = deliveryRoot.replace(/\\\\/g, '/');\n const absDeliveryRoot = deliveryRoot;\n\n // Check: absRawPath must be under absDeliveryRoot\n const relToDelivery = path.relative(absDeliveryRoot, absRawPath);\n if (relToDelivery.startsWith('..') || path.isAbsolute(relToDelivery)) {\n stderr(`wiki ingest: ${rawPath} not under .cleargate/delivery/\\n`);\n exit(2);\n return;\n }\n\n void deliveryRootNorm; // suppress lint warning\n\n // Step 2: Exclusion check (defense-in-depth)\n const isExcluded = EXCLUDED_SUFFIXES.some((excl) => relRawPath.startsWith(excl));\n if (isExcluded) {\n stdout(`wiki ingest: ${rawPath} excluded (skip)\\n`);\n exit(0);\n return;\n }\n\n // Step 3: Derive bucket + id + type + repo\n const filename = path.basename(absRawPath);\n let bucketInfo: ReturnType<typeof deriveBucket>;\n try {\n bucketInfo = deriveBucket(filename);\n } catch (e) {\n stderr(`wiki ingest: cannot determine bucket for ${rawPath}: ${(e as Error).message}\\n`);\n exit(1);\n return;\n }\n\n let repo: ReturnType<typeof deriveRepo>;\n try {\n repo = deriveRepo(relRawPath);\n } catch (e) {\n stderr(`wiki ingest: cannot derive repo for ${rawPath}: ${(e as Error).message}\\n`);\n exit(1);\n return;\n }\n\n const { type, id, bucket } = bucketInfo;\n\n const wikiRoot = path.join(cwd, '.cleargate', 'wiki');\n const pageDir = path.join(wikiRoot, bucket);\n const pagePath = path.join(pageDir, `${id}.md`);\n\n // Read and parse the raw file\n let rawContent: string;\n try {\n rawContent = fs.readFileSync(absRawPath, 'utf8');\n } catch (e) {\n stderr(`wiki ingest: cannot read ${rawPath}: ${(e as Error).message}\\n`);\n exit(1);\n return;\n }\n\n let fm: Record<string, unknown>;\n let body: string;\n try {\n const parsed = parseFrontmatter(rawContent);\n fm = parsed.fm;\n body = parsed.body;\n } catch (e) {\n stderr(`wiki ingest: malformed frontmatter in ${rawPath}: ${(e as Error).message}\\n`);\n exit(1);\n return;\n }\n\n // Step 4: Idempotency guard (A2)\n const currentSha = getGitSha(absRawPath, gitRunner) ?? '';\n const pageExists = fs.existsSync(pagePath);\n\n if (pageExists && currentSha !== '') {\n let isNoOp = false;\n try {\n const existingPageContent = fs.readFileSync(pagePath, 'utf8');\n const existingPage = parsePage(existingPageContent);\n\n if (existingPage.last_ingest_commit === currentSha) {\n // Check if raw file content matches what git shows for that SHA\n const contentUnchanged = checkContentUnchanged(absRawPath, currentSha, relRawPath, gitRunner);\n if (contentUnchanged) {\n isNoOp = true;\n }\n }\n } catch {\n // If we can't parse the existing page, proceed with ingest\n }\n\n if (isNoOp) {\n stdout(`wiki ingest: ${id} unchanged (no-op)\\n`);\n exit(0);\n return;\n }\n }\n\n // Determine action\n const action = pageExists ? 'update' : 'create';\n\n // Step 5: Build new WikiPage and write it\n const parent = buildParentRef(fm);\n const children = buildChildrenRefs(fm);\n const timestamp = now();\n\n const wikiPage: WikiPage = {\n type,\n id,\n parent,\n children,\n status: String(fm['status'] ?? ''),\n remote_id: String(fm['remote_id'] ?? ''),\n raw_path: relRawPath,\n last_ingest: timestamp,\n last_ingest_commit: currentSha,\n repo,\n };\n\n const pageBody = buildPageBody({ id, fm, body });\n const pageContent = serializePage(wikiPage, pageBody);\n\n fs.mkdirSync(pageDir, { recursive: true });\n fs.writeFileSync(pagePath, pageContent, 'utf8');\n\n // Step 6: Append one log entry to wiki/log.md\n appendLogEntry(wikiRoot, { timestamp, action, id, relRawPath });\n\n // Step 7: Update wiki/index.md (atomic write-temp-then-rename)\n updateIndex(wikiRoot, { id, type, status: wikiPage.status, relRawPath, rename });\n\n // Step 8: Recompile affected synthesis pages (all four — M3 over-recompiles)\n recompileSynthesis(wikiRoot, cwd, templateDir);\n\n // Step 9: Print result\n stdout(`wiki ingest: ${action} ${bucket}/${id}.md\\n`);\n}\n\nfunction checkContentUnchanged(\n absRawPath: string,\n sha: string,\n relRawPath: string,\n gitRunner?: GitRunner,\n): boolean {\n try {\n const run = gitRunner ?? defaultGitRunner;\n // git show <sha>:<relRawPath> returns file content at that commit\n const gitContent = run('git', ['show', `${sha}:${relRawPath}`]);\n // Non-zero exit is handled by runner returning empty string (defaultRunner returns stdout)\n // If empty string returned from show when sha is valid, treat as changed\n if (!gitContent && gitContent !== '') return false;\n const currentContent = fs.readFileSync(absRawPath, 'utf8');\n return gitContent === currentContent;\n } catch {\n return false;\n }\n}\n\nfunction defaultGitRunner(cmd: string, args: string[]): string {\n const result = spawnSync(cmd, args, { encoding: 'utf8' });\n if (result.status !== 0) return '\\0__NONZERO__'; // sentinel for non-zero exit\n return result.stdout ?? '';\n}\n\nfunction buildParentRef(fm: Record<string, unknown>): string {\n const raw = fm['parent_epic_ref'] ?? fm['parent'] ?? '';\n const s = String(raw);\n if (!s) return '';\n if (s.startsWith('[[') && s.endsWith(']]')) return s;\n return `[[${s}]]`;\n}\n\nfunction buildChildrenRefs(fm: Record<string, unknown>): string[] {\n const raw = fm['children'];\n if (!raw) return [];\n const arr = Array.isArray(raw) ? raw : [raw];\n return arr.map((c) => {\n const s = String(c);\n if (s.startsWith('[[') && s.endsWith(']]')) return s;\n return `[[${s}]]`;\n });\n}\n\nfunction buildPageBody(item: { id: string; fm: Record<string, unknown>; body: string }): string {\n const title = String(item.fm['title'] ?? item.id);\n const summary = String(\n item.fm['description'] ?? item.body.split('\\n')[0] ?? 'No summary available.',\n ).slice(0, 200);\n\n const parent = buildParentRef(item.fm);\n const children = buildChildrenRefs(item.fm);\n const blastParts: string[] = [];\n if (parent) blastParts.push(parent);\n for (const child of children) blastParts.push(child);\n const blastLine = blastParts.length > 0 ? blastParts.join(', ') : 'None.';\n\n return [\n `# ${item.id}: ${title}`,\n '',\n summary,\n '',\n '## Blast radius',\n `Affects: ${blastLine}`,\n '',\n '## Open questions',\n 'None.',\n '',\n ].join('\\n');\n}\n\nfunction appendLogEntry(\n wikiRoot: string,\n entry: { timestamp: string; action: string; id: string; relRawPath: string },\n): void {\n const logPath = path.join(wikiRoot, 'log.md');\n const logEntry = [\n `- timestamp: \"${entry.timestamp}\"`,\n ` actor: \"cleargate wiki ingest\"`,\n ` action: \"${entry.action}\"`,\n ` target: \"${entry.id}\"`,\n ` path: \"${entry.relRawPath}\"`,\n ].join('\\n');\n\n if (fs.existsSync(logPath)) {\n const existing = fs.readFileSync(logPath, 'utf8');\n // Append to existing log\n const newContent = existing.trimEnd() + '\\n' + logEntry + '\\n';\n fs.writeFileSync(logPath, newContent, 'utf8');\n } else {\n fs.mkdirSync(wikiRoot, { recursive: true });\n fs.writeFileSync(logPath, `# Wiki Event Log\\n\\n${logEntry}\\n`, 'utf8');\n }\n}\n\nfunction updateIndex(\n wikiRoot: string,\n opts: {\n id: string;\n type: string;\n status: string;\n relRawPath: string;\n rename: (src: string, dst: string) => void;\n },\n): void {\n const indexPath = path.join(wikiRoot, 'index.md');\n const tmpPath = `${indexPath}.tmp`;\n\n const newRow = `| [[${opts.id}]] | ${opts.type} | ${opts.status} | ${opts.relRawPath} |`;\n\n let content: string;\n if (fs.existsSync(indexPath)) {\n content = fs.readFileSync(indexPath, 'utf8');\n // Check if a row with this id already exists; if so, replace it\n const idPattern = `[[${opts.id}]]`;\n const lines = content.split('\\n');\n let replaced = false;\n const newLines = lines.map((line) => {\n if (line.includes(idPattern) && line.startsWith('|')) {\n replaced = true;\n return newRow;\n }\n return line;\n });\n\n if (replaced) {\n content = newLines.join('\\n');\n } else {\n // Insert into the correct bucket section\n content = insertIntoSection(content, opts.id, newRow);\n }\n } else {\n // Build a minimal index.md with the item\n content = buildMinimalIndex(opts.id, opts.type, opts.status, opts.relRawPath);\n }\n\n fs.writeFileSync(tmpPath, content, 'utf8');\n opts.rename(tmpPath, indexPath);\n}\n\nfunction insertIntoSection(content: string, id: string, newRow: string): string {\n // Determine which bucket section to insert into\n const bucket = getBucketFromId(id);\n const label = BUCKET_LABELS[bucket] ?? bucket;\n const sectionHeader = `## ${label}`;\n\n const lines = content.split('\\n');\n let sectionStart = -1;\n let nextSectionStart = -1;\n\n for (let i = 0; i < lines.length; i++) {\n if (lines[i] === sectionHeader) {\n sectionStart = i;\n // Find next section\n for (let j = i + 1; j < lines.length; j++) {\n if (lines[j].startsWith('## ')) {\n nextSectionStart = j;\n break;\n }\n }\n break;\n }\n }\n\n if (sectionStart === -1) {\n // Section doesn't exist — append new section at end\n const sectionContent = [\n '',\n sectionHeader,\n '',\n newRow,\n '',\n ].join('\\n');\n return content.trimEnd() + sectionContent;\n }\n\n // Find insertion point: after any existing rows in this section, sorted by id\n const sectionEnd = nextSectionStart === -1 ? lines.length : nextSectionStart;\n const sectionLines = lines.slice(sectionStart + 1, sectionEnd);\n\n // Find existing row entries and insert in sorted order\n let insertAt = -1;\n for (let i = 0; i < sectionLines.length; i++) {\n const line = sectionLines[i];\n if (line.startsWith('|') && !line.startsWith('|---|')) {\n // Extract the id from the row: | [[ID]] | ...\n const match = /\\|\\s*\\[\\[([^\\]]+)\\]\\]/.exec(line);\n if (match) {\n const rowId = match[1];\n if (id.localeCompare(rowId) <= 0) {\n insertAt = sectionStart + 1 + i;\n break;\n }\n }\n }\n }\n\n if (insertAt === -1) {\n // Append before the next section or at end of section\n // Find last row in section\n let lastRowIdx = sectionStart + 1;\n for (let i = sectionStart + 1; i < sectionEnd; i++) {\n if (lines[i].startsWith('|')) {\n lastRowIdx = i + 1;\n }\n }\n lines.splice(lastRowIdx, 0, newRow);\n } else {\n lines.splice(insertAt, 0, newRow);\n }\n\n return lines.join('\\n');\n}\n\nfunction getBucketFromId(id: string): string {\n if (id.startsWith('EPIC-')) return 'epics';\n if (id.startsWith('STORY-')) return 'stories';\n if (id.startsWith('SPRINT-')) return 'sprints';\n if (id.startsWith('PROPOSAL-')) return 'proposals';\n if (id.startsWith('CR-')) return 'crs';\n if (id.startsWith('BUG-')) return 'bugs';\n return 'topics';\n}\n\nfunction buildMinimalIndex(id: string, type: string, status: string, relRawPath: string): string {\n const bucket = getBucketFromId(id);\n const label = BUCKET_LABELS[bucket] ?? bucket;\n\n const lines: string[] = [\n '# Wiki Index',\n '',\n '> Auto-generated by `cleargate wiki build`. Do not edit manually.',\n '',\n '| ID | Type | Status | Raw Path |',\n '|---|---|---|---|',\n ];\n\n for (const b of BUCKET_ORDER) {\n if (b === 'topics') continue;\n lines.push('', `## ${BUCKET_LABELS[b]}`, '');\n if (b === bucket) {\n lines.push(`| [[${id}]] | ${type} | ${status} | ${relRawPath} |`);\n } else {\n lines.push('_No items._');\n }\n }\n lines.push('');\n\n void label; // suppress\n return lines.join('\\n');\n}\n\nfunction recompileSynthesis(wikiRoot: string, cwd: string, templateDir?: string): void {\n // Recompile all four synthesis pages\n // Gather current state from wiki pages to pass to recipes\n const deliveryRoot = path.join(cwd, '.cleargate', 'delivery');\n let items: RawItem[] = [];\n if (fs.existsSync(deliveryRoot)) {\n try {\n items = scanRawItems(deliveryRoot, cwd);\n } catch {\n // If scan fails, pass empty state — synthesis pages will reflect empty\n }\n }\n\n fs.writeFileSync(path.join(wikiRoot, 'active-sprint.md'), compileActiveSprint(items, templateDir), 'utf8');\n fs.writeFileSync(path.join(wikiRoot, 'open-gates.md'), compileOpenGates(items, templateDir), 'utf8');\n fs.writeFileSync(path.join(wikiRoot, 'product-state.md'), compileProductState(items, templateDir), 'utf8');\n fs.writeFileSync(path.join(wikiRoot, 'roadmap.md'), compileRoadmap(items, templateDir), 'utf8');\n}\n","/**\n * STORY-002-08: cleargate wiki lint\n *\n * Scans .cleargate/wiki/ pages against their raw source files.\n * Enforcement mode (default): exits non-zero on any drift finding.\n * Suggest mode (--suggest): exits 0, prefixes flags with [advisory].\n *\n * Output format matches cleargate-wiki-lint subagent def lines 220-227:\n * <category>: <primary-path> -> <secondary-path-or-detail> (<optional context>)\n * Summary line always last:\n * lint: <OK|FAIL> (N pages checked, M findings)\n */\n\nimport * as path from 'node:path';\nimport { loadWikiPages } from '../wiki/load-wiki.js';\nimport type { GitRunner } from '../wiki/git-sha.js';\nimport {\n checkOrphan,\n checkRepoMismatch,\n checkStaleCommit,\n checkMissingIngest,\n checkBrokenBacklinks,\n checkInvalidatedCitations,\n checkExcludedPathIngested,\n checkPaginationNeeded,\n checkGateFailure,\n checkGateStaleness,\n discoverPlainTextMentions,\n type LintFinding,\n} from '../wiki/lint-checks.js';\n\nexport interface WikiLintOptions {\n /** Test seam: working directory (defaults to process.cwd()) */\n cwd?: string;\n /** Test seam: replaces process.stdout.write */\n stdout?: (s: string) => void;\n /** Test seam: replaces process.stderr.write */\n stderr?: (s: string) => void;\n /** Test seam: replaces process.exit */\n exit?: (code: number) => never;\n /** Test seam: forwarded to git-sha calls */\n gitRunner?: GitRunner;\n /** Lint mode: 'enforce' (default, exits 1 on findings) or 'suggest' (always exits 0) */\n mode?: 'enforce' | 'suggest';\n}\n\nexport async function wikiLintHandler(opts: WikiLintOptions = {}): Promise<void> {\n const cwd = opts.cwd ?? process.cwd();\n const stdout = opts.stdout ?? ((s: string) => process.stdout.write(s));\n // stderr seam is wired but lint outputs everything to stdout per subagent def\n opts.stderr;\n const exit = opts.exit ?? ((c: number): never => process.exit(c));\n const gitRunner = opts.gitRunner;\n const mode = opts.mode ?? 'enforce';\n\n const wikiRoot = path.join(cwd, '.cleargate', 'wiki');\n const repoRoot = cwd;\n\n // Step 1: load all wiki pages (single discovery pass)\n let pages = loadWikiPages(wikiRoot);\n\n const findings: LintFinding[] = [];\n\n // Meta-check: pagination-needed (fires on bucket > 50 entries)\n const paginationFindings = checkPaginationNeeded(pages);\n findings.push(...paginationFindings);\n\n // Step 2: per-page checks (O(n))\n for (const page of pages) {\n // (a) orphan\n const orphan = checkOrphan(page, repoRoot);\n if (orphan) findings.push(orphan);\n\n // (b) repo-mismatch\n const repoMismatch = checkRepoMismatch(page, repoRoot);\n if (repoMismatch) findings.push(repoMismatch);\n\n // (c) stale-commit\n const staleCommit = checkStaleCommit(page, repoRoot, gitRunner);\n if (staleCommit) findings.push(staleCommit);\n\n // (d) missing-ingest\n const missingIngest = checkMissingIngest(page, repoRoot);\n if (missingIngest) findings.push(missingIngest);\n\n // (e) excluded-path-ingested\n const excludedPath = checkExcludedPathIngested(page, repoRoot);\n if (excludedPath) findings.push(excludedPath);\n\n // (f) gate-failure — enforcing for Epic/Story/CR/Bug\n const gateFail = checkGateFailure(page, repoRoot);\n if (gateFail) findings.push(gateFail);\n\n // (g) gate-stale — applies to ALL types\n const gateStale = checkGateStaleness(page, repoRoot);\n if (gateStale) findings.push(gateStale);\n }\n\n // Step 3: single index cross-check pass — broken backlinks\n const backlinkFindings = checkBrokenBacklinks(pages, repoRoot);\n findings.push(...backlinkFindings);\n\n // Step 4: topic-page invalidated-citation check\n const citationFindings = checkInvalidatedCitations(pages, repoRoot);\n findings.push(...citationFindings);\n\n const pageCount = pages.length;\n const findingCount = findings.length;\n\n // Step 5: emit results\n if (mode === 'suggest') {\n // Advisory mode: prefix flags with [advisory] + do Karpathy discovery pass\n for (const finding of findings) {\n stdout(`[advisory] ${finding.line}\\n`);\n }\n\n // Karpathy discovery pass\n const suggestions = discoverPlainTextMentions(pages, repoRoot);\n for (const suggestion of suggestions) {\n stdout(`${suggestion}\\n`);\n }\n\n stdout(`lint: OK (${pageCount} pages checked, ${findingCount} findings)\\n`);\n exit(0);\n return;\n }\n\n // Enforce mode\n for (const finding of findings) {\n stdout(`${finding.line}\\n`);\n }\n\n if (findingCount > 0) {\n stdout(`lint: FAIL (${pageCount} pages checked, ${findingCount} findings)\\n`);\n exit(1);\n } else {\n stdout(`lint: OK (${pageCount} pages checked, 0 findings)\\n`);\n exit(0);\n }\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { parseFrontmatter } from './parse-frontmatter.js';\nimport type { WikiPage } from './page-schema.js';\nimport type { WikiPageType, RepoTag } from './page-schema.js';\n\nexport interface LoadedWikiPage {\n absPath: string;\n page: WikiPage;\n body: string;\n}\n\nconst BUCKET_DIRS = ['epics', 'stories', 'sprints', 'proposals', 'crs', 'bugs', 'topics'];\n\n/**\n * Glob+Read every wiki page from wikiRoot once.\n * Shared by wiki-lint and wiki-query (STORY-002-07 and STORY-002-08).\n */\nexport function loadWikiPages(wikiRoot: string): LoadedWikiPage[] {\n const results: LoadedWikiPage[] = [];\n\n for (const bucket of BUCKET_DIRS) {\n const dir = path.join(wikiRoot, bucket);\n if (!fs.existsSync(dir)) continue;\n\n const entries = fs.readdirSync(dir, { encoding: 'utf8' }) as string[];\n for (const filename of entries) {\n if (!filename.endsWith('.md')) continue;\n const absPath = path.join(dir, filename);\n const stat = fs.statSync(absPath);\n if (!stat.isFile()) continue;\n\n const raw = fs.readFileSync(absPath, 'utf8');\n let fm: Record<string, unknown>;\n let body: string;\n try {\n const parsed = parseFrontmatter(raw);\n fm = parsed.fm;\n body = parsed.body;\n } catch {\n continue;\n }\n\n const page: WikiPage = {\n type: (fm['type'] as WikiPageType) ?? 'epic',\n id: String(fm['id'] ?? ''),\n parent: String(fm['parent'] ?? ''),\n children: Array.isArray(fm['children'])\n ? (fm['children'] as unknown[]).map(String)\n : [],\n status: String(fm['status'] ?? ''),\n remote_id: String(fm['remote_id'] ?? ''),\n raw_path: String(fm['raw_path'] ?? ''),\n last_ingest: String(fm['last_ingest'] ?? ''),\n last_ingest_commit: String(fm['last_ingest_commit'] ?? ''),\n repo: (fm['repo'] as RepoTag) ?? 'planning',\n };\n\n results.push({ absPath, page, body });\n }\n }\n\n return results;\n}\n","/**\n * Pure-function lint check implementations.\n * One exported function per category so they can be unit-tested in isolation.\n * Categories must use these exact strings (subagent + CLI agree):\n * orphan, repo-mismatch, stale-commit, missing-ingest, broken-backlink,\n * invalidated-citation, excluded-path-ingested, pagination-needed\n */\n\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { spawnSync } from 'node:child_process';\nimport yaml from 'js-yaml';\nimport type { GitRunner } from './git-sha.js';\nimport type { LoadedWikiPage } from './load-wiki.js';\nimport { deriveRepo } from './derive-repo.js';\nimport { parseFrontmatter } from './parse-frontmatter.js';\nimport { detectWorkItemTypeFromFm } from '../lib/work-item-type.js';\n\nexport interface LintFinding {\n category: string;\n line: string;\n}\n\n/** §10.3 excluded directories — wiki pages must not exist for raw files under these. */\nconst EXCLUDED_DIRS = [\n '.cleargate/knowledge/',\n '.cleargate/templates/',\n '.cleargate/sprint-runs/',\n '.cleargate/hook-log/',\n '.cleargate/wiki/',\n];\n\n/** Maximum entries per bucket before pagination-needed fires. */\nconst MAX_BUCKET_ENTRIES = 50;\n\n/**\n * Check (a): Orphan — wiki page's raw_path doesn't exist on disk.\n * Skips pages whose raw_path is under an excluded directory (caught by check 7).\n */\nexport function checkOrphan(page: LoadedWikiPage, repoRoot: string): LintFinding | null {\n const rawPath = page.page.raw_path;\n if (!rawPath) return null;\n // Don't flag orphan for excluded paths — that's caught by excluded-path-ingested\n const isExcluded = EXCLUDED_DIRS.some((excl) => rawPath.startsWith(excl));\n if (isExcluded) return null;\n\n const absRaw = path.join(repoRoot, rawPath);\n if (!fs.existsSync(absRaw)) {\n const relPage = path.relative(path.join(repoRoot, '.cleargate', 'wiki'), page.absPath).replace(/\\\\/g, '/');\n return {\n category: 'orphan',\n line: `orphan: ${relPage} -> missing ${rawPath} (raw missing)`,\n };\n }\n return null;\n}\n\n/**\n * Check (b): repo-mismatch — stored repo field doesn't match raw_path prefix.\n */\nexport function checkRepoMismatch(page: LoadedWikiPage, repoRoot: string): LintFinding | null {\n const rawPath = page.page.raw_path;\n if (!rawPath) return null;\n\n let derivedRepo: string;\n try {\n derivedRepo = deriveRepo(rawPath);\n } catch {\n return null; // Can't derive — not our responsibility to flag here\n }\n\n if (page.page.repo !== derivedRepo) {\n const relPage = path.relative(path.join(repoRoot, '.cleargate', 'wiki'), page.absPath).replace(/\\\\/g, '/');\n return {\n category: 'repo-mismatch',\n line: `repo-mismatch: ${relPage} declares repo:${page.page.repo} but raw_path implies repo:${derivedRepo}`,\n };\n }\n return null;\n}\n\n/**\n * Check (c): stale-commit — stored last_ingest_commit differs from current git HEAD SHA.\n * Empty stored SHA is tolerated (untracked file).\n */\nexport function checkStaleCommit(\n page: LoadedWikiPage,\n repoRoot: string,\n gitRunner?: GitRunner,\n): LintFinding | null {\n const rawPath = page.page.raw_path;\n if (!rawPath) return null;\n\n const storedSha = page.page.last_ingest_commit;\n // If stored SHA is empty, file was untracked at ingest time — tolerate\n if (!storedSha) return null;\n\n // Run git log -1\n let currentSha: string;\n if (gitRunner) {\n currentSha = gitRunner('git', ['log', '-1', '--format=%H', '--', rawPath]).trim();\n } else {\n const result = spawnSync('git', ['log', '-1', '--format=%H', '--', rawPath], {\n encoding: 'utf8',\n cwd: repoRoot,\n });\n currentSha = (result.stdout ?? '').trim();\n }\n\n if (!currentSha) return null; // untracked now — don't flag\n if (storedSha !== currentSha) {\n const relPage = path.relative(path.join(repoRoot, '.cleargate', 'wiki'), page.absPath).replace(/\\\\/g, '/');\n return {\n category: 'stale-commit',\n line: `stale-commit: ${relPage} at ${storedSha}, current ${currentSha}`,\n };\n }\n return null;\n}\n\n/**\n * Check (d): missing-ingest — raw file mtime newer than wiki page mtime.\n */\nexport function checkMissingIngest(page: LoadedWikiPage, repoRoot: string): LintFinding | null {\n const rawPath = page.page.raw_path;\n if (!rawPath) return null;\n\n const absRaw = path.join(repoRoot, rawPath);\n if (!fs.existsSync(absRaw)) return null; // orphan check handles this\n\n const rawStat = fs.statSync(absRaw);\n const pageStat = fs.statSync(page.absPath);\n\n // Use > 2s gap to avoid HFS+ mtime resolution flakiness (per blueprint gotcha)\n const rawMtimeMs = rawStat.mtimeMs;\n const pageMtimeMs = pageStat.mtimeMs;\n\n if (rawMtimeMs - pageMtimeMs > 2000) {\n const relPage = path.relative(path.join(repoRoot, '.cleargate', 'wiki'), page.absPath).replace(/\\\\/g, '/');\n const rawMtime = rawStat.mtime.toISOString();\n const pageMtime = pageStat.mtime.toISOString();\n return {\n category: 'missing-ingest',\n line: `missing-ingest: ${rawPath} newer than ${relPage} (raw mtime: ${rawMtime}, page mtime: ${pageMtime})`,\n };\n }\n return null;\n}\n\n/**\n * Check (backlink): broken backlink — child's parent exists but parent doesn't list the child.\n * O(n) linear scan over collected parent declarations.\n */\nexport function checkBrokenBacklinks(pages: LoadedWikiPage[], repoRoot: string): LintFinding[] {\n const wikiRoot = path.join(repoRoot, '.cleargate', 'wiki');\n // Build a map of id -> page for O(1) lookup\n const byId = new Map<string, LoadedWikiPage>();\n for (const p of pages) {\n if (p.page.id) byId.set(p.page.id, p);\n }\n\n const findings: LintFinding[] = [];\n\n for (const childPage of pages) {\n const parentRef = childPage.page.parent;\n if (!parentRef) continue;\n\n // Extract parent ID from \"[[PARENT-ID]]\" form\n const match = parentRef.match(/\\[\\[(.+?)\\]\\]/);\n if (!match) continue;\n const parentId = match[1];\n\n const parentPage = byId.get(parentId);\n if (!parentPage) {\n // Parent page missing — flag\n const relChild = path.relative(wikiRoot, childPage.absPath).replace(/\\\\/g, '/');\n findings.push({\n category: 'broken-backlink',\n line: `broken-backlink: ${relChild} -> ${parentId} (parent missing child entry)`,\n });\n continue;\n }\n\n // Check that parent's children list contains [[childId]]\n const childId = childPage.page.id;\n const childRef = `[[${childId}]]`;\n const parentHasChild = parentPage.page.children.some(\n (c) => c === childRef || c === childId,\n );\n\n if (!parentHasChild) {\n const relChild = path.relative(wikiRoot, childPage.absPath).replace(/\\\\/g, '/');\n findings.push({\n category: 'broken-backlink',\n line: `broken-backlink: ${relChild} -> ${parentId} (parent missing child entry)`,\n });\n }\n }\n\n return findings;\n}\n\n/**\n * Check: invalidated-citation — topic page cites a cancelled or missing item.\n */\nexport function checkInvalidatedCitations(pages: LoadedWikiPage[], repoRoot: string): LintFinding[] {\n const wikiRoot = path.join(repoRoot, '.cleargate', 'wiki');\n const byId = new Map<string, LoadedWikiPage>();\n for (const p of pages) {\n if (p.page.id) byId.set(p.page.id, p);\n }\n\n const findings: LintFinding[] = [];\n\n const topicPages = pages.filter((p) => p.page.type === 'topic');\n\n for (const topicPage of topicPages) {\n // WikiPage doesn't have a cites field — re-parse raw frontmatter to get it.\n const relTopic = path.relative(wikiRoot, topicPage.absPath).replace(/\\\\/g, '/');\n\n let citesList: string[] = [];\n try {\n const raw = fs.readFileSync(topicPage.absPath, 'utf8');\n const { fm } = parseFrontmatter(raw);\n const rawCites = fm['cites'];\n if (Array.isArray(rawCites)) {\n citesList = (rawCites as unknown[]).map(String);\n }\n } catch {\n continue;\n }\n\n for (const cite of citesList) {\n const match = cite.match(/\\[\\[(.+?)\\]\\]/);\n const id = match ? match[1] : cite;\n\n const citedPage = byId.get(id);\n if (!citedPage) {\n findings.push({\n category: 'invalidated-citation',\n line: `invalidated-citation: ${relTopic} cites [[${id}]] (missing)`,\n });\n continue;\n }\n\n const status = citedPage.page.status;\n if (status === 'cancelled' || status.toLowerCase().includes('cancelled')) {\n findings.push({\n category: 'invalidated-citation',\n line: `invalidated-citation: ${relTopic} cites [[${id}]] (cancelled)`,\n });\n }\n }\n }\n\n return findings;\n}\n\n/**\n * Check: excluded-path-ingested — wiki page exists for a raw file under an excluded directory.\n */\nexport function checkExcludedPathIngested(page: LoadedWikiPage, repoRoot: string): LintFinding | null {\n const rawPath = page.page.raw_path;\n if (!rawPath) return null;\n\n const isExcluded = EXCLUDED_DIRS.some((excl) => rawPath.startsWith(excl));\n if (isExcluded) {\n const relPage = path.relative(path.join(repoRoot, '.cleargate', 'wiki'), page.absPath).replace(/\\\\/g, '/');\n return {\n category: 'excluded-path-ingested',\n line: `excluded-path-ingested: ${relPage} (raw_path ${rawPath} is under an excluded directory)`,\n };\n }\n return null;\n}\n\n/**\n * Meta-check: pagination-needed — fires if any bucket has more than 50 entries.\n */\nexport function checkPaginationNeeded(pages: LoadedWikiPage[]): LintFinding[] {\n // Count by bucket (derived from absPath directory name)\n const bucketCounts = new Map<string, number>();\n for (const p of pages) {\n const bucket = path.basename(path.dirname(p.absPath));\n bucketCounts.set(bucket, (bucketCounts.get(bucket) ?? 0) + 1);\n }\n\n const findings: LintFinding[] = [];\n for (const [bucket, count] of bucketCounts) {\n if (count > MAX_BUCKET_ENTRIES) {\n findings.push({\n category: 'pagination-needed',\n line: `pagination-needed: ${bucket} (${count} entries, max ${MAX_BUCKET_ENTRIES} per bucket)`,\n });\n }\n }\n return findings;\n}\n\n/** Work-item types that trigger enforcing gate-failure lint (not advisory). */\nconst ENFORCING_TYPES = new Set(['epic', 'story', 'cr', 'bug']);\n\n/** Status values considered \"ready\" (🟢-candidate). */\nconst READY_STATUSES = new Set(['Ready', 'Active']);\n\n/**\n * Parse the cached_gate_result from a raw frontmatter record.\n * parseFrontmatter stores nested YAML objects as opaque strings starting with '{'.\n * This helper resolves either form into a plain object or null.\n */\nfunction parseCachedGateResult(\n raw: unknown,\n): { pass: unknown; failing_criteria: unknown; last_gate_check: unknown } | null {\n if (!raw || raw === null) return null;\n\n // Opaque string form — inline flow YAML written by writeCachedGate\n if (typeof raw === 'string') {\n if (!raw.startsWith('{')) return null;\n try {\n const parsed = yaml.load(raw);\n if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) return null;\n const p = parsed as Record<string, unknown>;\n return { pass: p['pass'], failing_criteria: p['failing_criteria'], last_gate_check: p['last_gate_check'] };\n } catch {\n return null;\n }\n }\n\n // Already-parsed object form (future-proofing)\n if (typeof raw === 'object' && !Array.isArray(raw)) {\n const p = raw as Record<string, unknown>;\n return { pass: p['pass'], failing_criteria: p['failing_criteria'], last_gate_check: p['last_gate_check'] };\n }\n\n return null;\n}\n\n/**\n * Check: gate-failure — 🟢-candidate Epic/Story/CR/Bug with cached_gate_result.pass === false.\n * Reads the raw work-item file (not the wiki page).\n * Proposal / Sprint / Initiative are advisory only → returns null (no enforcing block).\n */\nexport function checkGateFailure(page: LoadedWikiPage, repoRoot: string): LintFinding | null {\n const rawPath = page.page.raw_path;\n if (!rawPath) return null;\n\n const absRaw = path.join(repoRoot, rawPath);\n if (!fs.existsSync(absRaw)) return null;\n\n let rawFm: Record<string, unknown>;\n try {\n const raw = fs.readFileSync(absRaw, 'utf8');\n const { fm } = parseFrontmatter(raw);\n rawFm = fm;\n } catch {\n return null;\n }\n\n const cgr = parseCachedGateResult(rawFm['cached_gate_result']);\n if (!cgr || cgr.pass !== false) return null;\n\n // Check if the work-item type is enforcing\n const wiType = detectWorkItemTypeFromFm(rawFm);\n if (!wiType || !ENFORCING_TYPES.has(wiType)) return null;\n\n // Check if this is a 🟢-candidate (status Ready/Active or ambiguity 🟢 Low)\n const status = String(rawFm['status'] ?? '');\n const ambiguity = String(rawFm['ambiguity'] ?? '');\n const isReadyCandidate = READY_STATUSES.has(status) || ambiguity === '🟢 Low';\n if (!isReadyCandidate) return null;\n\n // Collect failing criteria IDs\n const failingCriteria = cgr.failing_criteria;\n const criteriaIds: string[] = [];\n if (Array.isArray(failingCriteria)) {\n for (const criterion of failingCriteria as unknown[]) {\n if (criterion && typeof criterion === 'object' && 'id' in (criterion as object)) {\n criteriaIds.push(String((criterion as Record<string, unknown>)['id']));\n } else if (typeof criterion === 'string') {\n criteriaIds.push(criterion);\n }\n }\n }\n\n const criteriaStr = criteriaIds.length > 0 ? criteriaIds.join(', ') : 'unknown';\n return {\n category: 'gate-failure',\n line: `gate-failure: ${rawPath} failed criteria: ${criteriaStr}`,\n };\n}\n\n/**\n * Check: gate-stale — cached_gate_result.last_gate_check < updated_at (ISO-8601 lexical compare).\n * Applies to ALL work-item types (including Proposal/Sprint/Initiative).\n * Reads the raw work-item file (not the wiki page).\n */\nexport function checkGateStaleness(page: LoadedWikiPage, repoRoot: string): LintFinding | null {\n const rawPath = page.page.raw_path;\n if (!rawPath) return null;\n\n const absRaw = path.join(repoRoot, rawPath);\n if (!fs.existsSync(absRaw)) return null;\n\n let rawFm: Record<string, unknown>;\n try {\n const raw = fs.readFileSync(absRaw, 'utf8');\n const { fm } = parseFrontmatter(raw);\n rawFm = fm;\n } catch {\n return null;\n }\n\n const cgr = parseCachedGateResult(rawFm['cached_gate_result']);\n if (!cgr) return null;\n\n const lastGateCheck = cgr.last_gate_check;\n if (!lastGateCheck || lastGateCheck === null) return null;\n\n const updatedAt = rawFm['updated_at'];\n if (!updatedAt) return null;\n\n const lastCheckStr = String(lastGateCheck);\n const updatedAtStr = String(updatedAt);\n\n // ISO-8601 lexical compare: if last_gate_check < updated_at → stale\n if (lastCheckStr < updatedAtStr) {\n return {\n category: 'gate-stale',\n line: `gate-stale: ${rawPath} last_gate_check=${lastCheckStr} < updated_at=${updatedAtStr}`,\n };\n }\n return null;\n}\n\n/**\n * Karpathy discovery pass: scan page bodies for plain-text ID mentions\n * (not wrapped in [[]]). Emit suggest lines.\n */\nexport function discoverPlainTextMentions(pages: LoadedWikiPage[], repoRoot: string): string[] {\n const wikiRoot = path.join(repoRoot, '.cleargate', 'wiki');\n const byId = new Map<string, boolean>();\n for (const p of pages) {\n if (p.page.id) byId.set(p.page.id, true);\n }\n\n const suggestions: string[] = [];\n const ID_PATTERN = /\\b((?:EPIC|STORY|SPRINT|PROPOSAL|CR|BUG)-[\\w-]+)\\b/g;\n const LINK_PATTERN = /\\[\\[[\\w-]+\\]\\]/g;\n\n for (const page of pages) {\n const relPage = path.relative(wikiRoot, page.absPath).replace(/\\\\/g, '/');\n // Find all [[...]] wrapped references to exclude\n const wrappedRefs = new Set<string>();\n for (const m of page.body.matchAll(LINK_PATTERN)) {\n const inner = m[0].slice(2, -2);\n wrappedRefs.add(inner);\n }\n\n // Find plain-text ID mentions\n for (const m of page.body.matchAll(ID_PATTERN)) {\n const mentionedId = m[1];\n if (!byId.has(mentionedId)) continue;\n if (wrappedRefs.has(mentionedId)) continue;\n if (mentionedId === page.page.id) continue; // self-reference\n suggestions.push(`suggest: ${relPage} mentions ${mentionedId} in plain text, consider [[${mentionedId}]] wrap`);\n }\n }\n\n return suggestions;\n}\n","/**\n * work-item-type.ts — Shared work-item type detection utility.\n *\n * STORY-008-03: extracted here for STORY-008-05 to import without duplication.\n * Maps frontmatter ID keys and filename patterns to canonical work-item types.\n */\n\nexport type WorkItemType = 'story' | 'epic' | 'proposal' | 'cr' | 'bug';\n\n/**\n * Frontmatter key → work-item type mapping.\n * Keys are checked in order; first match wins.\n */\nconst FM_KEY_MAP: Array<{ key: string; type: WorkItemType }> = [\n { key: 'story_id', type: 'story' },\n { key: 'epic_id', type: 'epic' },\n { key: 'proposal_id', type: 'proposal' },\n { key: 'cr_id', type: 'cr' },\n { key: 'bug_id', type: 'bug' },\n];\n\n/**\n * Filename / ID prefix → work-item type mapping.\n */\nconst PREFIX_MAP: Array<{ prefix: string; type: WorkItemType }> = [\n { prefix: 'STORY-', type: 'story' },\n { prefix: 'EPIC-', type: 'epic' },\n { prefix: 'PROPOSAL-', type: 'proposal' },\n { prefix: 'CR-', type: 'cr' },\n { prefix: 'BUG-', type: 'bug' },\n];\n\n/**\n * Detect the work-item type from a parsed frontmatter record.\n * Returns null if no recognized ID key is found.\n */\nexport function detectWorkItemTypeFromFm(\n fm: Record<string, unknown>,\n): WorkItemType | null {\n for (const { key, type } of FM_KEY_MAP) {\n if (fm[key] !== undefined && fm[key] !== null && fm[key] !== '') {\n return type;\n }\n }\n return null;\n}\n\n/**\n * Detect the work-item type from an ID string or file path.\n * Matches against the uppercase prefix (STORY-, EPIC-, etc.).\n * Returns null if no prefix matches.\n */\nexport function detectWorkItemType(idOrPath: string): WorkItemType | null {\n const upper = idOrPath.toUpperCase();\n // Strip leading directory path components\n const basename = upper.split('/').pop() ?? upper;\n for (const { prefix, type } of PREFIX_MAP) {\n if (basename.includes(prefix)) {\n return type;\n }\n }\n return null;\n}\n\n/**\n * Canonical transitions per work-item type.\n * Epic has 2; all others have 1.\n */\nexport const WORK_ITEM_TRANSITIONS: Record<WorkItemType, string[]> = {\n proposal: ['ready-for-decomposition'],\n epic: ['ready-for-decomposition', 'ready-for-coding'],\n story: ['ready-for-execution'],\n cr: ['ready-to-apply'],\n bug: ['ready-for-fix'],\n};\n","/**\n * STORY-002-08: cleargate wiki query [--persist]\n *\n * Read-only by default: grep .cleargate/wiki/index.md for query terms,\n * return matching [[ID]] list with one-line excerpts to stdout. Exit 0.\n *\n * --persist: compute slug, write wiki/topics/<slug>.md with frontmatter\n * type: topic, id, created_by, created_at, cites. Append to wiki/index.md\n * ## Topics section.\n *\n * NOTE: CLI synthesis is grep-and-list. For NL synthesis with the\n * cleargate-wiki-query subagent, invoke from a Claude Code session.\n * This diverges from PROPOSAL-002 §2.2 intentionally for testability and\n * offline/scripted use.\n */\n\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\n\nexport interface WikiQueryOptions {\n /** Test seam: working directory (defaults to process.cwd()) */\n cwd?: string;\n /** Test seam: replaces process.stdout.write */\n stdout?: (s: string) => void;\n /** Test seam: replaces process.stderr.write */\n stderr?: (s: string) => void;\n /** Test seam: replaces process.exit */\n exit?: (code: number) => never;\n /** Test seam: frozen ISO timestamp (defaults to new Date().toISOString()) */\n now?: () => string;\n /** The query string */\n query: string;\n /** If true, write result as a topic page under wiki/topics/ */\n persist?: boolean;\n}\n\n/**\n * Compute a slug from a query string.\n * Lowercase, replace spaces and punctuation with hyphens,\n * strip consecutive hyphens, truncate to ≤40 chars.\n */\nexport function computeSlug(query: string): string {\n return query\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-') // non-alphanumeric → hyphen\n .replace(/^-+|-+$/g, '') // strip leading/trailing hyphens\n .replace(/-{2,}/g, '-') // collapse consecutive hyphens\n .slice(0, 40)\n .replace(/-+$/, ''); // strip trailing hyphens after truncation\n}\n\n/**\n * Parse index.md and extract matching IDs for the given query terms.\n * Returns array of { id, line } matching lines.\n */\nfunction searchIndex(indexContent: string, query: string): Array<{ id: string; excerpt: string }> {\n const terms = query\n .toLowerCase()\n .split(/\\s+/)\n .filter((t) => t.length > 0);\n\n const results: Array<{ id: string; excerpt: string }> = [];\n const seenIds = new Set<string>();\n\n for (const line of indexContent.split('\\n')) {\n const lower = line.toLowerCase();\n const matchesAll = terms.every((term) => lower.includes(term));\n if (!matchesAll) continue;\n\n // Extract [[ID]] from line\n const match = line.match(/\\[\\[([^\\]]+)\\]\\]/);\n if (!match) continue;\n const id = match[1];\n if (seenIds.has(id)) continue;\n seenIds.add(id);\n\n results.push({ id, excerpt: line.trim() });\n }\n\n return results;\n}\n\nexport async function wikiQueryHandler(opts: WikiQueryOptions): Promise<void> {\n const cwd = opts.cwd ?? process.cwd();\n const stdout = opts.stdout ?? ((s: string) => process.stdout.write(s));\n const stderr = opts.stderr ?? ((s: string) => process.stderr.write(s));\n const exit = opts.exit ?? ((c: number): never => process.exit(c));\n const now = opts.now ?? (() => new Date().toISOString());\n const query = opts.query;\n const persist = opts.persist ?? false;\n\n void stderr; // suppress unused warning\n\n const wikiRoot = path.join(cwd, '.cleargate', 'wiki');\n const indexPath = path.join(wikiRoot, 'index.md');\n\n if (!fs.existsSync(indexPath)) {\n stdout(`wiki query: no index.md found at ${indexPath}\\n`);\n stdout(`Run \\`cleargate wiki build\\` first.\\n`);\n exit(1);\n return;\n }\n\n const indexContent = fs.readFileSync(indexPath, 'utf8');\n const matches = searchIndex(indexContent, query);\n\n if (matches.length === 0) {\n stdout(`wiki query: no matches for \"${query}\"\\n`);\n exit(0);\n return;\n }\n\n // Build output body\n const bodyLines: string[] = [\n `# Query: ${query}`,\n '',\n `Found ${matches.length} match(es):`,\n '',\n ];\n\n for (const { id, excerpt } of matches) {\n bodyLines.push(`- [[${id}]] — ${excerpt}`);\n }\n bodyLines.push('');\n\n const body = bodyLines.join('\\n');\n\n // Output to stdout (read-only mode: always output to stdout)\n stdout(body);\n\n if (!persist) {\n exit(0);\n return;\n }\n\n // Persist mode: write topic page\n const slug = computeSlug(query);\n const topicsDir = path.join(wikiRoot, 'topics');\n fs.mkdirSync(topicsDir, { recursive: true });\n\n const citesArray = matches.map(({ id }) => `\"[[${id}]]\"`);\n const createdAt = now();\n\n // Build topic page frontmatter\n const frontmatter = [\n '---',\n `type: topic`,\n `id: \"${slug}\"`,\n `created_by: \"cleargate-wiki-query\"`,\n `created_at: \"${createdAt}\"`,\n `cites: [${citesArray.join(', ')}]`,\n '---',\n ].join('\\n');\n\n const topicContent = `${frontmatter}\\n\\n${body}`;\n const topicPath = path.join(topicsDir, `${slug}.md`);\n\n // Overwrite if exists (slug collision → overwrite per subagent def line 136)\n fs.writeFileSync(topicPath, topicContent, 'utf8');\n\n // Update wiki/index.md Topics section\n updateIndexTopicsSection(indexPath, slug, query, createdAt);\n\n exit(0);\n}\n\n/**\n * Append one row to the ## Topics section of wiki/index.md.\n * Creates the section header if absent.\n */\nfunction updateIndexTopicsSection(\n indexPath: string,\n slug: string,\n query: string,\n createdAt: string,\n): void {\n let content = fs.readFileSync(indexPath, 'utf8');\n\n const row = `| ${slug} | ${query} | ${createdAt} |`;\n\n if (content.includes('## Topics')) {\n // Append after the last line of the Topics section (end of file or before next ##)\n // Find the Topics section and append the row at the end\n const topicsIdx = content.indexOf('## Topics');\n const afterTopics = content.slice(topicsIdx);\n\n // Find the next ## section or end of file\n const nextSectionMatch = afterTopics.slice('## Topics'.length).match(/\\n## /);\n if (nextSectionMatch && nextSectionMatch.index !== undefined) {\n const insertPos = topicsIdx + '## Topics'.length + nextSectionMatch.index;\n content = content.slice(0, insertPos) + `\\n${row}` + content.slice(insertPos);\n } else {\n // Topics is the last section — append at end\n content = content.trimEnd() + `\\n${row}\\n`;\n }\n } else {\n // Create Topics section at end of file\n content = content.trimEnd() + `\\n\\n## Topics\\n\\n${row}\\n`;\n }\n\n fs.writeFileSync(indexPath, content, 'utf8');\n}\n","/**\n * doctor.ts — STORY-009-04 + STORY-008-06\n *\n * `cleargate doctor` base command + `--check-scaffold` / `--session-start` / `--pricing` modes.\n *\n * No top-level await (FLASHCARD #tsup #cjs #esm).\n */\n\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { parseFrontmatter } from '../wiki/parse-frontmatter.js';\nimport { computeUsd, type DraftTokensInput } from '../lib/pricing.js';\nimport {\n loadPackageManifest,\n loadInstallSnapshot,\n computeCurrentSha,\n classify,\n writeDriftState,\n readDriftState,\n type DriftMap,\n type DriftMapEntry,\n type DriftState,\n} from '../lib/manifest.js';\nimport { shortHash } from '../lib/sha256.js';\n\n// ─── Public types ─────────────────────────────────────────────────────────────\n\nexport interface DoctorCliOptions {\n cwd?: string;\n now?: () => Date;\n stdout?: (s: string) => void;\n stderr?: (s: string) => void;\n exit?: (code: number) => never;\n /** Override the package root for loadPackageManifest (test seam). */\n packageRoot?: string;\n}\n\n/**\n * Flags for `cleargate doctor`.\n *\n * Reserved keys for 008-06 (M3): sessionStart, pricing.\n * All flags are mutually exclusive — selectMode throws when >1 is set.\n */\nexport interface DoctorFlags {\n checkScaffold?: boolean;\n /** Hidden flag: used by the M3 session-start hook; enables daily throttle. */\n sessionStartMode?: boolean;\n verbose?: boolean;\n /** --session-start: emit blocked pending-sync items summary */\n sessionStart?: boolean;\n /** --pricing: compute USD estimate for a work item */\n pricing?: boolean;\n /** File path passed to --pricing <file> */\n pricingFile?: string;\n}\n\nexport type DoctorMode = 'check-scaffold' | 'session-start' | 'pricing' | 'hook-health';\n\n// ─── Mode dispatcher ──────────────────────────────────────────────────────────\n\n/**\n * Determine which doctor mode to run based on flags.\n *\n * Throws when multiple mutually-exclusive mode flags are set.\n * Returns 'hook-health' when no mode flag is set (default).\n *\n * Exported so STORY-008-06 can add cases without re-editing the switch.\n */\nexport function selectMode(flags: DoctorFlags): DoctorMode {\n const modes: DoctorMode[] = [];\n if (flags.checkScaffold) modes.push('check-scaffold');\n if (flags.sessionStart) modes.push('session-start');\n if (flags.pricing) modes.push('pricing');\n\n if (modes.length > 1) {\n throw new Error(\n `cleargate doctor: mutually exclusive flags set: ${modes.join(', ')}. Use only one mode flag at a time.`\n );\n }\n\n if (modes.length === 1) {\n return modes[0]!;\n }\n\n return 'hook-health';\n}\n\n// ─── Hook-health default mode ─────────────────────────────────────────────────\n\nconst HOOK_LOG_24H_MS = 24 * 60 * 60 * 1000;\n\n/**\n * Parse a single gate-check.log line.\n * Format: [ISO_TS] stamp=N gate=N ingest=N file=<path>\n * Returns null if the line does not match.\n */\nexport interface HookLogEntry {\n ts: string;\n stamp: number;\n gate: number;\n ingest: number;\n file: string;\n}\n\nexport function parseHookLogLine(line: string): HookLogEntry | null {\n // [2026-04-19T12:00:00Z] stamp=0 gate=1 ingest=0 file=/some/path\n const m = line.match(\n /^\\[([^\\]]+)\\]\\s+stamp=(\\d+)\\s+gate=(\\d+)\\s+ingest=(\\d+)\\s+file=(.+)$/\n );\n if (!m) return null;\n return {\n ts: m[1]!,\n stamp: parseInt(m[2]!, 10),\n gate: parseInt(m[3]!, 10),\n ingest: parseInt(m[4]!, 10),\n file: m[5]!.trim(),\n };\n}\n\nfunction runHookHealth(\n stdout: (s: string) => void,\n cwd: string,\n now?: Date\n): void {\n // Minimal hook-config report: check that .claude/settings.json has the\n // SubagentStop hook wired (if the .claude directory exists).\n const settingsPath = path.join(cwd, '.claude', 'settings.json');\n if (!fs.existsSync(settingsPath)) {\n stdout('[doctor] No .claude/settings.json found — hook config unavailable.');\n return;\n }\n\n try {\n const raw = fs.readFileSync(settingsPath, 'utf-8');\n const settings = JSON.parse(raw) as unknown;\n const hasHooks =\n typeof settings === 'object' &&\n settings !== null &&\n 'hooks' in settings;\n if (hasHooks) {\n stdout('[doctor] Hook config present in .claude/settings.json.');\n } else {\n stdout('[doctor] .claude/settings.json found but no hooks key — SubagentStop hook not wired.');\n }\n } catch {\n stdout('[doctor] .claude/settings.json is not valid JSON — cannot verify hook config.');\n }\n\n // Scan gate-check.log for recent failures\n const logPath = path.join(cwd, '.cleargate', 'hook-log', 'gate-check.log');\n if (!fs.existsSync(logPath)) {\n return;\n }\n\n let logContent: string;\n try {\n logContent = fs.readFileSync(logPath, 'utf-8');\n } catch {\n return;\n }\n\n const nowMs = (now ?? new Date()).getTime();\n const lines = logContent.split('\\n').filter((l) => l.trim().length > 0);\n\n for (const line of lines) {\n const entry = parseHookLogLine(line);\n if (!entry) continue;\n\n const entryMs = new Date(entry.ts).getTime();\n if (isNaN(entryMs)) continue;\n\n // Only consider entries within the last 24h\n if (nowMs - entryMs > HOOK_LOG_24H_MS) continue;\n\n // A failure means ANY step exit code is non-zero\n const isFailing = entry.stamp !== 0 || entry.gate !== 0 || entry.ingest !== 0;\n if (!isFailing) continue;\n\n stdout(\n `\\u26a0 hook failure at ${entry.ts}: stamp=${entry.stamp} gate=${entry.gate} ingest=${entry.ingest} file=${entry.file}`\n );\n }\n}\n\n// ─── Check-scaffold mode ──────────────────────────────────────────────────────\n\nconst TWENTY_FOUR_HOURS_MS = 24 * 60 * 60 * 1000;\n\n/**\n * Throttle decision: returns true when the cache is fresh enough to skip\n * re-computation.\n *\n * Fresh = `now - lastRefreshed < 24h`.\n * Throttle only applies when `sessionStartMode` is set (non-interactive invocation).\n * Exported for unit tests.\n */\nexport function shouldUseCache(\n lastRefreshed: string,\n now: Date,\n sessionStartMode: boolean\n): boolean {\n if (!sessionStartMode) {\n // Interactive mode always recomputes.\n return false;\n }\n const age = now.getTime() - new Date(lastRefreshed).getTime();\n return age < TWENTY_FOUR_HOURS_MS;\n}\n\n/**\n * Format a single non-clean file line for verbose output.\n * `<path> <state> (<installed>→<current> vs <package>)`\n * with 6-char short hashes.\n */\nexport function formatVerboseLine(\n filePath: string,\n entry: DriftMapEntry\n): string {\n const inst = entry.install_sha ? shortHash(entry.install_sha).slice(0, 6) : 'null';\n const curr = entry.current_sha ? shortHash(entry.current_sha).slice(0, 6) : 'null';\n const pkg = entry.package_sha ? shortHash(entry.package_sha).slice(0, 6) : 'null';\n return ` ${filePath} ${entry.state} (${inst}→${curr} vs ${pkg})`;\n}\n\ntype CountsByState = Record<Exclude<DriftState, 'untracked'>, number> & { untracked: number };\n\nfunction zeroCounts(): CountsByState {\n return {\n 'clean': 0,\n 'user-modified': 0,\n 'upstream-changed': 0,\n 'both-changed': 0,\n 'untracked': 0,\n };\n}\n\nasync function runCheckScaffold(\n flags: DoctorFlags,\n cli: DoctorCliOptions,\n cwd: string,\n now: Date,\n stdout: (s: string) => void,\n _stderr: (s: string) => void\n): Promise<void> {\n // 1. Check daily throttle when in session-start mode\n const sessionStartMode = flags.sessionStartMode ?? false;\n const existingState = await readDriftState(cwd);\n\n if (existingState && shouldUseCache(existingState.last_refreshed, now, sessionStartMode)) {\n // Reuse cached result — emit summary from cached data\n emitSummary(existingState.drift, flags.verbose ?? false, stdout);\n return;\n }\n\n // 2. Load manifests\n const pkgManifest = loadPackageManifest({ packageRoot: cli.packageRoot });\n const installSnapshot = await loadInstallSnapshot(cwd);\n\n // 3. Compute SHAs + classify\n const driftMap: DriftMap = {};\n\n await Promise.all(\n pkgManifest.files.map(async (entry) => {\n // Silently skip user-artifact tier (EPIC-009 §6 Q8)\n if (entry.tier === 'user-artifact') {\n return;\n }\n\n const currentSha = await computeCurrentSha(entry, cwd);\n const installSha =\n installSnapshot?.files.find((f) => f.path === entry.path)?.sha256 ?? null;\n const pkgSha = entry.sha256;\n const state = classify(pkgSha, installSha, currentSha, entry.tier);\n\n driftMap[entry.path] = {\n state,\n entry,\n install_sha: installSha,\n current_sha: currentSha,\n package_sha: pkgSha,\n };\n })\n );\n\n // 4. Write drift state atomically\n await writeDriftState(cwd, driftMap, { lastRefreshed: now.toISOString() });\n\n // 5. Emit summary\n emitSummary(driftMap, flags.verbose ?? false, stdout);\n}\n\nfunction emitSummary(\n driftMap: DriftMap,\n verbose: boolean,\n stdout: (s: string) => void\n): void {\n const counts = zeroCounts();\n for (const entry of Object.values(driftMap)) {\n counts[entry.state]++;\n }\n\n stdout(\n `Scaffold drift: ${counts['user-modified']} user-modified, ` +\n `${counts['upstream-changed']} upstream-changed, ` +\n `${counts['both-changed']} both-changed, ` +\n `${counts['clean']} clean`\n );\n\n if (counts['upstream-changed'] > 0 || counts['both-changed'] > 0) {\n stdout('Run cleargate upgrade to review.');\n }\n\n if (verbose) {\n for (const [filePath, entry] of Object.entries(driftMap)) {\n if (entry.state !== 'clean' && entry.state !== 'untracked') {\n stdout(formatVerboseLine(filePath, entry));\n }\n }\n }\n}\n\n// ─── Session-start mode ───────────────────────────────────────────────────────\n\nconst SESSION_START_MAX_ITEMS = 10;\nconst SESSION_START_MAX_CHARS = 400;\n\ninterface BlockedItem {\n id: string;\n firstCriterionId: string;\n}\n\n/**\n * Coerce `cached_gate_result` into a typed shape.\n * Accepts both the current native-object form (parseFrontmatter via js-yaml)\n * and the legacy JSON-in-a-string form (pre-BUG-001 files).\n */\nfunction parseCachedGateResult(\n raw: unknown\n): { pass: boolean | null; failing_criteria: Array<{ id: string }> } | null {\n if (raw == null) return null;\n\n let parsed: { pass?: boolean | null; failing_criteria?: Array<{ id: string }> } | null = null;\n\n if (typeof raw === 'object' && !Array.isArray(raw)) {\n parsed = raw as { pass?: boolean | null; failing_criteria?: Array<{ id: string }> };\n } else if (typeof raw === 'string') {\n try {\n parsed = JSON.parse(raw) as { pass?: boolean | null; failing_criteria?: Array<{ id: string }> };\n } catch {\n return null;\n }\n } else {\n return null;\n }\n\n return {\n pass: parsed.pass ?? null,\n failing_criteria: parsed.failing_criteria ?? [],\n };\n}\n\nexport async function runSessionStart(\n cwd: string,\n stdout: (s: string) => void\n): Promise<void> {\n const pendingSyncDir = path.join(cwd, '.cleargate', 'delivery', 'pending-sync');\n\n let files: string[];\n try {\n files = fs\n .readdirSync(pendingSyncDir)\n .filter((f) => f.endsWith('.md'))\n .map((f) => path.join(pendingSyncDir, f));\n } catch {\n // Directory doesn't exist or unreadable — nothing to report\n return;\n }\n\n const blocked: BlockedItem[] = [];\n\n for (const filePath of files) {\n let raw: string;\n try {\n raw = fs.readFileSync(filePath, 'utf-8');\n } catch {\n continue;\n }\n\n if (!raw.trimStart().startsWith('---')) continue;\n\n let fm: Record<string, unknown>;\n try {\n fm = parseFrontmatter(raw).fm;\n } catch {\n continue;\n }\n\n const gate = parseCachedGateResult(fm['cached_gate_result']);\n if (!gate || gate.pass !== false) continue;\n\n // Determine item ID from frontmatter\n const idKeys = ['story_id', 'epic_id', 'proposal_id', 'cr_id', 'bug_id', 'sprint_id'];\n let itemId = '';\n for (const key of idKeys) {\n const val = fm[key];\n if (typeof val === 'string' && val.trim()) {\n itemId = val.trim();\n break;\n }\n }\n if (!itemId) {\n // Fallback: use filename stem\n itemId = path.basename(filePath, '.md');\n }\n\n const firstCriterionId =\n gate.failing_criteria.length > 0 ? (gate.failing_criteria[0]?.id ?? '') : '';\n\n blocked.push({ id: itemId, firstCriterionId });\n }\n\n if (blocked.length === 0) {\n return;\n }\n\n const overflow = blocked.length > SESSION_START_MAX_ITEMS\n ? blocked.length - SESSION_START_MAX_ITEMS\n : 0;\n const visible = blocked.slice(0, SESSION_START_MAX_ITEMS);\n\n const lines: string[] = [`${blocked.length} items blocked:`];\n for (const item of visible) {\n const line = item.firstCriterionId\n ? ` ${item.id}: ${item.firstCriterionId}`\n : ` ${item.id}`;\n lines.push(line);\n }\n if (overflow > 0) {\n lines.push(`…and ${overflow} more — run cleargate doctor for full list`);\n }\n\n let output = lines.join('\\n');\n\n // Cap at SESSION_START_MAX_CHARS (100-token proxy)\n if (output.length > SESSION_START_MAX_CHARS) {\n output = output.slice(0, SESSION_START_MAX_CHARS - 3) + '...';\n }\n\n stdout(output);\n}\n\n// ─── Pricing mode ─────────────────────────────────────────────────────────────\n\nexport async function runPricing(\n filePath: string,\n cwd: string,\n stdout: (s: string) => void,\n stderr: (s: string) => void,\n exit: (code: number) => never\n): Promise<void> {\n if (!filePath) {\n stderr('cleargate doctor --pricing: missing <file> argument');\n exit(1);\n return;\n }\n\n const absPath = path.isAbsolute(filePath) ? filePath : path.resolve(cwd, filePath);\n\n let raw: string;\n try {\n raw = fs.readFileSync(absPath, 'utf-8');\n } catch {\n stderr(`cleargate doctor --pricing: cannot read file: ${absPath}`);\n exit(1);\n return;\n }\n\n if (!raw.trimStart().startsWith('---')) {\n stderr(`cleargate doctor --pricing: file has no frontmatter: ${absPath}`);\n exit(1);\n return;\n }\n\n let fm: Record<string, unknown>;\n try {\n fm = parseFrontmatter(raw).fm;\n } catch {\n stderr(`cleargate doctor --pricing: cannot parse frontmatter in: ${absPath}`);\n exit(1);\n return;\n }\n\n const draftTokensRaw = fm['draft_tokens'];\n if (!draftTokensRaw) {\n stdout('draft_tokens unpopulated — run cleargate stamp-tokens first');\n exit(1);\n return;\n }\n\n let draftTokens: DraftTokensInput & { model: string | null };\n if (typeof draftTokensRaw === 'object' && !Array.isArray(draftTokensRaw)) {\n draftTokens = draftTokensRaw as DraftTokensInput & { model: string | null };\n } else if (typeof draftTokensRaw === 'string') {\n try {\n draftTokens = JSON.parse(draftTokensRaw) as DraftTokensInput & { model: string | null };\n } catch {\n stdout('draft_tokens unpopulated — run cleargate stamp-tokens first');\n exit(1);\n return;\n }\n } else {\n stdout('draft_tokens unpopulated — run cleargate stamp-tokens first');\n exit(1);\n return;\n }\n\n // Check if tokens are actually populated\n if (\n draftTokens.input === null &&\n draftTokens.output === null &&\n draftTokens.cache_read === null &&\n draftTokens.cache_creation === null\n ) {\n stdout('draft_tokens unpopulated — run cleargate stamp-tokens first');\n exit(1);\n return;\n }\n\n const { usd, unknownModel } = computeUsd(draftTokens);\n const model = draftTokens.model ?? 'unknown';\n\n if (unknownModel) {\n stderr(`cleargate doctor --pricing: unknown model '${model}' — no pricing data available`);\n }\n\n const input = draftTokens.input ?? 0;\n const output = draftTokens.output ?? 0;\n const cacheRead = draftTokens.cache_read ?? 0;\n const cacheCreation = draftTokens.cache_creation ?? 0;\n const fileName = path.basename(absPath);\n\n stdout(\n `${fileName}: ${model} — input:${input} output:${output} cache_read:${cacheRead} cache_creation:${cacheCreation} ≈ $${usd.toFixed(4)}`\n );\n}\n\n// ─── Main handler ─────────────────────────────────────────────────────────────\n\nexport async function doctorHandler(\n flags: DoctorFlags,\n cli?: DoctorCliOptions\n): Promise<void> {\n const cwd = cli?.cwd ?? process.cwd();\n const now = cli?.now ? cli.now() : new Date();\n const stdout = cli?.stdout ?? ((s: string) => process.stdout.write(s + '\\n'));\n const stderr = cli?.stderr ?? ((s: string) => process.stderr.write(s + '\\n'));\n const exit = cli?.exit ?? ((code: number) => process.exit(code) as never);\n\n let mode: DoctorMode;\n try {\n mode = selectMode(flags);\n } catch (err) {\n stderr((err as Error).message);\n exit(1);\n return;\n }\n\n switch (mode) {\n case 'check-scaffold':\n await runCheckScaffold(flags, cli ?? {}, cwd, now, stdout, stderr);\n break;\n\n case 'hook-health':\n runHookHealth(stdout, cwd, now);\n break;\n\n case 'session-start':\n await runSessionStart(cwd, stdout);\n break;\n\n case 'pricing':\n await runPricing(flags.pricingFile ?? '', cwd, stdout, stderr, exit);\n break;\n\n default: {\n const exhaustiveCheck: never = mode;\n stderr(`cleargate doctor: unknown mode '${String(exhaustiveCheck)}'`);\n exit(1);\n }\n }\n}\n","/**\n * pricing.ts — STORY-008-06\n *\n * USD pricing table for Claude models (per 1M tokens).\n * Numbers from Anthropic public pricing as of 2026-04-19.\n * No network. No config file. Numbers live in source.\n */\n\nexport interface ModelPricing {\n input: number;\n output: number;\n cache_read: number;\n cache_creation: number;\n}\n\n/**\n * Pricing table: USD per 1,000,000 tokens.\n *\n * claude-opus-4-7: $15 input / $75 output / $1.50 cache_read / $18.75 cache_creation\n * claude-sonnet-4-5: $3 input / $15 output / $0.30 cache_read / $3.75 cache_creation\n * claude-haiku-4-5: $0.80 input / $4 output / $0.08 cache_read / $1 cache_creation\n */\nexport const PRICING_TABLE: Record<string, ModelPricing> = {\n 'claude-opus-4-7': {\n input: 15.0,\n output: 75.0,\n cache_read: 1.5,\n cache_creation: 18.75,\n },\n 'claude-sonnet-4-5': {\n input: 3.0,\n output: 15.0,\n cache_read: 0.3,\n cache_creation: 3.75,\n },\n 'claude-sonnet-4-6': {\n input: 3.0,\n output: 15.0,\n cache_read: 0.3,\n cache_creation: 3.75,\n },\n 'claude-haiku-4-5': {\n input: 0.8,\n output: 4.0,\n cache_read: 0.08,\n cache_creation: 1.0,\n },\n};\n\nexport interface DraftTokensInput {\n input: number | null;\n output: number | null;\n cache_read: number | null;\n cache_creation: number | null;\n model: string | null;\n}\n\nexport interface ComputeUsdResult {\n usd: number;\n unknownModel: boolean;\n}\n\n/**\n * Compute USD cost from draft_tokens and model.\n *\n * If modelOverride is provided, it takes precedence over draftTokens.model.\n * Unknown model → {usd: 0, unknownModel: true}.\n * All token counts default to 0 if null.\n */\nexport function computeUsd(\n draftTokens: DraftTokensInput,\n modelOverride?: string\n): ComputeUsdResult {\n const model = modelOverride ?? draftTokens.model ?? '';\n const pricing = PRICING_TABLE[model];\n\n if (!pricing) {\n return { usd: 0, unknownModel: true };\n }\n\n const input = draftTokens.input ?? 0;\n const output = draftTokens.output ?? 0;\n const cacheRead = draftTokens.cache_read ?? 0;\n const cacheCreation = draftTokens.cache_creation ?? 0;\n\n const usd =\n (input * pricing.input +\n output * pricing.output +\n cacheRead * pricing.cache_read +\n cacheCreation * pricing.cache_creation) /\n 1_000_000;\n\n return { usd, unknownModel: false };\n}\n","/**\n * gate.ts — `cleargate gate check|explain` command handlers.\n *\n * STORY-008-03: Wires readiness-predicates.evaluate() + frontmatter-cache into\n * two Commander subcommands.\n *\n * FLASHCARD #cli #commander #optional-key: opts.transition may be undefined — strip key.\n * FLASHCARD #cli #determinism #test-seam: thread `now`, `exit`, `stdout`, `stderr` seams.\n * FLASHCARD #tsup #cjs #esm: no top-level await.\n * Output is agent-facing: only ❌ / ⚠ / ✅ emoji; no ANSI color codes.\n */\n\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport yaml from 'js-yaml';\nimport { parseFrontmatter } from '../wiki/parse-frontmatter.js';\nimport { evaluate } from '../lib/readiness-predicates.js';\nimport type { ParsedDoc } from '../lib/readiness-predicates.js';\nimport { readCachedGate, writeCachedGate } from '../lib/frontmatter-cache.js';\nimport type { CachedGate } from '../lib/frontmatter-cache.js';\nimport {\n detectWorkItemTypeFromFm,\n WORK_ITEM_TRANSITIONS,\n} from '../lib/work-item-type.js';\nimport type { WorkItemType } from '../lib/work-item-type.js';\nimport { toIsoSecond } from '../lib/frontmatter-yaml.js';\n\n// ─── Public types ─────────────────────────────────────────────────────────────\n\nexport interface GateCliOptions {\n cwd?: string;\n now?: () => Date;\n stdout?: (s: string) => void;\n stderr?: (s: string) => void;\n exit?: (code: number) => never;\n /** Override path to readiness-gates.md (test seam). */\n gatesDocPath?: string;\n /** Override path to wiki index (test seam). */\n wikiIndexPath?: string;\n}\n\n// ─── Internal gate-block shape ────────────────────────────────────────────────\n\ninterface GateCriterion {\n id: string;\n check: string;\n}\n\ninterface GateBlock {\n work_item_type: string;\n transition: string;\n severity: 'advisory' | 'enforcing';\n criteria: GateCriterion[];\n}\n\n// ─── Gate document loader ─────────────────────────────────────────────────────\n\n/**\n * Load and parse all fenced ```yaml blocks from readiness-gates.md.\n * Each block's yaml.load() returns an array — unwrap [0] per FLASHCARD.\n */\nfunction loadGateBlocks(gatesDocPath: string): GateBlock[] {\n const raw = fs.readFileSync(gatesDocPath, 'utf8');\n const blocks: GateBlock[] = [];\n\n // Match all fenced ```yaml ... ``` blocks\n const fenceRe = /^```yaml\\n([\\s\\S]*?)^```/gm;\n let match: RegExpExecArray | null;\n while ((match = fenceRe.exec(raw)) !== null) {\n const yamlContent = match[1]!;\n const parsed = yaml.load(yamlContent);\n // Per FLASHCARD: readiness-gates.md fenced yaml blocks are YAML lists; unwrap [0]\n const block = Array.isArray(parsed) ? parsed[0] : parsed;\n if (\n block &&\n typeof block === 'object' &&\n 'work_item_type' in block &&\n 'transition' in block &&\n 'severity' in block &&\n 'criteria' in block\n ) {\n blocks.push(block as GateBlock);\n }\n }\n return blocks;\n}\n\n/**\n * Find the gate block matching a work-item type + transition.\n */\nfunction findGate(\n blocks: GateBlock[],\n type: WorkItemType,\n transition: string,\n): GateBlock | null {\n return blocks.find(\n (b) => b.work_item_type === type && b.transition === transition,\n ) ?? null;\n}\n\n/**\n * Infer the default transition for a work-item type given the current cached gate state.\n * - If cached_gate_result is absent or failing → return first transition.\n * - If cached_gate_result.pass === true and there's a next transition → return next.\n * - Otherwise return first transition.\n */\nfunction inferTransition(\n type: WorkItemType,\n cachedGate: CachedGate | null,\n): string {\n const transitions = WORK_ITEM_TRANSITIONS[type];\n if (!cachedGate || !cachedGate.pass) {\n return transitions[0]!;\n }\n // Find next unpassed transition\n // We don't know which transition was last checked from cache alone;\n // for Epic: if cached pass=true, assume first is done → pick second.\n // For types with only one transition: always return that one.\n if (transitions.length === 1) {\n return transitions[0]!;\n }\n // Multi-transition (Epic): if cached gate passes, infer next\n return transitions[1]!;\n}\n\n// ─── gateCheckHandler ─────────────────────────────────────────────────────────\n\nexport async function gateCheckHandler(\n file: string,\n opts: { verbose?: boolean; transition?: string },\n cli?: GateCliOptions,\n): Promise<void> {\n const stdoutFn = cli?.stdout ?? ((s: string) => process.stdout.write(s + '\\n'));\n const stderrFn = cli?.stderr ?? ((s: string) => process.stderr.write(s + '\\n'));\n const exitFn: (code: number) => never =\n cli?.exit ?? ((code: number) => process.exit(code) as never);\n const cwd = cli?.cwd ?? process.cwd();\n const nowFn = cli?.now ?? (() => new Date());\n\n // Resolve file path\n const absPath = path.isAbsolute(file) ? file : path.resolve(cwd, file);\n if (!fs.existsSync(absPath)) {\n stderrFn(`[cleargate gate] error: file not found: ${absPath}`);\n return exitFn(1);\n }\n\n // Parse the document\n let raw: string;\n try {\n raw = fs.readFileSync(absPath, 'utf8');\n } catch (err) {\n stderrFn(`[cleargate gate] error: cannot read file: ${absPath}`);\n return exitFn(1);\n }\n\n let fm: Record<string, unknown>;\n let body: string;\n try {\n ({ fm, body } = parseFrontmatter(raw));\n } catch {\n stderrFn(`[cleargate gate] error: cannot parse frontmatter in: ${absPath}`);\n return exitFn(1);\n }\n\n // Detect work-item type from frontmatter\n const detectedType = detectWorkItemTypeFromFm(fm);\n if (!detectedType) {\n stderrFn(`[cleargate gate] error: unable to detect work-item type from frontmatter in: ${absPath}`);\n return exitFn(1);\n }\n\n // Load gates document\n const projectRoot = cwd;\n const gatesDocPath = cli?.gatesDocPath\n ?? path.join(projectRoot, '.cleargate', 'knowledge', 'readiness-gates.md');\n\n if (!fs.existsSync(gatesDocPath)) {\n stderrFn(`[cleargate gate] error: readiness-gates.md not found at: ${gatesDocPath}`);\n return exitFn(1);\n }\n\n let gateBlocks: GateBlock[];\n try {\n gateBlocks = loadGateBlocks(gatesDocPath);\n } catch (err) {\n stderrFn(`[cleargate gate] error: failed to parse readiness-gates.md: ${String(err)}`);\n return exitFn(1);\n }\n\n // Read current cached gate for transition inference\n const cachedGate = await readCachedGate(absPath);\n\n // Determine transition\n const transition = opts.transition ?? inferTransition(detectedType, cachedGate);\n\n // Find the matching gate\n const gate = findGate(gateBlocks, detectedType, transition);\n if (!gate) {\n stderrFn(\n `[cleargate gate] error: no gate definition found for ${detectedType}.${transition}`,\n );\n return exitFn(1);\n }\n\n const wikiIndexPath = cli?.wikiIndexPath;\n const parsedDoc: ParsedDoc = { fm, body, absPath };\n const evalOpts = { projectRoot, ...(wikiIndexPath ? { wikiIndexPath } : {}) };\n\n // Evaluate each criterion\n const failingCriteria: { id: string; detail: string }[] = [];\n const allResults: Array<{ id: string; pass: boolean; detail: string }> = [];\n\n for (const criterion of gate.criteria) {\n let result: { pass: boolean; detail: string };\n try {\n result = evaluate(criterion.check, parsedDoc, evalOpts);\n } catch (err) {\n result = { pass: false, detail: `predicate error: ${String(err)}` };\n }\n allResults.push({ id: criterion.id, ...result });\n if (!result.pass) {\n failingCriteria.push({ id: criterion.id, detail: result.detail });\n }\n }\n\n const overallPass = failingCriteria.length === 0;\n const lastGateCheck = toIsoSecond(nowFn());\n\n // Write cached gate result\n const cacheResult: CachedGate = {\n pass: overallPass,\n failing_criteria: failingCriteria,\n last_gate_check: lastGateCheck,\n };\n await writeCachedGate(absPath, cacheResult, { now: nowFn });\n\n // Format and emit output\n const isAdvisory = gate.severity === 'advisory';\n const headerLine = `Gate: ${detectedType}.${transition} (${gate.severity})`;\n stdoutFn(headerLine);\n\n if (overallPass) {\n stdoutFn(`\\u2705 ${detectedType}.${transition} passed (${gate.criteria.length} criteria)`);\n } else {\n for (const r of allResults) {\n if (!r.pass) {\n if (isAdvisory) {\n stdoutFn(`\\u26A0 ${r.id}: ${r.detail} (advisory)`);\n } else {\n stdoutFn(`\\u274C ${r.id}: ${r.detail}`);\n }\n }\n if (opts.verbose) {\n // In verbose mode, emit full detail per criterion\n stdoutFn(` [${r.pass ? 'pass' : 'fail'}] ${r.id}: ${r.detail}`);\n }\n }\n }\n\n // Severity-based exit routing\n if (!overallPass && !isAdvisory) {\n return exitFn(1);\n }\n // advisory or pass → exit 0 (implicit return)\n}\n\n// ─── gateExplainHandler ───────────────────────────────────────────────────────\n\nexport async function gateExplainHandler(\n file: string,\n cli?: GateCliOptions,\n): Promise<void> {\n const stdoutFn = cli?.stdout ?? ((s: string) => process.stdout.write(s + '\\n'));\n const stderrFn = cli?.stderr ?? ((s: string) => process.stderr.write(s + '\\n'));\n const exitFn: (code: number) => never =\n cli?.exit ?? ((code: number) => process.exit(code) as never);\n const cwd = cli?.cwd ?? process.cwd();\n\n // Resolve file path\n const absPath = path.isAbsolute(file) ? file : path.resolve(cwd, file);\n if (!fs.existsSync(absPath)) {\n stderrFn(`[cleargate gate] error: file not found: ${absPath}`);\n return exitFn(1);\n }\n\n // Read cached gate result — read-only, no evaluate calls\n const cached = await readCachedGate(absPath);\n\n if (!cached) {\n stdoutFn('no gate check cached; run: cleargate gate check <file>');\n return;\n }\n\n // Parse frontmatter to get type info (read-only — no writes)\n let raw: string;\n try {\n raw = fs.readFileSync(absPath, 'utf8');\n } catch {\n stderrFn(`[cleargate gate] error: cannot read file: ${absPath}`);\n return exitFn(1);\n }\n\n let fm: Record<string, unknown>;\n try {\n ({ fm } = parseFrontmatter(raw));\n } catch {\n stderrFn(`[cleargate gate] error: cannot parse frontmatter in: ${absPath}`);\n return exitFn(1);\n }\n\n const detectedType = detectWorkItemTypeFromFm(fm) ?? 'unknown';\n\n // Render ≤50-LLM-token summary\n const failingIds = cached.failing_criteria.map((c) => c.id).join(', ');\n const statusStr = cached.pass ? 'pass' : 'fail';\n const summary = failingIds\n ? `${detectedType}: ${statusStr} at ${cached.last_gate_check}; ${cached.failing_criteria.length} failing: ${failingIds}`\n : `${detectedType}: ${statusStr} at ${cached.last_gate_check}`;\n\n stdoutFn(summary);\n}\n","/**\n * STORY-008-02: Predicate evaluator for ClearGate readiness gates.\n * Supports exactly 6 closed-set predicate shapes. Any other shape throws.\n * Sandboxed: no shell-out, no network, read-only FS limited to projectRoot.\n */\n\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\n\n// ─── Types ────────────────────────────────────────────────────────────────────\n\nexport type ParsedPredicate =\n | { kind: 'frontmatter'; ref: string; field: string; op: '==' | '!=' | '>=' | '<='; value: string | number | boolean }\n | { kind: 'body-contains'; needle: string; negated: boolean }\n | { kind: 'section'; index: number; count: { op: '>=' | '==' | '>'; n: number }; itemType: 'checked-checkbox' | 'unchecked-checkbox' | 'listed-item' }\n | { kind: 'file-exists'; path: string }\n | { kind: 'link-target-exists'; id: string }\n | { kind: 'status-of'; id: string; value: string };\n\nexport interface ParsedDoc {\n fm: Record<string, unknown>;\n body: string;\n absPath: string;\n}\n\nexport interface EvalOptions {\n projectRoot?: string;\n wikiIndexPath?: string;\n}\n\n// ─── Parser ───────────────────────────────────────────────────────────────────\n\n/**\n * Parse a predicate string into a typed ParsedPredicate.\n * Throws with \"unsupported predicate shape: <src>\" on any unrecognized input.\n * Target: ≤150 LoC, hand-rolled tokenizer + switch on first token.\n */\nexport function parsePredicate(src: string): ParsedPredicate {\n const s = src.trim();\n\n // 1. frontmatter(<ref>).<field> <op> <value>\n const fmMatch = s.match(\n /^frontmatter\\(([^)]*)\\)\\.(\\w+)\\s*(==|!=|>=|<=)\\s*(.+)$/\n );\n if (fmMatch) {\n const ref = fmMatch[1]!.trim();\n if (ref === '') throw new Error(`unsupported predicate shape: ${src}`);\n const field = fmMatch[2]!;\n const op = fmMatch[3] as '==' | '!=' | '>=' | '<=';\n const rawVal = fmMatch[4]!.trim();\n const value = parseValue(rawVal);\n return { kind: 'frontmatter', ref, field, op, value };\n }\n\n // 2a. body does not contain '<needle>'\n const bodyNotMatch = s.match(/^body does not contain ['\"](.+)['\"]$/);\n if (bodyNotMatch) {\n return { kind: 'body-contains', needle: bodyNotMatch[1]!, negated: true };\n }\n\n // 2b. body contains '<needle>'\n const bodyMatch = s.match(/^body contains ['\"](.+)['\"]$/);\n if (bodyMatch) {\n return { kind: 'body-contains', needle: bodyMatch[1]!, negated: false };\n }\n\n // 3. section(<N>) has <count> <item-type>\n const sectionMatch = s.match(\n /^section\\((\\d+)\\) has (≥|>=|==|>)(\\d+) (checked-checkbox|unchecked-checkbox|listed-item)$/\n );\n if (sectionMatch) {\n const index = parseInt(sectionMatch[1]!, 10);\n const opChar = sectionMatch[2]!;\n const n = parseInt(sectionMatch[3]!, 10);\n const itemType = sectionMatch[4] as 'checked-checkbox' | 'unchecked-checkbox' | 'listed-item';\n let countOp: '>=' | '==' | '>';\n if (opChar === '≥' || opChar === '>=') countOp = '>=';\n else if (opChar === '>') countOp = '>';\n else countOp = '==';\n return { kind: 'section', index, count: { op: countOp, n }, itemType };\n }\n\n // 4. file-exists(<path>)\n const fileExistsMatch = s.match(/^file-exists\\((.+)\\)$/);\n if (fileExistsMatch) {\n const filePath = fileExistsMatch[1]!.trim().replace(/^['\"]|['\"]$/g, '');\n return { kind: 'file-exists', path: filePath };\n }\n\n // 5. link-target-exists([[ID]])\n const linkMatch = s.match(/^link-target-exists\\(\\[\\[([A-Z0-9\\-]+)\\]\\]\\)$/);\n if (linkMatch) {\n return { kind: 'link-target-exists', id: linkMatch[1]! };\n }\n\n // 6. status-of([[ID]]) == <value>\n const statusMatch = s.match(/^status-of\\(\\[\\[([A-Z0-9\\-]+)\\]\\]\\)\\s*==\\s*(.+)$/);\n if (statusMatch) {\n const id = statusMatch[1]!;\n const value = statusMatch[2]!.trim().replace(/^['\"]|['\"]$/g, '');\n return { kind: 'status-of', id, value };\n }\n\n throw new Error(`unsupported predicate shape: ${src}`);\n}\n\n/** Parse a YAML scalar value string to string | number | boolean. */\nfunction parseValue(raw: string): string | number | boolean {\n if (raw === 'true') return true;\n if (raw === 'false') return false;\n if (raw === 'null') return 'null'; // treat null as string \"null\" for comparison\n const num = Number(raw);\n if (!isNaN(num) && raw !== '') return num;\n // Strip quotes\n return raw.replace(/^['\"]|['\"]$/g, '');\n}\n\n// ─── Evaluator ────────────────────────────────────────────────────────────────\n\n/**\n * Evaluate a predicate string against a document. Returns {pass, detail}.\n * Throws on malformed predicate (delegate to parsePredicate).\n */\nexport function evaluate(\n predicate: string,\n doc: ParsedDoc,\n opts?: EvalOptions\n): { pass: boolean; detail: string } {\n const parsed = parsePredicate(predicate);\n const projectRoot = opts?.projectRoot ?? process.cwd();\n\n switch (parsed.kind) {\n case 'frontmatter':\n return evalFrontmatter(parsed, doc, projectRoot);\n case 'body-contains':\n return evalBodyContains(parsed, doc);\n case 'section':\n return evalSection(parsed, doc);\n case 'file-exists':\n return evalFileExists(parsed, projectRoot);\n case 'link-target-exists':\n return evalLinkTargetExists(parsed, opts);\n case 'status-of':\n return evalStatusOf(parsed, opts, projectRoot);\n }\n}\n\n// ─── Frontmatter evaluator ────────────────────────────────────────────────────\n\nfunction evalFrontmatter(\n parsed: Extract<ParsedPredicate, { kind: 'frontmatter' }>,\n doc: ParsedDoc,\n projectRoot: string\n): { pass: boolean; detail: string } {\n let fm: Record<string, unknown>;\n\n if (parsed.ref === '.') {\n fm = doc.fm;\n } else {\n // ref is a frontmatter key whose value is a path to another document\n const refVal = doc.fm[parsed.ref];\n if (refVal === undefined || refVal === null) {\n return {\n pass: false,\n detail: `frontmatter key '${parsed.ref}' is missing or null in ${doc.absPath}`,\n };\n }\n // Resolve the path\n const linkedPath = resolveLinkedPath(String(refVal), doc.absPath, projectRoot);\n if (!linkedPath) {\n return {\n pass: false,\n detail: `linked file not found: ${refVal}`,\n };\n }\n fm = readFrontmatterFromFile(linkedPath);\n }\n\n const actual = fm[parsed.field];\n\n // Compare\n const pass = compareValues(actual, parsed.op, parsed.value);\n const detail = pass\n ? `frontmatter(${parsed.ref}).${parsed.field} ${parsed.op} ${JSON.stringify(parsed.value)} → actual: ${JSON.stringify(actual)}`\n : `expected ${parsed.field} ${parsed.op} ${JSON.stringify(parsed.value)}, got ${JSON.stringify(actual)}`;\n\n return { pass, detail };\n}\n\nfunction compareValues(\n actual: unknown,\n op: '==' | '!=' | '>=' | '<=',\n expected: string | number | boolean\n): boolean {\n // null check for != null\n if (expected === 'null') {\n const isNull = actual === null || actual === undefined || actual === '' || actual === 'null';\n return op === '==' ? isNull : !isNull;\n }\n // Normalize actual: strip quotes\n let a: unknown = actual;\n if (typeof a === 'string') {\n a = a.replace(/^[\"']|[\"']$/g, '');\n // Try to coerce to bool/number for comparison\n if (a === 'true') a = true;\n else if (a === 'false') a = false;\n else {\n const n = Number(a);\n if (!isNaN(n) && (a as string) !== '') a = n;\n }\n }\n\n switch (op) {\n case '==': return a === expected || String(a) === String(expected);\n case '!=': return a !== expected && String(a) !== String(expected);\n case '>=': return Number(a) >= Number(expected);\n case '<=': return Number(a) <= Number(expected);\n }\n}\n\n/** Resolve a path reference relative to the document or project root. */\nfunction resolveLinkedPath(\n ref: string,\n docAbsPath: string,\n projectRoot: string\n): string | null {\n // Try relative to doc first, then relative to projectRoot\n const candidates = [\n path.resolve(path.dirname(docAbsPath), ref),\n path.resolve(projectRoot, ref),\n ];\n for (const candidate of candidates) {\n // Sandbox check\n if (!candidate.startsWith(projectRoot)) continue;\n if (fs.existsSync(candidate)) return candidate;\n }\n return null;\n}\n\n/** Read frontmatter from a file as a plain Record. Does not throw on body. */\nfunction readFrontmatterFromFile(absPath: string): Record<string, unknown> {\n try {\n const raw = fs.readFileSync(absPath, 'utf8');\n const lines = raw.split('\\n');\n if (lines[0] !== '---') return {};\n let closeIdx = -1;\n for (let i = 1; i < lines.length; i++) {\n if (lines[i] === '---') { closeIdx = i; break; }\n }\n if (closeIdx === -1) return {};\n const fmLines = lines.slice(1, closeIdx);\n const fm: Record<string, unknown> = {};\n for (const line of fmLines) {\n if (line.trim() === '' || line.trim().startsWith('#')) continue;\n const colon = line.indexOf(':');\n if (colon === -1) continue;\n const key = line.slice(0, colon).trim();\n const val = line.slice(colon + 1).trim();\n if (val === '' || val === '[]') { fm[key] = []; continue; }\n if (val.startsWith('{')) { fm[key] = val; continue; }\n if (val.startsWith('[') && val.endsWith(']')) {\n const inner = val.slice(1, -1).trim();\n fm[key] = inner === '' ? [] : inner.split(',').map((s) => s.trim().replace(/^[\"']|[\"']$/g, ''));\n continue;\n }\n fm[key] = val.replace(/^[\"']|[\"']$/g, '');\n }\n return fm;\n } catch {\n return {};\n }\n}\n\n// ─── Body-contains evaluator ──────────────────────────────────────────────────\n\nfunction evalBodyContains(\n parsed: Extract<ParsedPredicate, { kind: 'body-contains' }>,\n doc: ParsedDoc\n): { pass: boolean; detail: string } {\n const body = doc.body;\n const needle = parsed.needle;\n\n // Count occurrences and find section context\n let count = 0;\n let pos = 0;\n const sections: number[] = []; // 1-indexed section numbers for each occurrence\n const bodySections = body.split(/^## /m);\n\n // Simple occurrence count\n while ((pos = body.indexOf(needle, pos)) !== -1) {\n count++;\n // Find which section this occurrence is in\n const before = body.slice(0, pos);\n const sectionCount = (before.match(/^## /gm) || []).length;\n sections.push(sectionCount + 1); // 1-indexed\n pos += needle.length;\n }\n\n const present = count > 0;\n void bodySections; // suppress unused warning\n\n if (parsed.negated) {\n // \"body does not contain\" → pass when absent\n if (present) {\n const sectionList = [...new Set(sections)].map((s) => `§${s}`).join(', ');\n return {\n pass: false,\n detail: `${count} occurrence${count === 1 ? '' : 's'} at ${sectionList}`,\n };\n }\n return { pass: true, detail: `'${needle}' not found in body` };\n } else {\n // \"body contains\" → pass when present\n if (present) {\n return { pass: true, detail: `'${needle}' found ${count} time${count === 1 ? '' : 's'}` };\n }\n return { pass: false, detail: `'${needle}' not found in body` };\n }\n}\n\n// ─── Section evaluator ────────────────────────────────────────────────────────\n\nfunction evalSection(\n parsed: Extract<ParsedPredicate, { kind: 'section' }>,\n doc: ParsedDoc\n): { pass: boolean; detail: string } {\n // Split body on ## headings (1-indexed).\n // Use lookahead so each part starts with \"## \" (or is preamble if body doesn't start with ##).\n const body = doc.body;\n\n const rawParts = body.split(/^(?=## )/m);\n // If body starts with \"## \", rawParts[0] = \"## Section 1\\n...\", rawParts[1] = \"## Section 2\\n...\", etc.\n // Section N is rawParts[N-1] (0-based array, 1-indexed sections).\n // If body has preamble before first ##, rawParts[0] = preamble (section 0), rawParts[1] = section 1, etc.\n\n // Detect if there is a preamble (content before first ##)\n const hasPreamble = rawParts.length > 0 && !rawParts[0]!.startsWith('## ');\n // Section N → rawParts index: with preamble, index = N; without, index = N - 1\n const arrayIndex = hasPreamble ? parsed.index : parsed.index - 1;\n const sectionContent = rawParts[arrayIndex];\n const totalSections = hasPreamble ? rawParts.length - 1 : rawParts.length;\n\n if (!sectionContent) {\n return {\n pass: false,\n detail: `section ${parsed.index} not found (body has ${totalSections} sections)`,\n };\n }\n\n let actualCount: number;\n switch (parsed.itemType) {\n case 'checked-checkbox':\n actualCount = (sectionContent.match(/^\\s*- \\[x\\]/gim) || []).length;\n break;\n case 'unchecked-checkbox':\n actualCount = (sectionContent.match(/^\\s*- \\[ \\]/gim) || []).length;\n break;\n case 'listed-item':\n actualCount = (sectionContent.match(/^\\s*- /gm) || []).length;\n break;\n }\n\n const pass = applyCountOp(actualCount, parsed.count.op, parsed.count.n);\n const opStr = parsed.count.op === '>=' ? '≥' : parsed.count.op;\n const detail = pass\n ? `section ${parsed.index} has ${actualCount} ${parsed.itemType} (${opStr}${parsed.count.n} required)`\n : `section ${parsed.index} has ${actualCount} ${parsed.itemType} (${opStr}${parsed.count.n} required)`;\n\n return { pass, detail };\n}\n\nfunction applyCountOp(actual: number, op: '>=' | '==' | '>', n: number): boolean {\n switch (op) {\n case '>=': return actual >= n;\n case '==': return actual === n;\n case '>': return actual > n;\n }\n}\n\n// ─── File-exists evaluator ────────────────────────────────────────────────────\n\nfunction evalFileExists(\n parsed: Extract<ParsedPredicate, { kind: 'file-exists' }>,\n projectRoot: string\n): { pass: boolean; detail: string } {\n const resolved = path.resolve(projectRoot, parsed.path);\n\n // Sandbox check: must be inside projectRoot\n if (!resolved.startsWith(projectRoot + path.sep) && resolved !== projectRoot) {\n return {\n pass: false,\n detail: `path '${parsed.path}' resolves outside project root (sandbox violation)`,\n };\n }\n\n const exists = fs.existsSync(resolved);\n return {\n pass: exists,\n detail: exists ? `${parsed.path} exists` : `${parsed.path} not found`,\n };\n}\n\n// ─── Link-target-exists evaluator ────────────────────────────────────────────\n\nfunction evalLinkTargetExists(\n parsed: Extract<ParsedPredicate, { kind: 'link-target-exists' }>,\n opts?: EvalOptions\n): { pass: boolean; detail: string } {\n const projectRoot = opts?.projectRoot ?? process.cwd();\n const wikiIndexPath =\n opts?.wikiIndexPath ?? path.join(projectRoot, '.cleargate', 'wiki', 'index.md');\n\n // Sandbox check\n if (!wikiIndexPath.startsWith(projectRoot)) {\n return { pass: false, detail: 'wikiIndexPath resolves outside project root' };\n }\n\n let indexContent: string;\n try {\n indexContent = fs.readFileSync(wikiIndexPath, 'utf8');\n } catch {\n return { pass: false, detail: `wiki index not found at ${wikiIndexPath}` };\n }\n\n const found = indexContent.includes(`[[${parsed.id}]]`);\n return {\n pass: found,\n detail: found\n ? `[[${parsed.id}]] found in wiki index`\n : `[[${parsed.id}]] not found in wiki index`,\n };\n}\n\n// ─── Status-of evaluator ─────────────────────────────────────────────────────\n\nfunction evalStatusOf(\n parsed: Extract<ParsedPredicate, { kind: 'status-of' }>,\n opts: EvalOptions | undefined,\n projectRoot: string\n): { pass: boolean; detail: string } {\n const wikiIndexPath =\n opts?.wikiIndexPath ?? path.join(projectRoot, '.cleargate', 'wiki', 'index.md');\n\n // Sandbox check\n if (!wikiIndexPath.startsWith(projectRoot)) {\n return { pass: false, detail: 'wikiIndexPath resolves outside project root' };\n }\n\n let indexContent: string;\n try {\n indexContent = fs.readFileSync(wikiIndexPath, 'utf8');\n } catch {\n return { pass: false, detail: `wiki index not found at ${wikiIndexPath}` };\n }\n\n // Find the raw path for this ID in the wiki index\n // Wiki index format: | [[STORY-003-13]] | story | Draft | .cleargate/delivery/... |\n const rowMatch = indexContent.match(\n new RegExp(`\\\\[\\\\[${parsed.id}\\\\]\\\\]\\\\s*\\\\|[^|]+\\\\|[^|]+\\\\|\\\\s*([^|\\\\n]+)`)\n );\n if (!rowMatch) {\n return { pass: false, detail: `[[${parsed.id}]] not found in wiki index` };\n }\n\n const rawPath = rowMatch[1]!.trim();\n const fullPath = path.resolve(projectRoot, rawPath);\n\n // Sandbox check\n if (!fullPath.startsWith(projectRoot)) {\n return { pass: false, detail: `wiki path for ${parsed.id} resolves outside project root` };\n }\n\n const linkedFm = readFrontmatterFromFile(fullPath);\n const status = linkedFm['status'];\n if (status === undefined) {\n return { pass: false, detail: `[[${parsed.id}]] has no status field` };\n }\n\n const pass = String(status).replace(/^[\"']|[\"']$/g, '') === parsed.value;\n return {\n pass,\n detail: pass\n ? `status-of([[${parsed.id}]]) == ${parsed.value}`\n : `status-of([[${parsed.id}]]) is '${status}', expected '${parsed.value}'`,\n };\n}\n","/**\n * STORY-008-02: Idempotent cached_gate_result frontmatter writer.\n * Reuses the shared frontmatter serializer from frontmatter-yaml.ts.\n *\n * writeCachedGate is byte-identical on re-run with identical inputs (same now + same result).\n *\n * Post-BUG-001: cached_gate_result is stored as a native YAML mapping\n * (parseFrontmatter returns it as an object). Legacy flow-style strings are\n * still accepted on read for backwards-compat with old files.\n */\n\nimport * as fs from 'node:fs/promises';\nimport yaml from 'js-yaml';\nimport { parseFrontmatter } from '../wiki/parse-frontmatter.js';\nimport { serializeFrontmatter, toIsoSecond } from './frontmatter-yaml.js';\n\nexport interface CachedGate {\n pass: boolean;\n failing_criteria: { id: string; detail: string }[];\n last_gate_check: string;\n}\n\n/**\n * Read the cached_gate_result from a file's frontmatter.\n * Returns null if the key is absent or the file has no valid frontmatter.\n */\nexport async function readCachedGate(absPath: string): Promise<CachedGate | null> {\n let raw: string;\n try {\n raw = await fs.readFile(absPath, 'utf8');\n } catch {\n return null;\n }\n\n let fm: Record<string, unknown>;\n try {\n ({ fm } = parseFrontmatter(raw));\n } catch {\n return null;\n }\n\n return coerceCachedGate(fm['cached_gate_result']);\n}\n\n/**\n * Write (or update) cached_gate_result in a file's frontmatter.\n * Idempotent: if the result deep-equals the existing cached value AND the same\n * now() is supplied, the file bytes are left untouched.\n *\n * @param absPath Absolute path to the markdown file.\n * @param result The gate result to cache.\n * @param opts Optional: inject `now` for test determinism.\n */\nexport async function writeCachedGate(\n absPath: string,\n result: CachedGate,\n opts?: { now?: () => Date }\n): Promise<void> {\n const nowFn = opts?.now ?? (() => new Date());\n const lastGateCheck = result.last_gate_check || toIsoSecond(nowFn());\n\n const newResult: CachedGate = {\n pass: result.pass,\n failing_criteria: result.failing_criteria,\n last_gate_check: lastGateCheck,\n };\n\n const raw = await fs.readFile(absPath, 'utf8');\n\n let fm: Record<string, unknown>;\n let body: string;\n try {\n ({ fm, body } = parseFrontmatter(raw));\n } catch {\n throw new Error(`writeCachedGate: failed to parse frontmatter in ${absPath}`);\n }\n\n // Idempotency check: compare existing cached_gate_result\n const existing = coerceCachedGate(fm['cached_gate_result']);\n if (existing && JSON.stringify(existing) === JSON.stringify(newResult)) {\n return;\n }\n\n // Build new frontmatter: preserve all existing keys, inject/update cached_gate_result\n const newFm: Record<string, unknown> = {};\n let inserted = false;\n for (const [k, v] of Object.entries(fm)) {\n if (k === 'cached_gate_result') {\n newFm['cached_gate_result'] = newResult as unknown as Record<string, unknown>;\n inserted = true;\n } else {\n newFm[k] = v;\n }\n }\n if (!inserted) {\n newFm['cached_gate_result'] = newResult as unknown as Record<string, unknown>;\n }\n\n const fmBlock = serializeFrontmatter(newFm);\n const newContent = body.length > 0 ? `${fmBlock}\\n\\n${body}` : `${fmBlock}\\n`;\n\n await fs.writeFile(absPath, newContent, 'utf8');\n}\n\n// ─── Internal helpers ─────────────────────────────────────────────────────────\n\n/**\n * Coerce a frontmatter value (native object or legacy flow-style string) into\n * a CachedGate. Returns null if absent or unrecognizable.\n */\nfunction coerceCachedGate(val: unknown): CachedGate | null {\n if (val === undefined || val === null) return null;\n\n // Native object (current format)\n if (typeof val === 'object' && !Array.isArray(val)) {\n const c = val as Record<string, unknown>;\n return {\n pass: Boolean(c['pass']),\n failing_criteria: Array.isArray(c['failing_criteria'])\n ? (c['failing_criteria'] as { id: string; detail: string }[])\n : [],\n last_gate_check: String(c['last_gate_check'] ?? ''),\n };\n }\n\n // Legacy flow-style string \"{pass: true, ...}\" — parse via js-yaml\n if (typeof val === 'string' && val.startsWith('{')) {\n try {\n const parsed = yaml.load(val, { schema: yaml.CORE_SCHEMA });\n if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) return null;\n const p = parsed as Record<string, unknown>;\n return {\n pass: Boolean(p['pass']),\n failing_criteria: Array.isArray(p['failing_criteria'])\n ? (p['failing_criteria'] as { id: string; detail: string }[])\n : [],\n last_gate_check: String(p['last_gate_check'] ?? ''),\n };\n } catch {\n return null;\n }\n }\n\n return null;\n}\n","/**\n * stamp-tokens.ts — STORY-008-05\n *\n * `cleargate stamp-tokens <file>` CLI command.\n * Reads token-ledger rows for a work item, aggregates per-session totals, and\n * stamps `draft_tokens:` into the file's YAML frontmatter.\n *\n * Hook-invoked. Idempotent within a session (last_stamp check), accumulative\n * across sessions (sessions[] array).\n *\n * No top-level await.\n */\n\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { parseFrontmatter } from '../wiki/parse-frontmatter.js';\nimport { serializeFrontmatter, toIsoSecond } from '../lib/frontmatter-yaml.js';\nimport { readLedgerForWorkItem } from '../lib/ledger-reader.js';\nimport { detectWorkItemType } from '../lib/work-item-type.js';\nimport type { SessionBucket } from '../lib/ledger-reader.js';\n\n// ─── Public API ───────────────────────────────────────────────────────────────\n\nexport interface StampTokensCliOptions {\n cwd?: string;\n now?: () => Date;\n stdout?: (s: string) => void;\n exit?: (code: number) => never;\n sprintRunsRoot?: string;\n}\n\nexport interface DraftTokensSession {\n session: string;\n model: string;\n input: number;\n output: number;\n cache_read: number;\n cache_creation: number;\n ts: string;\n}\n\nexport interface DraftTokens {\n input: number | null;\n output: number | null;\n cache_creation: number | null;\n cache_read: number | null;\n model: string | null;\n last_stamp: string;\n sessions: DraftTokensSession[];\n}\n\nexport async function stampTokensHandler(\n file: string,\n opts: { dryRun?: boolean },\n cli?: StampTokensCliOptions,\n): Promise<void> {\n const stdoutFn = cli?.stdout ?? ((s: string) => process.stdout.write(s + '\\n'));\n const exitFn =\n cli?.exit ??\n ((code: number) => {\n process.exit(code);\n });\n const nowFn = cli?.now ?? (() => new Date());\n const cwd = cli?.cwd ?? process.cwd();\n\n // Resolve file to absolute path\n const absPath = path.isAbsolute(file) ? file : path.resolve(cwd, file);\n\n // Archive freeze: if path contains /.cleargate/delivery/archive/, noop\n if (/\\/\\.cleargate\\/delivery\\/archive\\//.test(absPath)) {\n stdoutFn(`[frozen] ${absPath}`);\n exitFn(0);\n return;\n }\n\n // Read the file\n let rawContent: string;\n try {\n rawContent = fs.readFileSync(absPath, 'utf-8');\n } catch {\n stdoutFn(`[stamp-tokens] error: cannot read file: ${absPath}`);\n exitFn(1);\n return;\n }\n\n // Parse frontmatter\n let fm: Record<string, unknown> = {};\n let body = '';\n\n const hasFrontmatter = rawContent.trimStart().startsWith('---');\n if (hasFrontmatter) {\n try {\n const parsed = parseFrontmatter(rawContent);\n fm = parsed.fm;\n body = parsed.body;\n } catch {\n stdoutFn(`[stamp-tokens] error: cannot parse frontmatter in: ${absPath}`);\n exitFn(1);\n return;\n }\n } else {\n body = rawContent;\n }\n\n // Extract work_item_id from frontmatter ID key or filename fallback\n const workItemId = extractWorkItemId(fm, absPath);\n if (!workItemId) {\n stdoutFn(`[stamp-tokens] error: cannot determine work_item_id from frontmatter or filename: ${absPath}`);\n exitFn(1);\n return;\n }\n\n // Read existing draft_tokens from frontmatter (parsed as native nested object\n // since parseFrontmatter now returns typed values)\n const existingDraftTokens = coerceDraftTokens(fm['draft_tokens']);\n const existingLastStamp = existingDraftTokens?.last_stamp ?? null;\n\n // Read ledger\n const buckets = readLedgerForWorkItem(workItemId, { sprintRunsRoot: cli?.sprintRunsRoot });\n\n // Idempotency check: if all ledger rows are older than last_stamp, and we\n // already have sessions, no-op.\n if (existingLastStamp && buckets.length > 0) {\n const allRowsOlderThanLastStamp = buckets.every((bucket) =>\n bucket.rows.every((row) => row.ts < existingLastStamp),\n );\n if (allRowsOlderThanLastStamp && existingDraftTokens !== null) {\n // No new rows since last stamp — no-op\n exitFn(0);\n return;\n }\n }\n\n const nowIso = toIsoSecond(nowFn());\n\n let newFm: Record<string, unknown>;\n let stampError: string | undefined;\n\n if (buckets.length === 0) {\n // Missing ledger: write all-null draft_tokens + stamp_error\n stampError = `no ledger rows for work_item_id ${workItemId}`;\n const nullTokens: DraftTokens = {\n input: null,\n output: null,\n cache_creation: null,\n cache_read: null,\n model: null,\n last_stamp: nowIso,\n sessions: [],\n };\n newFm = buildNewFrontmatter(fm, nullTokens, stampError);\n } else {\n // Aggregate across all sessions\n const tokens = aggregateBuckets(buckets, nowIso);\n newFm = buildNewFrontmatter(fm, tokens, undefined);\n // Remove stale stamp_error if ledger now has rows\n delete newFm['stamp_error'];\n }\n\n const serialized = buildSerializedContent(newFm, body);\n\n if (opts.dryRun) {\n // Print planned diff without writing\n stdoutFn(`[dry-run] stamp-tokens would write draft_tokens for ${workItemId}:`);\n const draftTokensVal = newFm['draft_tokens'];\n stdoutFn(` draft_tokens: ${JSON.stringify(draftTokensVal)}`);\n if (stampError) {\n stdoutFn(` stamp_error: \"${stampError}\"`);\n }\n exitFn(0);\n return;\n }\n\n // Write the file\n try {\n fs.writeFileSync(absPath, serialized, 'utf-8');\n } catch {\n stdoutFn(`[stamp-tokens] error: cannot write file: ${absPath}`);\n exitFn(1);\n return;\n }\n\n stdoutFn(`[stamped] ${absPath} (${workItemId})`);\n exitFn(0);\n}\n\n// ─── Internal helpers ─────────────────────────────────────────────────────────\n\n/**\n * Extract the work_item_id from frontmatter ID fields or filename regex fallback.\n */\nfunction extractWorkItemId(fm: Record<string, unknown>, absPath: string): string | null {\n // Try frontmatter ID keys in order\n const idKeys = ['story_id', 'epic_id', 'proposal_id', 'cr_id', 'bug_id'];\n for (const key of idKeys) {\n const val = fm[key];\n if (typeof val === 'string' && val.trim() !== '') {\n return val.trim();\n }\n }\n\n // Fallback: extract from filename\n const basename = path.basename(absPath);\n const match = basename.match(/^(STORY|EPIC|PROPOSAL|CR|BUG)-\\d+(-\\d+)?/i);\n if (match) {\n return match[0].toUpperCase();\n }\n\n // Also try detectWorkItemType for any prefix match\n const typeFromPath = detectWorkItemType(absPath);\n if (typeFromPath) {\n // Try to find the ID segment in the basename\n const idMatch = basename.match(/((?:STORY|EPIC|PROPOSAL|CR|BUG)-\\d+(?:-\\d+)?)/i);\n if (idMatch) {\n return idMatch[1].toUpperCase();\n }\n }\n\n return null;\n}\n\n/**\n * Coerce the existing draft_tokens value from frontmatter into a DraftTokens shape.\n * Handles two on-disk shapes:\n * 1. Native nested YAML map (current format, parsed by js-yaml as an object)\n * 2. Legacy JSON-in-a-string, from pre-fix files written before BUG-001\n */\nfunction coerceDraftTokens(val: unknown): DraftTokens | null {\n if (val == null) return null;\n\n if (typeof val === 'object' && !Array.isArray(val)) {\n const o = val as Record<string, unknown>;\n return {\n input: typeof o['input'] === 'number' ? o['input'] : null,\n output: typeof o['output'] === 'number' ? o['output'] : null,\n cache_creation: typeof o['cache_creation'] === 'number' ? o['cache_creation'] : null,\n cache_read: typeof o['cache_read'] === 'number' ? o['cache_read'] : null,\n model: typeof o['model'] === 'string' ? o['model'] : null,\n last_stamp: typeof o['last_stamp'] === 'string' ? o['last_stamp'] : '',\n sessions: Array.isArray(o['sessions']) ? (o['sessions'] as DraftTokensSession[]) : [],\n };\n }\n\n if (typeof val === 'string') {\n try {\n const parsed = JSON.parse(val) as DraftTokens;\n return parsed;\n } catch {\n return null;\n }\n }\n\n return null;\n}\n\n/**\n * Aggregate ledger buckets into a DraftTokens object.\n * model: comma-joined sorted unique models across all buckets' rows.\n * sessions[]: one entry per bucket, using bucket totals.\n */\nexport function aggregateBuckets(buckets: SessionBucket[], nowIso: string): DraftTokens {\n let totalInput = 0;\n let totalOutput = 0;\n let totalCacheCreation = 0;\n let totalCacheRead = 0;\n\n const uniqueModels = new Set<string>();\n const sessions: DraftTokensSession[] = [];\n\n for (const bucket of buckets) {\n totalInput += bucket.totals.input;\n totalOutput += bucket.totals.output;\n totalCacheCreation += bucket.totals.cache_creation;\n totalCacheRead += bucket.totals.cache_read;\n\n // Collect unique models from rows and derive session model\n const sessionModels = new Set<string>();\n for (const row of bucket.rows) {\n if (row.model) {\n uniqueModels.add(row.model);\n sessionModels.add(row.model);\n }\n }\n\n // Session model: comma-joined unique models for this session\n const sessionModel = Array.from(sessionModels).sort().join(', ');\n\n sessions.push({\n session: bucket.session_id,\n model: sessionModel,\n input: bucket.totals.input,\n output: bucket.totals.output,\n cache_read: bucket.totals.cache_read,\n cache_creation: bucket.totals.cache_creation,\n ts: bucket.rows[0]?.ts ?? '',\n });\n }\n\n const model = Array.from(uniqueModels).sort().join(', ') || null;\n\n return {\n input: totalInput,\n output: totalOutput,\n cache_creation: totalCacheCreation,\n cache_read: totalCacheRead,\n model,\n last_stamp: nowIso,\n sessions,\n };\n}\n\n/**\n * Build the new frontmatter record with draft_tokens as a native nested\n * object. serializeFrontmatter (js-yaml) emits it as a block-style YAML map.\n */\nfunction buildNewFrontmatter(\n existingFm: Record<string, unknown>,\n tokens: DraftTokens,\n stampError: string | undefined,\n): Record<string, unknown> {\n const newFm: Record<string, unknown> = {};\n\n // Preserve all existing keys except draft_tokens and stamp_error (we'll re-add)\n for (const [k, v] of Object.entries(existingFm)) {\n if (k !== 'draft_tokens' && k !== 'stamp_error') {\n newFm[k] = v;\n }\n }\n\n if (stampError) {\n newFm['stamp_error'] = stampError;\n }\n\n // Store as a plain object; serializer emits block-style YAML\n newFm['draft_tokens'] = tokens as unknown as Record<string, unknown>;\n\n return newFm;\n}\n\n/**\n * Build the final file content: frontmatter block + body.\n */\nfunction buildSerializedContent(fm: Record<string, unknown>, body: string): string {\n const fmBlock = serializeFrontmatter(fm);\n if (body.length > 0) {\n return `${fmBlock}\\n\\n${body}`;\n }\n return `${fmBlock}\\n`;\n}\n\n","/**\n * ledger-reader.ts — STORY-008-04\n *\n * Read-only library for scanning token-ledger.jsonl files across all sprint-run\n * directories and grouping rows by session for per-work-item cost attribution.\n *\n * Node built-ins only. No runtime deps.\n */\n\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\n\n// ─── Public types ─────────────────────────────────────────────────────────────\n\nexport interface LedgerRow {\n ts: string;\n sprint_id: string;\n agent_type: string;\n /** Populated only for STORY-* items (backward compat; empty string for non-story items) */\n story_id: string;\n /** Always populated when detection succeeded. Equals story_id for STORY items. */\n work_item_id: string;\n session_id: string;\n transcript: string;\n input: number;\n output: number;\n cache_creation: number;\n cache_read: number;\n model: string;\n turns: number;\n}\n\nexport interface SessionBucket {\n session_id: string;\n rows: LedgerRow[];\n totals: {\n input: number;\n output: number;\n cache_creation: number;\n cache_read: number;\n turns: number;\n };\n}\n\nexport interface ReadLedgerOptions {\n /** ISO timestamp string; rows with ts < since are excluded */\n since?: string;\n /**\n * Root directory for sprint-runs/. Defaults to\n * <repo_root>/.cleargate/sprint-runs where repo_root is resolved by\n * walking up from cwd to find .cleargate/.\n * Override in tests to avoid touching the real repo.\n */\n sprintRunsRoot?: string;\n}\n\n// ─── Internal helpers ─────────────────────────────────────────────────────────\n\n/**\n * Walk up from cwd until we find a directory containing `.cleargate/sprint-runs/`.\n * Returns the sprint-runs path or null if not found.\n */\nfunction findSprintRunsRoot(startDir: string): string | null {\n let dir = startDir;\n while (true) {\n const candidate = path.join(dir, '.cleargate', 'sprint-runs');\n if (fs.existsSync(candidate)) {\n return candidate;\n }\n const parent = path.dirname(dir);\n if (parent === dir) {\n return null;\n }\n dir = parent;\n }\n}\n\nfunction normalizeRow(raw: Record<string, unknown>): LedgerRow {\n // work_item_id may be absent in pre-STORY-008-04 rows; default from story_id.\n const story_id = typeof raw['story_id'] === 'string' ? raw['story_id'] : '';\n const work_item_id =\n typeof raw['work_item_id'] === 'string' && raw['work_item_id'] !== ''\n ? raw['work_item_id']\n : story_id;\n\n return {\n ts: typeof raw['ts'] === 'string' ? raw['ts'] : '',\n sprint_id: typeof raw['sprint_id'] === 'string' ? raw['sprint_id'] : '',\n agent_type: typeof raw['agent_type'] === 'string' ? raw['agent_type'] : 'unknown',\n story_id,\n work_item_id,\n session_id: typeof raw['session_id'] === 'string' ? raw['session_id'] : '',\n transcript: typeof raw['transcript'] === 'string' ? raw['transcript'] : '',\n input: typeof raw['input'] === 'number' ? raw['input'] : 0,\n output: typeof raw['output'] === 'number' ? raw['output'] : 0,\n cache_creation: typeof raw['cache_creation'] === 'number' ? raw['cache_creation'] : 0,\n cache_read: typeof raw['cache_read'] === 'number' ? raw['cache_read'] : 0,\n model: typeof raw['model'] === 'string' ? raw['model'] : '',\n turns: typeof raw['turns'] === 'number' ? raw['turns'] : 0,\n };\n}\n\nfunction rowMatchesWorkItem(row: LedgerRow, workItemId: string): boolean {\n return row.work_item_id === workItemId || row.story_id === workItemId;\n}\n\nfunction buildBucket(session_id: string, rows: LedgerRow[]): SessionBucket {\n const totals = rows.reduce(\n (acc, r) => ({\n input: acc.input + r.input,\n output: acc.output + r.output,\n cache_creation: acc.cache_creation + r.cache_creation,\n cache_read: acc.cache_read + r.cache_read,\n turns: acc.turns + r.turns,\n }),\n { input: 0, output: 0, cache_creation: 0, cache_read: 0, turns: 0 }\n );\n return { session_id, rows, totals };\n}\n\n// ─── Public API ───────────────────────────────────────────────────────────────\n\n/**\n * Scan all sprint-runs/<sprint>/token-ledger.jsonl files and return rows\n * matching the given workItemId, grouped by session_id.\n *\n * Rows are compared by work_item_id first, then story_id (for backward compat\n * with pre-STORY-008-04 rows that lack work_item_id).\n *\n * Pre-fix rows (missing work_item_id) default work_item_id from story_id.\n *\n * @param workItemId e.g. \"STORY-008-04\", \"EPIC-008\", \"PROPOSAL-042\"\n * @param opts optional filters and path overrides\n * @returns array of SessionBucket, one per unique session_id, sorted\n * by the ts of the earliest row in each bucket\n */\nexport function readLedgerForWorkItem(\n workItemId: string,\n opts: ReadLedgerOptions = {}\n): SessionBucket[] {\n // Resolve sprint-runs root\n let sprintRunsRoot: string;\n if (opts.sprintRunsRoot) {\n sprintRunsRoot = opts.sprintRunsRoot;\n } else {\n const found = findSprintRunsRoot(process.cwd());\n if (!found) {\n return [];\n }\n sprintRunsRoot = found;\n }\n\n if (!fs.existsSync(sprintRunsRoot)) {\n return [];\n }\n\n // Collect all token-ledger.jsonl files across all sprint dirs\n let ledgerFiles: string[];\n try {\n const entries = fs.readdirSync(sprintRunsRoot, { withFileTypes: true });\n ledgerFiles = entries\n .filter((e) => e.isDirectory())\n .map((e) => path.join(sprintRunsRoot, e.name, 'token-ledger.jsonl'))\n .filter((f) => fs.existsSync(f));\n } catch {\n return [];\n }\n\n // Parse matching rows from each file\n const matchingRows: LedgerRow[] = [];\n\n for (const ledgerFile of ledgerFiles) {\n let content: string;\n try {\n content = fs.readFileSync(ledgerFile, 'utf-8');\n } catch {\n continue;\n }\n\n const lines = content.split('\\n').filter((l) => l.trim() !== '');\n for (const line of lines) {\n let raw: Record<string, unknown>;\n try {\n raw = JSON.parse(line) as Record<string, unknown>;\n } catch {\n continue;\n }\n\n const row = normalizeRow(raw);\n\n // Apply since filter\n if (opts.since && row.ts < opts.since) {\n continue;\n }\n\n if (rowMatchesWorkItem(row, workItemId)) {\n matchingRows.push(row);\n }\n }\n }\n\n // Group by session_id\n const sessionMap = new Map<string, LedgerRow[]>();\n for (const row of matchingRows) {\n const key = row.session_id || '(unknown-session)';\n const existing = sessionMap.get(key);\n if (existing) {\n existing.push(row);\n } else {\n sessionMap.set(key, [row]);\n }\n }\n\n // Build buckets and sort by earliest row ts within each bucket\n const buckets = Array.from(sessionMap.entries()).map(([session_id, rows]) => {\n rows.sort((a, b) => a.ts.localeCompare(b.ts));\n return buildBucket(session_id, rows);\n });\n\n // Sort buckets by earliest row ts\n buckets.sort((a, b) => {\n const aTs = a.rows[0]?.ts ?? '';\n const bTs = b.rows[0]?.ts ?? '';\n return aTs.localeCompare(bTs);\n });\n\n return buckets;\n}\n\n","/**\n * upgrade.ts — STORY-009-05\n *\n * `cleargate upgrade [--dry-run] [--yes] [--only <tier>]`\n *\n * Three-way merge driver: walks each tracked scaffold file, classifies its\n * drift state, routes by overwrite_policy, and applies the user-chosen merge\n * action. Snapshot is updated atomically after every successfully handled file\n * so the command is resumable (re-run continues from the last clean state).\n *\n * Special-case handling:\n * - CLAUDE.md tier (cli-config): uses claude-md-surgery to merge only the\n * CLEARGATE:START…CLEARGATE:END bounded block, leaving user prose intact.\n * - settings.json tier (cli-config): uses settings-json-surgery to merge\n * only ClearGate-owned hooks, leaving user hooks intact.\n *\n * CRITICAL: all file mutations are atomic (write .tmp → fs.rename).\n * INCREMENTAL: each file is independent. Failure on file N does not roll back\n * file N-1. Re-running re-classifies against the updated snapshot.\n *\n * No top-level await (FLASHCARD #tsup #cjs #esm).\n * Inject `promptMergeChoice` + `openInEditor` via `UpgradeCliOptions` for tests\n * (FLASHCARD #cli #determinism #test-seam).\n */\n\nimport * as fsp from 'node:fs/promises';\nimport * as path from 'node:path';\nimport {\n loadPackageManifest,\n loadInstallSnapshot,\n computeCurrentSha,\n classify,\n writeDriftState,\n type ManifestFile,\n type ManifestEntry,\n type DriftMap,\n type Tier,\n} from '../lib/manifest.js';\nimport { hashNormalized } from '../lib/sha256.js';\nimport { readBlock, writeBlock } from '../lib/claude-md-surgery.js';\nimport { removeClearGateHooks, type ClaudeSettings } from '../lib/settings-json-surgery.js';\nimport {\n promptMergeChoice as defaultPromptMergeChoice,\n type MergeChoice,\n} from '../lib/merge-ui.js';\nimport {\n openInEditor as defaultOpenInEditor,\n containsConflictMarkers,\n} from '../lib/editor.js';\n\n// ─── Public types ─────────────────────────────────────────────────────────────\n\nexport interface UpgradeCliOptions {\n cwd?: string;\n now?: () => Date;\n stdout?: (s: string) => void;\n stderr?: (s: string) => void;\n exit?: (code: number) => never;\n /** Test seam: override the package root for loadPackageManifest. */\n packageRoot?: string;\n /** Test seam: inject a custom promptMergeChoice (avoids interactive stdin). */\n promptMergeChoice?: typeof defaultPromptMergeChoice;\n /** Test seam: inject a custom openInEditor (avoids forking real editors). */\n openInEditor?: typeof defaultOpenInEditor;\n /** Test seam: inject a custom stdin for promptMergeChoice. */\n stdin?: NodeJS.ReadableStream;\n}\n\n// ─── Internal helpers ─────────────────────────────────────────────────────────\n\n/** Write file atomically: write to .tmp, then rename. Never leaves partial writes. */\nasync function writeAtomic(filePath: string, content: string): Promise<void> {\n const tmpPath = filePath + '.tmp.' + Date.now();\n await fsp.writeFile(tmpPath, content, 'utf-8');\n await fsp.rename(tmpPath, filePath);\n}\n\n/**\n * Update a single file's sha256 in the install snapshot atomically.\n * Reads the snapshot file, patches the matching entry, and re-writes atomically.\n */\nasync function updateSnapshotEntry(\n projectRoot: string,\n filePath: string,\n newSha: string | null\n): Promise<void> {\n const snapshotPath = path.join(projectRoot, '.cleargate', '.install-manifest.json');\n let snapshot: ManifestFile;\n\n try {\n const raw = await fsp.readFile(snapshotPath, 'utf-8');\n snapshot = JSON.parse(raw) as ManifestFile;\n } catch {\n // If no snapshot exists yet, cannot update — silently skip.\n return;\n }\n\n const updated: ManifestFile = {\n ...snapshot,\n files: snapshot.files.map((entry) =>\n entry.path === filePath ? { ...entry, sha256: newSha } : entry\n ),\n };\n\n await writeAtomic(snapshotPath, JSON.stringify(updated, null, 2) + '\\n');\n}\n\n/**\n * Determine if this is a CLAUDE.md file (needs block surgery).\n */\nfunction isClaudeMd(filePath: string): boolean {\n return path.basename(filePath) === 'CLAUDE.md';\n}\n\n/**\n * Determine if this is a settings.json file (needs hook surgery).\n */\nfunction isSettingsJson(filePath: string): boolean {\n return path.basename(filePath) === 'settings.json' && filePath.includes('.claude');\n}\n\n/**\n * Merge-3way handler: always-policy — overwrite file with package content.\n * Used for `always` overwrite_policy files.\n */\nasync function applyAlwaysOverwrite(\n entry: ManifestEntry,\n projectRoot: string,\n packageRoot: string,\n stdout: (s: string) => void\n): Promise<void> {\n const targetPath = path.join(projectRoot, entry.path);\n const sourcePath = path.join(packageRoot, entry.path);\n\n try {\n const pkgContent = await fsp.readFile(sourcePath, 'utf-8');\n await fsp.mkdir(path.dirname(targetPath), { recursive: true });\n await writeAtomic(targetPath, pkgContent);\n await updateSnapshotEntry(projectRoot, entry.path, entry.sha256);\n stdout(`[always] overwritten: ${entry.path}`);\n } catch (err) {\n stdout(`[always] error overwriting ${entry.path}: ${(err as Error).message}`);\n }\n}\n\n/**\n * Merge-3way handler for `merge-3way` overwrite_policy files.\n * Supports k/t/e choices with conflict-marker semantics for 'e'.\n * Returns the post-merge sha or null if skipped/failed.\n */\nasync function applyMerge3Way(\n entry: ManifestEntry,\n projectRoot: string,\n packageRoot: string,\n installSha: string | null,\n currentSha: string | null,\n flags: { yes?: boolean; dryRun?: boolean },\n opts: {\n stdout: (s: string) => void;\n stderr: (s: string) => void;\n promptMergeChoiceFn: typeof defaultPromptMergeChoice;\n openInEditorFn: typeof defaultOpenInEditor;\n stdin?: NodeJS.ReadableStream;\n }\n): Promise<{ updated: boolean; newSha: string | null }> {\n const { stdout, stderr, promptMergeChoiceFn, openInEditorFn, stdin } = opts;\n\n const targetPath = path.join(projectRoot, entry.path);\n const sourcePath = path.join(packageRoot, entry.path);\n\n // Read current (ours) and package (theirs) content\n let ours = '';\n let theirs = '';\n\n try {\n ours = await fsp.readFile(targetPath, 'utf-8');\n } catch {\n // File missing on disk — treat as empty\n ours = '';\n }\n\n try {\n theirs = await fsp.readFile(sourcePath, 'utf-8');\n } catch {\n // Package file missing — skip\n stdout(`[merge] skip: package file not found for ${entry.path}`);\n return { updated: false, newSha: null };\n }\n\n // Compute drift state for display\n const state = classify(entry.sha256, installSha, currentSha, entry.tier);\n\n let choice: MergeChoice;\n\n if (flags.yes) {\n // --yes: auto-take-theirs\n choice = 't';\n stdout(`[yes] taking theirs: ${entry.path} state=${state}`);\n } else {\n // Interactive prompt\n choice = await promptMergeChoiceFn({\n path: entry.path,\n state,\n ours,\n theirs,\n stdin,\n stdout,\n });\n }\n\n if (choice === 'k') {\n // Keep mine: file unchanged, snapshot records current_sha as installed_sha\n stdout(`[keep] ${entry.path}`);\n await updateSnapshotEntry(projectRoot, entry.path, currentSha);\n return { updated: true, newSha: currentSha };\n }\n\n if (choice === 't') {\n // Take theirs: apply CLAUDE.md or settings.json surgery if needed, else raw overwrite\n let mergedContent = theirs;\n\n if (isClaudeMd(entry.path)) {\n // Merge only the bounded block; preserve user prose\n try {\n const ourBlock = readBlock(ours);\n const theirBlock = readBlock(theirs);\n if (ourBlock !== null && theirBlock !== null) {\n mergedContent = writeBlock(ours, theirBlock);\n } else if (theirBlock !== null) {\n // No block in ours — full overwrite\n mergedContent = theirs;\n }\n // If no block in theirs, skip (no ClearGate content to take)\n } catch {\n // Surgery failed — fall back to full overwrite\n mergedContent = theirs;\n }\n } else if (isSettingsJson(entry.path)) {\n // Merge only ClearGate-owned hooks; preserve user hooks\n try {\n const ourSettings = JSON.parse(ours) as ClaudeSettings;\n const theirSettings = JSON.parse(theirs) as ClaudeSettings;\n // Remove ClearGate hooks from ours, then add ClearGate hooks from theirs\n const withoutOurCg = removeClearGateHooks(ourSettings);\n // Build merged: user hooks from ours + ClearGate hooks from theirs\n const cgHooks = theirSettings.hooks ?? {};\n const merged: ClaudeSettings = { ...withoutOurCg };\n if (Object.keys(cgHooks).length > 0) {\n merged.hooks = { ...(withoutOurCg.hooks ?? {}), ...cgHooks };\n }\n mergedContent = JSON.stringify(merged, null, 2) + '\\n';\n } catch {\n // Surgery failed — full overwrite\n mergedContent = theirs;\n }\n }\n\n await fsp.mkdir(path.dirname(targetPath), { recursive: true });\n await writeAtomic(targetPath, mergedContent);\n const newSha = hashNormalized(mergedContent);\n await updateSnapshotEntry(projectRoot, entry.path, newSha);\n stdout(`[take] ${entry.path}`);\n return { updated: true, newSha };\n }\n\n // choice === 'e': write conflict-marker file + open editor\n const mergeFilePath = targetPath + '.cleargate-merge';\n const conflictContent =\n `<<<<<<< ours (installed)\\n${ours}=======\\n${theirs}>>>>>>> theirs (upstream)\\n`;\n\n await fsp.mkdir(path.dirname(mergeFilePath), { recursive: true });\n await writeAtomic(mergeFilePath, conflictContent);\n\n try {\n const result = await openInEditorFn(mergeFilePath);\n if (result.exitCode !== 0) {\n stderr(`[edit] editor exited with code ${result.exitCode}; markers may remain in ${mergeFilePath}`);\n }\n } catch (err) {\n stderr(`[edit] could not open editor: ${(err as Error).message}`);\n stderr(`[edit] resolve markers manually in: ${mergeFilePath}`);\n return { updated: false, newSha: null };\n }\n\n // Read post-edit content\n let edited = '';\n try {\n edited = await fsp.readFile(mergeFilePath, 'utf-8');\n } catch {\n stderr(`[edit] could not read ${mergeFilePath} after editor exit`);\n return { updated: false, newSha: null };\n }\n\n if (containsConflictMarkers(edited)) {\n stderr(`[edit] unresolved conflict markers remain in ${mergeFilePath}`);\n stderr(`[edit] file NOT updated. Resolve manually and re-run upgrade.`);\n // Leave .cleargate-merge in place for manual resolution\n return { updated: false, newSha: null };\n }\n\n // Markers resolved — overwrite target file, remove merge file\n await writeAtomic(targetPath, edited);\n try {\n await fsp.unlink(mergeFilePath);\n } catch {\n // Non-fatal if cleanup fails\n }\n\n const newSha = hashNormalized(edited);\n await updateSnapshotEntry(projectRoot, entry.path, newSha);\n stdout(`[edit] resolved: ${entry.path}`);\n return { updated: true, newSha };\n}\n\n// ─── Main handler ─────────────────────────────────────────────────────────────\n\nexport async function upgradeHandler(\n flags: { dryRun?: boolean; yes?: boolean; only?: string },\n cli?: UpgradeCliOptions\n): Promise<void> {\n const cwd = cli?.cwd ?? process.cwd();\n const now = cli?.now ? cli.now() : new Date();\n const stdout = cli?.stdout ?? ((s: string) => process.stdout.write(s + '\\n'));\n const stderr = cli?.stderr ?? ((s: string) => process.stderr.write(s + '\\n'));\n const exit = cli?.exit ?? ((code: number) => process.exit(code) as never);\n const promptMergeChoiceFn = cli?.promptMergeChoice ?? defaultPromptMergeChoice;\n const openInEditorFn = cli?.openInEditor ?? defaultOpenInEditor;\n const stdin = cli?.stdin;\n\n // ─── 1. Load manifests + compute drift ──────────────────────────────────────\n\n let pkgManifest: ManifestFile;\n try {\n pkgManifest = loadPackageManifest({ packageRoot: cli?.packageRoot });\n } catch (err) {\n stderr(`[upgrade] ${(err as Error).message}`);\n exit(1);\n return;\n }\n\n const installSnapshot = await loadInstallSnapshot(cwd);\n\n // Build a lookup from the snapshot\n const snapshotByPath = new Map<string, string | null>();\n for (const entry of installSnapshot?.files ?? []) {\n snapshotByPath.set(entry.path, entry.sha256);\n }\n\n // ─── 2. Apply --only <tier> filter ──────────────────────────────────────────\n\n const onlyTier: Tier | undefined = flags.only as Tier | undefined;\n const filteredFiles = onlyTier\n ? pkgManifest.files.filter((e) => e.tier === onlyTier)\n : pkgManifest.files;\n\n // ─── 3. Classify all files ──────────────────────────────────────────────────\n\n interface FileWork {\n entry: ManifestEntry;\n currentSha: string | null;\n installSha: string | null;\n action: 'overwrite' | 'skip' | 'merge-3way';\n }\n\n const workItems: FileWork[] = [];\n\n await Promise.all(\n filteredFiles.map(async (entry) => {\n if (entry.tier === 'user-artifact') {\n // Always skip user-artifact tier (never tracked)\n return;\n }\n\n const currentSha = await computeCurrentSha(entry, cwd);\n const installSha = snapshotByPath.get(entry.path) ?? null;\n\n let action: FileWork['action'];\n switch (entry.overwrite_policy) {\n case 'always':\n action = 'overwrite';\n break;\n case 'skip':\n case 'preserve':\n action = 'skip';\n break;\n case 'merge-3way':\n default:\n action = 'merge-3way';\n break;\n }\n\n workItems.push({ entry, currentSha, installSha, action });\n })\n );\n\n // Sort for deterministic output\n workItems.sort((a, b) => a.entry.path.localeCompare(b.entry.path));\n\n // ─── 4. --dry-run: print plan and exit ──────────────────────────────────────\n\n if (flags.dryRun) {\n let count = 0;\n for (const item of workItems) {\n const state = classify(item.entry.sha256, item.installSha, item.currentSha, item.entry.tier);\n stdout(`[dry-run] ${item.entry.path} action=${item.action} state=${state}`);\n count++;\n }\n stdout(`[dry-run] ${count} files planned. No changes made.`);\n return;\n }\n\n // ─── 5. Execute per file ─────────────────────────────────────────────────────\n\n // Determine package root for reading source files.\n // cli.packageRoot is the test seam (always injected in tests).\n // In production, use the same default resolution as loadPackageManifest.\n // Since we already loaded the manifest above (which resolves the path internally),\n // we simply use cli.packageRoot when provided, otherwise fall back to cwd\n // (in production the actual resolution is inside loadPackageManifest).\n const packageRoot = cli?.packageRoot ?? cwd;\n\n const driftMap: DriftMap = {};\n\n for (const item of workItems) {\n const { entry, currentSha, installSha, action } = item;\n\n switch (action) {\n case 'skip': {\n // never / preserve — no prompt, no write\n stdout(`[skip] ${entry.path} policy=${entry.overwrite_policy}`);\n break;\n }\n\n case 'overwrite': {\n // always — overwrite silently\n await applyAlwaysOverwrite(entry, cwd, packageRoot, stdout);\n break;\n }\n\n case 'merge-3way': {\n // Interactive 3-way merge (unless --yes)\n await applyMerge3Way(\n entry,\n cwd,\n packageRoot,\n installSha,\n currentSha,\n { yes: flags.yes, dryRun: false },\n { stdout, stderr, promptMergeChoiceFn, openInEditorFn, stdin }\n );\n break;\n }\n }\n\n // Re-compute current sha after potential mutation (for drift map)\n const postSha = await computeCurrentSha(entry, cwd);\n driftMap[entry.path] = {\n state: classify(entry.sha256, installSha, postSha, entry.tier),\n entry,\n install_sha: installSha,\n current_sha: postSha,\n package_sha: entry.sha256,\n };\n }\n\n // ─── 6. Refresh .drift-state.json ────────────────────────────────────────────\n\n await writeDriftState(cwd, driftMap, { lastRefreshed: now.toISOString() });\n\n stdout('[upgrade] complete.');\n}\n","export const CLEARGATE_START = '<!-- CLEARGATE:START -->';\nexport const CLEARGATE_END = '<!-- CLEARGATE:END -->';\n\n// IMPORTANT: regex MUST be GREEDY ([\\s\\S]* not [\\s\\S]*?)\n// The block body itself may reference both markers in prose (FLASHCARD 2026-04-19 #init #inject-claude-md #regex).\n// Non-greedy would stop at the first inline END marker in prose, cutting off the real block.\nconst BLOCK_REGEX = /<!-- CLEARGATE:START -->([\\s\\S]*)<!-- CLEARGATE:END -->/;\n\n/**\n * Returns the content between CLEARGATE:START and CLEARGATE:END markers.\n * Returns null if either marker is missing.\n */\nexport function readBlock(content: string): string | null {\n const match = BLOCK_REGEX.exec(content);\n if (!match) return null;\n return match[1];\n}\n\n/**\n * Replaces the content between CLEARGATE:START and CLEARGATE:END markers,\n * preserving the markers themselves and all surrounding content.\n * Throws if markers are missing.\n */\nexport function writeBlock(content: string, newBlockBody: string): string {\n if (!content.includes(CLEARGATE_START)) {\n throw new Error('CLAUDE.md is missing <!-- CLEARGATE:START --> marker');\n }\n if (!content.includes(CLEARGATE_END)) {\n throw new Error('CLAUDE.md is missing <!-- CLEARGATE:END --> marker');\n }\n return content.replace(BLOCK_REGEX, `${CLEARGATE_START}${newBlockBody}${CLEARGATE_END}`);\n}\n\n/**\n * Removes both markers AND the content between them, leaving surrounding content intact.\n * Throws if markers are missing.\n */\nexport function removeBlock(content: string): string {\n if (!content.includes(CLEARGATE_START)) {\n throw new Error('CLAUDE.md is missing <!-- CLEARGATE:START --> marker');\n }\n if (!content.includes(CLEARGATE_END)) {\n throw new Error('CLAUDE.md is missing <!-- CLEARGATE:END --> marker');\n }\n return content.replace(BLOCK_REGEX, '');\n}\n","export interface HookCommand {\n type: 'command';\n command: string;\n if?: string;\n}\n\nexport interface HookEntry {\n matcher?: string;\n hooks?: HookCommand[];\n}\n\nexport interface ClaudeSettings {\n hooks?: {\n PostToolUse?: HookEntry[];\n SessionStart?: HookEntry[];\n SubagentStop?: HookEntry[];\n [k: string]: HookEntry[] | undefined;\n };\n [k: string]: unknown;\n}\n\n/**\n * Returns true if the given command string belongs to ClearGate.\n * Matches:\n * - .claude/hooks/token-ledger.sh\n * - .claude/hooks/stamp-and-gate.sh\n * - .claude/hooks/session-start.sh\n * - .claude/hooks/wiki-ingest.sh (legacy)\n * - .claude/hooks/cleargate-*.sh (catch-all for future hooks)\n * - inline commands containing 'wiki ingest' (legacy SPRINT-04 PostToolUse inline)\n */\nfunction isClearGateCommand(command: string): boolean {\n if (command.includes('wiki ingest')) return true;\n return /\\/\\.claude\\/hooks\\/(token-ledger|stamp-and-gate|session-start|wiki-ingest|cleargate-[^/]*)\\.sh/.test(command);\n}\n\n/**\n * Removes ClearGate-owned hook entries from a ClaudeSettings object.\n * - Removes individual inner `hooks[]` sub-entries whose `command` matches ClearGate patterns.\n * - If the parent HookEntry's `hooks[]` array becomes empty, removes that HookEntry.\n * - If an event-category array (e.g. hooks.PostToolUse) becomes empty, removes the key.\n * - Preserves all other hook entries and all other top-level keys.\n */\nexport function removeClearGateHooks(settings: ClaudeSettings): ClaudeSettings {\n if (!settings.hooks) return { ...settings };\n\n const newHooks: NonNullable<ClaudeSettings['hooks']> = {};\n\n for (const [eventName, entries] of Object.entries(settings.hooks)) {\n if (!entries) continue;\n\n const filteredEntries: HookEntry[] = [];\n\n for (const entry of entries) {\n if (!entry.hooks || entry.hooks.length === 0) {\n // No inner hooks — keep as-is (not a ClearGate entry)\n filteredEntries.push(entry);\n continue;\n }\n\n const remainingInnerHooks = entry.hooks.filter(\n (h) => !isClearGateCommand(h.command)\n );\n\n if (remainingInnerHooks.length === 0) {\n // All inner hooks were ClearGate — drop this HookEntry entirely\n continue;\n }\n\n if (remainingInnerHooks.length === entry.hooks.length) {\n // No change — keep original entry reference\n filteredEntries.push(entry);\n } else {\n // Some removed — keep entry with remaining inner hooks\n filteredEntries.push({ ...entry, hooks: remainingInnerHooks });\n }\n }\n\n if (filteredEntries.length > 0) {\n newHooks[eventName] = filteredEntries;\n }\n // If filteredEntries is empty, skip the key entirely\n }\n\n const result: ClaudeSettings = { ...settings };\n\n if (Object.keys(newHooks).length > 0) {\n result.hooks = newHooks;\n } else {\n delete result.hooks;\n }\n\n return result;\n}\n\n/**\n * Returns true if settings contains any ClearGate-owned hook entries.\n */\nexport function hasClearGateHooks(settings: ClaudeSettings): boolean {\n if (!settings.hooks) return false;\n\n for (const entries of Object.values(settings.hooks)) {\n if (!entries) continue;\n for (const entry of entries) {\n if (!entry.hooks) continue;\n for (const h of entry.hooks) {\n if (isClearGateCommand(h.command)) return true;\n }\n }\n }\n\n return false;\n}\n","/**\n * merge-ui.ts — STORY-009-05\n *\n * Diff renderer + 3-choice interactive prompt for `cleargate upgrade`.\n *\n * No top-level await (FLASHCARD #tsup #cjs #esm).\n */\n\nimport { createPatch } from 'diff';\nimport type { DriftState } from './manifest.js';\n\n// ─── Public types ─────────────────────────────────────────────────────────────\n\nexport type MergeChoice = 'k' | 't' | 'e';\n\n// ─── Diff renderer ────────────────────────────────────────────────────────────\n\n/**\n * Render an inline unified diff of `ours` vs `theirs` for the given `filePath`.\n * Uses the `diff` npm package's `createPatch`.\n */\nexport function renderInlineDiff(ours: string, theirs: string, filePath: string): string {\n return createPatch(filePath, ours, theirs, 'installed', 'upstream');\n}\n\n// ─── Prompt ───────────────────────────────────────────────────────────────────\n\n/**\n * Print file info + inline diff, then prompt the user for a merge choice.\n * Returns one of: 'k' (keep mine), 't' (take theirs), 'e' (edit in $EDITOR).\n *\n * Test seam: pass `stdin` to drive from a buffer instead of process.stdin.\n * Test seam: pass `stdout` to capture output instead of process.stdout.write.\n */\nexport async function promptMergeChoice(opts: {\n path: string;\n state: DriftState;\n ours: string;\n theirs: string;\n stdin?: NodeJS.ReadableStream;\n stdout?: (s: string) => void;\n}): Promise<MergeChoice> {\n const { path: filePath, state, ours, theirs } = opts;\n const stdout = opts.stdout ?? ((s: string) => process.stdout.write(s));\n const stdin = opts.stdin ?? process.stdin;\n\n // Print file header\n stdout(`\\n[merge] ${filePath} state=${state}\\n`);\n\n // Print diff\n const patch = renderInlineDiff(ours, theirs, filePath);\n stdout(patch + '\\n');\n\n // Prompt\n stdout('[k]eep mine / [t]ake theirs / [e]dit in $EDITOR: ');\n\n return new Promise<MergeChoice>((resolve, reject) => {\n let buf = '';\n\n const onData = (chunk: Buffer | string) => {\n buf += typeof chunk === 'string' ? chunk : chunk.toString('utf-8');\n const newline = buf.indexOf('\\n');\n if (newline !== -1) {\n const answer = buf.slice(0, newline).trim().toLowerCase();\n stdin.removeListener('data', onData);\n stdin.removeListener('error', onError);\n if (answer === 'k' || answer === 't' || answer === 'e') {\n resolve(answer as MergeChoice);\n } else {\n // Default to 'k' (keep mine) for unrecognised input\n stdout(`Unknown choice '${answer}'; defaulting to [k]eep mine.\\n`);\n resolve('k');\n }\n }\n };\n\n const onError = (err: Error) => {\n stdin.removeListener('data', onData);\n reject(err);\n };\n\n stdin.on('data', onData);\n stdin.once('error', onError);\n });\n}\n","/**\n * editor.ts — STORY-009-05\n *\n * Safely spawn $EDITOR for the `cleargate upgrade` edit-in-editor flow.\n * Uses child_process.spawn with stdio: 'inherit' — does NOT use execSync\n * (would block the event loop and prevent test injection).\n *\n * No top-level await (FLASHCARD #tsup #cjs #esm).\n */\n\nimport { spawn } from 'node:child_process';\n\n// ─── Public API ───────────────────────────────────────────────────────────────\n\n/**\n * Spawn $EDITOR for `filePath`, waiting for the editor process to exit.\n *\n * Returns the editor's exit code.\n * If `opts.editor` is provided, uses it instead of $EDITOR.\n * If neither is set, returns `{ exitCode: -1 }` with an error (handled by caller).\n *\n * Uses `stdio: 'inherit'` so the terminal is fully connected to the editor.\n * Do NOT use execSync — it blocks the event loop and breaks tests.\n */\nexport async function openInEditor(\n filePath: string,\n opts?: { editor?: string; env?: NodeJS.ProcessEnv }\n): Promise<{ exitCode: number }> {\n const env = opts?.env ?? process.env;\n const editor = opts?.editor ?? env['EDITOR'] ?? env['VISUAL'];\n\n if (!editor) {\n throw new Error('$EDITOR not set; cannot [e]dit option. Set the EDITOR environment variable.');\n }\n\n return new Promise<{ exitCode: number }>((resolve, reject) => {\n const child = spawn(editor, [filePath], {\n stdio: 'inherit',\n env: { ...env },\n });\n\n child.on('error', (err) => {\n reject(new Error(`Failed to start editor '${editor}': ${err.message}`));\n });\n\n child.on('close', (code) => {\n resolve({ exitCode: code ?? 0 });\n });\n });\n}\n\n/**\n * Return true if `content` contains unresolved conflict markers.\n *\n * Checks for any of:\n * <<<<<<< ours\n * =======\n * >>>>>>> theirs\n */\nexport function containsConflictMarkers(content: string): boolean {\n return (\n content.includes('<<<<<<< ours') ||\n content.includes('>>>>>>> theirs') ||\n // Also catch generic git-style markers in case user merged manually\n /^<<<<<<< /m.test(content) ||\n /^>>>>>>> /m.test(content)\n );\n}\n","/**\n * uninstall.ts — STORY-009-07\n *\n * `cleargate uninstall [--dry-run] [--preserve <tiers>] [--remove <tiers>] [--yes] [--path <dir>] [--force]`\n *\n * Most-destructive command in the CLI. Preservation-first: user artifacts\n * (FLASHCARD, archive, pending-sync, sprint retrospectives) are kept by default.\n * Framework files (knowledge, templates, wiki, hook-log, agents, hooks, skills)\n * are removed. CLAUDE.md and settings.json are surgically stripped — the rest\n * of those files is left intact.\n *\n * Safety rails:\n * - Typed confirmation: user must type the project name (or pass --yes).\n * - Uncommitted-changes check: git status --porcelain on manifest-tracked files.\n * - --dry-run: preview only, zero disk writes.\n * - Single-target: does NOT recurse into nested .cleargate/ directories.\n * - Idempotency: if .uninstalled marker exists and .install-manifest.json is absent → \"already uninstalled\".\n *\n * All test-facing behaviours are injectable via UninstallOptions seams.\n * No top-level await (FLASHCARD #tsup #cjs #esm).\n */\n\nimport * as fs from 'node:fs';\nimport * as fsp from 'node:fs/promises';\nimport * as path from 'node:path';\nimport { execSync } from 'node:child_process';\nimport {\n loadInstallSnapshot,\n type ManifestFile,\n type ManifestEntry,\n type Tier,\n} from '../lib/manifest.js';\nimport {\n removeBlock,\n CLEARGATE_START,\n CLEARGATE_END,\n} from '../lib/claude-md-surgery.js';\nimport { removeClearGateHooks, type ClaudeSettings } from '../lib/settings-json-surgery.js';\n\n// ─── Public types ─────────────────────────────────────────────────────────────\n\n/** Tiers that belong to \"user-artifact\" bucket (preserved by default). */\nconst USER_ARTIFACT_TIERS: Tier[] = ['user-artifact'];\n\n/** Framework tiers that are removed by default. */\nconst FRAMEWORK_TIERS: Tier[] = ['protocol', 'template', 'agent', 'hook', 'skill', 'cli-config', 'derived'];\n\nexport interface UninstallOptions {\n cwd?: string;\n path?: string; // resolved target dir (defaults to cwd)\n dryRun?: boolean;\n yes?: boolean; // skip typed confirmation\n force?: boolean; // override uncommitted-changes refusal\n preserve?: string[]; // tier ids to force-preserve (comma-split at CLI level)\n remove?: string[]; // tier ids to force-remove (comma-split at CLI level, 'all' = all tiers)\n stdout?: (s: string) => void;\n stderr?: (s: string) => void;\n exit?: (code: number) => never;\n /** Test seam: prompt for typed project-name confirmation. */\n promptName?: () => Promise<string>;\n /** Test seam: prompt yes/no for interactive category decisions. */\n promptYesNo?: (q: string) => Promise<boolean>;\n /** Test seam: injectable clock. */\n now?: () => Date;\n /** Test seam: git status --porcelain runner. Returns { stdout, code }. */\n git?: (args: string[]) => { stdout: string; code: number };\n}\n\nexport interface UninstalledMarker {\n uninstalled_at: string;\n prior_version: string;\n preserved: string[];\n removed: string[];\n}\n\n// ─── Helpers ──────────────────────────────────────────────────────────────────\n\n/**\n * Parse a tier list string (comma-separated) into a Set.\n * 'all' expands to all known tiers.\n */\nfunction parseTierList(raw: string[]): Set<Tier> {\n const result = new Set<Tier>();\n for (const item of raw) {\n for (const t of item.split(',')) {\n const tier = t.trim();\n if (tier === 'all') {\n for (const f of FRAMEWORK_TIERS) result.add(f);\n for (const u of USER_ARTIFACT_TIERS) result.add(u);\n } else {\n result.add(tier as Tier);\n }\n }\n }\n return result;\n}\n\n/**\n * Determine if an entry should be preserved (true) or removed (false).\n *\n * Rules (highest priority first):\n * 1. --remove tier override → remove\n * 2. --preserve tier override → preserve\n * 3. user-artifact tier → preserve (default)\n * 4. Framework tiers (protocol/template/agent/hook/skill/cli-config/derived) → remove (default)\n */\nexport function shouldPreserve(\n entry: ManifestEntry,\n preserveSet: Set<Tier>,\n removeSet: Set<Tier>\n): boolean {\n if (removeSet.has(entry.tier)) return false;\n if (preserveSet.has(entry.tier)) return true;\n if (USER_ARTIFACT_TIERS.includes(entry.tier)) return true;\n return false;\n}\n\n/**\n * Read the project name from package.json (name field), or fall back to\n * the basename of the target directory.\n */\nfunction resolveProjectName(target: string): string {\n const pkgPath = path.join(target, 'package.json');\n if (fs.existsSync(pkgPath)) {\n try {\n const raw = fs.readFileSync(pkgPath, 'utf-8');\n const parsed = JSON.parse(raw) as { name?: string };\n if (parsed.name && typeof parsed.name === 'string') {\n return parsed.name;\n }\n } catch {\n // Fall through to basename\n }\n }\n return path.basename(target);\n}\n\n/**\n * Run git status --porcelain in the target directory, filtered to manifest-tracked paths.\n * Returns the list of uncommitted files that overlap with the manifest.\n *\n * Non-git targets return an empty array (skip silently per orchestrator decision).\n */\nfunction detectUncommittedChanges(\n target: string,\n manifestPaths: string[],\n gitRunner?: UninstallOptions['git']\n): string[] {\n const run = gitRunner ?? ((args: string[]) => {\n try {\n const out = execSync(['git', ...args].join(' '), {\n cwd: target,\n stdio: ['pipe', 'pipe', 'pipe'],\n encoding: 'utf-8',\n });\n return { stdout: out, code: 0 };\n } catch (e: unknown) {\n const err = e as { stdout?: string; status?: number };\n return { stdout: err.stdout ?? '', code: err.status ?? 1 };\n }\n });\n\n // First check if this is a git repo at all\n const isGit = run(['-C', target, 'rev-parse', '--is-inside-work-tree']);\n if (isGit.code !== 0) {\n // Not a git repo — skip silently (orchestrator decision)\n return [];\n }\n\n const result = run(['-C', target, 'status', '--porcelain']);\n if (result.code !== 0) {\n return [];\n }\n\n // Parse porcelain output — each line: XY path\n const changedFiles = result.stdout\n .split('\\n')\n .filter(Boolean)\n .map((line) => line.slice(3).trim());\n\n // Only flag files that are listed in the install manifest\n const manifestSet = new Set(manifestPaths);\n return changedFiles.filter((f) => manifestSet.has(f));\n}\n\n/**\n * Remove @cleargate/cli from package.json dependencies/devDependencies.\n * Writes back if modified. Returns true if modified.\n */\nasync function removeFromPackageJson(target: string, dryRun: boolean): Promise<boolean> {\n const pkgPath = path.join(target, 'package.json');\n if (!fs.existsSync(pkgPath)) return false;\n\n let raw: string;\n try {\n raw = await fsp.readFile(pkgPath, 'utf-8');\n } catch {\n return false;\n }\n\n let parsed: Record<string, unknown>;\n try {\n parsed = JSON.parse(raw) as Record<string, unknown>;\n } catch {\n return false;\n }\n\n let modified = false;\n\n for (const key of ['dependencies', 'devDependencies'] as const) {\n const deps = parsed[key];\n if (deps && typeof deps === 'object' && '@cleargate/cli' in (deps as Record<string, unknown>)) {\n const updated = { ...(deps as Record<string, unknown>) };\n delete updated['@cleargate/cli'];\n parsed[key] = updated;\n modified = true;\n }\n }\n\n if (modified && !dryRun) {\n await fsp.writeFile(pkgPath, JSON.stringify(parsed, null, 2) + '\\n', 'utf-8');\n }\n\n return modified;\n}\n\n/** Atomically write a file (tmp → rename). */\nasync function writeAtomic(filePath: string, content: string): Promise<void> {\n const tmpPath = `${filePath}.tmp.${Date.now()}`;\n await fsp.writeFile(tmpPath, content, 'utf-8');\n await fsp.rename(tmpPath, filePath);\n}\n\n/** Remove a file, silently ignoring missing files. */\nasync function removeFile(filePath: string): Promise<void> {\n try {\n await fsp.unlink(filePath);\n } catch {\n // Ignore ENOENT and other errors\n }\n}\n\n/** Remove a directory tree, silently ignoring missing directories. */\nasync function removeDir(dirPath: string): Promise<void> {\n try {\n fs.rmSync(dirPath, { recursive: true, force: true });\n } catch {\n // Ignore\n }\n}\n\n// ─── Main handler ─────────────────────────────────────────────────────────────\n\nexport async function uninstallHandler(opts: UninstallOptions): Promise<void> {\n const cwd = opts.cwd ?? process.cwd();\n const stdout = opts.stdout ?? ((s: string) => process.stdout.write(s + '\\n'));\n const stderr = opts.stderr ?? ((s: string) => process.stderr.write(s + '\\n'));\n const exit = opts.exit ?? ((code: number) => process.exit(code) as never);\n const now = opts.now ?? (() => new Date());\n const dryRun = opts.dryRun ?? false;\n const yes = opts.yes ?? false;\n const force = opts.force ?? false;\n\n // Parse tier overrides\n const preserveSet = parseTierList(opts.preserve ?? []);\n const removeSet = parseTierList(opts.remove ?? []);\n const removeAll = (opts.remove ?? []).some((r) => r === 'all');\n if (removeAll) {\n for (const t of FRAMEWORK_TIERS) removeSet.add(t);\n for (const u of USER_ARTIFACT_TIERS) removeSet.add(u);\n }\n\n // ─── 1. Resolve target ────────────────────────────────────────────────────────\n\n const target = opts.path ? path.resolve(opts.path) : cwd;\n const cleargateDir = path.join(target, '.cleargate');\n const manifestPath = path.join(cleargateDir, '.install-manifest.json');\n const uninstalledPath = path.join(cleargateDir, '.uninstalled');\n\n // ─── 2. Missing manifest → no install detected ────────────────────────────────\n\n if (!fs.existsSync(manifestPath)) {\n // Check idempotency: if .uninstalled exists without manifest → already done\n if (fs.existsSync(uninstalledPath)) {\n stdout('already uninstalled');\n exit(0);\n return;\n }\n stdout(`no ClearGate install detected at ${target}`);\n exit(0);\n return;\n }\n\n // ─── 3. Idempotency short-circuit ────────────────────────────────────────────\n\n if (fs.existsSync(uninstalledPath) && !fs.existsSync(manifestPath)) {\n stdout('already uninstalled');\n exit(0);\n return;\n }\n\n // ─── 4. Load install manifest ────────────────────────────────────────────────\n\n const snapshot: ManifestFile | null = await loadInstallSnapshot(target);\n if (!snapshot) {\n stdout(`no ClearGate install detected at ${target}`);\n exit(0);\n return;\n }\n\n // ─── 5. Uncommitted-changes check ────────────────────────────────────────────\n\n if (!force) {\n const manifestPaths = snapshot.files.map((e) => e.path);\n const uncommitted = detectUncommittedChanges(target, manifestPaths, opts.git);\n if (uncommitted.length > 0) {\n stderr(\n `Uncommitted changes to tracked files: ${uncommitted.slice(0, 5).join(', ')}${uncommitted.length > 5 ? ` and ${uncommitted.length - 5} more` : ''}. Commit, stash, or pass --force.`\n );\n exit(1);\n return;\n }\n }\n\n // ─── 6. CLAUDE.md marker check ───────────────────────────────────────────────\n\n const claudeMdPath = path.join(target, 'CLAUDE.md');\n let claudeMdContent: string | null = null;\n\n if (fs.existsSync(claudeMdPath)) {\n claudeMdContent = fs.readFileSync(claudeMdPath, 'utf-8');\n if (!claudeMdContent.includes(CLEARGATE_START)) {\n stderr('CLAUDE.md is missing <!-- CLEARGATE:START --> marker');\n exit(1);\n return;\n }\n if (!claudeMdContent.includes(CLEARGATE_END)) {\n stderr('CLAUDE.md is missing <!-- CLEARGATE:END --> marker');\n exit(1);\n return;\n }\n }\n\n // ─── 7. Classify entries ──────────────────────────────────────────────────────\n\n const toRemove: ManifestEntry[] = [];\n const toPreserve: ManifestEntry[] = [];\n const toSkip: ManifestEntry[] = []; // missing from disk\n\n for (const entry of snapshot.files) {\n const filePath = path.join(target, entry.path);\n if (!fs.existsSync(filePath)) {\n toSkip.push(entry);\n continue;\n }\n if (shouldPreserve(entry, preserveSet, removeSet)) {\n toPreserve.push(entry);\n } else {\n toRemove.push(entry);\n }\n }\n\n // ─── 8. Preview summary ───────────────────────────────────────────────────────\n\n stdout(`Will remove ${toRemove.length} files, keep ${toPreserve.length} files, update CLAUDE.md to strip CLEARGATE block, remove @cleargate/cli from package.json.`);\n\n if (dryRun) {\n stdout('');\n stdout('[dry-run] Planned removals:');\n for (const e of toRemove) {\n stdout(` [remove] ${e.path}`);\n }\n stdout('');\n stdout('[dry-run] Planned preservations:');\n for (const e of toPreserve) {\n stdout(` [keep] ${e.path}`);\n }\n if (toSkip.length > 0) {\n stdout('');\n stdout('[dry-run] Untracked (already missing on disk):');\n for (const e of toSkip) {\n stdout(` [skip] ${e.path}`);\n }\n }\n stdout('');\n stdout('[dry-run] No files changed.');\n exit(0);\n return;\n }\n\n // ─── 9. Typed confirmation (skipped with --yes) ───────────────────────────────\n\n if (!yes) {\n const projectName = resolveProjectName(target);\n\n const promptNameFn = opts.promptName ?? (() => {\n // Real interactive prompt — readline\n return new Promise<string>((resolve) => {\n process.stdout.write(`Type the project name \"${projectName}\" to confirm uninstall: `);\n let buf = '';\n process.stdin.setEncoding('utf-8');\n process.stdin.once('data', (chunk: Buffer | string) => {\n buf = chunk.toString().trim();\n resolve(buf);\n });\n });\n });\n\n const typed = await promptNameFn();\n if (typed !== projectName) {\n stdout('name mismatch — aborting');\n exit(1);\n return;\n }\n }\n\n // ─── 10. Execute removal ──────────────────────────────────────────────────────\n\n const removedPaths: string[] = [];\n const preservedPaths: string[] = [];\n\n // Remove classified entries\n for (const entry of toRemove) {\n const filePath = path.join(target, entry.path);\n await removeFile(filePath);\n removedPaths.push(entry.path);\n }\n\n // Collect preserved paths\n for (const entry of toPreserve) {\n preservedPaths.push(entry.path);\n }\n\n // Surgery: CLAUDE.md — strip only the CLEARGATE block\n if (claudeMdContent !== null) {\n try {\n const stripped = removeBlock(claudeMdContent);\n await writeAtomic(claudeMdPath, stripped);\n removedPaths.push('CLAUDE.md (CLEARGATE block)');\n } catch (err) {\n stderr(`Warning: could not strip CLAUDE.md block: ${(err as Error).message}`);\n }\n }\n\n // Surgery: settings.json — remove ClearGate hooks only\n const settingsPath = path.join(target, '.claude', 'settings.json');\n if (fs.existsSync(settingsPath)) {\n try {\n const raw = fs.readFileSync(settingsPath, 'utf-8');\n const settings = JSON.parse(raw) as ClaudeSettings;\n const cleaned = removeClearGateHooks(settings);\n await writeAtomic(settingsPath, JSON.stringify(cleaned, null, 2) + '\\n');\n removedPaths.push('.claude/settings.json (ClearGate hooks)');\n } catch (err) {\n stderr(`Warning: could not update settings.json: ${(err as Error).message}`);\n }\n }\n\n // Remove @cleargate/cli from package.json\n const pkgModified = await removeFromPackageJson(target, false);\n if (pkgModified) {\n removedPaths.push('package.json (@cleargate/cli dep)');\n stdout('Removed @cleargate/cli from package.json. Run `npm install` to update package-lock.json.');\n }\n\n // Remove the install manifest itself (and drift-state)\n await removeFile(manifestPath);\n await removeFile(path.join(cleargateDir, '.drift-state.json'));\n\n // ─── 11. Write .uninstalled marker ───────────────────────────────────────────\n\n const marker: UninstalledMarker = {\n uninstalled_at: now().toISOString(),\n prior_version: snapshot.cleargate_version,\n preserved: preservedPaths,\n removed: removedPaths,\n };\n\n // Ensure .cleargate/ dir still exists (may have had files removed from it)\n await fsp.mkdir(cleargateDir, { recursive: true });\n await writeAtomic(uninstalledPath, JSON.stringify(marker, null, 2) + '\\n');\n\n // ─── 12. Empty .cleargate/ cleanup ───────────────────────────────────────────\n\n // Per story Gherkin scenario 11: when --remove all removes all user-artifact\n // items too (nothing preserved inside .cleargate/), the directory itself is\n // removed (including the .uninstalled marker we just wrote).\n // In the default case (preservations exist), we leave .cleargate/ with the\n // preserved files + .uninstalled marker.\n if (removeAll) {\n const hasPreservedInsideCleargate = preservedPaths.some((p) =>\n p.startsWith('.cleargate/')\n );\n if (!hasPreservedInsideCleargate) {\n // Remove the entire .cleargate/ directory (including the marker we wrote)\n await removeDir(cleargateDir);\n }\n }\n\n // ─── 13. Restore hint ────────────────────────────────────────────────────────\n\n if (preservedPaths.length > 0) {\n stdout(`Preserved ${preservedPaths.length} items. Run cleargate init in this directory to restore.`);\n }\n}\n"],"mappings":"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","names":["os","os","path","fs","path","import_zod","Entry","hostname","fs","os","path","fs","path","fs","yaml","import_js_yaml","yaml","raw","fm","stampOpts","result","fs","path","import_node_url","fs","path","fs","path","fs","path","fs","path","fs","path","import_node_url","compile","resolveDefaultTemplateDir","fs","path","import_node_url","compile","resolveDefaultTemplateDir","fs","path","import_node_url","compile","resolveDefaultTemplateDir","isSet","compile","import_promises","path","resolve","fs","path","import_node_child_process","EXCLUDED_SUFFIXES","BUCKET_ORDER","BUCKET_LABELS","rename","buildParentRef","buildChildrenRefs","buildPageBody","compile","path","fs","path","fs","path","import_node_child_process","import_js_yaml","PREFIX_MAP","basename","yaml","fs","path","fs","path","parseCachedGateResult","gate","fs","path","import_js_yaml","fs","path","fs","import_js_yaml","yaml","yaml","gate","fs","path","fs","path","basename","path","BLOCK_REGEX","resolve","import_node_child_process","resolve","writeAtomic","newSha","fs","fsp","path","import_node_child_process","writeAtomic","resolve"]}