instar 1.2.76 → 1.2.77

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 (45) hide show
  1. package/dist/commands/init.d.ts.map +1 -1
  2. package/dist/commands/init.js +21 -1
  3. package/dist/commands/init.js.map +1 -1
  4. package/dist/core/Config.d.ts +2 -14
  5. package/dist/core/Config.d.ts.map +1 -1
  6. package/dist/core/Config.js +50 -1
  7. package/dist/core/Config.js.map +1 -1
  8. package/dist/core/PostUpdateMigrator.d.ts.map +1 -1
  9. package/dist/core/PostUpdateMigrator.js +64 -3
  10. package/dist/core/PostUpdateMigrator.js.map +1 -1
  11. package/dist/core/SessionManager.d.ts.map +1 -1
  12. package/dist/core/SessionManager.js +14 -2
  13. package/dist/core/SessionManager.js.map +1 -1
  14. package/dist/core/codexHookArm.d.ts +81 -0
  15. package/dist/core/codexHookArm.d.ts.map +1 -0
  16. package/dist/core/codexHookArm.js +191 -0
  17. package/dist/core/codexHookArm.js.map +1 -0
  18. package/dist/core/codexHookTrust.d.ts +52 -0
  19. package/dist/core/codexHookTrust.d.ts.map +1 -0
  20. package/dist/core/codexHookTrust.js +114 -0
  21. package/dist/core/codexHookTrust.js.map +1 -0
  22. package/dist/core/installCodexHooks.d.ts.map +1 -1
  23. package/dist/core/installCodexHooks.js +19 -12
  24. package/dist/core/installCodexHooks.js.map +1 -1
  25. package/dist/core/types.d.ts +4 -0
  26. package/dist/core/types.d.ts.map +1 -1
  27. package/dist/core/types.js.map +1 -1
  28. package/dist/providers/adapters/openai-codex/canary/codexHookContractCanary.d.ts +1 -0
  29. package/dist/providers/adapters/openai-codex/canary/codexHookContractCanary.d.ts.map +1 -1
  30. package/dist/providers/adapters/openai-codex/canary/codexHookContractCanary.js +17 -3
  31. package/dist/providers/adapters/openai-codex/canary/codexHookContractCanary.js.map +1 -1
  32. package/package.json +1 -1
  33. package/src/data/builtin-manifest.json +18 -18
  34. package/upgrades/1.2.77.md +99 -0
  35. package/upgrades/side-effects/codex-full-parity-bundle.md +46 -0
  36. package/upgrades/side-effects/codex-parity-arm-model-literal.md +24 -0
  37. package/upgrades/side-effects/codex-parity-arm-vitest-guard.md +31 -0
  38. package/upgrades/side-effects/codex-parity-asdf-and-model-badge.md +41 -0
  39. package/upgrades/side-effects/codex-parity-asdf-convergence-fixes.md +44 -0
  40. package/upgrades/side-effects/codex-parity-c3-scope-coherence-reentry.md +34 -0
  41. package/upgrades/side-effects/codex-parity-p0-arm-realpath-liveproof.md +35 -0
  42. package/upgrades/side-effects/codex-parity-p0-arm-wiring.md +40 -0
  43. package/upgrades/side-effects/codex-parity-p0-hook-arm.md +50 -0
  44. package/upgrades/side-effects/codex-parity-p0-hook-trust-core.md +43 -0
  45. package/upgrades/side-effects/codex-parity-stop-trio-and-deferral.md +76 -0
