greprag 5.74.11 → 5.74.12

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.
@@ -0,0 +1,213 @@
1
+ "use strict";
2
+ /** Codex delivery coordination - interrupt the first delivery action once,
3
+ * then keep the rest of that delivery run non-blocking.
4
+ *
5
+ * The hook cannot call native Codex task tools. It names the exact agent-owned
6
+ * discovery and messaging actions, persists the open delivery window before
7
+ * denying, and never waits for peer replies or attestation.
8
+ *
9
+ * adr: adr/codex-coordinate-gate.md */
10
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
11
+ if (k2 === undefined) k2 = k;
12
+ var desc = Object.getOwnPropertyDescriptor(m, k);
13
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
14
+ desc = { enumerable: true, get: function() { return m[k]; } };
15
+ }
16
+ Object.defineProperty(o, k2, desc);
17
+ }) : (function(o, m, k, k2) {
18
+ if (k2 === undefined) k2 = k;
19
+ o[k2] = m[k];
20
+ }));
21
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
22
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
23
+ }) : function(o, v) {
24
+ o["default"] = v;
25
+ });
26
+ var __importStar = (this && this.__importStar) || (function () {
27
+ var ownKeys = function(o) {
28
+ ownKeys = Object.getOwnPropertyNames || function (o) {
29
+ var ar = [];
30
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
31
+ return ar;
32
+ };
33
+ return ownKeys(o);
34
+ };
35
+ return function (mod) {
36
+ if (mod && mod.__esModule) return mod;
37
+ var result = {};
38
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
39
+ __setModuleDefault(result, mod);
40
+ return result;
41
+ };
42
+ })();
43
+ Object.defineProperty(exports, "__esModule", { value: true });
44
+ exports.DELIVERY_COORDINATION_WINDOW_MS = void 0;
45
+ exports.codexDeliveryTrigger = codexDeliveryTrigger;
46
+ exports.codexDeliveryCoordinationText = codexDeliveryCoordinationText;
47
+ exports.evaluateCodexDeliveryCoordination = evaluateCodexDeliveryCoordination;
48
+ const crypto = __importStar(require("crypto"));
49
+ const fs = __importStar(require("fs"));
50
+ const path = __importStar(require("path"));
51
+ const child_process_1 = require("child_process");
52
+ const coordinate_gate_1 = require("./commands/coordinate-gate");
53
+ exports.DELIVERY_COORDINATION_WINDOW_MS = 30 * 60 * 1000;
54
+ function homeDir() {
55
+ return process.env.USERPROFILE || process.env.HOME || '';
56
+ }
57
+ function normalize(value) {
58
+ return path.resolve(value).replace(/\\/g, '/').toLowerCase();
59
+ }
60
+ function gitRoot(cwd) {
61
+ try {
62
+ const root = (0, child_process_1.execFileSync)('git', ['rev-parse', '--show-toplevel'], {
63
+ cwd,
64
+ encoding: 'utf8',
65
+ stdio: ['ignore', 'pipe', 'ignore'],
66
+ windowsHide: true,
67
+ }).trim();
68
+ return root ? normalize(root) : null;
69
+ }
70
+ catch {
71
+ return null;
72
+ }
73
+ }
74
+ function statePath(input, repoRoot) {
75
+ const home = homeDir();
76
+ const session = (input.session_id || '').trim();
77
+ if (!home || !session)
78
+ return null;
79
+ const key = crypto.createHash('sha256')
80
+ .update(`${session}\0${repoRoot}`)
81
+ .digest('hex')
82
+ .slice(0, 24);
83
+ return path.join(home, '.greprag', 'state', `codex-delivery-${key}.json`);
84
+ }
85
+ function readWindow(file) {
86
+ try {
87
+ return JSON.parse(fs.readFileSync(file, 'utf8'));
88
+ }
89
+ catch {
90
+ return null;
91
+ }
92
+ }
93
+ function writeWindow(file, window) {
94
+ try {
95
+ fs.mkdirSync(path.dirname(file), { recursive: true });
96
+ fs.writeFileSync(file, JSON.stringify(window, null, 2) + '\n');
97
+ return true;
98
+ }
99
+ catch {
100
+ return false;
101
+ }
102
+ }
103
+ function isShellCapableTool(input) {
104
+ const name = (input.tool_name || '').toLowerCase();
105
+ return /(?:^|[.:/_-])(bash|shell|exec|exec_command)$/.test(name);
106
+ }
107
+ function decodeQuoted(value) {
108
+ if (value.startsWith('"')) {
109
+ try {
110
+ return JSON.parse(value);
111
+ }
112
+ catch {
113
+ return null;
114
+ }
115
+ }
116
+ if (value.startsWith("'")) {
117
+ return value.slice(1, -1).replace(/\\'/g, "'").replace(/\\\\/g, '\\');
118
+ }
119
+ return null;
120
+ }
121
+ function embeddedCommands(code) {
122
+ const commands = [];
123
+ const re = /(?:command|cmd)\s*:\s*("(?:\\.|[^"])*"|'(?:\\.|[^'])*')/g;
124
+ for (const match of code.matchAll(re)) {
125
+ const decoded = decodeQuoted(match[1]);
126
+ if (decoded)
127
+ commands.push(decoded);
128
+ }
129
+ return commands;
130
+ }
131
+ function commandCandidates(input) {
132
+ if (!isShellCapableTool(input))
133
+ return [];
134
+ const toolInput = input.tool_input;
135
+ if (typeof toolInput === 'string')
136
+ return embeddedCommands(toolInput);
137
+ if (!toolInput || typeof toolInput !== 'object')
138
+ return [];
139
+ const candidates = [];
140
+ const fields = toolInput;
141
+ for (const key of ['command', 'cmd', 'script']) {
142
+ const value = fields[key];
143
+ if (typeof value === 'string')
144
+ candidates.push(value);
145
+ }
146
+ for (const key of ['code', 'input']) {
147
+ const value = fields[key];
148
+ if (typeof value === 'string')
149
+ candidates.push(...embeddedCommands(value));
150
+ }
151
+ return candidates;
152
+ }
153
+ function codexDeliveryTrigger(input) {
154
+ for (const command of commandCandidates(input)) {
155
+ const trigger = (0, coordinate_gate_1.classifyRiskyCommand)(command);
156
+ if (trigger)
157
+ return trigger;
158
+ }
159
+ return null;
160
+ }
161
+ function codexDeliveryCoordinationText(trigger) {
162
+ return `[DELIVERY NOW]
163
+
164
+ Before ${trigger.label}, call codex_app.list_threads unfiltered and keep only peers in the same repo. Use codex_app.send_message_to_thread once for peers with ready or overlapping work; include your branch/commit and ask only for ready commits or concrete blockers.
165
+
166
+ Include ready handoffs and clear known blockers, then retry immediately. Do not call wait_threads, wait for replies, or send follow-ups. Missing replies and unfinished peer work do not block delivery.`;
167
+ }
168
+ /** First delivery action opens a 30-minute session/repo window and interrupts
169
+ * once. Later merge/push/deploy/release actions refresh the same window and
170
+ * proceed without another coordination round. */
171
+ function evaluateCodexDeliveryCoordination(input, now = Date.now()) {
172
+ if (input.hook_event_name !== 'PreToolUse')
173
+ return null;
174
+ const trigger = codexDeliveryTrigger(input);
175
+ if (!trigger)
176
+ return null;
177
+ const cwd = input.cwd || process.cwd();
178
+ const repoRoot = gitRoot(cwd);
179
+ if (!repoRoot)
180
+ return null;
181
+ const file = statePath(input, repoRoot);
182
+ if (!file)
183
+ return null;
184
+ const previous = readWindow(file);
185
+ const previousLastAction = previous ? Date.parse(previous.lastActionAt) : NaN;
186
+ if (previous
187
+ && previous.repoRoot === repoRoot
188
+ && Number.isFinite(previousLastAction)
189
+ && now - previousLastAction < exports.DELIVERY_COORDINATION_WINDOW_MS) {
190
+ writeWindow(file, {
191
+ ...previous,
192
+ lastActionAt: new Date(now).toISOString(),
193
+ });
194
+ return null;
195
+ }
196
+ const openedAt = new Date(now).toISOString();
197
+ if (!writeWindow(file, {
198
+ sessionId: input.session_id || '',
199
+ repoRoot,
200
+ openedAt,
201
+ lastActionAt: openedAt,
202
+ })) {
203
+ return null;
204
+ }
205
+ return {
206
+ hookSpecificOutput: {
207
+ hookEventName: 'PreToolUse',
208
+ additionalContext: codexDeliveryCoordinationText(trigger),
209
+ permissionDecision: 'deny',
210
+ permissionDecisionReason: `Run one same-repo coordination pass, then retry ${trigger.label} immediately; peer replies are not required.`,
211
+ },
212
+ };
213
+ }
@@ -83,10 +83,8 @@ async function main() {
83
83
  return;
84
84
  }
