@rasensio/aidlc 1.66.0 → 1.72.0

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 (149) hide show
  1. package/README.md +2 -1
  2. package/dist/autopilot/driver.d.ts +35 -2
  3. package/dist/autopilot/driver.d.ts.map +1 -1
  4. package/dist/autopilot/driver.js +650 -27
  5. package/dist/autopilot/driver.js.map +1 -1
  6. package/dist/autopilot/presets.d.ts.map +1 -1
  7. package/dist/autopilot/presets.js +5 -0
  8. package/dist/autopilot/presets.js.map +1 -1
  9. package/dist/autopilot/result.d.ts +133 -0
  10. package/dist/autopilot/result.d.ts.map +1 -0
  11. package/dist/autopilot/result.js +431 -0
  12. package/dist/autopilot/result.js.map +1 -0
  13. package/dist/autopilot/run.d.ts +2 -0
  14. package/dist/autopilot/run.d.ts.map +1 -1
  15. package/dist/autopilot/run.js +33 -6
  16. package/dist/autopilot/run.js.map +1 -1
  17. package/dist/autopilot/state.d.ts +51 -0
  18. package/dist/autopilot/state.d.ts.map +1 -1
  19. package/dist/autopilot/state.js.map +1 -1
  20. package/dist/autopilot/typed.d.ts +98 -0
  21. package/dist/autopilot/typed.d.ts.map +1 -0
  22. package/dist/autopilot/typed.js +122 -0
  23. package/dist/autopilot/typed.js.map +1 -0
  24. package/dist/cli.d.ts.map +1 -1
  25. package/dist/cli.js +2 -0
  26. package/dist/cli.js.map +1 -1
  27. package/dist/commands/hook.d.ts +37 -0
  28. package/dist/commands/hook.d.ts.map +1 -0
  29. package/dist/commands/hook.js +208 -0
  30. package/dist/commands/hook.js.map +1 -0
  31. package/dist/commands/init.d.ts +18 -0
  32. package/dist/commands/init.d.ts.map +1 -1
  33. package/dist/commands/init.js +66 -3
  34. package/dist/commands/init.js.map +1 -1
  35. package/dist/commands/knowledge.d.ts.map +1 -1
  36. package/dist/commands/knowledge.js +8 -4
  37. package/dist/commands/knowledge.js.map +1 -1
  38. package/dist/commands/roadmap.d.ts +20 -3
  39. package/dist/commands/roadmap.d.ts.map +1 -1
  40. package/dist/commands/roadmap.js +60 -15
  41. package/dist/commands/roadmap.js.map +1 -1
  42. package/dist/commands/update.d.ts.map +1 -1
  43. package/dist/commands/update.js +8 -2
  44. package/dist/commands/update.js.map +1 -1
  45. package/dist/compile/adapters/claude-code.d.ts.map +1 -1
  46. package/dist/compile/adapters/claude-code.js +35 -4
  47. package/dist/compile/adapters/claude-code.js.map +1 -1
  48. package/dist/compile/adapters/codex.d.ts +12 -0
  49. package/dist/compile/adapters/codex.d.ts.map +1 -1
  50. package/dist/compile/adapters/codex.js +58 -8
  51. package/dist/compile/adapters/codex.js.map +1 -1
  52. package/dist/compile/loaders.d.ts.map +1 -1
  53. package/dist/compile/loaders.js +2 -0
  54. package/dist/compile/loaders.js.map +1 -1
  55. package/dist/compile/skill-metadata.d.ts +82 -0
  56. package/dist/compile/skill-metadata.d.ts.map +1 -0
  57. package/dist/compile/skill-metadata.js +156 -0
  58. package/dist/compile/skill-metadata.js.map +1 -0
  59. package/dist/concurrency/claim-store.d.ts +17 -0
  60. package/dist/concurrency/claim-store.d.ts.map +1 -1
  61. package/dist/concurrency/claim-store.js +42 -2
  62. package/dist/concurrency/claim-store.js.map +1 -1
  63. package/dist/concurrency/common-dir.d.ts +15 -0
  64. package/dist/concurrency/common-dir.d.ts.map +1 -1
  65. package/dist/concurrency/common-dir.js +39 -0
  66. package/dist/concurrency/common-dir.js.map +1 -1
  67. package/dist/core/types.d.ts +17 -0
  68. package/dist/core/types.d.ts.map +1 -1
  69. package/dist/cost/hooks/arm.d.ts +9 -1
  70. package/dist/cost/hooks/arm.d.ts.map +1 -1
  71. package/dist/cost/hooks/arm.js +16 -2
  72. package/dist/cost/hooks/arm.js.map +1 -1
  73. package/dist/cost/providers/codex.d.ts +13 -0
  74. package/dist/cost/providers/codex.d.ts.map +1 -1
  75. package/dist/cost/providers/codex.js +74 -2
  76. package/dist/cost/providers/codex.js.map +1 -1
  77. package/dist/doctor/migrations/index.d.ts.map +1 -1
  78. package/dist/doctor/migrations/index.js +5 -0
  79. package/dist/doctor/migrations/index.js.map +1 -1
  80. package/dist/doctor/migrations/roadmap-mermaid-graphs.d.ts +22 -0
  81. package/dist/doctor/migrations/roadmap-mermaid-graphs.d.ts.map +1 -0
  82. package/dist/doctor/migrations/roadmap-mermaid-graphs.js +74 -0
  83. package/dist/doctor/migrations/roadmap-mermaid-graphs.js.map +1 -0
  84. package/dist/hooks/guard.d.ts +41 -0
  85. package/dist/hooks/guard.d.ts.map +1 -0
  86. package/dist/hooks/guard.js +108 -0
  87. package/dist/hooks/guard.js.map +1 -0
  88. package/dist/hooks/install.d.ts +78 -0
  89. package/dist/hooks/install.d.ts.map +1 -0
  90. package/dist/hooks/install.js +207 -0
  91. package/dist/hooks/install.js.map +1 -0
  92. package/dist/hooks/lifecycle-context.d.ts +65 -0
  93. package/dist/hooks/lifecycle-context.d.ts.map +1 -0
  94. package/dist/hooks/lifecycle-context.js +212 -0
  95. package/dist/hooks/lifecycle-context.js.map +1 -0
  96. package/dist/knowledge/engine.d.ts +19 -2
  97. package/dist/knowledge/engine.d.ts.map +1 -1
  98. package/dist/knowledge/engine.js +35 -11
  99. package/dist/knowledge/engine.js.map +1 -1
  100. package/dist/knowledge/index/knowledge-index.d.ts +28 -2
  101. package/dist/knowledge/index/knowledge-index.d.ts.map +1 -1
  102. package/dist/knowledge/index/sqlite-index.d.ts +19 -1
  103. package/dist/knowledge/index/sqlite-index.d.ts.map +1 -1
  104. package/dist/knowledge/index/sqlite-index.js +66 -5
  105. package/dist/knowledge/index/sqlite-index.js.map +1 -1
  106. package/dist/knowledge/source-fingerprint.d.ts +71 -0
  107. package/dist/knowledge/source-fingerprint.d.ts.map +1 -0
  108. package/dist/knowledge/source-fingerprint.js +105 -0
  109. package/dist/knowledge/source-fingerprint.js.map +1 -0
  110. package/dist/knowledge/sync.d.ts +12 -1
  111. package/dist/knowledge/sync.d.ts.map +1 -1
  112. package/dist/knowledge/sync.js +23 -3
  113. package/dist/knowledge/sync.js.map +1 -1
  114. package/dist/knowledge/types.d.ts +10 -1
  115. package/dist/knowledge/types.d.ts.map +1 -1
  116. package/dist/knowledge/types.js +10 -1
  117. package/dist/knowledge/types.js.map +1 -1
  118. package/dist/menu/roster.d.ts.map +1 -1
  119. package/dist/menu/roster.js +2 -0
  120. package/dist/menu/roster.js.map +1 -1
  121. package/dist/roadmap/graph.d.ts +73 -28
  122. package/dist/roadmap/graph.d.ts.map +1 -1
  123. package/dist/roadmap/graph.js +184 -125
  124. package/dist/roadmap/graph.js.map +1 -1
  125. package/dist/roadmap/next.d.ts +5 -0
  126. package/dist/roadmap/next.d.ts.map +1 -1
  127. package/dist/roadmap/next.js +7 -1
  128. package/dist/roadmap/next.js.map +1 -1
  129. package/dist/roadmap/open-browser.d.ts +34 -0
  130. package/dist/roadmap/open-browser.d.ts.map +1 -0
  131. package/dist/roadmap/open-browser.js +40 -0
  132. package/dist/roadmap/open-browser.js.map +1 -0
  133. package/dist/roadmap/paths.d.ts +5 -1
  134. package/dist/roadmap/paths.d.ts.map +1 -1
  135. package/dist/roadmap/paths.js +5 -9
  136. package/dist/roadmap/paths.js.map +1 -1
  137. package/dist/roadmap/view-assets.d.ts +18 -0
  138. package/dist/roadmap/view-assets.d.ts.map +1 -0
  139. package/dist/roadmap/view-assets.js +301 -0
  140. package/dist/roadmap/view-assets.js.map +1 -0
  141. package/dist/roadmap/view-html.d.ts +37 -0
  142. package/dist/roadmap/view-html.d.ts.map +1 -0
  143. package/dist/roadmap/view-html.js +317 -0
  144. package/dist/roadmap/view-html.js.map +1 -0
  145. package/dist/roadmap/view-model.d.ts +93 -0
  146. package/dist/roadmap/view-model.d.ts.map +1 -0
  147. package/dist/roadmap/view-model.js +194 -0
  148. package/dist/roadmap/view-model.js.map +1 -0
  149. package/package.json +2 -2
