greprag 5.68.0 → 5.69.2

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 (39) hide show
  1. package/dist/capture-manifest.d.ts +5 -2
  2. package/dist/capture-manifest.js +9 -5
  3. package/dist/capture-manifest.js.map +1 -1
  4. package/dist/commands/codex-coordinate.d.ts +46 -0
  5. package/dist/commands/codex-coordinate.js +257 -0
  6. package/dist/commands/codex-coordinate.js.map +1 -0
  7. package/dist/commands/collision-check.d.ts +1 -1
  8. package/dist/commands/collision-check.js +10 -3
  9. package/dist/commands/collision-check.js.map +1 -1
  10. package/dist/commands/coordinate-gate.d.ts +5 -4
  11. package/dist/commands/coordinate-gate.js +43 -8
  12. package/dist/commands/coordinate-gate.js.map +1 -1
  13. package/dist/commands/inbox-primer-reminder.js +3 -3
  14. package/dist/commands/inbox-primer-reminder.js.map +1 -1
  15. package/dist/commands/init.js +21 -3
  16. package/dist/commands/init.js.map +1 -1
  17. package/dist/commands/mechanic-spawn.js +1 -1
  18. package/dist/commands/mechanic-spawn.js.map +1 -1
  19. package/dist/commands/status.d.ts +1 -0
  20. package/dist/commands/status.js +3 -1
  21. package/dist/commands/status.js.map +1 -1
  22. package/dist/hook.js +77 -77
  23. package/dist/hook.js.map +1 -1
  24. package/dist/index.js +17 -7
  25. package/dist/index.js.map +1 -1
  26. package/dist/inline-atom-episode.d.ts +72 -0
  27. package/dist/inline-atom-episode.js +380 -0
  28. package/dist/inline-atom-episode.js.map +1 -0
  29. package/dist/inline-atom-hook.d.ts +19 -0
  30. package/dist/inline-atom-hook.js +89 -0
  31. package/dist/inline-atom-hook.js.map +1 -0
  32. package/dist/inline-atom.d.ts +13 -13
  33. package/dist/inline-atom.js +15 -62
  34. package/dist/inline-atom.js.map +1 -1
  35. package/dist/opencode-plugin.bundle.js +44 -9
  36. package/package.json +1 -1
  37. package/skill/commander/SKILL.md +2 -2
  38. package/skill/greprag/SKILL.md +2 -2
  39. package/skill/templates/codex-chip-spawn.md +1 -1
package/dist/hook.js CHANGED
@@ -106,11 +106,13 @@ const archive_1 = require("./commands/archive");
106
106
  // repo (cloud watcher registry) and inject a coordinate-now directive. All real
107
107
  // logic lives in ./commands/collision-check. docs/schematic-triggers.md
108
108
  const collision_check_1 = require("./commands/collision-check");
109
- // Coordinate-GATE (PreToolUse) — on a risky shared-state action (git merge/push/
110
- // deploy) do a FRESH inbox-watchers read and, if a peer is live in THIS repo, raise
111
- // a permission `ask` so the agent coordinates before merging. Source-agnostic eval
112
- // (runCoordinateGate) + PreToolUse adapter. docs/collision-schematic.md
109
+ // Coordinate-GATE (PreToolUse) — on risky shared-state actions, Claude/OpenCode
110
+ // consult the watcher registry; Codex additionally requires committed,
111
+ // artifact-bound native/cross-harness conferral evidence. ask is unsupported by
112
+ // Codex, so its adapter uses deny + agent-correctable evidence. adr:
113
+ // adr/codex-coordinate-gate.md
113
114
  const coordinate_gate_1 = require("./commands/coordinate-gate");
115
+ const codex_coordinate_1 = require("./commands/codex-coordinate");
114
116
  // (The asyncRewake idle-wake poll was REVERTED 2026-06-23 — falsified: a detached
115
117
  // process's exit-2 has no harness event to attach to in true deep idle, so it never
116
118
  // woke an idle session. Only a live Monitor task delivers to idle. adr: adr/monitor-
@@ -123,11 +125,11 @@ const inbox_drain_1 = require("./commands/inbox-drain");
123
125
  const procedure_1 = require("./procedure");