85
85
  if (subcommand === 'codex-posttooluse') {
86
- const { evaluateCodexCommitResult } = await Promise.resolve().then(() => __importStar(require('./codex-checkpoint-hook')));
87
- const result = evaluateCodexCommitResult(input);
88
- if (result)
89
- process.stdout.write(JSON.stringify(result) + '\n');
86
+ // Compatibility no-op for installed configs predating the delivery-boundary
87
+ // cutover. `greprag init --codex` removes this hook.
90
88
  return;
91
89
  }
92
90
  const { evaluateCodexChipHook } = await Promise.resolve().then(() => __importStar(require('./codex-chip-hooks')));
@@ -97,10 +95,9 @@ async function main() {
97
95
  return;
98
96
  }
99
97
  let result = chipResult;
100
- if (subcommand === 'codex-pretooluse') {
101
- const { evaluatePendingCodexCheckpoint, recordCodexGitBoundary, } = await Promise.resolve().then(() => __importStar(require('./codex-checkpoint-hook')));
102
- result = mergeOutputs(result, evaluatePendingCodexCheckpoint(input));
103
- recordCodexGitBoundary(input);
98
+ if (subcommand === 'codex-pretooluse' && !result?.hookSpecificOutput.permissionDecision) {
99
+ const { evaluateCodexDeliveryCoordination } = await Promise.resolve().then(() => __importStar(require('./codex-delivery-coordination')));
100
+ result = mergeOutputs(result, evaluateCodexDeliveryCoordination(input));
104
101
  }
105
102
  if (!result?.hookSpecificOutput.permissionDecision && input.tool_name === 'Bash') {
106
103
  const { runSearchGuard } = await Promise.resolve().then(() => __importStar(require('./commands/search-guard')));
@@ -27,8 +27,8 @@
27
27
  * dedups to stay quiet), the merge gate must reflect live truth each time.
28
28
  *
29
29
  * EFFECT is the adapter's choice, not the eval's: Claude/OpenCode inject the
30
- * fresh roster as context; Codex denies until artifact-bound conferral evidence
31
- * exists because Codex does not support a permission `ask` decision. An
30
+ * fresh roster as context. Codex uses the separate local, bounded delivery
31
+ * interrupt in codex-delivery-coordination.ts and carries no attestation. An
32
32
  * ingress-source wrapper would inject instead. The eval below only produces
33
33
  * the message.
34
34
  *
@@ -12,27 +12,26 @@ exports.buildDeliveryAnnounce = buildDeliveryAnnounce;
12
12
  // adr: adr/delivery-announce-pilot.md
13
13
  function coordinationLine(platform) {
14
14
  if (platform === 'codex') {
15
- return 'Codex coordination: call list_threads unfiltered, filter to this repo/worktree, inspect matching tasks, then send_message_to_thread with your branch/commit/status before merge/push/deploy. Use GrepRAG only for cross-harness peers.';
15
+ return 'Codex: at the merge/deploy gate, call codex_app.list_threads unfiltered, filter to peers in the same repo, then use codex_app.send_message_to_thread once for ready or overlapping work.';
16
16
  }
17
17
  if (platform === 'claude-code') {
18
- return 'Claude Code coordination: discover peers with `greprag inbox watchers --json`, send to the exact session, and keep the Monitor armed for replies.';
18
+ return 'Claude Code: at the merge/deploy gate, discover peers in the same repo and send one concise delivery notice to peers with ready or overlapping work.';
19
19
  }
20
20
  if (platform === 'opencode') {
21
- return 'OpenCode coordination: use the GrepRAG project/session registry and session-targeted send; the plugin relay delivers replies.';
21
+ return 'OpenCode: at the merge/deploy gate, use the GrepRAG project/session registry and send one concise delivery notice to peers with ready or overlapping work.';
22
22
  }
23
- return 'Coordination: discover same-project peers through this harness and use GrepRAG for cross-harness peers.';
23
+ return 'At the merge/deploy gate, coordinate once with peers in the same repo who have ready or overlapping work.';
24
24
  }
25
25
  function buildDeliveryAnnounce(env) {
26
26
  if (!env.deliveryRepo)
27
27
  return null;
28
28
  const project = env.projectName?.trim() || 'current repo';
29
29
  return [
30
- `[DELIVERY CONTROL — ${project}]`,
31
- 'For full-goal code work, done means checkpointed, coordinated, integrated, pushed, deployed, and production-verified. Checkpoint each passing fix or feature.',
30
+ `[DELIVERY — ${project}]`,
31
+ 'Commit useful, passing work.',
32
32
  coordinationLine(env.platform),
33
- 'Before merge, push, deploy, or release: elect one delivery owner. That owner includes every ready peer commit, resolves ordinary mission conflicts, and settles unclaimed dirt by adopt, rescue, or discard.',
34
- 'Use the canonical commit, deploy, and release skills plus this repo\'s delivery configuration. Never borrow a branch, remote, provider command, or verification rule from another repo.',
35
- 'A full-goal delivery mission already provisions ordinary repo-scoped commit, merge, push, deploy, and verification; do not wait for a second keyword.',
33
+ 'Include ready peer commits and clear known blockers, then merge to the default branch and deploy immediately. Missing replies and unfinished peer work do not block delivery.',
34
+ 'Use this repo\'s delivery profile and verify production.',
36
35
  ].join('\n');
37
36
  }
38
37
  exports.deliveryControlModule = {
@@ -1130,18 +1130,9 @@ function applyCodexHooks(config) {
1130
1130
  if (removedPostToolInbox) {
1131
1131
  changes.push(`Removed ${removedPostToolInbox} Codex PostToolUse inbox hook(s); UserPromptSubmit now owns inbox steering`);
1132
1132
  }
1133
- const checkpointHook = {
1134
- matcher: '',
1135
- hooks: [commandHook('codex-posttooluse', 5, 'Coordinating Codex checkpoint', 'greprag-codex-hook')],
1136
- };
1137
- if (!hasGrepragHook(config.hooks.PostToolUse, 'codex-posttooluse')) {
1138
- if (!config.hooks.PostToolUse)
1139
- config.hooks.PostToolUse = [];
1140
- config.hooks.PostToolUse.push(checkpointHook);
1141
- changes.push('Added Codex PostToolUse hook (successful checkpoint coordination)');
1142
- }
1143
- else {
1144
- changes.push('Codex PostToolUse checkpoint hook already configured (skipped)');
1133
+ const removedPostToolCoord = removeGrepragHook(config.hooks, 'PostToolUse', 'codex-posttooluse');
1134
+ if (removedPostToolCoord) {
1135
+ changes.push(`Removed ${removedPostToolCoord} Codex commit-triggered coordination hook(s); delivery coordination now starts at PreToolUse`);
1145
1136
  }
1146
1137
  const permissionHook = {
1147
1138
  matcher: '',
@@ -1199,8 +1190,8 @@ function applyCodexHooks(config) {
1199
1190
  ];
1200
1191
  // adr: adr/codex-hook-latency.md
1201
1192
  // Collapse the hot PreToolUse safety pair into one fast command process. It
1202
- // runs the chip/apply_patch guard plus local Bash safety checks. The retired
1203
- // coordination gate is removed when found so old configs stop blocking.
1193
+ // runs the chip/apply_patch guard, one-shot delivery coordination, and local
1194
+ // Bash safety checks. The legacy split coordination gate is removed.
1204
1195
  const removedPreToolChip = removeGrepragHook(config.hooks, 'PreToolUse', 'codex-chip-hook');
1205
1196
  const removedPreToolCoord = removeGrepragHook(config.hooks, 'PreToolUse', 'codex-coordinate-gate');
1206
1197
  if (removedPreToolChip || removedPreToolCoord) {
@@ -1208,16 +1199,16 @@ function applyCodexHooks(config) {
1208
1199
  }
1209
1200
  const preToolUseHook = {
1210
1201
  matcher: '',
1211
- hooks: [commandHook('codex-pretooluse', 10, 'Checking GrepRAG Codex safety', 'greprag-codex-hook')],
1202
+ hooks: [commandHook('codex-pretooluse', 10, 'Checking GrepRAG Codex delivery and safety', 'greprag-codex-hook')],
1212
1203
  };
1213
1204
  if (!hasGrepragHookWithMatcher(config.hooks.PreToolUse, 'codex-pretooluse', preToolUseHook.matcher)) {
1214
1205
  if (!config.hooks.PreToolUse)
1215
1206
  config.hooks.PreToolUse = [];
1216
1207
  config.hooks.PreToolUse.push(preToolUseHook);
1217
- changes.push('Added Codex PreToolUse hook (multiplexed local safety)');
1208
+ changes.push('Added Codex PreToolUse hook (delivery coordination + local safety)');
1218
1209
  }
1219
1210
  else {
1220
- changes.push('Codex PreToolUse multiplexed safety hook already configured (skipped)');
1211
+ changes.push('Codex PreToolUse delivery/safety hook already configured (skipped)');
1221
1212
  }
1222
1213
  const removedStopChip = removeGrepragHook(config.hooks, 'Stop', 'codex-chip-hook');
1223
1214
  if (removedStopChip) {
@@ -1278,7 +1269,7 @@ function normalizeCodexHookCommands(hooks) {
1278
1269
  'codex-permission-context': { timeout: 3, statusMessage: 'Loading GrepRAG approval context' },
1279
1270
  'codex-subagent-start': { timeout: 3, statusMessage: 'Recording GrepRAG subagent metadata' },
1280
1271
  'codex-chip-hook': { timeout: 3, statusMessage: 'Enforcing Codex chip contract', runner: 'greprag-codex-hook' },
1281
- 'codex-pretooluse': { timeout: 10, statusMessage: 'Checking GrepRAG Codex safety', runner: 'greprag-codex-hook' },
1272
+ 'codex-pretooluse': { timeout: 10, statusMessage: 'Checking GrepRAG Codex delivery and safety', runner: 'greprag-codex-hook' },
1282
1273
  'codex-coordinate-gate': { timeout: 10, statusMessage: 'Checking peer coordination' },
1283
1274
  'codex-store': { timeout: 3, statusMessage: 'Storing GrepRAG turn', runner: 'greprag-codex-hook' },
1284
1275
  };
@@ -2401,27 +2401,26 @@ var loadoutRegistrarModule = {
2401
2401
  // src/commands/delivery-reminder.ts
2402
2402
  function coordinationLine(platform) {
2403
2403
  if (platform === "codex") {
2404
- return "Codex coordination: call list_threads unfiltered, filter to this repo/worktree, inspect matching tasks, then send_message_to_thread with your branch/commit/status before merge/push/deploy. Use GrepRAG only for cross-harness peers.";
2404
+ return "Codex: at the merge/deploy gate, call codex_app.list_threads unfiltered, filter to peers in the same repo, then use codex_app.send_message_to_thread once for ready or overlapping work.";
2405
2405
  }
2406
2406
  if (platform === "claude-code") {
2407
- return "Claude Code coordination: discover peers with `greprag inbox watchers --json`, send to the exact session, and keep the Monitor armed for replies.";
2407
+ return "Claude Code: at the merge/deploy gate, discover peers in the same repo and send one concise delivery notice to peers with ready or overlapping work.";
2408
2408
  }
2409
2409
  if (platform === "opencode") {
2410
- return "OpenCode coordination: use the GrepRAG project/session registry and session-targeted send; the plugin relay delivers replies.";
2410
+ return "OpenCode: at the merge/deploy gate, use the GrepRAG project/session registry and send one concise delivery notice to peers with ready or overlapping work.";
2411
2411
  }
2412
- return "Coordination: discover same-project peers through this harness and use GrepRAG for cross-harness peers.";
2412
+ return "At the merge/deploy gate, coordinate once with peers in the same repo who have ready or overlapping work.";
2413
2413
  }
2414
2414
  function buildDeliveryAnnounce(env) {
2415
2415
  if (!env.deliveryRepo)
2416
2416
  return null;
2417
2417
  const project = env.projectName?.trim() || "current repo";
2418
2418
  return [
2419
- `[DELIVERY CONTROL \u2014 ${project}]`,
2420
- "For full-goal code work, done means checkpointed, coordinated, integrated, pushed, deployed, and production-verified. Checkpoint each passing fix or feature.",
2419
+ `[DELIVERY \u2014 ${project}]`,
2420
+ "Commit useful, passing work.",
2421
2421
  coordinationLine(env.platform),
2422
- "Before merge, push, deploy, or release: elect one delivery owner. That owner includes every ready peer commit, resolves ordinary mission conflicts, and settles unclaimed dirt by adopt, rescue, or discard.",
2423
- "Use the canonical commit, deploy, and release skills plus this repo's delivery configuration. Never borrow a branch, remote, provider command, or verification rule from another repo.",
2424
- "A full-goal delivery mission already provisions ordinary repo-scoped commit, merge, push, deploy, and verification; do not wait for a second keyword."
2422
+ "Include ready peer commits and clear known blockers, then merge to the default branch and deploy immediately. Missing replies and unfinished peer work do not block delivery.",
2423
+ "Use this repo's delivery profile and verify production."
2425
2424
  ].join("\n");
2426
2425
  }
2427
2426
  var deliveryControlModule = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "greprag",
3
- "version": "5.74.11",
3
+ "version": "5.74.12",
4
4
  "description": "GrepRAG — agent memory for Claude Code, Codex, and OpenCode.",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -1,184 +0,0 @@
1
- "use strict";
2
- /** Codex checkpoint coordination — detect a successful Git commit transition
3
- * and inject the delivery handoff at that exact lifecycle boundary.
4
- *
5
- * PreToolUse records the prior HEAD around shell-capable tools. PostToolUse
6
- * proves HEAD changed via a commit reflog action and emits immediately; the
7
- * next PreToolUse is a fallback if that lifecycle event was unavailable.
8
- * User prompt and executor-wrapper wording are irrelevant.
9
- * adr: adr/codex-checkpoint-coordination.md */
10
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
11
- if (k2 === undefined) k2 = k;
12
- var desc = Object.getOwnPropertyDescriptor(m, k);
13
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
14
- desc = { enumerable: true, get: function() { return m[k]; } };
15
- }
16
- Object.defineProperty(o, k2, desc);
17
- }) : (function(o, m, k, k2) {
18
- if (k2 === undefined) k2 = k;
19
- o[k2] = m[k];
20
- }));
21
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
22
- Object.defineProperty(o, "default", { enumerable: true, value: v });
23
- }) : function(o, v) {
24
- o["default"] = v;
25
- });
26
- var __importStar = (this && this.__importStar) || (function () {
27
- var ownKeys = function(o) {
28
- ownKeys = Object.getOwnPropertyNames || function (o) {
29
- var ar = [];
30
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
31
- return ar;
32
- };
33
- return ownKeys(o);
34
- };
35
- return function (mod) {
36
- if (mod && mod.__esModule) return mod;
37
- var result = {};
38
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
39
- __setModuleDefault(result, mod);
40
- return result;
41
- };
42
- })();
43
- Object.defineProperty(exports, "__esModule", { value: true });
44
- exports.checkpointCoordinationText = checkpointCoordinationText;
45
- exports.recordCodexGitBoundary = recordCodexGitBoundary;
46
- exports.evaluateCodexCommitResult = evaluateCodexCommitResult;
47
- exports.evaluatePendingCodexCheckpoint = evaluatePendingCodexCheckpoint;
48
- const crypto = __importStar(require("crypto"));
49
- const fs = __importStar(require("fs"));
50
- const path = __importStar(require("path"));
51
- const child_process_1 = require("child_process");
52
- function homeDir() {
53
- return process.env.USERPROFILE || process.env.HOME || '';
54
- }
55
- function normalizedCwd(input) {
56
- return path.resolve(input.cwd || process.cwd()).replace(/\\/g, '/').toLowerCase();
57
- }
58
- function statePath(input) {
59
- const home = homeDir();
60
- const session = (input.session_id || '').trim();
61
- if (!home || !session)
62
- return null;
63
- const key = crypto.createHash('sha256')
64
- .update(`${session}\0${normalizedCwd(input)}`)
65
- .digest('hex')
66
- .slice(0, 24);
67
- return path.join(home, '.greprag', 'state', `codex-checkpoint-${key}.json`);
68
- }
69
- function git(cwd, args) {
70
- try {
71
- return (0, child_process_1.execFileSync)('git', args, {
72
- cwd,
73
- encoding: 'utf8',
74
- stdio: ['ignore', 'pipe', 'ignore'],
75
- windowsHide: true,
76
- }).trim() || null;
77
- }
78
- catch {
79
- return null;
80
- }
81
- }
82
- function currentHead(cwd) {
83
- return git(cwd, ['rev-parse', 'HEAD']);
84
- }
85
- function currentBranch(cwd) {
86
- return git(cwd, ['branch', '--show-current']) || '(detached HEAD)';
87
- }
88
- function latestHeadAction(cwd) {
89
- return git(cwd, ['reflog', '-1', '--format=%gs', 'HEAD']) || '';
90
- }
91
- function isCommitHeadAction(cwd) {
92
- return /^commit(?: \([^)]+\))?:/i.test(latestHeadAction(cwd));
93
- }
94
- function isShellCapableTool(input) {
95
- const name = (input.tool_name || '').toLowerCase();
96
- return /(?:^|[.:/_-])(bash|shell|exec|exec_command|write_stdin)$/.test(name);
97
- }
98
- function writePending(file, pending) {
99
- fs.mkdirSync(path.dirname(file), { recursive: true });
100
- fs.writeFileSync(file, JSON.stringify(pending, null, 2) + '\n');
101
- }
102
- function readPending(file) {
103
- try {
104
- return JSON.parse(fs.readFileSync(file, 'utf8'));
105
- }
106
- catch {
107
- return null;
108
- }
109
- }
110
- function clearPending(file) {
111
- try {
112
- fs.unlinkSync(file);
113
- }
114
- catch { /* already absent */ }
115
- }
116
- function consumePending(input, hookEventName) {
117
- const file = statePath(input);
118
- if (!file)
119
- return null;
120
- const pending = readPending(file);
121
- if (!pending || pending.cwd !== normalizedCwd(input))
122
- return null;
123
- clearPending(file);
124
- const cwd = input.cwd || process.cwd();
125
- const afterHead = currentHead(cwd);
126
- if (!afterHead || afterHead === pending.beforeHead || !isCommitHeadAction(cwd))
127
- return null;
128
- return {
129
- hookSpecificOutput: {
130
- hookEventName,
131
- additionalContext: checkpointCoordinationText(currentBranch(cwd), afterHead.slice(0, 12)),
132
- },
133
- };
134
- }
135
- function checkpointCoordinationText(branch, sha) {
136
- return `[DELIVERY COORDINATION — CHECKPOINT CREATED]
137
-
138
- Checkpoint: ${branch} @ ${sha}
139
-
140
- Coordinate now, before merge, push, deploy, publish, or release.
141
-
142
- - Child task: send the LEAD your branch, SHA, checks, status, owned dirt, and blockers. The LEAD owns integration.
143
- - LEAD/standalone task: call codex_app.list_threads unfiltered, scope to this repo/worktree, exclude yourself, and ask every live peer for its latest checkpoint, owned dirt, blockers, and sequencing needs.
144
- - Elect exactly one delivery owner. If no peers exist, you are the owner.
145
- - Use greprag send for cross-harness peers.
146
-
147
- Do not begin a delivery action until coordination is settled.`;
148
- }
149
- /** PreToolUse leg: remember HEAD around any shell-capable action. The result
150
- * leg classifies the actual Git transition, so nested executor syntax and
151
- * dynamically composed commands do not matter. */
152
- function recordCodexGitBoundary(input) {
153
- if (input.hook_event_name !== 'PreToolUse')
154
- return;
155
- if (!isShellCapableTool(input))
156
- return;
157
- const file = statePath(input);
158
- if (!file)
159
- return;
160
- const cwd = input.cwd || process.cwd();
161
- writePending(file, {
162
- sessionId: input.session_id || '',
163
- cwd: normalizedCwd(input),
164
- toolName: input.tool_name || '',
165
- beforeHead: currentHead(cwd),
166
- recordedAt: new Date().toISOString(),
167
- });
168
- }
169
- /** Preferred result leg: emit on the successful commit's own PostToolUse. */
170
- function evaluateCodexCommitResult(input) {
171
- if (input.hook_event_name !== 'PostToolUse')
172
- return null;
173
- if (!isShellCapableTool(input))
174
- return null;
175
- return consumePending(input, 'PostToolUse');
176
- }
177
- /** Fallback result leg: if PostToolUse was unavailable, emit before the first
178
- * later tool call. Failed/empty commits leave HEAD unchanged and clear
179
- * silently. */
180
- function evaluatePendingCodexCheckpoint(input) {
181
- if (input.hook_event_name !== 'PreToolUse')
182
- return null;
183
- return consumePending(input, 'PreToolUse');
184
- }