@@ -0,0 +1,108 @@
1
+ /**
2
+ * The phase guard: a Claude Code `PreToolUse` hook that asks before a code file
3
+ * is edited while the instance claimed here is still being planned
4
+ * (hooks-carry-lifecycle-state/AC-11..AC-13).
5
+ *
6
+ * The opposite contract to the reviewer guard (`compile/reviewer-guard.ts`), on
7
+ * purpose. That one fails closed because it is a security boundary for an agent
8
+ * that must not write. This one enforces a process rule — "no code before the
9
+ * design is agreed" — and the risk named for it is a hook that blocks legitimate
10
+ * work. So it only ever *asks*, and every way it can fail is silence: the
11
+ * decision falls back to the normal permission flow, never to a block (design D5).
12
+ * Writes made through `Bash` are not seen; it is a guardrail, not a boundary.
13
+ *
14
+ * Design: design.md C3
15
+ *
16
+ * @module
17
+ */
18
+ import { realpathSync } from 'node:fs';
19
+ import { isAbsolute, join, resolve } from 'node:path';
20
+ import { isWithin, toPosixRelative } from '../core/paths.js';
21
+ import { PLANNING_PHASES, claimsHere, currentPhase, plainLine } from './lifecycle-context.js';
22
+ /** The tools that write a file named in their input. */
23
+ export const GUARDED_TOOLS = ['Edit', 'Write', 'MultiEdit', 'NotebookEdit'];
24
+ function targetOf(toolInput) {
25
+ for (const key of ['file_path', 'notebook_path']) {
26
+ const value = toolInput[key];
27
+ if (typeof value === 'string' && value !== '')
28
+ return value;
29
+ }
30
+ return null;
31
+ }
32
+ /**
33
+ * The project root as written and as resolved through symlinks. Harnesses may
34
+ * name a file through either (macOS `/var` is `/private/var`), and a purely
35
+ * lexical test against only one form would call a project file "outside".
36
+ */
37
+ function rootForms(projectRoot) {
38
+ const forms = [resolve(projectRoot)];
39
+ try {
40
+ const real = realpathSync(projectRoot);
41
+ if (real !== forms[0])
42
+ forms.push(real);
43
+ }
44
+ catch {
45
+ // keep the lexical form only
46
+ }
47
+ return forms;
48
+ }
49
+ /**
50
+ * Whether to ask before this tool call, from the raw `PreToolUse` payload.
51
+ *
52
+ * Null in every case but one: a guarded tool, writing a file inside the project
53
+ * and outside `.aidlc/`, while an instance claimed here is in ideation,
54
+ * requirements or design (AC-11, AC-12). Unreadable input is null, never a throw.
55
+ */
56
+ export function guardDecision(projectRoot, raw) {
57
+ let input;
58
+ try {
59
+ input = JSON.parse(raw);
60
+ }
61
+ catch {
62
+ return null;
63
+ }
64
+ if (typeof input !== 'object' || input === null)
65
+ return null;
66
+ const { tool_name: toolName, tool_input: toolInput, cwd } = input;
67
+ if (typeof toolName !== 'string' || !GUARDED_TOOLS.includes(toolName))
68
+ return null;
69
+ if (typeof toolInput !== 'object' || toolInput === null)
70
+ return null;
71
+ const target = targetOf(toolInput);
72
+ if (target === null)
73
+ return null;
74
+ const base = typeof cwd === 'string' && isAbsolute(cwd) ? cwd : projectRoot;
75
+ const file = resolve(base, target);
76
+ const root = rootForms(projectRoot).find((r) => isWithin(r, file));
77
+ // The root itself is a directory, not a file anyone edits.
78
+ if (root === undefined || file === root || isWithin(join(root, '.aidlc'), file))
79
+ return null;
80
+ for (const instance of claimsHere(projectRoot)) {
81
+ const phase = currentPhase(projectRoot, instance);
82
+ if (phase === null || !PLANNING_PHASES.includes(phase))
83
+ continue;
84
+ const rel = toPosixRelative(root, file);
85
+ return {
86
+ instance,
87
+ phase,
88
+ file: rel,
89
+ reason: plainLine(`AIDLC: ${instance} is in the ${phase} phase; code is written in implementation. Edit ${rel} anyway?`),
90
+ };
91
+ }
92
+ return null;
93
+ }
94
+ /**
95
+ * Claude Code's `PreToolUse` answer for a decision. Always `ask` — never `deny`
96
+ * and never `allow` (AC-13): an `allow` would skip the permission prompt the
97
+ * user configured, which is not this hook's to waive.
98
+ */
99
+ export function guardOutput(decision) {
100
+ return JSON.stringify({
101
+ hookSpecificOutput: {
102
+ hookEventName: 'PreToolUse',
103
+ permissionDecision: 'ask',
104
+ permissionDecisionReason: decision.reason,
105
+ },
106
+ });
107
+ }
108
+ //# sourceMappingURL=guard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"guard.js","sourceRoot":"","sources":["../../src/hooks/guard.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEtD,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAC7D,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAE9F,wDAAwD;AACxD,MAAM,CAAC,MAAM,aAAa,GAAsB,CAAC,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,cAAc,CAAC,CAAC;AAU/F,SAAS,QAAQ,CAAC,SAAkC;IAClD,KAAK,MAAM,GAAG,IAAI,CAAC,WAAW,EAAE,eAAe,CAAC,EAAE,CAAC;QACjD,MAAM,KAAK,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC;QAC7B,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,EAAE;YAAE,OAAO,KAAK,CAAC;IAC9D,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;GAIG;AACH,SAAS,SAAS,CAAC,WAAmB;IACpC,MAAM,KAAK,GAAG,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC;IACrC,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,YAAY,CAAC,WAAW,CAAC,CAAC;QACvC,IAAI,IAAI,KAAK,KAAK,CAAC,CAAC,CAAC;YAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1C,CAAC;IAAC,MAAM,CAAC;QACP,6BAA6B;IAC/B,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,aAAa,CAAC,WAAmB,EAAE,GAAW;IAC5D,IAAI,KAAc,CAAC;IACnB,IAAI,CAAC;QACH,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC1B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAC7D,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,UAAU,EAAE,SAAS,EAAE,GAAG,EAAE,GAAG,KAAgC,CAAC;IAC7F,IAAI,OAAO,QAAQ,KAAK,QAAQ,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,QAAQ,CAAC;QAAE,OAAO,IAAI,CAAC;IACnF,IAAI,OAAO,SAAS,KAAK,QAAQ,IAAI,SAAS,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IACrE,MAAM,MAAM,GAAG,QAAQ,CAAC,SAAoC,CAAC,CAAC;IAC9D,IAAI,MAAM,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAEjC,MAAM,IAAI,GAAG,OAAO,GAAG,KAAK,QAAQ,IAAI,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,WAAW,CAAC;IAC5E,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACnC,MAAM,IAAI,GAAG,SAAS,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;IACnE,2DAA2D;IAC3D,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,KAAK,IAAI,IAAI,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,QAAQ,CAAC,EAAE,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IAE7F,KAAK,MAAM,QAAQ,IAAI,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;QAC/C,MAAM,KAAK,GAAG,YAAY,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;QAClD,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,eAAe,CAAC,QAAQ,CAAC,KAAK,CAAC;YAAE,SAAS;QACjE,MAAM,GAAG,GAAG,eAAe,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QACxC,OAAO;YACL,QAAQ;YACR,KAAK;YACL,IAAI,EAAE,GAAG;YACT,MAAM,EAAE,SAAS,CACf,UAAU,QAAQ,cAAc,KAAK,mDAAmD,GAAG,UAAU,CACtG;SACF,CAAC;IACJ,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,WAAW,CAAC,QAAuB;IACjD,OAAO,IAAI,CAAC,SAAS,CAAC;QACpB,kBAAkB,EAAE;YAClB,aAAa,EAAE,YAAY;YAC3B,kBAAkB,EAAE,KAAK;YACzB,wBAAwB,EAAE,QAAQ,CAAC,MAAM;SAC1C;KACF,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,78 @@
1
+ /**
2
+ * Installs the lifecycle hooks: the session-start hook for Claude Code and
3
+ * Codex, and the opt-in phase guard for Claude Code
4
+ * (hooks-carry-lifecycle-state/AC-14..AC-16, AC-20, AC-21).
5
+ *
6
+ * Identity is a trailing marker, as for the cost hooks, but a different one
7
+ * (design D9). With a shared marker `aidlc cost hooks status` would count a
8
+ * lifecycle hook as a cost hook and `cost hooks remove` would delete it. The cost
9
+ * installer matches `endsWith('#aidlc-cost-hook')`, which no command here
10
+ * satisfies, so neither installer sees the other's entries and the cost code is
11
+ * unchanged. The merge below is written again rather than generalised out of
12
+ * `cost/hooks/claude-code.ts` because it also writes Codex's file, and the cost
13
+ * installer's tests pin its exact behaviour.
14
+ *
15
+ * Codex trusts a hook by its content hash, and only the user's own config may
16
+ * record that hash (knowledge: `codex-hook-trust-model`). So this module writes
17
+ * the project's `.codex/hooks.json` and nothing else for Codex — never
18
+ * `~/.codex/`, never a trust hash — and writes only when the text would change,
19
+ * so installing twice cannot cost the user the trust they already gave.
20
+ *
21
+ * Design: design.md C4
22
+ *
23
+ * @module
24
+ */
25
+ export type LifecyclePlatform = 'claude-code' | 'codex';
26
+ export type LifecycleHook = 'session-start' | 'guard';
27
+ export declare const LIFECYCLE_PLATFORMS: readonly LifecyclePlatform[];
28
+ export declare const LIFECYCLE_HOOK_MARKER = "#aidlc-lifecycle-hook";
29
+ export declare const GUARD_MATCHER = "Edit|Write|MultiEdit|NotebookEdit";
30
+ /**
31
+ * The two hook commands for a platform. Both run through the cost-capture shim,
32
+ * which finds an absolute `node` and this project's CLI at run time and never
33
+ * consults `PATH` (cost-capture-goes-dark/AC-15) — a bare `aidlc` here would be a
34
+ * `PATH` lookup on every session start (design D1).
35
+ */
36
+ export declare function lifecycleCommands(platform?: LifecyclePlatform): Record<LifecycleHook, string>;
37
+ export declare function hookFilePath(projectRoot: string, platform: LifecyclePlatform): string;
38
+ /** Whether the phase guard can be installed for a platform. */
39
+ export declare function supportsGuard(platform: LifecyclePlatform): boolean;
40
+ /** The step the user still owes before the platform runs the hook, or null. */
41
+ export declare function trustStep(platform: LifecyclePlatform): string | null;
42
+ /** Whether writing a platform's hook needs the user's explicit yes (AC-18..AC-20). */
43
+ export declare function needsConsent(platform: LifecyclePlatform): boolean;
44
+ /** The command that writes a consent-gated platform's hook, for every path that does not. */
45
+ export declare function installCommand(platform: LifecyclePlatform): string;
46
+ export interface WriteResult {
47
+ /** False when the file already said exactly this. */
48
+ written: boolean;
49
+ path: string;
50
+ }
51
+ /**
52
+ * Install the session-start hook, and the guard when asked, into one platform's
53
+ * hook file (AC-15, AC-16, AC-20). Writes the shim first when it is missing or
54
+ * unusable, since every command here runs through it.
55
+ *
56
+ * @throws when the guard is asked for Codex — its `PreToolUse` can deny or
57
+ * rewrite a call but not ask, and the guard only ever asks.
58
+ */
59
+ export declare function installLifecycleHooks(projectRoot: string, opts: {
60
+ platform: LifecyclePlatform;
61
+ guard?: boolean;
62
+ }): WriteResult;
63
+ /**
64
+ * Remove the lifecycle hooks from one platform's file, or only the guard
65
+ * (AC-14, AC-16). Unmarked entries and every other key stay; a file that does
66
+ * not exist is not created.
67
+ */
68
+ export declare function removeLifecycleHooks(projectRoot: string, opts: {
69
+ platform: LifecyclePlatform;
70
+ guardOnly?: boolean;
71
+ }): WriteResult;
72
+ /** Whether one lifecycle hook is declared in a platform's file. Never throws. */
73
+ export declare function lifecycleHookInstalled(projectRoot: string, platform: LifecyclePlatform, which: LifecycleHook): boolean;
74
+ /** The line every Codex install prints: the hook is inert until the user trusts it. */
75
+ export declare const CODEX_TRUST_STEP: string;
76
+ /** The command that adds the Codex hook, for every path that does not write it. */
77
+ export declare const CODEX_INSTALL_COMMAND: string;
78
+ //# sourceMappingURL=install.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../../src/hooks/install.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAQH,MAAM,MAAM,iBAAiB,GAAG,aAAa,GAAG,OAAO,CAAC;AACxD,MAAM,MAAM,aAAa,GAAG,eAAe,GAAG,OAAO,CAAC;AAEtD,eAAO,MAAM,mBAAmB,EAAE,SAAS,iBAAiB,EAA6B,CAAC;AAC1F,eAAO,MAAM,qBAAqB,0BAA0B,CAAC;AAC7D,eAAO,MAAM,aAAa,sCAAsC,CAAC;AAuBjE;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,GAAE,iBAAiC,GAAG,MAAM,CAAC,aAAa,EAAE,MAAM,CAAC,CAM5G;AAkCD,wBAAgB,YAAY,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,iBAAiB,GAAG,MAAM,CAErF;AAED,+DAA+D;AAC/D,wBAAgB,aAAa,CAAC,QAAQ,EAAE,iBAAiB,GAAG,OAAO,CAElE;AAED,+EAA+E;AAC/E,wBAAgB,SAAS,CAAC,QAAQ,EAAE,iBAAiB,GAAG,MAAM,GAAG,IAAI,CAEpE;AAED,sFAAsF;AACtF,wBAAgB,YAAY,CAAC,QAAQ,EAAE,iBAAiB,GAAG,OAAO,CAEjE;AAED,6FAA6F;AAC7F,wBAAgB,cAAc,CAAC,QAAQ,EAAE,iBAAiB,GAAG,MAAM,CAElE;AAgED,MAAM,WAAW,WAAW;IAC1B,qDAAqD;IACrD,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CACnC,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE;IAAE,QAAQ,EAAE,iBAAiB,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CAAE,GACrD,WAAW,CAUb;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAClC,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE;IAAE,QAAQ,EAAE,iBAAiB,CAAC;IAAC,SAAS,CAAC,EAAE,OAAO,CAAA;CAAE,GACzD,WAAW,CAoBb;AAED,iFAAiF;AACjF,wBAAgB,sBAAsB,CACpC,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,iBAAiB,EAC3B,KAAK,EAAE,aAAa,GACnB,OAAO,CAOT;AAED,uFAAuF;AACvF,eAAO,MAAM,gBAAgB,EAAqC,MAAM,CAAC;AAEzE,mFAAmF;AACnF,eAAO,MAAM,qBAAqB,QAA0B,CAAC"}
@@ -0,0 +1,207 @@
1
+ /**
2
+ * Installs the lifecycle hooks: the session-start hook for Claude Code and
3
+ * Codex, and the opt-in phase guard for Claude Code
4
+ * (hooks-carry-lifecycle-state/AC-14..AC-16, AC-20, AC-21).
5
+ *
6
+ * Identity is a trailing marker, as for the cost hooks, but a different one
7
+ * (design D9). With a shared marker `aidlc cost hooks status` would count a
8
+ * lifecycle hook as a cost hook and `cost hooks remove` would delete it. The cost
9
+ * installer matches `endsWith('#aidlc-cost-hook')`, which no command here
10
+ * satisfies, so neither installer sees the other's entries and the cost code is
11
+ * unchanged. The merge below is written again rather than generalised out of
12
+ * `cost/hooks/claude-code.ts` because it also writes Codex's file, and the cost
13
+ * installer's tests pin its exact behaviour.
14
+ *
15
+ * Codex trusts a hook by its content hash, and only the user's own config may
16
+ * record that hash (knowledge: `codex-hook-trust-model`). So this module writes
17
+ * the project's `.codex/hooks.json` and nothing else for Codex — never
18
+ * `~/.codex/`, never a trust hash — and writes only when the text would change,
19
+ * so installing twice cannot cost the user the trust they already gave.
20
+ *
21
+ * Design: design.md C4
22
+ *
23
+ * @module
24
+ */
25
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
26
+ import { dirname, join } from 'node:path';
27
+ import { cliEntryPath } from '../cost/hooks/entry.js';
28
+ import { shimInvocation, shimProblem, writeShim } from '../cost/hooks/shim.js';
29
+ export const LIFECYCLE_PLATFORMS = ['claude-code', 'codex'];
30
+ export const LIFECYCLE_HOOK_MARKER = '#aidlc-lifecycle-hook';
31
+ export const GUARD_MATCHER = 'Edit|Write|MultiEdit|NotebookEdit';
32
+ /** A hook needs only to start the CLI and read a few files; ten seconds is generous. */
33
+ const TIMEOUT_SECONDS = 10;
34
+ const EVENT = { 'session-start': 'SessionStart', guard: 'PreToolUse' };
35
+ /**
36
+ * The two hook commands for a platform. Both run through the cost-capture shim,
37
+ * which finds an absolute `node` and this project's CLI at run time and never
38
+ * consults `PATH` (cost-capture-goes-dark/AC-15) — a bare `aidlc` here would be a
39
+ * `PATH` lookup on every session start (design D1).
40
+ */
41
+ export function lifecycleCommands(platform = 'claude-code') {
42
+ const base = shimInvocation(PLATFORM_HOOKS[platform].rootVar);
43
+ return {
44
+ 'session-start': `${base} hook session-start ${LIFECYCLE_HOOK_MARKER}`,
45
+ guard: `${base} hook guard ${LIFECYCLE_HOOK_MARKER}`,
46
+ };
47
+ }
48
+ /** The one table mapping a platform to its lifecycle hooks (agent-portability/AC-41). */
49
+ const PLATFORM_HOOKS = {
50
+ 'claude-code': { file: ['.claude', 'settings.json'], guard: true, trustStep: null, rootVar: 'CLAUDE_PROJECT_DIR' },
51
+ // Codex's PreToolUse can deny or rewrite a call but not ask (design D7), and a
52
+ // project hook runs only once the user trusts it by hash.
53
+ codex: {
54
+ file: ['.codex', 'hooks.json'],
55
+ guard: false,
56
+ trustStep: 'Codex runs it only after you trust it: open Codex in this project and run /hooks.',
57
+ rootVar: 'AIDLC_PROJECT_ROOT',
58
+ },
59
+ };
60
+ export function hookFilePath(projectRoot, platform) {
61
+ return join(projectRoot, ...PLATFORM_HOOKS[platform].file);
62
+ }
63
+ /** Whether the phase guard can be installed for a platform. */
64
+ export function supportsGuard(platform) {
65
+ return PLATFORM_HOOKS[platform].guard;
66
+ }
67
+ /** The step the user still owes before the platform runs the hook, or null. */
68
+ export function trustStep(platform) {
69
+ return PLATFORM_HOOKS[platform].trustStep;
70
+ }
71
+ /** Whether writing a platform's hook needs the user's explicit yes (AC-18..AC-20). */
72
+ export function needsConsent(platform) {
73
+ return trustStep(platform) !== null;
74
+ }
75
+ /** The command that writes a consent-gated platform's hook, for every path that does not. */
76
+ export function installCommand(platform) {
77
+ return `aidlc hook install --platform ${platform}`;
78
+ }
79
+ function isMarked(h) {
80
+ return typeof h.command === 'string' && h.command.endsWith(LIFECYCLE_HOOK_MARKER);
81
+ }
82
+ function groupFor(which, platform) {
83
+ const hook = { type: 'command', command: lifecycleCommands(platform)[which], timeout: TIMEOUT_SECONDS };
84
+ // No matcher on SessionStart, so it fires on startup, resume, clear and compact.
85
+ return which === 'guard' ? { matcher: GUARD_MATCHER, hooks: [hook] } : { hooks: [hook] };
86
+ }
87
+ function load(path) {
88
+ if (!existsSync(path))
89
+ return { raw: null, file: {} };
90
+ const raw = readFileSync(path, 'utf8');
91
+ // A file that does not parse is left alone: overwriting it would discard
92
+ // whatever the user had there. The error reaches the caller.
93
+ return { raw, file: JSON.parse(raw) };
94
+ }
95
+ function save(path, raw, file) {
96
+ const text = JSON.stringify(file, null, 2) + '\n';
97
+ if (text === raw)
98
+ return false;
99
+ mkdirSync(dirname(path), { recursive: true });
100
+ writeFileSync(path, text);
101
+ return true;
102
+ }
103
+ /**
104
+ * The event's groups with every marked command taken out, and how many were.
105
+ * Only a group this takes a command from is dropped for being left empty; a
106
+ * user's group is passed through as it was, empty or not.
107
+ */
108
+ function withoutMarked(groups) {
109
+ let removed = 0;
110
+ const kept = [];
111
+ for (const g of groups ?? []) {
112
+ const hooks = Array.isArray(g.hooks) ? g.hooks : [];
113
+ const unmarked = hooks.filter((h) => !isMarked(h));
114
+ removed += hooks.length - unmarked.length;
115
+ if (unmarked.length === hooks.length)
116
+ kept.push(g);
117
+ else if (unmarked.length > 0)
118
+ kept.push({ ...g, hooks: unmarked });
119
+ }
120
+ return { groups: kept, removed };
121
+ }
122
+ /** Exactly one marked command under the event, in the group shape the installer writes. */
123
+ function isCurrent(groups, which, platform) {
124
+ const expected = groupFor(which, platform);
125
+ const marked = (groups ?? []).filter((g) => (g.hooks ?? []).some(isMarked));
126
+ return marked.length === 1 && JSON.stringify(marked[0]) === JSON.stringify(expected);
127
+ }
128
+ function ensure(file, which, platform) {
129
+ const hooks = file.hooks ?? {};
130
+ const event = EVENT[which];
131
+ // Left where it is when already current, so a re-install does not even reorder
132
+ // the file (AC-16).
133
+ if (!isCurrent(hooks[event], which, platform)) {
134
+ hooks[event] = [...withoutMarked(hooks[event]).groups, groupFor(which, platform)];
135
+ }
136
+ file.hooks = hooks;
137
+ }
138
+ /**
139
+ * Install the session-start hook, and the guard when asked, into one platform's
140
+ * hook file (AC-15, AC-16, AC-20). Writes the shim first when it is missing or
141
+ * unusable, since every command here runs through it.
142
+ *
143
+ * @throws when the guard is asked for Codex — its `PreToolUse` can deny or
144
+ * rewrite a call but not ask, and the guard only ever asks.
145
+ */
146
+ export function installLifecycleHooks(projectRoot, opts) {
147
+ if (opts.guard && !supportsGuard(opts.platform)) {
148
+ throw new Error(`the phase guard is Claude Code only — ${opts.platform} hooks can deny or rewrite a call, not ask`);
149
+ }
150
+ const path = hookFilePath(projectRoot, opts.platform);
151
+ const { raw, file } = load(path);
152
+ if (shimProblem(projectRoot) !== null)
153
+ writeShim(projectRoot, process.execPath, cliEntryPath());
154
+ ensure(file, 'session-start', opts.platform);
155
+ if (opts.guard)
156
+ ensure(file, 'guard', opts.platform);
157
+ return { written: save(path, raw, file), path };
158
+ }
159
+ /**
160
+ * Remove the lifecycle hooks from one platform's file, or only the guard
161
+ * (AC-14, AC-16). Unmarked entries and every other key stay; a file that does
162
+ * not exist is not created.
163
+ */
164
+ export function removeLifecycleHooks(projectRoot, opts) {
165
+ const path = hookFilePath(projectRoot, opts.platform);
166
+ if (!existsSync(path))
167
+ return { written: false, path };
168
+ const { raw, file } = load(path);
169
+ if (!file.hooks)
170
+ return { written: false, path };
171
+ const events = opts.guardOnly ? [EVENT.guard] : Object.keys(file.hooks);
172
+ let removed = 0;
173
+ for (const event of events) {
174
+ if (!(event in file.hooks))
175
+ continue;
176
+ const result = withoutMarked(file.hooks[event]);
177
+ if (result.removed === 0)
178
+ continue;
179
+ removed += result.removed;
180
+ if (result.groups.length > 0)
181
+ file.hooks[event] = result.groups;
182
+ else
183
+ delete file.hooks[event];
184
+ }
185
+ // Nothing marked, nothing written: re-serialising would reformat a file this
186
+ // command had no business touching, and report a removal that did not happen.
187
+ if (removed === 0)
188
+ return { written: false, path };
189
+ if (Object.keys(file.hooks).length === 0)
190
+ delete file.hooks;
191
+ return { written: save(path, raw, file), path };
192
+ }
193
+ /** Whether one lifecycle hook is declared in a platform's file. Never throws. */
194
+ export function lifecycleHookInstalled(projectRoot, platform, which) {
195
+ try {
196
+ const { file } = load(hookFilePath(projectRoot, platform));
197
+ return (file.hooks?.[EVENT[which]] ?? []).some((g) => (g.hooks ?? []).some(isMarked));
198
+ }
199
+ catch {
200
+ return false;
201
+ }
202
+ }
203
+ /** The line every Codex install prints: the hook is inert until the user trusts it. */
204
+ export const CODEX_TRUST_STEP = PLATFORM_HOOKS.codex.trustStep;
205
+ /** The command that adds the Codex hook, for every path that does not write it. */
206
+ export const CODEX_INSTALL_COMMAND = installCommand('codex');
207
+ //# sourceMappingURL=install.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"install.js","sourceRoot":"","sources":["../../src/hooks/install.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,65 @@
1
+ /**
2
+ * What a harness hook needs to know about the lifecycle: which instance is
3
+ * claimed in this checkout, what phase it is in, and what comes next.
4
+ *
5
+ * Read-only by contract (hooks-carry-lifecycle-state/AC-8). Everything here runs
6
+ * inside a `SessionStart` or `PreToolUse` hook, on every session start or every
7
+ * edit, so it reads only the claims and the claimed instances' own files — never
8
+ * every instance, ledger or cache. `aidlc status --json` reads all of those and
9
+ * took 3.5 s on this repository; the CLI itself starts in 0.16 s (AC-10).
10
+ *
11
+ * Requirements: hooks-carry-lifecycle-state/AC-1..AC-9
12
+ * Design: design.md C2
13
+ *
14
+ * @module
15
+ */
16
+ import type { NextStep } from '../core/types.js';
17
+ /** Phases in which code is not yet written — what the phase guard asks about. */
18
+ export declare const PLANNING_PHASES: readonly string[];
19
+ /** Longest line either hook prints (AC-9). */
20
+ export declare const MAX_LINE = 200;
21
+ export interface InstanceContext {
22
+ name: string;
23
+ template: string;
24
+ scope: string;
25
+ /** `current_phase` from instance.yaml — what `aidlc status --json` reports (AC-2). */
26
+ phase: string;
27
+ /** What `aidlc continue --json` reports as `nextStep` (AC-2). */
28
+ step: NextStep;
29
+ /** The lowest-numbered open task, in implementation only (AC-3). */
30
+ openTask: {
31
+ id: number;
32
+ title: string;
33
+ } | null;
34
+ }
35
+ /**
36
+ * Instances claimed in this checkout, sorted by name (AC-6).
37
+ *
38
+ * Held here means recorded from this working directory: the claim's
39
+ * `worktree_path` is this checkout, or it has none and this is the primary
40
+ * checkout. Staleness is deliberately not consulted — claims renew only at phase
41
+ * transitions, and one phase routinely outlasts the 60-minute window, so a
42
+ * live-only rule would go quiet on a compaction deep into implementation, the
43
+ * case this hook exists for (design D3). Session ids are not compared either:
44
+ * they change across `startup`.
45
+ */
46
+ export declare function claimsHere(projectRoot: string): string[];
47
+ /** `current_phase` of one instance, or null when its state cannot be read. */
48
+ export declare function currentPhase(projectRoot: string, name: string): string | null;
49
+ /**
50
+ * One instance's phase and next step, or null when any of its state cannot be
51
+ * read (AC-7) — a hook must never stop a session starting.
52
+ */
53
+ export declare function instanceContext(projectRoot: string, name: string): InstanceContext | null;
54
+ /**
55
+ * One printable line: control characters (escape codes included) become spaces,
56
+ * and anything past `max` is cut with an ellipsis (AC-9).
57
+ */
58
+ export declare function plainLine(text: string, max?: number): string;
59
+ /**
60
+ * What `aidlc hook session-start` prints: three lines for one claim, one line
61
+ * for several, nothing for none (AC-1, AC-4, AC-5). An instance whose state
62
+ * cannot be read is left out (AC-7).
63
+ */
64
+ export declare function sessionStartLines(projectRoot: string): string[];
65
+ //# sourceMappingURL=lifecycle-context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lifecycle-context.d.ts","sourceRoot":"","sources":["../../src/hooks/lifecycle-context.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAMH,OAAO,KAAK,EAAiB,QAAQ,EAAgC,MAAM,kBAAkB,CAAC;AAQ9F,iFAAiF;AACjF,eAAO,MAAM,eAAe,EAAE,SAAS,MAAM,EAA2C,CAAC;AAEzF,8CAA8C;AAC9C,eAAO,MAAM,QAAQ,MAAM,CAAC;AAE5B,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,sFAAsF;IACtF,KAAK,EAAE,MAAM,CAAC;IACd,iEAAiE;IACjE,IAAI,EAAE,QAAQ,CAAC;IACf,oEAAoE;IACpE,QAAQ,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;CAChD;AAUD;;;;;;;;;;GAUG;AACH,wBAAgB,UAAU,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,EAAE,CAcxD;AAED,8EAA8E;AAC9E,wBAAgB,YAAY,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAO7E;AAiCD;;;GAGG;AACH,wBAAgB,eAAe,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,eAAe,GAAG,IAAI,CAmBzF;AAcD;;;GAGG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,SAAW,GAAG,MAAM,CAG9D;AAmDD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,EAAE,CAO/D"}