124
126
  const ship_through_gate_1 = require("./commands/ship-through-gate");
125
127
  // Procedure System LEARN leg (docs/procedure-system.md §V1 LEARN-leg build
126
- // spec): the span watch — opened at UserPromptSubmit (procedureCheck), observed
128
+ // spec): the episode watch — opened at UserPromptSubmit (procedureCheck), observed
127
129
  // per turn by the Stop hook (observeProcedureTurn), closed by negative
128
130
  // continuity, distilled server-side, transitions applied to the local store.
129
131
  const procedure_watch_1 = require("./procedure-watch");
130
- const inline_atom_1 = require("./inline-atom");
132
+ const inline_atom_hook_1 = require("./inline-atom-hook");
131
133
  const skill_landing_1 = require("./skill-landing");
132
134
  const skill_mirror_client_1 = require("./skill-mirror-client");
133
135
  const equipped_loadouts_cache_1 = require("./equipped-loadouts-cache");
@@ -950,42 +952,6 @@ async function observeProcedureTurn(cfg, anchor, turn, cwd, redaction) {
950
952
  }
951
953
  (0, procedure_watch_1.writeProcedureWatch)(anchor.projectId, next);
952
954
  }
953
- async function observeInlineAtoms(cfg, anchor, turn, sessionId, userPrompt, agentResponse) {
954
- const atoms = (0, inline_atom_1.mergeInlineAtoms)(userPrompt, agentResponse);
955
- if (atoms.length === 0)
956
- return;
957
- // Provider policy:
958
- // - auto/greprag: portable command-hook path, costed to GrepRAG Flash-Lite.
959
- // - harness: reserved for Claude Code's native Haiku prompt-hook bridge. Until
960
- // that bridge can write the same local state file, fall back to GrepRAG.
961
- // - off: disable the detector.
962
- const provider = (process.env.GREPRAG_INLINE_ATOM_JUDGE || 'auto').toLowerCase();
963
- if (provider === 'off')
964
- return;
965
- let verdicts = [];
966
- try {
967
- const res = await fetch(`${cfg.apiUrl}/v1/inline-atom/${anchor.projectId}/judge`, {
968
- method: 'POST',
969
- headers: { 'Authorization': `Bearer ${cfg.apiKey}`, 'Content-Type': 'application/json' },
970
- body: JSON.stringify({
971
- projectName: anchor.projectName,
972
- user: userPrompt,
973
- assistant: agentResponse,
974
- atoms,
975
- provider: provider === 'harness' ? 'greprag-fallback' : 'greprag',
976
- }),
977
- });
978
- if (res.ok) {
979
- const data = await res.json();
980
- verdicts = Array.isArray(data.verdicts) ? data.verdicts : [];
981
- }
982
- }
983
- catch { /* detector is best-effort */ }
984
- (0, inline_atom_1.promoteInlineAtomResolutions)(anchor.projectId, (0, session_id_1.truncateSessionId)(sessionId) || null, verdicts);
985
- if (verdicts.some(v => v.label === 'friction')) {
986
- (0, inline_atom_1.writeInlineAtomFriction)(anchor.projectId, (0, session_id_1.truncateSessionId)(sessionId) || null, verdicts);
987
- }
988
- }
989
955
  /** SessionStart fetch: the live enrichment-health verdict (fix c2eb8777).
990
956
  * Null = healthy OR unreachable — the outage announce only fires on a
991
957
  * POSITIVE probe failure, so an API blip never cries wolf. The worker
@@ -1249,7 +1215,7 @@ async function store(input, source = 'claude-code') {
1249
1215
  }
1250
1216
  catch { /* best-effort — a docptr outage never fails the Stop hook */ }
1251
1217
  }
1252
- // Procedure System span observer (docs/procedure-system.md V1 LEARN leg):
1218
+ // Procedure System episode observer (docs/procedure-system.md V1 LEARN leg):
1253
1219
  // gated on "a watch file exists" — zero cost when no watch is open. One
1254
1220
  // synchronous flash-lite continuity call per observed turn; close/watchdog
1255
1221
  // logic is pure in procedure-watch.ts. Best-effort, never throws.
