greprag 5.73.7 → 5.73.8
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/ccr-store.js +57 -3
- package/dist/ccr-store.js.map +1 -1
- package/dist/codex-chip-hooks.js +2 -2
- package/dist/codex-chip-hooks.js.map +1 -1
- package/dist/codex-fast-hook.js +4 -0
- package/dist/codex-fast-hook.js.map +1 -1
- package/dist/codex-pretooluse.js +2 -29
- package/dist/codex-pretooluse.js.map +1 -1
- package/dist/commands/codex-chip/cleanup-command.d.ts +1 -0
- package/dist/commands/codex-chip/cleanup-command.js +73 -10
- package/dist/commands/codex-chip/cleanup-command.js.map +1 -1
- package/dist/commands/codex-chip/git.js +2 -10
- package/dist/commands/codex-chip/git.js.map +1 -1
- package/dist/commands/codex-chip/help.d.ts +1 -1
- package/dist/commands/codex-chip/help.js +4 -2
- package/dist/commands/codex-chip/help.js.map +1 -1
- package/dist/commands/codex-chip/prompt.js +4 -2
- package/dist/commands/codex-chip/prompt.js.map +1 -1
- package/dist/commands/codex-coordinate.d.ts +4 -5
- package/dist/commands/codex-coordinate.js +32 -96
- package/dist/commands/codex-coordinate.js.map +1 -1
- package/dist/commands/mechanic-spawn.js +9 -9
- package/dist/commands/mechanic-spawn.js.map +1 -1
- package/dist/commands/shell-dialect-guard.d.ts +25 -0
- package/dist/commands/shell-dialect-guard.js +183 -0
- package/dist/commands/shell-dialect-guard.js.map +1 -0
- package/dist/hook.js +31 -32
- package/dist/hook.js.map +1 -1
- package/dist/opencode-plugin.bundle.js +9 -2
- package/dist/procedure.d.ts +1 -1
- package/dist/procedure.js +10 -3
- package/dist/procedure.js.map +1 -1
- package/package.json +1 -1
- package/skill/greprag/SKILL.md +2 -2
- package/skill/greprag/docs/codex-chip.md +11 -6
- package/skill/mechanic/SKILL.md +4 -3
- package/skill/templates/chip-spawn.md +4 -4
- package/skill/templates/codex-chip-spawn.md +66 -22
|
@@ -3,9 +3,10 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Codex's native task roster is available to the agent through codex_app tools,
|
|
5
5
|
* not to a shell hook. The PreToolUse gate therefore opens an artifact-bound
|
|
6
|
-
* coordination request; the agent performs the native
|
|
7
|
-
* waits for real peer replies, and
|
|
8
|
-
* accepts only evidence for the current
|
|
6
|
+
* coordination request; the agent performs the native Codex task scan,
|
|
7
|
+
* waits for real peer replies when peers exist, and records the completed
|
|
8
|
+
* conference. The gate accepts only evidence for the current worktree content
|
|
9
|
+
* and action kind.
|
|
9
10
|
* adr: adr/codex-coordinate-gate.md */
|
|
10
11
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
11
12
|
if (k2 === undefined) k2 = k;
|
|
@@ -50,9 +51,8 @@ const path = __importStar(require("path"));
|
|
|
50
51
|
const crypto = __importStar(require("crypto"));
|
|
51
52
|
const project_anchor_1 = require("../project-anchor");
|
|
52
53
|
const procedure_run_1 = require("../procedure-run");
|
|
53
|
-
const proc_1 = require("../proc");
|
|
54
54
|
const session_id_1 = require("../session-id");
|
|
55
|
-
const EVIDENCE_VERSION =
|
|
55
|
+
const EVIDENCE_VERSION = 3;
|
|
56
56
|
const MAX_EVIDENCE_AGE_MS = 10 * 60_000;
|
|
57
57
|
function stateDir() {
|
|
58
58
|
const home = process.env.HOME || process.env.USERPROFILE || '';
|
|
@@ -87,86 +87,33 @@ function writeCodexCoordinationState(state) {
|
|
|
87
87
|
function unique(values) {
|
|
88
88
|
return [...new Set(values.map(value => value.trim()).filter(Boolean))];
|
|
89
89
|
}
|
|
90
|
-
function committedArtifactState(cwd) {
|
|
91
|
-
try {
|
|
92
|
-
(0, proc_1.safeExecFileSync)('git', ['rev-parse', '--verify', 'HEAD'], {
|
|
93
|
-
cwd, encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'],
|
|
94
|
-
});
|
|
95
|
-
}
|
|
96
|
-
catch {
|
|
97
|
-
return { ok: false, reason: 'no-head' };
|
|
98
|
-
}
|
|
99
|
-
try {
|
|
100
|
-
const status = (0, proc_1.safeExecFileSync)('git', ['status', '--porcelain=v1', '--untracked-files=normal'], {
|
|
101
|
-
cwd, encoding: 'utf8',
|
|
102
|
-
}).trim();
|
|
103
|
-
return status === '' ? { ok: true } : { ok: false, reason: 'dirty' };
|
|
104
|
-
}
|
|
105
|
-
catch {
|
|
106
|
-
return { ok: false, reason: 'git-error' };
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
function isCommittedArtifact(cwd) {
|
|
110
|
-
return committedArtifactState(cwd).ok;
|
|
111
|
-
}
|
|
112
|
-
function dirtyArtifactInstructions(label) {
|
|
113
|
-
return [
|
|
114
|
-
`REPO DIRT MUST BE SETTLED before ${label}.`,
|
|
115
|
-
'Peer review/deploy must bind to a committed artifact, not a dirty checkout.',
|
|
116
|
-
'Confer with reachable same-repo peers, classify every dirty file as yours/a peer\'s/pre-existing user work, and resolve or explicitly claim unowned dirt.',
|
|
117
|
-
'Do not stash, revert, or commit unrelated files just to satisfy a clean-tree deploy guard.',
|
|
118
|
-
'Unsourced dirt still blocks deploy: exhaust local evidence (git status/diff/log, worktrees, recent peer messages), ask the human for direction if needed, then clean it only after it is confirmed stale or discardable.',
|
|
119
|
-
'Commit the coherent deploy source.',
|
|
120
|
-
'If tracked build output must be committed (for example site dist/) and unrelated dirt makes the shared checkout unsafe, build from a clean source worktree/branch, commit only that generated artifact there, then retry.',
|
|
121
|
-
].join(' ');
|
|
122
|
-
}
|
|
123
90
|
function commandFingerprint(command) {
|
|
124
91
|
return crypto.createHash('sha256').update(command.trim()).digest('hex');
|
|
125
92
|
}
|
|
126
|
-
function
|
|
127
|
-
const ref = peerRef.toLowerCase();
|
|
128
|
-
const short = watcherShort.toLowerCase();
|
|
129
|
-
return ref === short || ref.startsWith(`${short}-`) || ref.startsWith(short);
|
|
130
|
-
}
|
|
131
|
-
function missingWatcherPeers(attestation, watcherPeers) {
|
|
132
|
-
return watcherPeers.filter(short => !attestation.peerRefs.some(ref => refMatches(ref, short)));
|
|
133
|
-
}
|
|
134
|
-
function coordinationInstructions(trigger, watcherPeers) {
|
|
135
|
-
const watcherNote = watcherPeers.length
|
|
136
|
-
? ` Cross-harness peers currently live here: ${watcherPeers.join(', ')}.`
|
|
137
|
-
: '';
|
|
93
|
+
function coordinationInstructions(trigger) {
|
|
138
94
|
return [
|
|
139
95
|
`CODEX COORDINATION REQUIRED before ${trigger.label}.`,
|
|
140
|
-
'
|
|
141
|
-
'
|
|
142
|
-
'
|
|
143
|
-
'Message each peer with the
|
|
144
|
-
'
|
|
145
|
-
`
|
|
146
|
-
|
|
96
|
+
'Run native codex_app.list_threads unfiltered first; do not use query as project discovery.',
|
|
97
|
+
'Scope the resulting Codex task roster by cwd, not title/text: for GrepRAG, keep only cwd exactly C:\\greprag or matching C:\\Users\\travy\\.codex\\worktrees\\*\\greprag.',
|
|
98
|
+
'After cwd scoping, keep live-relevant peers (active, idle, or unread as appropriate), exclude the current Codex thread, and use query only as an optional narrowing aid inside that cwd-scoped set.',
|
|
99
|
+
'Message each same-project Codex peer through codex_app.send_message_to_thread with the branch, files, and intended merge/deploy; ask only for blockers, owned dirt, or sequencing constraints; wait for real replies before recording evidence.',
|
|
100
|
+
'This is collision coordination, not peer review. Do not ask contacted active peers to review the work. If review is needed, spawn a separate review chip/session with an explicit review brief.',
|
|
101
|
+
'Use `greprag send` only for known non-Codex cross-harness peers where no native Codex thread endpoint exists.',
|
|
102
|
+
'Then record the native roster result with `greprag coordinate attest --peer <codex-thread-or-non-codex-session-id>` (repeat --peer), or `greprag coordinate attest --none` only when no active same-project Codex peers and no known non-Codex peers exist.',
|
|
103
|
+
`Retry ${trigger.label}; evidence is bound to the current worktree content and exact action.`,
|
|
104
|
+
].join(' ');
|
|
147
105
|
}
|
|
148
106
|
/** Open/refresh the request and enforce evidence for this exact artifact/action. */
|
|
149
107
|
function evaluateCodexCoordinationGate(params) {
|
|
150
|
-
const artifactState = committedArtifactState(params.cwd);
|
|
151
|
-
if (!artifactState.ok) {
|
|
152
|
-
return {
|
|
153
|
-
ready: false,
|
|
154
|
-
reason: artifactState.reason === 'dirty'
|
|
155
|
-
? dirtyArtifactInstructions(params.trigger.label)
|
|
156
|
-
: `COMMIT REQUIRED before ${params.trigger.label}. Commit the coherent artifact, then retry so peer review binds to immutable work.`,
|
|
157
|
-
};
|
|
158
|
-
}
|
|
159
108
|
const fingerprint = (0, procedure_run_1.currentArtifactFingerprint)(params.cwd);
|
|
160
109
|
if (!fingerprint) {
|
|
161
|
-
return { ready: false, reason: `Cannot fingerprint the
|
|
110
|
+
return { ready: false, reason: `Cannot fingerprint the current worktree content before ${params.trigger.label}.` };
|
|
162
111
|
}
|
|
163
|
-
const watcherPeers = unique(params.watcherPeers);
|
|
164
112
|
const actionFingerprint = commandFingerprint(params.command);
|
|
165
113
|
const state = readCodexCoordinationState(params.projectId, params.sessionId);
|
|
166
114
|
const attestation = state?.attestation;
|
|
167
115
|
const nowMs = params.nowMs ?? Date.now();
|
|
168
116
|
const ageMs = attestation ? nowMs - Date.parse(attestation.attestedAt) : Number.POSITIVE_INFINITY;
|
|
169
|
-
const missing = attestation ? missingWatcherPeers(attestation, watcherPeers) : watcherPeers;
|
|
170
117
|
const matches = !!attestation
|
|
171
118
|
&& attestation.kind === params.trigger.kind
|
|
172
119
|
&& attestation.label === params.trigger.label
|
|
@@ -174,9 +121,7 @@ function evaluateCodexCoordinationGate(params) {
|
|
|
174
121
|
&& attestation.artifactFingerprint === fingerprint
|
|
175
122
|
&& Number.isFinite(ageMs)
|
|
176
123
|
&& ageMs >= 0
|
|
177
|
-
&& ageMs <= MAX_EVIDENCE_AGE_MS
|
|
178
|
-
&& missing.length === 0
|
|
179
|
-
&& (!attestation.noPeers || watcherPeers.length === 0);
|
|
124
|
+
&& ageMs <= MAX_EVIDENCE_AGE_MS;
|
|
180
125
|
if (matches)
|
|
181
126
|
return { ready: true };
|
|
182
127
|
const pending = {
|
|
@@ -185,7 +130,6 @@ function evaluateCodexCoordinationGate(params) {
|
|
|
185
130
|
artifactFingerprint: fingerprint,
|
|
186
131
|
actionFingerprint,
|
|
187
132
|
requestedAt: new Date(nowMs).toISOString(),
|
|
188
|
-
watcherPeers,
|
|
189
133
|
};
|
|
190
134
|
writeCodexCoordinationState({
|
|
191
135
|
version: EVIDENCE_VERSION,
|
|
@@ -194,10 +138,7 @@ function evaluateCodexCoordinationGate(params) {
|
|
|
194
138
|
pending,
|
|
195
139
|
...(attestation ? { attestation } : {}),
|
|
196
140
|
});
|
|
197
|
-
|
|
198
|
-
? ` Missing current cross-harness peer evidence: ${missing.join(', ')}.`
|
|
199
|
-
: '';
|
|
200
|
-
return { ready: false, reason: coordinationInstructions(params.trigger, watcherPeers) + suffix };
|
|
141
|
+
return { ready: false, reason: coordinationInstructions(params.trigger) };
|
|
201
142
|
}
|
|
202
143
|
function flagValues(args, flag) {
|
|
203
144
|
const values = [];
|
|
@@ -217,9 +158,17 @@ function help() {
|
|
|
217
158
|
greprag coordinate attest --none
|
|
218
159
|
greprag coordinate status
|
|
219
160
|
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
161
|
+
Record evidence only after checking native Codex tasks scoped to this same
|
|
162
|
+
project/workspace. Call codex_app.list_threads with no query first, scope the
|
|
163
|
+
roster by cwd (for GrepRAG: C:\\greprag and
|
|
164
|
+
C:\\Users\\travy\\.codex\\worktrees\\*\\greprag), then filter live relevance and
|
|
165
|
+
exclude the current thread. Query may narrow an already cwd-scoped roster; it is
|
|
166
|
+
never primary project discovery. Message active same-project Codex peers, asking
|
|
167
|
+
only for blockers, owned dirt, or sequencing constraints, and wait for real
|
|
168
|
+
replies. Do not use ordinary coordination as review; spawn a separate review
|
|
169
|
+
chip/session when review is needed. Use greprag send only for known non-Codex
|
|
170
|
+
cross-harness peers where no native Codex thread endpoint exists. Evidence is
|
|
171
|
+
scoped to the pending merge/push/deploy action and current worktree content.`;
|
|
223
172
|
}
|
|
224
173
|
function runCoordinate(args) {
|
|
225
174
|
const command = args[0];
|
|
@@ -248,27 +197,14 @@ function runCoordinate(args) {
|
|
|
248
197
|
throw new Error(`Unknown coordinate command: ${command}`);
|
|
249
198
|
if (!state?.pending)
|
|
250
199
|
throw new Error('No pending Codex coordination gate. Retry the merge/deploy command first.');
|
|
251
|
-
const artifactState = committedArtifactState(process.cwd());
|
|
252
|
-
if (!artifactState.ok) {
|
|
253
|
-
throw new Error(artifactState.reason === 'dirty'
|
|
254
|
-
? dirtyArtifactInstructions(state.pending.label)
|
|
255
|
-
: 'Commit the current work before recording peer review.');
|
|
256
|
-
}
|
|
257
200
|
const fingerprint = (0, procedure_run_1.currentArtifactFingerprint)(process.cwd());
|
|
258
201
|
if (!fingerprint || fingerprint !== state.pending.artifactFingerprint) {
|
|
259
|
-
throw new Error('The
|
|
202
|
+
throw new Error('The worktree content changed after the gate opened. Retry the merge/deploy command, then coordinate against the current content.');
|
|
260
203
|
}
|
|
261
204
|
const peers = unique(flagValues(args, '--peer'));
|
|
262
205
|
const noPeers = args.includes('--none');
|
|
263
206
|
if (noPeers === (peers.length > 0)) {
|
|
264
|
-
throw new Error('Choose exactly one: repeat --peer <id>, or use --none when
|
|
265
|
-
}
|
|
266
|
-
if (noPeers && state.pending.watcherPeers.length > 0) {
|
|
267
|
-
throw new Error(`Cannot attest --none; cross-harness peers are live: ${state.pending.watcherPeers.join(', ')}.`);
|
|
268
|
-
}
|
|
269
|
-
const missing = state.pending.watcherPeers.filter(short => !peers.some(ref => refMatches(ref, short)));
|
|
270
|
-
if (missing.length) {
|
|
271
|
-
throw new Error(`Attestation is missing live cross-harness peers: ${missing.join(', ')}.`);
|
|
207
|
+
throw new Error('Choose exactly one: repeat --peer <id>, or use --none when no active same-repo Codex peers and no known non-Codex peers exist.');
|
|
272
208
|
}
|
|
273
209
|
const attestation = {
|
|
274
210
|
...state.pending,
|
|
@@ -278,7 +214,7 @@ function runCoordinate(args) {
|
|
|
278
214
|
};
|
|
279
215
|
writeCodexCoordinationState({ ...state, attestation });
|
|
280
216
|
console.log(noPeers
|
|
281
|
-
? `Recorded no-peer
|
|
217
|
+
? `Recorded no-peer native roster scan for ${state.pending.label}.`
|
|
282
218
|
: `Recorded peer conferral for ${state.pending.label}: ${peers.join(', ')}.`);
|
|
283
219
|
}
|
|
284
220
|
//# sourceMappingURL=codex-coordinate.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"codex-coordinate.js","sourceRoot":"","sources":["../../src/commands/codex-coordinate.ts"],"names":[],"mappings":";AAAA
|
|
1
|
+
{"version":3,"file":"codex-coordinate.js","sourceRoot":"","sources":["../../src/commands/codex-coordinate.ts"],"names":[],"mappings":"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"}
|
|
@@ -37,28 +37,28 @@ function missionSummary(friction) {
|
|
|
37
37
|
* SHAPE: a FIX mission self-lands everywhere; only the PEER DISCOVERY,
|
|
38
38
|
* PRUNE, and REPORT mechanics adapt per harness. On Codex the chip runs in a
|
|
39
39
|
* Codex-managed checkout (~/.codex/worktrees) whose lifecycle Codex owns — it
|
|
40
|
-
* merges to main itself but never removes the worktree;
|
|
41
|
-
*
|
|
40
|
+
* merges to main itself but never removes the worktree; explicit cleanup
|
|
41
|
+
* parameters plus archive clearance replace the self-prune. Harness templates state the default parent-owned
|
|
42
42
|
* rule plus one explicit deference to this contract; they never restate it. */
|
|
43
43
|
function conferralLine(scope) {
|
|
44
44
|
if (scope === 'codex') {
|
|
45
|
-
return '- Confer with live peers first. For Codex peers: discover tasks and their repo/workspace with `codex_app.list_threads`, then send heads-up via `codex_app.send_message_to_thread`. Use `greprag
|
|
45
|
+
return '- Confer with live peers first. For Codex peers: discover tasks and their repo/workspace with `codex_app.list_threads`, then send heads-up via `codex_app.send_message_to_thread`. Use `greprag send` only for known Claude Code, OpenCode, or other non-Codex cross-harness peers where no native Codex thread endpoint exists. Give peers a beat to object before you touch main.';
|
|
46
46
|
}
|
|
47
47
|
return '- Confer with live peers first: `greprag inbox watchers`. Any session live in THIS repo gets a heads-up (`greprag send "…merging <branch>, touches <files>…" --to <handle>@greprag.com/<their-8hex>`) and a beat to object before you touch main.';
|
|
48
48
|
}
|
|
49
49
|
function phase3Lines(scope) {
|
|
50
50
|
const confer = conferralLine(scope);
|
|
51
|
-
const boundary = '- Before commit/merge/deploy/push,
|
|
51
|
+
const boundary = '- Before commit/merge/deploy/push, classify dirty repository state: intentional deploy work, peer-owned work, user-owned work, or stale/discardable residue. Sweep intentional dirt into the boundary; block only on unknown ownership, overlapping peer work, or unproven stale residue.';
|
|
52
52
|
const merge = '- Merge your chip branch → main yourself; re-verify the build on merged main.';
|
|
53
|
-
const gates = '- Routine deploys are yours too, where the project docs mark them routine. HARD STOP at sensitive landings: `git push`, releases, `npm publish`, migrations, anything approval-gated — report READY-TO-PUSH with the commit hash instead
|
|
53
|
+
const gates = '- Routine deploys are yours too, where the project docs mark them routine. HARD STOP at sensitive landings only for ordinary repair missions: `git push`, releases, `npm publish`, migrations, anything approval-gated — report READY-TO-PUSH with the commit hash instead. If the operator explicitly provisioned release/deploy as the mission completion, carry that authority through the landing and verify production.';
|
|
54
54
|
if (scope === 'codex') {
|
|
55
55
|
return [
|
|
56
56
|
'**Phase 3 — LAND IT (you own the merge; the native parent reply is an FYI, not a review gate)**',
|
|
57
|
-
'A repair stranded on a chip branch is not a repair — never wait for the parent to land it. This Phase 3 supersedes the generic Codex chip rule "do not merge; the parent
|
|
57
|
+
'A repair stranded on a chip branch is not a repair — never wait for the parent to land it. This Phase 3 supersedes the generic Codex chip rule "do not merge; the parent integrates" for THIS mission only; every non-FIX Codex chip shape (Chip A/B/C, LEAD, PLANNER, ADVISOR) keeps the native parent-owned landing. After a ≥90 implementation passes verification:',
|
|
58
58
|
confer,
|
|
59
59
|
boundary,
|
|
60
60
|
merge,
|
|
61
|
-
'- Cleanup stays NATIVE: never `git worktree remove` the Codex-managed checkout and never delete its branch
|
|
61
|
+
'- Cleanup stays NATIVE: never `git worktree remove` the Codex-managed checkout and never delete its branch. After your merge is on main, reply in the native parent-child task thread with `DONE`, the merge commit, checks, `Cleanup: archive task; Codex may prune managed worktree; branch may be deleted after merge`, and `Clearance: safe to archive`. If anything must stay open, use `Cleanup: keep task/worktree/branch because ...` and `Clearance: keep open because ...`.',
|
|
62
62
|
gates,
|
|
63
63
|
'- Reporting: the native reply to the parent is an FYI — the merge already happened. If the parent thread is gone, cold-open the operator (`greprag send … --to <handle>@greprag.com`) so the landing is on record.',
|
|
64
64
|
];
|
|
@@ -69,7 +69,7 @@ function phase3Lines(scope) {
|
|
|
69
69
|
confer,
|
|
70
70
|
boundary,
|
|
71
71
|
merge,
|
|
72
|
-
'- Prune in the same breath: junction-guard, then `git worktree remove` YOUR worktree and `git branch -d` the merged branch. This landing duty supersedes any generic "never remove worktrees" chip rule — your own worktree only, only after the merge is on main.',
|
|
72
|
+
'- Prune in the same breath: junction-guard, then `git worktree remove` YOUR worktree and `git branch -d` the merged branch. This landing duty supersedes any generic "never remove worktrees" chip rule — your own worktree only, only after the merge is on main. Report `Cleanup: pruned worktree; deleted merged branch`; if anything must stay open, report `Cleanup: keep worktree/branch because ...`.',
|
|
73
73
|
gates,
|
|
74
74
|
'- Reporting: DONE to the parent task is an FYI, not a handoff — the merge already happened. If the parent inbox is dead/unwatched, cold-open the operator (`greprag send … --to <handle>@greprag.com`) so the landing is on record.',
|
|
75
75
|
];
|
|
@@ -94,7 +94,7 @@ function buildFixMission(friction, scope, parentSession) {
|
|
|
94
94
|
'',
|
|
95
95
|
'**Phase 2 — the confidence gate**',
|
|
96
96
|
'- Confidence ≥90: implement autonomously. Own the repair, regression tests, focused verification, and the commit — then LAND it (Phase 3). Report DONE with the confidence score and the merge commit.',
|
|
97
|
-
'- Confidence <90: STOP before changing code. Report INVESTIGATED: findings, the repair option(s) with trade-offs, your confidence
|
|
97
|
+
'- Confidence <90: STOP before changing code. Report INVESTIGATED: findings, the repair option(s) with trade-offs, your confidence, what would raise it, and `Cleanup: keep task/worktree/branch because confidence <90`. Leave your worktree + branch intact for co-design. The operator co-designs the repair; implement only after direction.',
|
|
98
98
|
'- Blocked either way: report BLOCKED with what you need.',
|
|
99
99
|
'',
|
|
100
100
|
...phase3Lines(scope),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mechanic-spawn.js","sourceRoot":"","sources":["../../src/commands/mechanic-spawn.ts"],"names":[],"mappings":";;AA4EA,0CAuCC;AAED,4BA4BC;AAGD,sCAEC;AAtJD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wCAAsE;AAEtE,SAAS,IAAI,CAAC,IAAc,EAAE,IAAY;IACxC,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IACjC,OAAO,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AAClD,CAAC;AAED,SAAS,cAAc,CAAC,QAAgB;IACtC,OAAO,QAAQ,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;AACrF,CAAC;AAED;;;;;;;gFAOgF;AAChF,SAAS,aAAa,CAAC,KAAqB;IAC1C,IAAI,KAAK,KAAK,OAAO,EAAE,CAAC;QACtB,OAAO,
|
|
1
|
+
{"version":3,"file":"mechanic-spawn.js","sourceRoot":"","sources":["../../src/commands/mechanic-spawn.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export interface ShellDialectGuardHookInput {
|
|
2
|
+
hook_event_name?: string;
|
|
3
|
+
tool_name?: string;
|
|
4
|
+
tool_input?: {
|
|
5
|
+
command?: string;
|
|
6
|
+
};
|
|
7
|
+
}
|
|
8
|
+
export interface ShellDialectGuardHookOutput {
|
|
9
|
+
hookSpecificOutput: {
|
|
10
|
+
hookEventName: string;
|
|
11
|
+
permissionDecision: 'deny';
|
|
12
|
+
permissionDecisionReason: string;
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
export interface ShellDialectGuardHit {
|
|
16
|
+
command: 'head' | 'tail' | 'sed';
|
|
17
|
+
stage: string;
|
|
18
|
+
replacement: string;
|
|
19
|
+
}
|
|
20
|
+
export interface ShellDialectGuardOptions {
|
|
21
|
+
platform?: NodeJS.Platform;
|
|
22
|
+
}
|
|
23
|
+
export declare function findWindowsUnixTruncator(command: string): ShellDialectGuardHit | null;
|
|
24
|
+
export declare function buildShellDialectGuardReason(hit: ShellDialectGuardHit): string;
|
|
25
|
+
export declare function runShellDialectGuard(input: ShellDialectGuardHookInput, opts?: ShellDialectGuardOptions): ShellDialectGuardHookOutput | null;
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.findWindowsUnixTruncator = findWindowsUnixTruncator;
|
|
4
|
+
exports.buildShellDialectGuardReason = buildShellDialectGuardReason;
|
|
5
|
+
exports.runShellDialectGuard = runShellDialectGuard;
|
|
6
|
+
function shellWords(input) {
|
|
7
|
+
const words = [];
|
|
8
|
+
const re = /"((?:\\"|[^"])*)"|'([^']*)'|(\S+)/g;
|
|
9
|
+
let m;
|
|
10
|
+
while ((m = re.exec(input)))
|
|
11
|
+
words.push(m[1] ?? m[2] ?? m[3]);
|
|
12
|
+
return words;
|
|
13
|
+
}
|
|
14
|
+
function splitPipeStages(command) {
|
|
15
|
+
const stages = [];
|
|
16
|
+
let current = '';
|
|
17
|
+
let inSingle = false;
|
|
18
|
+
let inDouble = false;
|
|
19
|
+
for (let i = 0; i < command.length; i++) {
|
|
20
|
+
const ch = command[i];
|
|
21
|
+
if (!inSingle && ch === '\\') {
|
|
22
|
+
current += ch;
|
|
23
|
+
if (i + 1 < command.length)
|
|
24
|
+
current += command[++i];
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
if (!inSingle && ch === '"')
|
|
28
|
+
inDouble = !inDouble;
|
|
29
|
+
else if (!inDouble && ch === "'")
|
|
30
|
+
inSingle = !inSingle;
|
|
31
|
+
if (!inSingle && !inDouble && ch === '|') {
|
|
32
|
+
stages.push(current.trim());
|
|
33
|
+
current = '';
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
current += ch;
|
|
37
|
+
}
|
|
38
|
+
stages.push(current.trim());
|
|
39
|
+
return stages;
|
|
40
|
+
}
|
|
41
|
+
function parseLineCount(tokens) {
|
|
42
|
+
for (let i = 1; i < tokens.length; i++) {
|
|
43
|
+
const tok = tokens[i];
|
|
44
|
+
let m = tok.match(/^-(\d+)$/);
|
|
45
|
+
if (m)
|
|
46
|
+
return Number(m[1]);
|
|
47
|
+
m = tok.match(/^-n(\d+)$/);
|
|
48
|
+
if (m)
|
|
49
|
+
return Number(m[1]);
|
|
50
|
+
m = tok.match(/^--lines=(\d+)$/);
|
|
51
|
+
if (m)
|
|
52
|
+
return Number(m[1]);
|
|
53
|
+
if (tok === '-n' || tok === '--lines') {
|
|
54
|
+
const next = tokens[++i];
|
|
55
|
+
return next && /^\d+$/.test(next) ? Number(next) : null;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return 10;
|
|
59
|
+
}
|
|
60
|
+
function replacementFor(command, tokens) {
|
|
61
|
+
const count = parseLineCount(tokens);
|
|
62
|
+
const direction = command === 'head' ? 'First' : 'Last';
|
|
63
|
+
return count ? `Select-Object -${direction} ${count}` : `Select-Object -${direction} <N>`;
|
|
64
|
+
}
|
|
65
|
+
function commandName(raw) {
|
|
66
|
+
const name = (raw || '').replace(/\\/g, '/').split('/').pop()?.toLowerCase();
|
|
67
|
+
if (name === 'head' || name === 'head.exe')
|
|
68
|
+
return 'head';
|
|
69
|
+
if (name === 'tail' || name === 'tail.exe')
|
|
70
|
+
return 'tail';
|
|
71
|
+
if (name === 'sed' || name === 'sed.exe')
|
|
72
|
+
return 'sed';
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
function psLiteralArg(value) {
|
|
76
|
+
return /^[A-Za-z0-9_./:\\-]+$/.test(value) ? value : `'${value.replace(/'/g, "''")}'`;
|
|
77
|
+
}
|
|
78
|
+
function replacementForSedPrintRead(tokens) {
|
|
79
|
+
let sawQuiet = false;
|
|
80
|
+
let script = null;
|
|
81
|
+
let file = null;
|
|
82
|
+
for (let i = 1; i < tokens.length; i++) {
|
|
83
|
+
const tok = tokens[i];
|
|
84
|
+
if (tok === '-n' || tok === '--quiet' || tok === '--silent' || /^-[A-Za-z]*n[A-Za-z]*$/.test(tok)) {
|
|
85
|
+
sawQuiet = true;
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
if (tok === '-e' || tok === '--expression') {
|
|
89
|
+
script = tokens[++i] || null;
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
if (tok.startsWith('-e') && tok.length > 2) {
|
|
93
|
+
script = tok.slice(2);
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
if (tok.startsWith('-'))
|
|
97
|
+
continue;
|
|
98
|
+
if (!script) {
|
|
99
|
+
script = tok;
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
file = tok;
|
|
103
|
+
break;
|
|
104
|
+
}
|
|
105
|
+
if (!sawQuiet || !script)
|
|
106
|
+
return null;
|
|
107
|
+
const m = script.match(/^(\d+)(?:,(\d+|\$))?p$/);
|
|
108
|
+
if (!m)
|
|
109
|
+
return null;
|
|
110
|
+
const start = Number(m[1]);
|
|
111
|
+
const endRaw = m[2] || m[1];
|
|
112
|
+
if (!Number.isFinite(start) || start < 1)
|
|
113
|
+
return null;
|
|
114
|
+
const pathArg = file ? psLiteralArg(file) : '<file>';
|
|
115
|
+
const base = `Get-Content -LiteralPath ${pathArg}`;
|
|
116
|
+
if (endRaw === '$') {
|
|
117
|
+
return start === 1 ? base : `${base} | Select-Object -Skip ${start - 1}`;
|
|
118
|
+
}
|
|
119
|
+
const end = Number(endRaw);
|
|
120
|
+
if (!Number.isFinite(end) || end < start)
|
|
121
|
+
return null;
|
|
122
|
+
if (start === 1)
|
|
123
|
+
return `${base} -TotalCount ${end}`;
|
|
124
|
+
return `${base} | Select-Object -Skip ${start - 1} -First ${end - start + 1}`;
|
|
125
|
+
}
|
|
126
|
+
function isShellTool(toolName) {
|
|
127
|
+
return toolName === 'Bash' || toolName === 'functions.exec_command' || !!toolName?.endsWith('.exec_command');
|
|
128
|
+
}
|
|
129
|
+
function findWindowsUnixTruncator(command) {
|
|
130
|
+
const stages = splitPipeStages(command);
|
|
131
|
+
for (const stage of stages) {
|
|
132
|
+
const tokens = shellWords(stage);
|
|
133
|
+
const name = commandName(tokens[0]);
|
|
134
|
+
if (!name)
|
|
135
|
+
continue;
|
|
136
|
+
if (name === 'sed') {
|
|
137
|
+
const replacement = replacementForSedPrintRead(tokens);
|
|
138
|
+
if (!replacement)
|
|
139
|
+
continue;
|
|
140
|
+
return { command: name, stage, replacement };
|
|
141
|
+
}
|
|
142
|
+
return {
|
|
143
|
+
command: name,
|
|
144
|
+
stage,
|
|
145
|
+
replacement: replacementFor(name, tokens),
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
return null;
|
|
149
|
+
}
|
|
150
|
+
function buildShellDialectGuardReason(hit) {
|
|
151
|
+
if (hit.command === 'sed') {
|
|
152
|
+
return [
|
|
153
|
+
'POWERSHELL UNIX FILE READ: Codex is running this shell command through PowerShell on Windows, where `sed` is not available.',
|
|
154
|
+
`Bad stage: \`${hit.stage}\`.`,
|
|
155
|
+
`Use PowerShell's \`${hit.replacement}\` instead.`,
|
|
156
|
+
].join(' ');
|
|
157
|
+
}
|
|
158
|
+
return [
|
|
159
|
+
'POWERSHELL UNIX TRUNCATOR: Codex is running this shell command through PowerShell on Windows, where `head`/`tail` is not available.',
|
|
160
|
+
`Bad stage: \`${hit.stage}\`.`,
|
|
161
|
+
`Use PowerShell's \`${hit.replacement}\` instead, or narrow the search paths so no truncation is needed.`,
|
|
162
|
+
].join(' ');
|
|
163
|
+
}
|
|
164
|
+
function runShellDialectGuard(input, opts = {}) {
|
|
165
|
+
if ((opts.platform || process.platform) !== 'win32')
|
|
166
|
+
return null;
|
|
167
|
+
if (!isShellTool(input.tool_name))
|
|
168
|
+
return null;
|
|
169
|
+
const command = input.tool_input?.command;
|
|
170
|
+
if (typeof command !== 'string' || !command.trim())
|
|
171
|
+
return null;
|
|
172
|
+
const hit = findWindowsUnixTruncator(command);
|
|
173
|
+
if (!hit)
|
|
174
|
+
return null;
|
|
175
|
+
return {
|
|
176
|
+
hookSpecificOutput: {
|
|
177
|
+
hookEventName: input.hook_event_name || 'PreToolUse',
|
|
178
|
+
permissionDecision: 'deny',
|
|
179
|
+
permissionDecisionReason: buildShellDialectGuardReason(hit),
|
|
180
|
+
},
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
//# sourceMappingURL=shell-dialect-guard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shell-dialect-guard.js","sourceRoot":"","sources":["../../src/commands/shell-dialect-guard.ts"],"names":[],"mappings":"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"}
|