codealmanac 0.1.10 → 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 (53) hide show
  1. package/README.md +124 -104
  2. package/dist/agents-A4II4YJC.js +15 -0
  3. package/dist/auth-S5DVUIUJ.js +18 -0
  4. package/dist/{chunk-Z4MWLVS2.js → chunk-447U3GQJ.js} +162 -5
  5. package/dist/chunk-447U3GQJ.js.map +1 -0
  6. package/dist/{chunk-QLHJP2XK.js → chunk-B2AGSRXL.js} +13 -9
  7. package/dist/{chunk-QLHJP2XK.js.map → chunk-B2AGSRXL.js.map} +1 -1
  8. package/dist/{chunk-AXFPUHBN.js → chunk-F53U6JQG.js} +8 -49
  9. package/dist/chunk-F53U6JQG.js.map +1 -0
  10. package/dist/{chunk-3C5SY5SE.js → chunk-KQUVMF27.js} +5 -2
  11. package/dist/chunk-KQUVMF27.js.map +1 -0
  12. package/dist/{chunk-BJVZLP6O.js → chunk-MX2EW5MR.js} +3 -3
  13. package/dist/{chunk-Z6MBJ3D2.js → chunk-QQHIVTXT.js} +6 -4
  14. package/dist/{chunk-Z6MBJ3D2.js.map → chunk-QQHIVTXT.js.map} +1 -1
  15. package/dist/chunk-R3URPHGH.js +194 -0
  16. package/dist/chunk-R3URPHGH.js.map +1 -0
  17. package/dist/chunk-SSYMRT4I.js +126 -0
  18. package/dist/chunk-SSYMRT4I.js.map +1 -0
  19. package/dist/{chunk-QHQ6YH7U.js → chunk-V3QOQSXI.js} +5 -3
  20. package/dist/{chunk-QHQ6YH7U.js.map → chunk-V3QOQSXI.js.map} +1 -1
  21. package/dist/chunk-WRUSDYYE.js +97 -0
  22. package/dist/chunk-WRUSDYYE.js.map +1 -0
  23. package/dist/{chunk-3LC55TG6.js → chunk-ZDJSJIB6.js} +77 -126
  24. package/dist/chunk-ZDJSJIB6.js.map +1 -0
  25. package/dist/{cli-W3OYVJYH.js → cli-MZEXRV6E.js} +238 -24
  26. package/dist/cli-MZEXRV6E.js.map +1 -0
  27. package/dist/codealmanac.js +1 -1
  28. package/dist/doctor-3BYSF3JD.js +17 -0
  29. package/dist/{hook-CRJMWSSO.js → hook-2NP3UE7U.js} +2 -2
  30. package/dist/{register-commands-JHC2OFKM.js → register-commands-DPH4ZWEE.js} +621 -60
  31. package/dist/register-commands-DPH4ZWEE.js.map +1 -0
  32. package/dist/uninstall-FDIOBAAR.js +15 -0
  33. package/dist/uninstall-FDIOBAAR.js.map +1 -0
  34. package/dist/update-RAF7QRYF.js +11 -0
  35. package/dist/update-RAF7QRYF.js.map +1 -0
  36. package/dist/{wiki-IPSRRGOT.js → wiki-IGNRNLUZ.js} +2 -2
  37. package/hooks/almanac-capture.sh +40 -7
  38. package/package.json +3 -2
  39. package/dist/chunk-3C5SY5SE.js.map +0 -1
  40. package/dist/chunk-3LC55TG6.js.map +0 -1
  41. package/dist/chunk-AXFPUHBN.js.map +0 -1
  42. package/dist/chunk-Z4MWLVS2.js.map +0 -1
  43. package/dist/cli-W3OYVJYH.js.map +0 -1
  44. package/dist/doctor-ODFNJUKH.js +0 -15
  45. package/dist/register-commands-JHC2OFKM.js.map +0 -1
  46. package/dist/uninstall-HE2Z2LN2.js +0 -12
  47. package/dist/update-IL243I4E.js +0 -10
  48. /package/dist/{doctor-ODFNJUKH.js.map → agents-A4II4YJC.js.map} +0 -0
  49. /package/dist/{hook-CRJMWSSO.js.map → auth-S5DVUIUJ.js.map} +0 -0
  50. /package/dist/{chunk-BJVZLP6O.js.map → chunk-MX2EW5MR.js.map} +0 -0
  51. /package/dist/{uninstall-HE2Z2LN2.js.map → doctor-3BYSF3JD.js.map} +0 -0
  52. /package/dist/{update-IL243I4E.js.map → hook-2NP3UE7U.js.map} +0 -0
  53. /package/dist/{wiki-IPSRRGOT.js.map → wiki-IGNRNLUZ.js.map} +0 -0
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/commands/hook.ts","../src/commands/hook/script.ts"],"sourcesContent":["import { existsSync } from \"node:fs\";\nimport { mkdir, readFile, rename, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\n\nimport {\n copyToStableHooksDir,\n resolveHookScriptPath,\n resolveSettingsPath,\n type ScriptResolution,\n} from \"./hook/script.js\";\n\n/**\n * `almanac hook install|uninstall|status` — wires the bundled\n * `hooks/almanac-capture.sh` into `~/.claude/settings.json` as a\n * `SessionEnd` hook.\n *\n * Design notes:\n *\n * - **Schema.** Claude Code validates `settings.json` against a strict\n * schema: each entry in an event array (like `SessionEnd`) is a\n * `{matcher, hooks: [...]}` container, and the actual command objects\n * live in the nested `hooks` array. v0.1.0–v0.1.4 wrote command objects\n * directly at the event-array level; newer Claude Code versions now\n * reject that shape. We produce the wrapped form on install, and when\n * encountering a legacy unwrapped entry that we recognize as ours (by\n * `command` ending in `almanac-capture.sh`) we migrate it on next\n * install. `SessionEnd` never uses the `matcher` field to discriminate\n * anything — we always emit an empty `matcher: \"\"` (matches\n * everything, which is what session-end lifecycle hooks want).\n *\n * - **Idempotent.** `install` twice leaves one entry, not two. We match by\n * `command` string equality on the inner `hooks[]` entries. If the user\n * replaces our absolute path with a symlink pointing at the same\n * script, we'll treat it as foreign. That's acceptable; the `status`\n * output shows the path we'd use, so the user can reconcile manually.\n *\n * - **Refuse foreign entries.** If `SessionEnd` is already populated with\n * a command we don't recognize, we print the existing value and exit\n * non-zero. Claude Code lets users wire their own hooks (notifications,\n * git autocommit scripts, etc.) and silently replacing them would be\n * rude. Foreign wrapped containers that don't reference our script are\n * preserved byte-for-byte.\n *\n * - **Atomic write.** `settings.json` is small but heavily touched by\n * Claude Code. Writing via tmp-file + rename avoids corrupting the file\n * if we crash mid-write.\n *\n * - **Non-interactive.** No prompts, no confirmations. The caller is\n * already making an intentional choice by running `almanac hook\n * install`.\n */\n\nexport interface HookCommandOptions {\n /**\n * Override the hook script path. Production code leaves this undefined\n * and we resolve the bundled `hooks/almanac-capture.sh`. Tests pass a\n * fixture path to avoid depending on the runtime-install layout.\n */\n hookScriptPath?: string;\n /**\n * Override `~/.claude/settings.json`. Tests sandbox this to a tmpdir;\n * production code leaves it undefined.\n */\n settingsPath?: string;\n /**\n * Override the stable hooks directory where we copy the script.\n * Defaults to `~/.claude/hooks/`. Tests sandbox this to a tmpdir.\n *\n * Bug #1 fix: we always copy the bundled script to this stable path\n * before writing it into settings.json. This way the settings entry\n * points at a user-owned location that survives npm version bumps,\n * npx cache evictions, and nvm version switches — instead of an\n * ephemeral path inside ~/.npm/_npx/<sha>/... or the nvm-versioned\n * node_modules/.\n */\n stableHooksDir?: string;\n}\n\nexport interface HookCommandResult {\n stdout: string;\n stderr: string;\n exitCode: number;\n}\n\nconst HOOK_TIMEOUT_SECONDS = 10;\n\n/** A single command invocation inside a wrapper's `hooks[]` array. */\ninterface HookCommand {\n type: \"command\";\n command: string;\n timeout?: number;\n}\n\n/** A wrapped SessionEnd entry per Claude Code's schema. */\ninterface WrappedEntry {\n matcher: string;\n hooks: HookCommand[];\n}\n\n/**\n * What we read from `settings.hooks.SessionEnd`. During a read we may\n * encounter the legacy unwrapped shape (`HookCommand` directly) written\n * by v0.1.0–v0.1.4 — we recognize and migrate it. Unknown entries we\n * can't classify are preserved as-is via `unknown`.\n */\ntype RawEntry = WrappedEntry | HookCommand | unknown;\n\n/**\n * Claude Code's `settings.json` is a free-form JSON object; we only care\n * about the `hooks.SessionEnd` array. Preserve everything else verbatim\n * so we don't drop user settings when we write the file back.\n */\ntype SettingsJson = Record<string, unknown> & {\n hooks?: Record<string, RawEntry[] | undefined>;\n};\n\n/**\n * Heuristic: does this command path look like one we installed?\n *\n * We match on the filename `almanac-capture.sh` regardless of the parent\n * directory. This covers:\n * - the stable path: `~/.claude/hooks/almanac-capture.sh`\n * - legacy paths from v0.1.0–v0.1.5: inside the nvm node_modules or\n * npx cache\n * The stable path is what new installs produce; legacy paths are what\n * we migrate when the user runs `almanac hook install` again.\n */\nfunction isOurCommandPath(command: string): boolean {\n return command.endsWith(\"almanac-capture.sh\");\n}\n\n/**\n * Classify a raw SessionEnd entry. Wrapped entries are the canonical\n * shape; unwrapped-command entries are legacy output from v0.1.0–v0.1.4.\n * Anything else (random user JSON) is `unknown` and we leave it alone.\n */\ntype Classified =\n | { kind: \"wrapped\"; entry: WrappedEntry }\n | { kind: \"legacy\"; entry: HookCommand }\n | { kind: \"unknown\"; entry: unknown };\n\nfunction classifyEntry(raw: RawEntry): Classified {\n if (raw === null || typeof raw !== \"object\") {\n return { kind: \"unknown\", entry: raw };\n }\n const obj = raw as Record<string, unknown>;\n if (Array.isArray(obj.hooks)) {\n // Wrapped shape. `matcher` may be absent in hand-edited files; treat\n // absent as \"\" so we don't throw on slightly malformed input.\n const matcher = typeof obj.matcher === \"string\" ? obj.matcher : \"\";\n const hooks: HookCommand[] = [];\n for (const h of obj.hooks as unknown[]) {\n if (h !== null && typeof h === \"object\") {\n const ho = h as Record<string, unknown>;\n if (ho.type === \"command\" && typeof ho.command === \"string\") {\n const cmd: HookCommand = {\n type: \"command\",\n command: ho.command,\n };\n if (typeof ho.timeout === \"number\") cmd.timeout = ho.timeout;\n hooks.push(cmd);\n }\n }\n }\n return { kind: \"wrapped\", entry: { matcher, hooks } };\n }\n if (obj.type === \"command\" && typeof obj.command === \"string\") {\n // Legacy unwrapped shape — v0.1.0–v0.1.4 wrote this form.\n const cmd: HookCommand = {\n type: \"command\",\n command: obj.command as string,\n };\n if (typeof obj.timeout === \"number\") cmd.timeout = obj.timeout;\n return { kind: \"legacy\", entry: cmd };\n }\n return { kind: \"unknown\", entry: raw };\n}\n\n/** True when the entry references our script and is safely ours to manage. */\nfunction isOurWrapped(entry: WrappedEntry): boolean {\n return entry.hooks.some((h) => isOurCommandPath(h.command));\n}\n\nexport async function runHookInstall(\n options: HookCommandOptions = {},\n): Promise<HookCommandResult> {\n const bundled = resolveHookScriptPath(options);\n if (!bundled.ok) {\n return { stdout: \"\", stderr: `almanac: ${bundled.error}\\n`, exitCode: 1 };\n }\n\n // Copy the bundled hook script to a stable user-owned location before\n // writing that path into settings.json. This is the Bug #1 fix:\n //\n // OLD behavior: settings.json pointed at the bundled path (inside\n // ~/.nvm/versions/node/<ver>/lib/node_modules/codealmanac/hooks/... or\n // ~/.npm/_npx/<sha>/node_modules/codealmanac/hooks/...). When the user\n // switches Node versions or the npx cache is evicted, the path breaks\n // silently and captures stop firing.\n //\n // NEW behavior: we copy almanac-capture.sh to ~/.claude/hooks/ (same\n // directory Claude Code uses for its own built-in hooks, always present)\n // and point settings.json there. The stable path is independent of\n // Node version and npm cache state. When the user upgrades codealmanac,\n // `almanac hook install` copies a fresh script and updates settings.json\n // if the path changed.\n //\n // When `hookScriptPath` is explicitly provided (test injection), the\n // caller has already specified the destination path — skip the copy and\n // use that path directly. The stable-copy concern only applies to the\n // production flow where we resolved from the bundled package layout.\n const script: ScriptResolution = options.hookScriptPath !== undefined\n ? bundled // already the caller-provided path, no copy needed\n : await copyToStableHooksDir(bundled.path, options);\n if (!script.ok) {\n return { stdout: \"\", stderr: `almanac: ${script.error}\\n`, exitCode: 1 };\n }\n\n const settingsPath = resolveSettingsPath(options);\n const settings = await readSettings(settingsPath);\n const existing = (settings.hooks?.SessionEnd ?? []).slice();\n\n // Walk existing entries and split them into buckets:\n // - `preserved` — foreign wrapped/unknown entries we leave alone.\n // - `oursAlready` — a wrapped entry that already points at OUR exact\n // script path (makes install a no-op).\n // - `oursStale` — a wrapped or legacy entry that references our\n // capture script but at a different absolute path\n // (old install, `npm i` moved us) or in the legacy\n // unwrapped shape. We'll collapse these into a\n // single fresh entry at the new path.\n const preserved: RawEntry[] = [];\n let oursAlready: WrappedEntry | null = null;\n const staleCount = { n: 0 };\n\n for (const raw of existing) {\n const c = classifyEntry(raw);\n if (c.kind === \"wrapped\") {\n if (!isOurWrapped(c.entry)) {\n preserved.push(raw);\n continue;\n }\n // Entry belongs to us. Does it already point at the exact script\n // path? If every command in its `hooks[]` that looks like ours is\n // already at `script.path`, it's up to date.\n const exactMatch = c.entry.hooks.some(\n (h) => h.command === script.path,\n );\n if (exactMatch && oursAlready === null) {\n oursAlready = c.entry;\n } else {\n staleCount.n += 1;\n }\n } else if (c.kind === \"legacy\") {\n if (isOurCommandPath(c.entry.command)) {\n // Legacy unwrapped entry of ours — always migrate to wrapped.\n staleCount.n += 1;\n } else {\n // Foreign legacy entry (user had their own script before\n // settings.json required wrapping). Leave it alone.\n preserved.push(raw);\n }\n } else {\n // Unknown shape — we can't classify it. Preserve verbatim.\n preserved.push(raw);\n }\n }\n\n // If every non-ours entry is a foreign unwrapped command (not a\n // wrapped one) we refuse to touch the file — Claude Code's newer\n // schema will already reject such files, but surfacing it here lets\n // the user clean up before we stack our entry on top. Wrapped foreign\n // entries are fine to leave alongside ours.\n const foreignLegacy = preserved.filter((raw) => {\n const c = classifyEntry(raw);\n return c.kind === \"legacy\";\n });\n if (foreignLegacy.length > 0) {\n const lines = foreignLegacy\n .map((raw) => {\n const c = classifyEntry(raw);\n if (c.kind === \"legacy\") return ` - ${c.entry.command}`;\n return \" - <unrecognized>\";\n })\n .join(\"\\n\");\n return {\n stdout: \"\",\n stderr:\n `almanac: SessionEnd has a foreign legacy entry:\\n${lines}\\n` +\n `Remove or rewrap it manually in ${settingsPath} before installing.\\n`,\n exitCode: 1,\n };\n }\n\n if (oursAlready !== null && staleCount.n === 0) {\n return {\n stdout: `almanac: SessionEnd hook already installed at ${script.path}\\n`,\n stderr: \"\",\n exitCode: 0,\n };\n }\n\n // Build the fresh wrapped entry and append to preserved foreign\n // entries. Stale entries of ours are dropped (we only ever want a\n // single active entry; multiple copies of the capture hook would\n // double-fire on session end).\n const fresh: WrappedEntry = {\n matcher: \"\",\n hooks: [\n {\n type: \"command\",\n command: script.path,\n timeout: HOOK_TIMEOUT_SECONDS,\n },\n ],\n };\n\n const newEntries: RawEntry[] = [...preserved, fresh];\n\n settings.hooks = { ...(settings.hooks ?? {}), SessionEnd: newEntries };\n await writeSettings(settingsPath, settings);\n\n return {\n stdout:\n `almanac: SessionEnd hook installed\\n` +\n ` script: ${script.path}\\n` +\n ` settings: ${settingsPath}\\n`,\n stderr: \"\",\n exitCode: 0,\n };\n}\n\nexport async function runHookUninstall(\n options: HookCommandOptions = {},\n): Promise<HookCommandResult> {\n const settingsPath = resolveSettingsPath(options);\n\n if (!existsSync(settingsPath)) {\n return {\n stdout: `almanac: SessionEnd hook not installed (no settings file)\\n`,\n stderr: \"\",\n exitCode: 0,\n };\n }\n\n const settings = await readSettings(settingsPath);\n const existing = (settings.hooks?.SessionEnd ?? []).slice();\n\n const kept: RawEntry[] = [];\n let removed = 0;\n\n for (const raw of existing) {\n const c = classifyEntry(raw);\n if (c.kind === \"wrapped\") {\n // Filter out our command(s) from the inner hooks array. Keep\n // anything else in the array intact — a foreign wrapper that\n // happened to include our script alongside its own commands\n // (unusual, but survivable) loses our entry and keeps theirs.\n const innerKept = c.entry.hooks.filter(\n (h) => !isOurCommandPath(h.command),\n );\n const innerRemoved = c.entry.hooks.length - innerKept.length;\n removed += innerRemoved;\n if (innerKept.length === 0) {\n // Only drop the outer wrapper when it was entirely ours. A\n // foreign wrapper that never contained our script stays verbatim\n // below (handled by `innerRemoved === 0`, which leaves\n // `innerKept.length === c.entry.hooks.length`, hence we fall\n // through to the else-branch).\n if (innerRemoved === 0) kept.push(raw);\n // else: fully owned by us, drop the container.\n } else if (innerRemoved === 0) {\n // Untouched foreign wrapper — preserve the raw object to keep\n // any fields (like matcher) byte-for-byte.\n kept.push(raw);\n } else {\n // Partial: rebuild with just the kept inner entries, preserving\n // the original matcher string.\n kept.push({ matcher: c.entry.matcher, hooks: innerKept });\n }\n } else if (c.kind === \"legacy\") {\n if (isOurCommandPath(c.entry.command)) {\n removed += 1;\n } else {\n kept.push(raw);\n }\n } else {\n kept.push(raw);\n }\n }\n\n if (removed === 0) {\n return {\n stdout: `almanac: SessionEnd hook not installed\\n`,\n stderr: \"\",\n exitCode: 0,\n };\n }\n\n if (settings.hooks !== undefined) {\n if (kept.length === 0) {\n // Empty SessionEnd array confuses some linters; drop the key when\n // nothing's left.\n const { SessionEnd: _dropped, ...rest } = settings.hooks;\n void _dropped;\n settings.hooks = rest;\n } else {\n settings.hooks = { ...settings.hooks, SessionEnd: kept };\n }\n\n // If `hooks` itself is now empty (user had only our SessionEnd entry\n // and no other hook categories), drop the `hooks` key entirely so\n // uninstall leaves the settings file in the same shape it would be\n // in had we never run install. An empty `\"hooks\": {}` is an obvious\n // breadcrumb in commit diffs.\n if (Object.keys(settings.hooks).length === 0) {\n delete settings.hooks;\n }\n }\n\n await writeSettings(settingsPath, settings);\n\n return {\n stdout: `almanac: SessionEnd hook removed\\n`,\n stderr: \"\",\n exitCode: 0,\n };\n}\n\nexport async function runHookStatus(\n options: HookCommandOptions = {},\n): Promise<HookCommandResult> {\n const script = resolveHookScriptPath(options);\n const settingsPath = resolveSettingsPath(options);\n\n if (!existsSync(settingsPath)) {\n return {\n stdout:\n `SessionEnd hook: not installed\\n` +\n `settings: ${settingsPath} (does not exist)\\n` +\n (script.ok ? `script would be: ${script.path}\\n` : \"\"),\n stderr: \"\",\n exitCode: 0,\n };\n }\n\n const settings = await readSettings(settingsPath);\n const existing = settings.hooks?.SessionEnd ?? [];\n\n // Walk the array looking for any entry (wrapped or legacy) that\n // references our capture script. Gathering foreign entries separately\n // lets us show them to the user if nothing of ours was found.\n let ourCommand: string | null = null;\n const foreignSummary: string[] = [];\n for (const raw of existing) {\n const c = classifyEntry(raw);\n if (c.kind === \"wrapped\") {\n for (const h of c.entry.hooks) {\n if (isOurCommandPath(h.command)) {\n ourCommand ??= h.command;\n } else {\n foreignSummary.push(h.command);\n }\n }\n } else if (c.kind === \"legacy\") {\n if (isOurCommandPath(c.entry.command)) {\n ourCommand ??= c.entry.command;\n } else {\n foreignSummary.push(c.entry.command);\n }\n }\n }\n\n if (ourCommand === null) {\n const foreignLines = foreignSummary\n .map((c) => ` - ${c}`)\n .join(\"\\n\");\n return {\n stdout:\n `SessionEnd hook: not installed\\n` +\n `settings: ${settingsPath}\\n` +\n (foreignSummary.length > 0\n ? `(${foreignSummary.length} foreign entr${foreignSummary.length === 1 ? \"y\" : \"ies\"} present:\\n${foreignLines})\\n`\n : \"\") +\n (script.ok ? `script would be: ${script.path}\\n` : \"\"),\n stderr: \"\",\n exitCode: 0,\n };\n }\n\n return {\n stdout:\n `SessionEnd hook: installed\\n` +\n `script: ${ourCommand}\\n` +\n `settings: ${settingsPath}\\n`,\n stderr: \"\",\n exitCode: 0,\n };\n}\n\n// ─── Settings JSON helpers ───────────────────────────────────────────\n\nasync function readSettings(settingsPath: string): Promise<SettingsJson> {\n if (!existsSync(settingsPath)) return {};\n try {\n const raw = await readFile(settingsPath, \"utf8\");\n if (raw.trim().length === 0) return {};\n const parsed = JSON.parse(raw) as unknown;\n if (parsed === null || typeof parsed !== \"object\") return {};\n return parsed as SettingsJson;\n } catch (err: unknown) {\n const msg = err instanceof Error ? err.message : String(err);\n throw new Error(`failed to read ${settingsPath}: ${msg}`);\n }\n}\n\nasync function writeSettings(\n settingsPath: string,\n settings: SettingsJson,\n): Promise<void> {\n const dir = path.dirname(settingsPath);\n await mkdir(dir, { recursive: true });\n\n // Atomic write: JSON.stringify → tmp file → rename. `rename` within the\n // same filesystem is atomic on POSIX; Claude Code never sees a partial\n // file. Formatted with 2-space indent to match the existing settings.\n const tmp = `${settingsPath}.almanac-tmp-${process.pid}`;\n const body = `${JSON.stringify(settings, null, 2)}\\n`;\n await writeFile(tmp, body, \"utf8\");\n await rename(tmp, settingsPath);\n}\n","import { existsSync } from \"node:fs\";\nimport { copyFile, mkdir, readFile } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nexport interface HookPathOptions {\n hookScriptPath?: string;\n settingsPath?: string;\n stableHooksDir?: string;\n}\n\nexport type ScriptResolution =\n | { ok: true; path: string }\n | { ok: false; error: string };\n\nexport function resolveSettingsPath(options: HookPathOptions): string {\n if (options.settingsPath !== undefined) return options.settingsPath;\n return path.join(homedir(), \".claude\", \"settings.json\");\n}\n\n/**\n * Copy the bundled hook script to `~/.claude/hooks/almanac-capture.sh`.\n *\n * This stable, user-owned destination survives Node version switches and\n * npm/npx cache evictions. The copy is idempotent: if bytes already match\n * we skip writing so repeated setup runs do not bump mtimes.\n */\nexport async function copyToStableHooksDir(\n bundledPath: string,\n options: HookPathOptions,\n): Promise<ScriptResolution> {\n const stableHooksDir =\n options.stableHooksDir ?? path.join(homedir(), \".claude\", \"hooks\");\n const dest = path.join(stableHooksDir, \"almanac-capture.sh\");\n\n try {\n await mkdir(stableHooksDir, { recursive: true });\n const srcBytes = await readFile(bundledPath);\n let needsCopy = true;\n if (existsSync(dest)) {\n try {\n const destBytes = await readFile(dest);\n if (srcBytes.equals(destBytes)) needsCopy = false;\n } catch {\n // Can't read dest — overwrite.\n }\n }\n if (needsCopy) {\n await copyFile(bundledPath, dest);\n }\n return { ok: true, path: dest };\n } catch (err: unknown) {\n const msg = err instanceof Error ? err.message : String(err);\n return {\n ok: false,\n error: `could not copy hook script to ${dest}: ${msg}`,\n };\n }\n}\n\n/**\n * Locate the bundled `hooks/almanac-capture.sh`. Mirrors\n * `resolvePromptsDir` from `src/agent/prompts.ts`: two plausible layouts\n * (installed dist vs. source dev), probe each.\n */\nexport function resolveHookScriptPath(\n options: HookPathOptions,\n): ScriptResolution {\n if (options.hookScriptPath !== undefined) {\n return { ok: true, path: options.hookScriptPath };\n }\n\n const here = path.dirname(fileURLToPath(import.meta.url));\n\n const candidates = [\n // Bundled: `.../codealmanac/dist/codealmanac.js` → `../hooks/…`\n path.resolve(here, \"..\", \"hooks\", \"almanac-capture.sh\"),\n // Source after ts-node-style module layout or nested dist helpers.\n path.resolve(here, \"..\", \"..\", \"hooks\", \"almanac-capture.sh\"),\n // Source: `.../codealmanac/src/commands/hook/script.ts` → `../../../hooks/…`\n path.resolve(here, \"..\", \"..\", \"..\", \"hooks\", \"almanac-capture.sh\"),\n // Defensive nested fallback.\n path.resolve(here, \"..\", \"..\", \"..\", \"..\", \"hooks\", \"almanac-capture.sh\"),\n ];\n\n for (const candidate of candidates) {\n if (existsSync(candidate)) {\n return { ok: true, path: candidate };\n }\n }\n\n return {\n ok: false,\n error:\n `could not locate hooks/almanac-capture.sh. Tried:\\n` +\n candidates.map((c) => ` - ${c}`).join(\"\\n\"),\n };\n}\n"],"mappings":"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","names":["existsSync","mkdir","readFile","path","existsSync","readFile","path","mkdir"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/cli.ts","../src/cli/help.ts","../src/update/announce.ts"],"sourcesContent":["import { createRequire } from \"node:module\";\nimport { basename } from \"node:path\";\n\nimport { Command } from \"commander\";\n\nimport { runSetup } from \"./commands/setup.js\";\nimport { configureGroupedHelp } from \"./cli/help.js\";\nimport { emit } from \"./cli/helpers.js\";\nimport { announceUpdateIfAvailable } from \"./update/announce.js\";\nimport {\n runInternalUpdateCheck,\n scheduleBackgroundUpdateCheck,\n} from \"./update/schedule.js\";\n\n/**\n * Optional dependency overrides for `run`. Tests use these to avoid\n * spawning the real setup wizard, the real update background check,\n * and the real update banner. Production callers pass nothing.\n */\nexport interface RunDeps {\n /** Replace the setup wizard (bare `codealmanac` / `almanac setup`). */\n runSetup?: typeof runSetup;\n /** Replace the pre-command update-nag banner. */\n announceUpdate?: (stderr: NodeJS.WritableStream) => void;\n /** Replace the post-command background update check scheduler. */\n scheduleUpdateCheck?: (argv: string[]) => void;\n /** Replace the internal update-check worker (run on --internal-check-updates). */\n runInternalUpdateCheck?: () => Promise<void>;\n}\n\n/**\n * Process-level CLI entrypoint. This owns invocation-level behavior:\n * update checks, bare `codealmanac` setup routing, Commander creation,\n * grouped help, and parsing. Individual command wiring lives in\n * `src/cli/register-commands.ts`.\n */\nexport async function run(argv: string[], deps: RunDeps = {}): Promise<void> {\n const runSetupFn = deps.runSetup ?? runSetup;\n const announceUpdateFn = deps.announceUpdate ?? announceUpdateIfAvailable;\n const scheduleUpdateCheckFn =\n deps.scheduleUpdateCheck ?? scheduleBackgroundUpdateCheck;\n const runInternalUpdateCheckFn =\n deps.runInternalUpdateCheck ?? runInternalUpdateCheck;\n\n if (argv.slice(2).includes(\"--internal-check-updates\")) {\n await runInternalUpdateCheckFn();\n return;\n }\n\n const programName = getProgramName(argv);\n\n announceUpdateFn(process.stderr);\n scheduleUpdateCheckFn(argv);\n\n const program = new Command();\n program\n .name(programName)\n .description(\n \"codealmanac — a living wiki for codebases, maintained by AI agents\",\n )\n .version(readPackageVersion(), \"-v, --version\", \"print version\");\n\n if (isRootVersionInvocation(argv.slice(2))) {\n await program.parseAsync(argv);\n return;\n }\n\n if (programName === \"codealmanac\") {\n const setupInvocation = tryParseSetupShortcut(argv.slice(2));\n if (setupInvocation !== null) {\n emit(await runSetupFn(setupInvocation));\n return;\n }\n }\n\n if (await tryRunSqliteFreeCommand(argv.slice(2), runSetupFn)) {\n return;\n }\n\n const { registerCommands } = await import(\"./cli/register-commands.js\");\n registerCommands(program);\n configureGroupedHelp(program);\n\n await program.parseAsync(argv);\n}\n\nfunction getProgramName(argv: string[]): \"almanac\" | \"codealmanac\" {\n const invoked = argv[1] !== undefined ? basename(argv[1]) : \"almanac\";\n return invoked === \"codealmanac\" ? \"codealmanac\" : \"almanac\";\n}\n\nfunction isRootVersionInvocation(args: string[]): boolean {\n return args.length === 1 && (args[0] === \"--version\" || args[0] === \"-v\");\n}\n\nfunction parseSetupFlags(args: string[]): {\n yes?: boolean;\n skipHook?: boolean;\n skipGuides?: boolean;\n} {\n return {\n yes: args.includes(\"--yes\") || args.includes(\"-y\"),\n skipHook: args.includes(\"--skip-hook\"),\n skipGuides: args.includes(\"--skip-guides\"),\n };\n}\n\nfunction parseUpdateFlags(args: string[]): {\n dismiss?: boolean;\n check?: boolean;\n enableNotifier?: boolean;\n disableNotifier?: boolean;\n} {\n return {\n dismiss: args.includes(\"--dismiss\"),\n check: args.includes(\"--check\"),\n enableNotifier: args.includes(\"--enable-notifier\"),\n disableNotifier: args.includes(\"--disable-notifier\"),\n };\n}\n\nfunction parseUninstallFlags(args: string[]): {\n yes?: boolean;\n keepHook?: boolean;\n keepGuides?: boolean;\n} {\n return {\n yes: args.includes(\"--yes\") || args.includes(\"-y\"),\n keepHook: args.includes(\"--keep-hook\"),\n keepGuides: args.includes(\"--keep-guides\"),\n };\n}\n\nfunction parseDoctorFlags(args: string[]): {\n json?: boolean;\n installOnly?: boolean;\n wikiOnly?: boolean;\n} {\n return {\n json: args.includes(\"--json\"),\n installOnly: args.includes(\"--install-only\"),\n wikiOnly: args.includes(\"--wiki-only\"),\n };\n}\n\nasync function tryRunSqliteFreeCommand(\n args: string[],\n runSetupFn: typeof runSetup,\n): Promise<boolean> {\n if (args.includes(\"--help\") || args.includes(\"-h\")) return false;\n\n const [command, subcommand] = args;\n if (command === undefined) return false;\n\n if (command === \"setup\") {\n emit(await runSetupFn(parseSetupFlags(args.slice(1))));\n return true;\n }\n\n if (command === \"hook\") {\n const { runHookInstall, runHookStatus, runHookUninstall } = await import(\n \"./commands/hook.js\"\n );\n if (subcommand === \"install\") {\n emit(await runHookInstall());\n return true;\n }\n if (subcommand === \"uninstall\") {\n emit(await runHookUninstall());\n return true;\n }\n if (subcommand === \"status\") {\n emit(await runHookStatus());\n return true;\n }\n return false;\n }\n\n if (command === \"update\") {\n const { runUpdate } = await import(\"./commands/update.js\");\n emit(await runUpdate(parseUpdateFlags(args.slice(1))));\n return true;\n }\n\n if (command === \"doctor\") {\n const { runDoctor } = await import(\"./commands/doctor.js\");\n emit(await runDoctor({\n cwd: process.cwd(),\n ...parseDoctorFlags(args.slice(1)),\n }));\n return true;\n }\n\n if (command === \"uninstall\") {\n const { runUninstall } = await import(\"./commands/uninstall.js\");\n emit(await runUninstall(parseUninstallFlags(args.slice(1))));\n return true;\n }\n\n return false;\n}\n\nfunction readPackageVersion(): string {\n try {\n const require = createRequire(import.meta.url);\n const pkg = require(\"../package.json\") as { version?: unknown };\n if (typeof pkg.version === \"string\" && pkg.version.length > 0) {\n return pkg.version;\n }\n } catch {\n // Fall back to \"unknown\" rather than crashing the CLI on a broken install.\n }\n return \"unknown\";\n}\n\nexport interface SetupShortcutOptions {\n yes?: boolean;\n skipHook?: boolean;\n skipGuides?: boolean;\n}\n\n/**\n * Decide whether a bare `codealmanac [...args]` invocation should route\n * straight to `runSetup` (and if so, with which flags). Returns the\n * options object when it's a setup shortcut, or `null` when Commander\n * should parse the invocation normally.\n */\nexport function tryParseSetupShortcut(args: string[]): SetupShortcutOptions | null {\n if (args.length === 0) return {};\n\n const opts: SetupShortcutOptions = {};\n for (const arg of args) {\n if (arg === \"--yes\" || arg === \"-y\") {\n opts.yes = true;\n continue;\n }\n if (arg === \"--skip-hook\") {\n opts.skipHook = true;\n continue;\n }\n if (arg === \"--skip-guides\") {\n opts.skipGuides = true;\n continue;\n }\n return null;\n }\n return opts;\n}\n","import { Command, type Help } from \"commander\";\n\nimport { BLUE, BOLD, DIM, RST } from \"../ansi.js\";\n\nconst HELP_GROUPS: Array<{ title: string; commands: string[] }> = [\n {\n title: \"Query\",\n commands: [\"search\", \"show\", \"health\", \"list\"],\n },\n {\n title: \"Edit\",\n commands: [\"tag\", \"untag\", \"topics\"],\n },\n {\n title: \"Wiki lifecycle\",\n commands: [\"bootstrap\", \"capture\", \"hook\", \"reindex\"],\n },\n {\n title: \"Setup\",\n commands: [\"setup\", \"uninstall\", \"doctor\", \"update\"],\n },\n];\n\n/**\n * Install a custom `formatHelp` that replaces commander's flat\n * \"Commands:\" section with grouped headings. Keeps usage + options +\n * per-command short descriptions; only the commands section changes.\n */\nexport function configureGroupedHelp(program: Command): void {\n program.configureHelp({\n formatHelp(cmd, helper): string {\n if (cmd.parent !== null) {\n return renderDefault(cmd, helper);\n }\n\n const termWidth = helper.padWidth(cmd, helper);\n const helpWidth =\n helper.helpWidth ?? process.stdout.columns ?? 80;\n const itemSepWidth = 2;\n\n const out: string[] = [];\n out.push(`${BOLD}Usage:${RST} ${helper.commandUsage(cmd)}\\n`);\n\n const description = helper.commandDescription(cmd);\n if (description.length > 0) {\n out.push(\n helper.wrap(description, helpWidth, 0) + \"\\n\",\n );\n }\n\n const optionList = helper\n .visibleOptions(cmd)\n .map((o) => {\n const term = helper.optionTerm(o);\n const pad = \" \".repeat(Math.max(0, termWidth - term.length) + itemSepWidth);\n return `${BLUE}${term}${RST}${pad}${DIM}${helper.optionDescription(o)}${RST}`;\n });\n if (optionList.length > 0) {\n out.push(`${BOLD}Options:${RST}`);\n for (const l of optionList) out.push(` ${l}`);\n out.push(\"\");\n }\n\n const visible = helper.visibleCommands(cmd);\n const byName = new Map<string, (typeof visible)[number]>();\n for (const c of visible) byName.set(c.name(), c);\n\n for (const group of HELP_GROUPS) {\n const members = group.commands\n .map((n) => byName.get(n))\n .filter((c): c is (typeof visible)[number] => c !== undefined);\n if (members.length === 0) continue;\n out.push(`${BOLD}${group.title}:${RST}`);\n for (const c of members) {\n const term = helper.subcommandTerm(c);\n const desc = helper.subcommandDescription(c);\n const padding = Math.max(\n 0,\n termWidth - term.length + itemSepWidth,\n );\n out.push(` ${BLUE}${term}${RST}${\" \".repeat(padding)}${DIM}${desc}${RST}`);\n byName.delete(c.name());\n }\n out.push(\"\");\n }\n\n byName.delete(\"help\");\n if (byName.size > 0) {\n out.push(`${BOLD}Other:${RST}`);\n for (const c of byName.values()) {\n const term = helper.subcommandTerm(c);\n const desc = helper.subcommandDescription(c);\n const padding = Math.max(\n 0,\n termWidth - term.length + itemSepWidth,\n );\n out.push(` ${BLUE}${term}${RST}${\" \".repeat(padding)}${DIM}${desc}${RST}`);\n }\n out.push(\"\");\n }\n\n return out.join(\"\\n\");\n },\n });\n}\n\nfunction renderDefault(cmd: Command, helper: Help): string {\n const termWidth = helper.padWidth(cmd, helper);\n const helpWidth = helper.helpWidth ?? process.stdout.columns ?? 80;\n const itemSepWidth = 2;\n\n const lines: string[] = [`${BOLD}Usage:${RST} ${helper.commandUsage(cmd)}\\n`];\n const description = helper.commandDescription(cmd);\n if (description.length > 0) {\n lines.push(helper.wrap(description, helpWidth, 0) + \"\\n\");\n }\n\n const args = helper.visibleArguments(cmd).map((a) => {\n const term = helper.argumentTerm(a);\n const pad = \" \".repeat(Math.max(0, termWidth - term.length) + itemSepWidth);\n return `${BLUE}${term}${RST}${pad}${DIM}${helper.argumentDescription(a)}${RST}`;\n });\n if (args.length > 0) {\n lines.push(`${BOLD}Arguments:${RST}`);\n for (const a of args) lines.push(` ${a}`);\n lines.push(\"\");\n }\n\n const opts = helper.visibleOptions(cmd).map((o) => {\n const term = helper.optionTerm(o);\n const pad = \" \".repeat(Math.max(0, termWidth - term.length) + itemSepWidth);\n return `${BLUE}${term}${RST}${pad}${DIM}${helper.optionDescription(o)}${RST}`;\n });\n if (opts.length > 0) {\n lines.push(`${BOLD}Options:${RST}`);\n for (const o of opts) lines.push(` ${o}`);\n lines.push(\"\");\n }\n\n const subs = helper.visibleCommands(cmd).map((c) => {\n const term = helper.subcommandTerm(c);\n const pad = \" \".repeat(Math.max(0, termWidth - term.length) + itemSepWidth);\n return `${BLUE}${term}${RST}${pad}${DIM}${helper.subcommandDescription(c)}${RST}`;\n });\n if (subs.length > 0) {\n lines.push(`${BOLD}Commands:${RST}`);\n for (const s of subs) lines.push(` ${s}`);\n lines.push(\"\");\n }\n\n return lines.join(\"\\n\");\n}\n","import { readFileSync } from \"node:fs\";\nimport { createRequire } from \"node:module\";\n\nimport { getConfigPath } from \"./config.js\";\nimport { isNewer } from \"./semver.js\";\nimport { getStatePath, type UpdateState } from \"./state.js\";\n\n/**\n * Pre-command update-nag banner. Runs synchronously at the very top of\n * every `run()` invocation, before commander even touches argv. Prints\n * one line to stderr if:\n *\n * 1. `~/.almanac/update-state.json` exists and parses.\n * 2. `latest_version` is strictly newer than `installed_version`.\n * 3. `latest_version` is NOT in `dismissed_versions`.\n * 4. `~/.almanac/config.json`.`update_notifier` is not `false`.\n *\n * Otherwise silent. Deliberately synchronous and filesystem-blocking:\n * this runs in the CLI critical path and waiting on a Promise would\n * force every command to become async upfront. The files are tiny\n * (<1KB each); a sync read is cheap.\n *\n * Why stderr: agents and scripts parse stdout; stderr is the\n * conventional channel for diagnostics and nags. A tool piping\n * `almanac search` into `xargs` shouldn't see the banner mixed into\n * its slug list. Users running interactively see stderr anyway, so\n * the nag is visible in practice.\n */\n\nexport interface AnnounceOptions {\n statePath?: string;\n configPath?: string;\n /** Override for tests — normally reads from package.json at import time. */\n installedVersion?: string;\n /** Enable ANSI coloring regardless of isTTY. Tests pass `false`. */\n color?: boolean;\n}\n\nconst RST = \"\\x1b[0m\";\nconst BOLD = \"\\x1b[1m\";\nconst YELLOW = \"\\x1b[33m\";\n\nexport function announceUpdateIfAvailable(\n stderr: NodeJS.WritableStream,\n opts: AnnounceOptions = {},\n): void {\n const statePath = opts.statePath ?? getStatePath();\n const configPath = opts.configPath ?? getConfigPath();\n const installed = opts.installedVersion ?? readInstalledVersion();\n\n // Config gate. Must be checked before state: a user who disabled the\n // notifier shouldn't pay even a state-file read.\n if (!shouldNotify(configPath)) return;\n\n const state = readStateSync(statePath);\n if (state === null) return;\n if (state.latest_version.length === 0) return;\n if (!isNewer(state.latest_version, installed)) return;\n if (state.dismissed_versions.includes(state.latest_version)) return;\n\n const useColor =\n opts.color ?? (process.stderr.isTTY === true && !(\"NO_COLOR\" in process.env));\n const warn = useColor ? `${YELLOW}${BOLD}\\u26a0${RST}` : \"!\";\n const cmd = useColor ? `${BOLD}almanac update${RST}` : \"almanac update\";\n stderr.write(\n `${warn} codealmanac ${state.latest_version} available ` +\n `(you're on ${installed}) — run: ${cmd}\\n`,\n );\n}\n\n/**\n * Sync-read the state file. Returns `null` when missing, empty, or\n * malformed — the announce path MUST NOT throw into the CLI critical\n * path. Avoids the `async readState` used by the worker because\n * `run()` would otherwise need `await announceUpdateIfAvailable(...)`\n * on every invocation, which turns into a multi-millisecond penalty\n * on commands that don't care.\n */\nfunction readStateSync(path: string): UpdateState | null {\n let raw: string;\n try {\n raw = readFileSync(path, \"utf8\");\n } catch {\n return null;\n }\n const trimmed = raw.trim();\n if (trimmed.length === 0) return null;\n try {\n const parsed = JSON.parse(trimmed) as Partial<UpdateState>;\n return {\n last_check_at:\n typeof parsed.last_check_at === \"number\" ? parsed.last_check_at : 0,\n installed_version:\n typeof parsed.installed_version === \"string\"\n ? parsed.installed_version\n : \"\",\n latest_version:\n typeof parsed.latest_version === \"string\" ? parsed.latest_version : \"\",\n dismissed_versions: Array.isArray(parsed.dismissed_versions)\n ? parsed.dismissed_versions.filter(\n (v): v is string => typeof v === \"string\",\n )\n : [],\n };\n } catch {\n return null;\n }\n}\n\nfunction shouldNotify(configPath: string): boolean {\n let raw: string;\n try {\n raw = readFileSync(configPath, \"utf8\");\n } catch {\n return true; // no config file → default notify on\n }\n const trimmed = raw.trim();\n if (trimmed.length === 0) return true;\n try {\n const parsed = JSON.parse(trimmed) as { update_notifier?: unknown };\n if (parsed.update_notifier === false) return false;\n return true;\n } catch {\n return true;\n }\n}\n\nfunction readInstalledVersion(): string {\n // Dev: `src/update/announce.ts` → `../../package.json`. Bundled:\n // `dist/codealmanac.js` → `../package.json`. Try both.\n try {\n const require = createRequire(import.meta.url);\n const pkg = require(\"../../package.json\") as { version?: unknown };\n if (typeof pkg.version === \"string\" && pkg.version.length > 0) {\n return pkg.version;\n }\n } catch {\n // Fall through.\n }\n try {\n const require = createRequire(import.meta.url);\n const pkg = require(\"../package.json\") as { version?: unknown };\n if (typeof pkg.version === \"string\" && pkg.version.length > 0) {\n return pkg.version;\n }\n } catch {\n // Fall through.\n }\n return \"unknown\";\n}\n"],"mappings":"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","names":["createRequire","RST","BOLD","require","require","createRequire"]}
@@ -1,15 +0,0 @@
1
- #!/usr/bin/env node
2
- import {
3
- runDoctor
4
- } from "./chunk-QLHJP2XK.js";
5
- import "./chunk-4CODZRHH.js";
6
- import "./chunk-QHQ6YH7U.js";
7
- import "./chunk-FM3VRDK7.js";
8
- import "./chunk-3LC55TG6.js";
9
- import "./chunk-Z4MWLVS2.js";
10
- import "./chunk-AXFPUHBN.js";
11
- import "./chunk-7JUX4ADQ.js";
12
- export {
13
- runDoctor
14
- };
15
- //# sourceMappingURL=doctor-ODFNJUKH.js.map