@@ -1259,12 +1225,11 @@ async function store(input, source = 'claude-code') {
1259
1225
  }
1260
1226
  catch { /* fail-open — a procedure outage never fails the Stop hook */ }
1261
1227
  }
1262
- // Inline-Atom Friction Capture (docs/capture-system.md): if this turn's prose
1263
- // contains inline backticked atoms, make ONE batched cheap-judge call. Neutral
1264
- // report atoms stop here; friction writes a local next-turn memory/search
1265
- // directive. Best-effort, never blocks capture.
1228
+ // Inline-Atom Episode Capture (docs/capture-system.md): new backtick
1229
+ // candidates, active episodes, and replay receipts share one Flash-Lite
1230
+ // observation call. Closed episodes alone reach the Flash distiller.
1266
1231
  try {
1267
- await observeInlineAtoms(cfg, anchor, turn, input.session_id, userPrompt, agentResponse);
1232
+ await (0, inline_atom_hook_1.observeInlineAtoms)(cfg, anchor, input.session_id, userPrompt, agentResponse, toolCalls);
1268
1233
  }
1269
1234
  catch { /* fail-open — an inline-atom miss never fails the Stop hook */ }
1270
1235
  // Skill mirror (docs/load-system.md Tier 3): a skill-load turn shadows that
@@ -1929,7 +1894,7 @@ async function notify(input, source = 'claude-code', chipContext) {
1929
1894
  excludeMessageIds: liveMessageId ? [liveMessageId] : [],
1930
1895
  });
1931
1896
  const reminders = await injectReminders(input, cfg, short, 'codex');
1932
- const inlineAtoms = buildPendingInlineAtomContext(input, short);
1897
+ const inlineAtoms = (0, inline_atom_hook_1.buildPendingInlineAtomContext)(input, short);
1933
1898
  const parts = [duplicateDelegation, chipContext, context, reminders, inlineAtoms].filter((p) => !!p);
1934
1899
  if (parts.length)
1935
1900
  writeAdditionalContext('UserPromptSubmit', parts.join('\n\n'));
@@ -1941,24 +1906,11 @@ async function notify(input, source = 'claude-code', chipContext) {
1941
1906
  // subcommand reaching the operator's settings. Fires whatever's deficient (stacking),
1942
1907
  // and auto-silences each module the instant its deficiency resolves.
1943
1908
  const reminders = await injectReminders(input, cfg, short);
1944
- const inlineAtoms = buildPendingInlineAtomContext(input, short);
1909
+ const inlineAtoms = (0, inline_atom_hook_1.buildPendingInlineAtomContext)(input, short);
1945
1910
  const parts = [reminders, inlineAtoms].filter((p) => !!p);
1946
1911
  if (parts.length)
1947
1912
  writeAdditionalContext('UserPromptSubmit', parts.join('\n\n'));
1948
1913
  }
1949
- function buildPendingInlineAtomContext(input, short) {
1950
- try {
1951
- const anchor = (0, project_anchor_1.readAnchor)(input.cwd || process.cwd());
1952
- if (!anchor.projectId)
1953
- return null;
1954
- const records = (0, inline_atom_1.readAndClearInlineAtomFriction)(anchor.projectId, short);
1955
- const prompt = typeof input.prompt === 'string' ? input.prompt : '';
1956
- return (0, inline_atom_1.buildInlineAtomContext)({ projectId: anchor.projectId, prompt, records });
1957
- }
1958
- catch {
1959
- return null;
1960
- }
1961
- }
1962
1914
  /** Has the operator hit the Mechanic kill switch (`mechanic off` → the D8 panic
1963
1915
  * switch file the guard dispatcher also checks first)? When set, the active-
1964
1916
  * Mechanic pair (SessionStart announce + per-turn friction reminder) stays quiet,
@@ -2356,17 +2308,16 @@ function stateUpdate(input) {
2356
2308
  }
2357
2309
  catch { /* state update is best-effort — never block the turn */ }
2358
2310
  }