@@ -0,0 +1,191 @@
1
+ /**
2
+ * codexHookArm — arm instar's project-scoped Codex gate hooks so they actually run
3
+ * on a freshly-init'd agent without a human clicking "trust". P0 of codex-full-parity.
4
+ *
5
+ * G2 verdict (spec §P0): per-agent scoping comes from trust entries being keyed by the
6
+ * project hooks.json PATH, so arming only the agent's own project hooks never touches the
7
+ * operator's personal Codex. Mechanism: Codex's own trust flow (the "Trust all and continue"
8
+ * prompt), driven non-interactively — NOT the machine-wide managed-config (rejected, G1).
9
+ *
10
+ * Review gates baked in (spec §7 F1-F3):
11
+ * F1 — manifest verify: only arm when the project hooks.json is exactly instar's own
12
+ * (matches buildInstarCodexHookGroups); never blind-trust arbitrary on-disk hooks.
13
+ * And the trust spawn runs WITHOUT the dangerous approvals/sandbox bypass flags.
14
+ * F2 — idempotent + readback: skip the spawn entirely when already armed; after the spawn,
15
+ * re-read config.toml and confirm the slots are now trusted (return armed=false if not).
16
+ * F3 — never silently re-enable a user-disabled hook (enabled=false is left as the user set it).
17
+ *
18
+ * The fragile TUI keystroke step is injected (`trustDriver`) so the orchestration — the part
19
+ * that decides whether/what to arm and verifies the outcome — is unit-testable without a real
20
+ * codex. The default driver spawns interactive codex in tmux and sends the trust keystrokes;
21
+ * it is validated by test-as-self on a live agent, not by unit tests.
22
+ */
23
+ import fs from 'node:fs';
24
+ import path from 'node:path';
25
+ import { execFileSync } from 'node:child_process';
26
+ import { buildInstarCodexHookGroups, INSTAR_HOOK_PATH_MARKER } from './installCodexHooks.js';
27
+ import { codexHooksArmingStatus, expectedHookSlots } from './codexHookTrust.js';
28
+ function readConfigToml(codexHome) {
29
+ const p = path.join(codexHome, 'config.toml');
30
+ try {
31
+ return fs.readFileSync(p, 'utf-8');
32
+ }
33
+ catch {
34
+ return ''; // fresh agent — no config yet = nothing trusted
35
+ }
36
+ }
37
+ /**
38
+ * F1 manifest verify: is the project's `.codex/hooks.json` exactly instar's own set?
39
+ * We compare the instar-owned hook command paths the file declares against what
40
+ * buildInstarCodexHookGroups would produce. If the file is missing, malformed, or carries
41
+ * a hook command outside `.instar/hooks/instar/`, we refuse to arm (don't blind-trust).
42
+ */
43
+ export function projectHooksAreInstarOwned(projectDir) {
44
+ const hooksPath = path.join(projectDir, '.codex', 'hooks.json');
45
+ let parsed;
46
+ try {
47
+ parsed = JSON.parse(fs.readFileSync(hooksPath, 'utf-8'));
48
+ }
49
+ catch {
50
+ return false;
51
+ }
52
+ const hooks = parsed.hooks ?? {};
53
+ const expected = buildInstarCodexHookGroups(projectDir);
54
+ // Every instar-owned command present must point under the instar hooks dir, and every
55
+ // event instar expects must be present with the expected command set.
56
+ for (const [event, groups] of Object.entries(expected)) {
57
+ const actualGroups = hooks[event] ?? [];
58
+ const expectedCmds = (groups[0]?.hooks ?? []).map((h) => h.command);
59
+ const actualCmds = (actualGroups[0]?.hooks ?? []).map((h) => h.command ?? '');
60
+ for (const cmd of expectedCmds) {
61
+ if (!actualCmds.includes(cmd))
62
+ return false; // expected instar hook missing
63
+ }
64
+ }
65
+ // No instar-owned command may live outside the instar hooks dir (anti-injection).
66
+ for (const groups of Object.values(hooks)) {
67
+ for (const group of groups ?? []) {
68
+ for (const h of group.hooks ?? []) {
69
+ const c = h.command ?? '';
70
+ if (c.includes(INSTAR_HOOK_PATH_MARKER)) {
71
+ const abs = path.join(projectDir, INSTAR_HOOK_PATH_MARKER);
72
+ if (!c.includes(abs))
73
+ return false; // instar-marker path that isn't THIS project's
74
+ }
75
+ }
76
+ }
77
+ }
78
+ return true;
79
+ }
80
+ /**
81
+ * Arm the agent's project Codex hooks. Idempotent. Returns the outcome without throwing
82
+ * on a benign no-op; throws only on a programming error in the driver.
83
+ */
84
+ export function armCodexHooks(opts) {
85
+ const codexHome = opts.codexHome || path.join(process.env.HOME || '', '.codex');
86
+ // Codex keys its [hooks.state] trust entries by the CANONICAL hooks.json path
87
+ // (it realpath-resolves the project dir — e.g. /tmp → /private/tmp on macOS). The
88
+ // readback must use the same canonical path or it false-negatives ("partial" when
89
+ // actually armed). Resolve the real project dir; fall back to the given path if it
90
+ // doesn't exist yet.
91
+ let realProjectDir = opts.projectDir;
92
+ try {
93
+ realProjectDir = fs.realpathSync(opts.projectDir);
94
+ }
95
+ catch { /* use as-is */ }
96
+ const hooksJsonPath = path.join(realProjectDir, '.codex', 'hooks.json');
97
+ const expectedSlots = expectedHookSlots(buildInstarCodexHookGroups(opts.projectDir));
98
+ // F2 — idempotency: already armed? skip the spawn entirely.
99
+ const before = codexHooksArmingStatus(readConfigToml(codexHome), hooksJsonPath, expectedSlots);
100
+ if (before.allArmed)
101
+ return { status: 'already-armed' };
102
+ // F1 — only arm instar's own verified hook set.
103
+ if (!projectHooksAreInstarOwned(opts.projectDir)) {
104
+ return { status: 'skipped', reason: 'project hooks.json is not instar-owned (manifest mismatch) — refusing to trust' };
105
+ }
106
+ // Drive Codex's trust flow (default = interactive tmux spawn + keystrokes; injected for tests).
107
+ const driver = opts.trustDriver ?? defaultTrustDriver;
108
+ driver({ projectDir: opts.projectDir, codexHome, hooksJsonPath });
109
+ // F2 — readback: confirm the slots are now trusted. F3 — surface (not silently fix) any that
110
+ // remain explicitly disabled (user choice; trust-all does not clear enabled=false).
111
+ const after = codexHooksArmingStatus(readConfigToml(codexHome), hooksJsonPath, expectedSlots);
112
+ if (after.allArmed)
113
+ return { status: 'armed' };
114
+ return { status: 'partial', untrusted: after.untrusted, disabled: after.disabled };
115
+ }
116
+ export function makeTmuxTrustDriver(deps) {
117
+ return function driveCodexTrustAll(ctx) {
118
+ const session = `instar-codex-arm-${Date.now().toString(36)}`;
119
+ const tmux = (args) => execFileSync(deps.tmuxPath, args, { encoding: 'utf-8', timeout: 10_000 });
120
+ // RULE 3.1 RATIONALE (state-detection): this capture-pane parse of Codex's TUI trust prompt is
121
+ // BEST-EFFORT and only gates WHEN to send the trust keystrokes — it never decides the
122
+ // outcome. The AUTHORITATIVE state detection is armCodexHooks' config.toml trust readback
123
+ // (codexHooksArmingStatus, robust line-based config parse, NOT TUI scraping). If the prompt
124
+ // wording drifts, this match fails → no keys sent → the readback reports not-armed
125
+ // (fail-safe, surfaced to the caller as `partial`) — never silent corruption. Drift
126
+ // detection for the prompt itself is the G5 runtime arming canary (spec §7, tracked).
127
+ // Registry: specs/provider-portability/06-state-detector-registry.md. <!-- tracked: codex-full-parity -->
128
+ const capture = () => {
129
+ try {
130
+ return tmux(['capture-pane', '-t', `${session}:`, '-p', '-S', '-60']);
131
+ }
132
+ catch {
133
+ return '';
134
+ }
135
+ };
136
+ try {
137
+ tmux(['new-session', '-d', '-s', session, '-c', ctx.projectDir, '-x', '200', '-y', '50',
138
+ '-e', `CODEX_HOME=${ctx.codexHome}`]);
139
+ // Launch interactive codex — NO --dangerously-bypass-* flags (F1).
140
+ const launch = `${deps.codexBinary}${deps.model ? ` -m ${deps.model}` : ''}`;
141
+ tmux(['send-keys', '-t', `${session}:`, launch, 'Enter']);
142
+ // A fresh project shows up to TWO prompts in sequence: (1) "Do you trust the contents
143
+ // of this directory?" (cursor on "Yes, continue") then (2) the hook-trust prompt
144
+ // ("1. Review / 2. Trust all and continue / 3. Continue without"). Production agent dirs
145
+ // are usually pre-trusted so (1) is skipped — but handle both so the driver is robust.
146
+ // State machine, bounded ~50s total (codex cold-start + two prompts).
147
+ let handledDirTrust = false;
148
+ let handledHookTrust = false;
149
+ const deadline = Date.now() + 50_000;
150
+ while (Date.now() < deadline && !handledHookTrust) {
151
+ const pane = capture();
152
+ if (!handledHookTrust && /Trust all and continue|Hooks need review|hook is new or changed/i.test(pane)) {
153
+ // Hook-trust prompt: cursor on "1. Review hooks"; Down → "Trust all and continue", Enter.
154
+ tmux(['send-keys', '-t', `${session}:`, 'Down']);
155
+ execFileSync('sleep', ['1']);
156
+ tmux(['send-keys', '-t', `${session}:`, 'Enter']);
157
+ handledHookTrust = true;
158
+ execFileSync('sleep', ['3']);
159
+ break;
160
+ }
161
+ if (!handledDirTrust && /trust the contents of this directory|Do you trust/i.test(pane)) {
162
+ // Dir-trust prompt: cursor on "1. Yes, continue" → Enter accepts (do NOT move down,
163
+ // which would select "No, quit").
164
+ tmux(['send-keys', '-t', `${session}:`, 'Enter']);
165
+ handledDirTrust = true;
166
+ execFileSync('sleep', ['2']);
167
+ continue;
168
+ }
169
+ execFileSync('sleep', ['2']);
170
+ }
171
+ if (!handledHookTrust)
172
+ return; // readback will report not-armed; caller decides
173
+ }
174
+ finally {
175
+ // Exit codex + tear down the pane (best-effort).
176
+ try {
177
+ tmux(['send-keys', '-t', `${session}:`, 'C-c']);
178
+ }
179
+ catch { /* noop */ }
180
+ try {
181
+ tmux(['kill-session', '-t', session]);
182
+ }
183
+ catch { /* noop */ }
184
+ }
185
+ };
186
+ }
187
+ /** Placeholder default driver — real callers pass a configured driver via opts.trustDriver. */
188
+ function defaultTrustDriver(_ctx) {
189
+ throw new Error('armCodexHooks: no trustDriver provided — pass makeTmuxTrustDriver({tmuxPath, codexBinary}) from the caller');
190
+ }
191
+ //# sourceMappingURL=codexHookArm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codexHookArm.js","sourceRoot":"","sources":["../../src/core/codexHookArm.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,0BAA0B,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AAC7F,OAAO,EAAE,sBAAsB,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAmBhF,SAAS,cAAc,CAAC,SAAiB;IACvC,MAAM,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC;IAC9C,IAAI,CAAC;QACH,OAAO,EAAE,CAAC,YAAY,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;IACrC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC,CAAC,gDAAgD;IAC7D,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,0BAA0B,CAAC,UAAkB;IAC3D,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,QAAQ,EAAE,YAAY,CAAC,CAAC;IAChE,IAAI,MAAkF,CAAC;IACvF,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC,CAAC;IAC3D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;IACD,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,IAAI,EAAE,CAAC;IACjC,MAAM,QAAQ,GAAG,0BAA0B,CAAC,UAAU,CAAC,CAAC;IACxD,sFAAsF;IACtF,sEAAsE;IACtE,KAAK,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;QACvD,MAAM,YAAY,GAAG,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;QACxC,MAAM,YAAY,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;QACpE,MAAM,UAAU,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC;QAC9E,KAAK,MAAM,GAAG,IAAI,YAAY,EAAE,CAAC;YAC/B,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,GAAG,CAAC;gBAAE,OAAO,KAAK,CAAC,CAAC,+BAA+B;QAC9E,CAAC;IACH,CAAC;IACD,kFAAkF;IAClF,KAAK,MAAM,MAAM,IAAI,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;QAC1C,KAAK,MAAM,KAAK,IAAI,MAAM,IAAI,EAAE,EAAE,CAAC;YACjC,KAAK,MAAM,CAAC,IAAI,KAAK,CAAC,KAAK,IAAI,EAAE,EAAE,CAAC;gBAClC,MAAM,CAAC,GAAG,CAAC,CAAC,OAAO,IAAI,EAAE,CAAC;gBAC1B,IAAI,CAAC,CAAC,QAAQ,CAAC,uBAAuB,CAAC,EAAE,CAAC;oBACxC,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,uBAAuB,CAAC,CAAC;oBAC3D,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC;wBAAE,OAAO,KAAK,CAAC,CAAC,+CAA+C;gBACrF,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,IAA0B;IACtD,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,EAAE,EAAE,QAAQ,CAAC,CAAC;IAChF,8EAA8E;IAC9E,kFAAkF;IAClF,kFAAkF;IAClF,mFAAmF;IACnF,qBAAqB;IACrB,IAAI,cAAc,GAAG,IAAI,CAAC,UAAU,CAAC;IACrC,IAAI,CAAC;QAAC,cAAc,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IAAC,CAAC;IAAC,MAAM,CAAC,CAAC,eAAe,CAAC,CAAC;IACpF,MAAM,aAAa,GAAG,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,QAAQ,EAAE,YAAY,CAAC,CAAC;IACxE,MAAM,aAAa,GAAG,iBAAiB,CAAC,0BAA0B,CAAC,IAAI,CAAC,UAAU,CAAQ,CAAC,CAAC;IAE5F,4DAA4D;IAC5D,MAAM,MAAM,GAAG,sBAAsB,CAAC,cAAc,CAAC,SAAS,CAAC,EAAE,aAAa,EAAE,aAAa,CAAC,CAAC;IAC/F,IAAI,MAAM,CAAC,QAAQ;QAAE,OAAO,EAAE,MAAM,EAAE,eAAe,EAAE,CAAC;IAExD,gDAAgD;IAChD,IAAI,CAAC,0BAA0B,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC;QACjD,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,gFAAgF,EAAE,CAAC;IACzH,CAAC;IAED,gGAAgG;IAChG,MAAM,MAAM,GAAG,IAAI,CAAC,WAAW,IAAI,kBAAkB,CAAC;IACtD,MAAM,CAAC,EAAE,UAAU,EAAE,IAAI,CAAC,UAAU,EAAE,SAAS,EAAE,aAAa,EAAE,CAAC,CAAC;IAElE,6FAA6F;IAC7F,oFAAoF;IACpF,MAAM,KAAK,GAAG,sBAAsB,CAAC,cAAc,CAAC,SAAS,CAAC,EAAE,aAAa,EAAE,aAAa,CAAC,CAAC;IAC9F,IAAI,KAAK,CAAC,QAAQ;QAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC;IAC/C,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,CAAC;AACrF,CAAC;AAgBD,MAAM,UAAU,mBAAmB,CAAC,IAAqB;IACvD,OAAO,SAAS,kBAAkB,CAAC,GAAqE;QACtG,MAAM,OAAO,GAAG,oBAAoB,IAAI,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,CAAC;QAC9D,MAAM,IAAI,GAAG,CAAC,IAAc,EAAE,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC;QAC3G,+FAA+F;QAC/F,sFAAsF;QACtF,0FAA0F;QAC1F,4FAA4F;QAC5F,mFAAmF;QACnF,oFAAoF;QACpF,sFAAsF;QACtF,0GAA0G;QAC1G,MAAM,OAAO,GAAG,GAAW,EAAE;YAC3B,IAAI,CAAC;gBAAC,OAAO,IAAI,CAAC,CAAC,cAAc,EAAE,IAAI,EAAE,GAAG,OAAO,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC;YAAC,CAAC;YAAC,MAAM,CAAC;gBAAC,OAAO,EAAE,CAAC;YAAC,CAAC;QACrG,CAAC,CAAC;QACF,IAAI,CAAC;YACH,IAAI,CAAC,CAAC,aAAa,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,CAAC,UAAU,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI;gBACrF,IAAI,EAAE,cAAc,GAAG,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC;YACxC,mEAAmE;YACnE,MAAM,MAAM,GAAG,GAAG,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;YAC7E,IAAI,CAAC,CAAC,WAAW,EAAE,IAAI,EAAE,GAAG,OAAO,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;YAC1D,sFAAsF;YACtF,iFAAiF;YACjF,yFAAyF;YACzF,uFAAuF;YACvF,sEAAsE;YACtE,IAAI,eAAe,GAAG,KAAK,CAAC;YAC5B,IAAI,gBAAgB,GAAG,KAAK,CAAC;YAC7B,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,MAAM,CAAC;YACrC,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ,IAAI,CAAC,gBAAgB,EAAE,CAAC;gBAClD,MAAM,IAAI,GAAG,OAAO,EAAE,CAAC;gBACvB,IAAI,CAAC,gBAAgB,IAAI,kEAAkE,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;oBACvG,0FAA0F;oBAC1F,IAAI,CAAC,CAAC,WAAW,EAAE,IAAI,EAAE,GAAG,OAAO,GAAG,EAAE,MAAM,CAAC,CAAC,CAAC;oBACjD,YAAY,CAAC,OAAO,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;oBAC7B,IAAI,CAAC,CAAC,WAAW,EAAE,IAAI,EAAE,GAAG,OAAO,GAAG,EAAE,OAAO,CAAC,CAAC,CAAC;oBAClD,gBAAgB,GAAG,IAAI,CAAC;oBACxB,YAAY,CAAC,OAAO,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;oBAC7B,MAAM;gBACR,CAAC;gBACD,IAAI,CAAC,eAAe,IAAI,oDAAoD,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;oBACxF,oFAAoF;oBACpF,kCAAkC;oBAClC,IAAI,CAAC,CAAC,WAAW,EAAE,IAAI,EAAE,GAAG,OAAO,GAAG,EAAE,OAAO,CAAC,CAAC,CAAC;oBAClD,eAAe,GAAG,IAAI,CAAC;oBACvB,YAAY,CAAC,OAAO,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;oBAC7B,SAAS;gBACX,CAAC;gBACD,YAAY,CAAC,OAAO,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;YAC/B,CAAC;YACD,IAAI,CAAC,gBAAgB;gBAAE,OAAO,CAAC,iDAAiD;QAClF,CAAC;gBAAS,CAAC;YACT,iDAAiD;YACjD,IAAI,CAAC;gBAAC,IAAI,CAAC,CAAC,WAAW,EAAE,IAAI,EAAE,GAAG,OAAO,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC;YAAC,CAAC;YAAC,MAAM,CAAC,CAAC,UAAU,CAAC,CAAC;YAC7E,IAAI,CAAC;gBAAC,IAAI,CAAC,CAAC,cAAc,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC;YAAC,CAAC;YAAC,MAAM,CAAC,CAAC,UAAU,CAAC,CAAC;QACrE,CAAC;IACH,CAAC,CAAC;AACJ,CAAC;AAED,+FAA+F;AAC/F,SAAS,kBAAkB,CAAC,IAAsE;IAChG,MAAM,IAAI,KAAK,CAAC,4GAA4G,CAAC,CAAC;AAChI,CAAC"}
@@ -0,0 +1,52 @@
1
+ /**
2
+ * codexHookTrust — read/verify Codex's per-hook trust state for instar's
3
+ * project-scoped gate hooks. P0 of the codex-full-parity spec.
4
+ *
5
+ * WHY: Codex 0.133 runs a hook only if its content hash matches a `trusted_hash`
6
+ * entry in `$CODEX_HOME/config.toml [hooks.state]`. instar writes its gates to the
7
+ * agent's PROJECT `.codex/hooks.json`; the trust entries are keyed by that file's
8
+ * path (`<hooks.json-path>:<event>:<group>:<idx>`), so arming them only affects
9
+ * that agent's project — the operator's personal Codex (run from another cwd) never
10
+ * loads them (G2 verdict, spec §P0). A freshly-init'd Codex agent has these UNtrusted
11
+ * → its safety guards are dark until armed. This module is the read/verify half
12
+ * (idempotency + post-arm readback); the arming spawn lives in codexHookArm.
13
+ *
14
+ * No TOML dependency (instar deliberately avoids one — see mcpToolRegistry). The
15
+ * `[hooks.state]` block is simple enough to parse line-based for the specific
16
+ * project-path-keyed entries we care about.
17
+ */
18
+ export interface CodexHookTrustEntry {
19
+ /** The full state key: `<hooks.json-path>:<event>:<group>:<idx>`. */
20
+ key: string;
21
+ /** `<event>:<group>:<idx>` portion (path-stripped). */
22
+ slot: string;
23
+ trustedHash: string | null;
24
+ /** Codex omits `enabled` when true; an explicit `enabled = false` disables the hook. */
25
+ enabled: boolean;
26
+ }
27
+ /**
28
+ * Parse the `[hooks.state]` entries from a `config.toml` body that belong to a
29
+ * specific hooks.json path. Returns one entry per `<event>:<group>:<idx>` slot.
30
+ *
31
+ * Matches the on-disk shape:
32
+ * [hooks.state."/abs/.codex/hooks.json:stop:0:0"]
33
+ * trusted_hash = "sha256:..."
34
+ * enabled = false # only present when disabled
35
+ */
36
+ export declare function parseCodexHookTrust(configTomlBody: string, hooksJsonPath: string): CodexHookTrustEntry[];
37
+ /**
38
+ * Idempotency check (F2): are ALL of the agent's project hooks trusted + enabled?
39
+ * `expectedSlots` is the set of `<event>:<group>:<idx>` slots instar wrote into the
40
+ * project hooks.json (derived from buildInstarCodexHookGroups). Returns the slots
41
+ * that still need arming (untrusted) and the ones explicitly disabled (enabled=false,
42
+ * which "trust all" does NOT clear — F3: never silently re-enable a user-disabled hook).
43
+ */
44
+ export declare function codexHooksArmingStatus(configTomlBody: string, hooksJsonPath: string, expectedSlots: string[]): {
45
+ untrusted: string[];
46
+ disabled: string[];
47
+ allArmed: boolean;
48
+ };
49
+ export declare function expectedHookSlots(hooks: Record<string, Array<{
50
+ hooks?: unknown[];
51
+ }>>): string[];
52
+ //# sourceMappingURL=codexHookTrust.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codexHookTrust.d.ts","sourceRoot":"","sources":["../../src/core/codexHookTrust.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,MAAM,WAAW,mBAAmB;IAClC,qEAAqE;IACrE,GAAG,EAAE,MAAM,CAAC;IACZ,uDAAuD;IACvD,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,wFAAwF;IACxF,OAAO,EAAE,OAAO,CAAC;CAClB;AAED;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CACjC,cAAc,EAAE,MAAM,EACtB,aAAa,EAAE,MAAM,GACpB,mBAAmB,EAAE,CA0BvB;AAED;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CACpC,cAAc,EAAE,MAAM,EACtB,aAAa,EAAE,MAAM,EACrB,aAAa,EAAE,MAAM,EAAE,GACtB;IAAE,SAAS,EAAE,MAAM,EAAE,CAAC;IAAC,QAAQ,EAAE,MAAM,EAAE,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAA;CAAE,CAchE;AAoBD,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC;IAAE,KAAK,CAAC,EAAE,OAAO,EAAE,CAAA;CAAE,CAAC,CAAC,GAClD,MAAM,EAAE,CAaV"}
@@ -0,0 +1,114 @@
1
+ /**
2
+ * codexHookTrust — read/verify Codex's per-hook trust state for instar's
3
+ * project-scoped gate hooks. P0 of the codex-full-parity spec.
4
+ *
5
+ * WHY: Codex 0.133 runs a hook only if its content hash matches a `trusted_hash`
6
+ * entry in `$CODEX_HOME/config.toml [hooks.state]`. instar writes its gates to the
7
+ * agent's PROJECT `.codex/hooks.json`; the trust entries are keyed by that file's
8
+ * path (`<hooks.json-path>:<event>:<group>:<idx>`), so arming them only affects
9
+ * that agent's project — the operator's personal Codex (run from another cwd) never
10
+ * loads them (G2 verdict, spec §P0). A freshly-init'd Codex agent has these UNtrusted
11
+ * → its safety guards are dark until armed. This module is the read/verify half
12
+ * (idempotency + post-arm readback); the arming spawn lives in codexHookArm.
13
+ *
14
+ * No TOML dependency (instar deliberately avoids one — see mcpToolRegistry). The
15
+ * `[hooks.state]` block is simple enough to parse line-based for the specific
16
+ * project-path-keyed entries we care about.
17
+ */
18
+ /**
19
+ * Parse the `[hooks.state]` entries from a `config.toml` body that belong to a
20
+ * specific hooks.json path. Returns one entry per `<event>:<group>:<idx>` slot.
21
+ *
22
+ * Matches the on-disk shape:
23
+ * [hooks.state."/abs/.codex/hooks.json:stop:0:0"]
24
+ * trusted_hash = "sha256:..."
25
+ * enabled = false # only present when disabled
26
+ */
27
+ export function parseCodexHookTrust(configTomlBody, hooksJsonPath) {
28
+ const entries = [];
29
+ const lines = configTomlBody.split('\n');
30
+ // A hooks.state header looks like: [hooks.state."<key>"]
31
+ const headerRe = /^\s*\[hooks\.state\."(.+)"\]\s*$/;
32
+ for (let i = 0; i < lines.length; i++) {
33
+ const m = lines[i].match(headerRe);
34
+ if (!m)
35
+ continue;
36
+ const key = m[1];
37
+ // Only entries for THIS project's hooks.json path.
38
+ if (!key.startsWith(hooksJsonPath + ':'))
39
+ continue;
40
+ const slot = key.slice(hooksJsonPath.length + 1);
41
+ let trustedHash = null;
42
+ let enabled = true; // default: Codex omits the field when trusted+enabled
43
+ // Scan the block body until the next header or blank-separated section.
44
+ for (let j = i + 1; j < lines.length; j++) {
45
+ const line = lines[j];
46
+ if (headerRe.test(line) || /^\s*\[/.test(line))
47
+ break; // next table
48
+ const th = line.match(/^\s*trusted_hash\s*=\s*"([^"]*)"\s*$/);
49
+ if (th)
50
+ trustedHash = th[1];
51
+ const en = line.match(/^\s*enabled\s*=\s*(true|false)\s*$/);
52
+ if (en)
53
+ enabled = en[1] === 'true';
54
+ }
55
+ entries.push({ key, slot, trustedHash, enabled });
56
+ }
57
+ return entries;
58
+ }
59
+ /**
60
+ * Idempotency check (F2): are ALL of the agent's project hooks trusted + enabled?
61
+ * `expectedSlots` is the set of `<event>:<group>:<idx>` slots instar wrote into the
62
+ * project hooks.json (derived from buildInstarCodexHookGroups). Returns the slots
63
+ * that still need arming (untrusted) and the ones explicitly disabled (enabled=false,
64
+ * which "trust all" does NOT clear — F3: never silently re-enable a user-disabled hook).
65
+ */
66
+ export function codexHooksArmingStatus(configTomlBody, hooksJsonPath, expectedSlots) {
67
+ const entries = parseCodexHookTrust(configTomlBody, hooksJsonPath);
68
+ const bySlot = new Map(entries.map((e) => [e.slot, e]));
69
+ const untrusted = [];
70
+ const disabled = [];
71
+ for (const slot of expectedSlots) {
72
+ const e = bySlot.get(slot);
73
+ if (!e || !e.trustedHash) {
74
+ untrusted.push(slot);
75
+ }
76
+ else if (!e.enabled) {
77
+ disabled.push(slot);
78
+ }
79
+ }
80
+ return { untrusted, disabled, allArmed: untrusted.length === 0 && disabled.length === 0 };
81
+ }
82
+ /**
83
+ * Derive the `<event>:<group>:<idx>` slots from a Codex hooks.json config object
84
+ * (the shape buildInstarCodexHookGroups produces). Codex lowercases+snake_cases the
85
+ * event for the state key (PreToolUse → pre_tool_use, etc.).
86
+ */
87
+ const EVENT_TO_STATE_KEY = {
88
+ PreToolUse: 'pre_tool_use',
89
+ PermissionRequest: 'permission_request',
90
+ PostToolUse: 'post_tool_use',
91
+ PreCompact: 'pre_compact',
92
+ PostCompact: 'post_compact',
93
+ SessionStart: 'session_start',
94
+ UserPromptSubmit: 'user_prompt_submit',
95
+ SubagentStart: 'subagent_start',
96
+ SubagentStop: 'subagent_stop',
97
+ Stop: 'stop',
98
+ };
99
+ export function expectedHookSlots(hooks) {
100
+ const slots = [];
101
+ for (const [event, groups] of Object.entries(hooks)) {
102
+ const stateEvent = EVENT_TO_STATE_KEY[event];
103
+ if (!stateEvent)
104
+ continue;
105
+ (groups ?? []).forEach((group, groupIdx) => {
106
+ const count = Array.isArray(group.hooks) ? group.hooks.length : 0;
107
+ for (let hookIdx = 0; hookIdx < count; hookIdx++) {
108
+ slots.push(`${stateEvent}:${groupIdx}:${hookIdx}`);
109
+ }
110
+ });
111
+ }
112
+ return slots;
113
+ }
114
+ //# sourceMappingURL=codexHookTrust.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codexHookTrust.js","sourceRoot":"","sources":["../../src/core/codexHookTrust.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"installCodexHooks.d.ts","sourceRoot":"","sources":["../../src/core/installCodexHooks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAKH,oFAAoF;AACpF,eAAO,MAAM,uBAAuB,0BAA0B,CAAC;AAE/D,UAAU,gBAAgB;IACxB,IAAI,EAAE,SAAS,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AACD,UAAU,cAAc;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,gBAAgB,EAAE,CAAC;CAC3B;AAMD,2FAA2F;AAC3F,wBAAgB,0BAA0B,CACxC,UAAU,EAAE,MAAM,GACjB,MAAM,CAAC,MAAM,EAAE,cAAc,EAAE,CAAC,CAiDlC;AAQD;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAwB5D"}
1
+ {"version":3,"file":"installCodexHooks.d.ts","sourceRoot":"","sources":["../../src/core/installCodexHooks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAKH,oFAAoF;AACpF,eAAO,MAAM,uBAAuB,0BAA0B,CAAC;AAE/D,UAAU,gBAAgB;IACxB,IAAI,EAAE,SAAS,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AACD,UAAU,cAAc;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,gBAAgB,EAAE,CAAC;CAC3B;AAMD,2FAA2F;AAC3F,wBAAgB,0BAA0B,CACxC,UAAU,EAAE,MAAM,GACjB,MAAM,CAAC,MAAM,EAAE,cAAc,EAAE,CAAC,CAwDlC;AAQD;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAwB5D"}
@@ -54,26 +54,33 @@ export function buildInstarCodexHookGroups(projectDir) {
54
54
  // exec_command tool and blocks `rm -rf /`; with '*'/'' it did not fire at all).
55
55
  // Each script classifies and decides: dangerous-command-guard covers Codex's
56
56
  // native shell/exec_command (the main destructive surface); external-operation-gate
57
- // covers mcp__* tools; grounding-before-messaging gates messaging commands. All
58
- // read the command from Codex's stdin payload — Codex's exec_command puts it in
59
- // tool_input.cmd (Claude uses tool_input.command); the scripts shim arg→stdin and
60
- // accept both field names.
57
+ // covers mcp__* tools; grounding-before-messaging gates messaging commands;
58
+ // deferral-detector inspects messaging commands for false-blocker / orphan-TODO
59
+ // language (it is a PreToolUse hook on Claude too NOT a Stop hook). All read the
60
+ // command from Codex's stdin payload — Codex's exec_command puts it in
61
+ // tool_input.cmd (Claude uses tool_input.command); the scripts accept both field
62
+ // names AND both tool names (Bash | exec_command).
61
63
  PreToolUse: [
62
- { matcher: '.*', hooks: [sh('dangerous-command-guard.sh'), node('external-operation-gate.js'), sh('grounding-before-messaging.sh')] },
64
+ { matcher: '.*', hooks: [sh('dangerous-command-guard.sh'), node('external-operation-gate.js'), sh('grounding-before-messaging.sh'), node('deferral-detector.js')] },
63
65
  ],
64
66
  // Codex-only checkpoint. Routes to the same gate; the trust system
65
67
  // auto-decides (allow/deny) with NO human prompt so autonomy is preserved.
66
68
  PermissionRequest: [
67
69
  { matcher: '.*', hooks: [node('external-operation-gate.js')] },
68
70
  ],
69
- // End-of-turn review: coherence/tone + deferral + scope-coherence checkpoint.
70
- // All three are framework-neutral (read stdin, POST to the local server). Codex
71
- // honors `{decision:"block", reason}` on Stop (verified in the 0.133 binary's
72
- // StopCommandOutputWire)the same grounding-pause semantics as Claude, NOT a
73
- // hard termination. scope-coherence defaults to `approve` and self-throttles
74
- // (depth threshold + 30-min cooldown), so it can't loop an autonomous Codex run.
71
+ // End-of-turn review trio MUST MIRROR the Claude Stop trio
72
+ // (settings-template.json): response-review + claim-intercept-response +
73
+ // scope-coherence-checkpoint. (Earlier this wrongly substituted
74
+ // deferral-detectora PreToolUse hook whose `tool_name==='Bash'` guard
75
+ // no-ops on a Stop payload; deferral-detector now lives on PreToolUse above,
76
+ // matching Claude.) All three are framework-neutral (read stdin, POST to the
77
+ // local server). Codex honors `{decision:"block", reason}` on Stop (verified
78
+ // in the 0.133 binary's StopCommandOutputWire) — the same grounding-pause
79
+ // semantics as Claude, NOT a hard termination. scope-coherence defaults to
80
+ // `approve` and self-throttles (depth threshold + 30-min cooldown), so it
81
+ // can't loop an autonomous Codex run.
75
82
  Stop: [
76
- { matcher: '', hooks: [{ ...node('response-review.js'), timeout: 10000 }, node('deferral-detector.js'), node('scope-coherence-checkpoint.js')] },
83
+ { matcher: '', hooks: [{ ...node('response-review.js'), timeout: 10000 }, node('claim-intercept-response.js'), node('scope-coherence-checkpoint.js')] },
77
84
  ],
78
85
  // Identity/context injection.
79
86
  SessionStart: [
@@ -1 +1 @@
1
- {"version":3,"file":"installCodexHooks.js","sourceRoot":"","sources":["../../src/core/installCodexHooks.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"installCodexHooks.js","sourceRoot":"","sources":["../../src/core/installCodexHooks.ts"],"names":[],"mappings":"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"}
@@ -52,6 +52,10 @@ export interface Session {
52
52
  * model id. Per-framework resolution happens in the headless/
53
53
  * interactive launch builders, not at the session-state level. */
54
54
  model?: ModelTier | string;
55
+ /** The AI framework/engine powering this session. Carried so the dashboard
56
+ * renders engine-aware (a Codex session must not display as a Claude one).
57
+ * Populated at spawn from the resolved framework; undefined on legacy records. */
58
+ framework?: 'claude-code' | 'codex-cli';
55
59
  /** The initial prompt/instruction sent to the framework's CLI */
56
60
  prompt?: string;
57
61
  /** Maximum duration in minutes before the session is killed */