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.
- package/dist/codex-delivery-coordination.js +213 -0
- package/dist/codex-fast-hook.js +5 -8
- package/dist/commands/coordinate-gate.js +2 -2
- package/dist/commands/delivery-reminder.js +8 -9
- package/dist/commands/init.js +9 -18
- package/dist/opencode-plugin.bundle.js +8 -9
- package/package.json +1 -1
- package/dist/codex-checkpoint-hook.js +0 -184
|
@@ -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
|
+
}
|
package/dist/codex-fast-hook.js
CHANGED
|
@@ -83,10 +83,8 @@ async function main() {
|
|
|
83
83
|
return;
|
|
84
84
|
}
|
|
85
85
|
if (subcommand === 'codex-posttooluse') {
|
|
86
|
-
|
|
87
|
-
|
|
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 {
|
|
102
|
-
result = mergeOutputs(result,
|
|
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
|
|
31
|
-
*
|
|
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
|
|
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
|
|
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
|
|
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 '
|
|
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
|
|
31
|
-
'
|
|
30
|
+
`[DELIVERY — ${project}]`,
|
|
31
|
+
'Commit useful, passing work.',
|
|
32
32
|
coordinationLine(env.platform),
|
|
33
|
-
'
|
|
34
|
-
'Use
|
|
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 = {
|
package/dist/commands/init.js
CHANGED
|
@@ -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
|
|
1134
|
-
|
|
1135
|
-
|
|
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
|
|
1203
|
-
//
|
|
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 (
|
|
1208
|
+
changes.push('Added Codex PreToolUse hook (delivery coordination + local safety)');
|
|
1218
1209
|
}
|
|
1219
1210
|
else {
|
|
1220
|
-
changes.push('Codex PreToolUse
|
|
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
|
|
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
|
|
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
|
|
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 "
|
|
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
|
|
2420
|
-
"
|
|
2419
|
+
`[DELIVERY \u2014 ${project}]`,
|
|
2420
|
+
"Commit useful, passing work.",
|
|
2421
2421
|
coordinationLine(env.platform),
|
|
2422
|
-
"
|
|
2423
|
-
"Use
|
|
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,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
|
-
}
|