2359
- /** PreToolUse coordinate-GATE `greprag-hook coordinate-gate`. On a risky
2360
- * shared-state action (git merge / push / deploy) does a FRESH inbox-watchers
2361
- * read and, if another live session is working in THIS repo, raises a permission
2362
- * `ask` (a true pause before the irreversible action) whose reason names the
2363
- * live peers and tells the agent to message them first. Fires the network read
2311
+ /** PreToolUse coordinate-GATE. On a risky shared-state action (git merge / push /
2312
+ * deploy), does a FRESH inbox-watchers read. Claude/OpenCode inject the roster;
2313
+ * Codex denies until committed, artifact-bound conferral evidence exists.
2314
+ * Both paths name live peers and tell the agent to message them first. Fires the network read
2364
2315
  * ONLY for risky commands — a non-risky Bash call is classified locally and
2365
2316
  * exits silent, no network. NO dedup: a fresh read every fire (a stale roster at
2366
2317
  * merge is the exact failure this prevents). Reads only the watcher registry (no
2367
- * inbox content) — no eavesdrop surface. Fail-quiet: any miss silent, the
2368
- * action proceeds ungated. docs/collision-schematic.md */
2369
- async function coordinateGate(input) {
2318
+ * inbox content) — no eavesdrop surface. Watcher misses fail quiet; Codex still
2319
+ * requires its local artifact/action attestation. docs/collision-schematic.md */
2320
+ async function coordinateGate(input, codex = false) {
2370
2321
  const cwd = input.cwd || process.cwd();
2371
2322
  const cfg = getConfig(cwd);
2372
2323
  if (!cfg.enabled || !cfg.apiKey)
@@ -2388,6 +2339,28 @@ async function coordinateGate(input) {
2388
2339
  }
2389
2340
  if (!anchor.projectId)
2390
2341
  return; // unanchored → nothing to match
2342
+ // First Codex denial is local. Only an already-attested retry pays for the
2343
+ // fresh watcher read, so API latency cannot bypass commit-first enforcement.
2344
+ if (codex) {
2345
+ const local = (0, codex_coordinate_1.evaluateCodexCoordinationGate)({
2346
+ projectId: anchor.projectId,
2347
+ sessionId: short,
2348
+ cwd,
2349
+ trigger,
2350
+ command: typeof toolInput.command === 'string' ? toolInput.command : '',
2351
+ watcherPeers: [],
2352
+ });
2353
+ if (!local.ready) {
2354
+ process.stdout.write(JSON.stringify({
2355
+ hookSpecificOutput: {
2356
+ hookEventName: input.hook_event_name || 'PreToolUse',
2357
+ permissionDecision: 'deny',
2358
+ permissionDecisionReason: local.reason,
2359
+ },
2360
+ }) + '\n');
2361
+ return;
2362
+ }
2363
+ }
2391
2364
  // I/O stays in the hook: fresh peer read off the hot path → env.collisionPeers.
2392
2365
  const peers = await (0, coordinate_gate_1.resolveCollisionPeers)({
2393
2366
  short,
@@ -2397,6 +2370,26 @@ async function coordinateGate(input) {
2397
2370
  apiKey: cfg.apiKey,
2398
2371
  alias: (0, session_id_1.readIdentityAlias)(),
2399
2372
  });
2373
+ if (codex) {
2374
+ const current = (0, codex_coordinate_1.evaluateCodexCoordinationGate)({
2375
+ projectId: anchor.projectId,
2376
+ sessionId: short,
2377
+ cwd,
2378
+ trigger,
2379
+ command: typeof toolInput.command === 'string' ? toolInput.command : '',
2380
+ watcherPeers: peers.map(peer => peer.short),
2381
+ });
2382
+ if (!current.ready) {
2383
+ process.stdout.write(JSON.stringify({
2384
+ hookSpecificOutput: {
2385
+ hookEventName: input.hook_event_name || 'PreToolUse',
2386
+ permissionDecision: 'deny',
2387
+ permissionDecisionReason: current.reason,
2388
+ },
2389
+ }) + '\n');
2390
+ return;
2391
+ }
2392
+ }
2400
2393
  // ship-through: review is a run prerequisite, not a human permission prompt.
2401
2394
  // It applies to routine merge/deploy only; standalone push keeps its own gate.
2402
2395
  try {
@@ -2434,9 +2427,10 @@ async function coordinateGate(input) {
2434
2427
  const fired = (0, reminder_registry_1.collectReminders)(env, (0, reminder_registry_1.commandModules)());
2435
2428
  if (!fired.length)
2436
2429
  return;
2437
- // EFFECT: inject as additionalContext — advisory heads-up, NO permission pause.
2430
+ // Non-Codex effect: inject as additionalContext — advisory heads-up, NO permission pause.
2438
2431
  // `ask` was too intrusive (prompted on every git op while peers were live); inject
2439
- // keeps the agent aware without a manual-allow. adr: adr/monitor-resilience.md
2432
+ // keeps the agent aware without a manual-allow. Codex uses the evidence gate above.
2433
+ // adr: adr/codex-coordinate-gate.md
2440
2434
  process.stdout.write(JSON.stringify({
2441
2435
  hookSpecificOutput: {
2442
2436
  hookEventName: input.hook_event_name || 'PreToolUse',
@@ -2466,7 +2460,7 @@ async function main() {
2466
2460
  const subcommand = process.argv[2];
2467
2461
  const validSubs = new Set([
2468
2462
  'store', 'recap', 'recompact', 'notify', 'mail', 'friction-reminder', 'session-id', 'pre-spawn-check', 'armcheck',
2469
- 'collision-check', 'drain', 'coordinate-gate', 'procedure-check',
2463
+ 'collision-check', 'drain', 'coordinate-gate', 'codex-coordinate-gate', 'procedure-check',
2470
2464
  'guard', 'guard-refresh', 'guard-flush',
2471
2465
  'context-probe', 'context-check', 'crush-wrap',
2472
2466
  'pre-compact', 'archive-pointer',
@@ -2475,7 +2469,7 @@ async function main() {
2475
2469
  'codex-chip-hook',
2476
2470
  ]);
2477
2471
  if (!validSubs.has(subcommand)) {
2478
- process.stderr.write(`Usage: greprag-hook <store|recap|recompact|notify|mail|friction-reminder|procedure-check|session-id|pre-spawn-check|armcheck|collision-check|drain|coordinate-gate|guard|guard-refresh|guard-flush|context-probe|context-check|crush-wrap|pre-compact|archive-pointer|codex-store|codex-notify|codex-inbox|codex-recap|codex-permission-context|codex-subagent-start|codex-chip-hook>\n`);
2472
+ process.stderr.write(`Usage: greprag-hook <store|recap|recompact|notify|mail|friction-reminder|procedure-check|session-id|pre-spawn-check|armcheck|collision-check|drain|coordinate-gate|codex-coordinate-gate|guard|guard-refresh|guard-flush|context-probe|context-check|crush-wrap|pre-compact|archive-pointer|codex-store|codex-notify|codex-inbox|codex-recap|codex-permission-context|codex-subagent-start|codex-chip-hook>\n`);
2479
2473
  process.exit(1);
2480
2474
  }
2481
2475
  let input = {};
@@ -2578,11 +2572,17 @@ async function main() {
2578
2572
  await drain(input);
2579
2573
  }
2580
2574
  else if (subcommand === 'coordinate-gate') {
2581
- // PreToolUse[Bash] — on a risky shared-state action (git merge/push/deploy),
2582
- // fresh inbox-watchers read permission `ask` if a peer is live in this repo.
2575
+ // Claude/OpenCode PreToolUse[Bash] — fresh watcher read + context injection
2576
+ // when a risky shared-state action has a live same-repo peer.
2583
2577
  // docs/collision-schematic.md
2584
2578
  await coordinateGate(input);
2585
2579
  }
2580
+ else if (subcommand === 'codex-coordinate-gate') {
2581
+ // Codex PreToolUse[Bash] — deny risky shared-state actions until the
2582
+ // committed artifact has fresh native + cross-harness conferral evidence.
2583
+ // adr: adr/codex-coordinate-gate.md
2584
+ await coordinateGate(input, true);
2585
+ }
2586
2586
  else if (subcommand === 'context-probe') {
2587
2587
  // Stop probe — transcript-tail context-size measurement, local state only.
2588
2588
  (0, context_governor_1.runContextProbe)(input);