greprag 5.74.18 → 5.74.20
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.
|
@@ -59,6 +59,7 @@ exports.classifyContent = classifyContent;
|
|
|
59
59
|
exports.crushField = crushField;
|
|
60
60
|
exports.crushMessages = crushMessages;
|
|
61
61
|
const crush_1 = require("./crush");
|
|
62
|
+
const crypto_1 = require("crypto");
|
|
62
63
|
// ---------- CCR marker (inlined — see header: ccr-store.ts drags sql.js) ------
|
|
63
64
|
/** First 16 hex of sha256 — must match ccr-store.ts CCR_MARKER_HASH_LEN. */
|
|
64
65
|
const CCR_MARKER_HASH_LEN = 16;
|
|
@@ -157,13 +158,19 @@ function runEngine(type, content) {
|
|
|
157
158
|
* passthrough, and token-validate-or-revert. The stash side effect fires ONLY
|
|
158
159
|
* on a real crush (after validation passes), so a reverted/skipped field is
|
|
159
160
|
* never persisted. */
|
|
160
|
-
function crushField(content, stash, thresholdBytes = exports.DEFAULT_THRESHOLD_BYTES) {
|
|
161
|
+
function crushField(content, stash, thresholdBytes = exports.DEFAULT_THRESHOLD_BYTES, seenHashes) {
|
|
161
162
|
if (typeof content !== 'string')
|
|
162
163
|
return null;
|
|
163
164
|
if (CCR_MARKER_RE.test(content))
|
|
164
165
|
return null; // idempotent
|
|
165
166
|
if (Buffer.byteLength(content, 'utf8') < thresholdBytes)
|
|
166
167
|
return null; // below floor
|
|
168
|
+
// Compute the stash hash first — if we've already stashed this exact
|
|
169
|
+
// content (e.g. it was retrieved via greprag retrieve), skip re-crushing
|
|
170
|
+
// to break the infinite marker→retrieve→same-marker loop.
|
|
171
|
+
const contentHash = (0, crypto_1.createHash)('sha256').update(content, 'utf8').digest('hex').slice(0, CCR_MARKER_HASH_LEN);
|
|
172
|
+
if (seenHashes?.has(contentHash))
|
|
173
|
+
return null;
|
|
167
174
|
const type = classifyContent(content);
|
|
168
175
|
const result = runEngine(type, content);
|
|
169
176
|
if (result.stats.passthrough)
|
|
@@ -177,6 +184,7 @@ function crushField(content, stash, thresholdBytes = exports.DEFAULT_THRESHOLD_B
|
|
|
177
184
|
if (finalTokens >= (0, crush_1.estimateTokens)(content))
|
|
178
185
|
return null;
|
|
179
186
|
const hash = stash(content, type);
|
|
187
|
+
seenHashes?.add(hash);
|
|
180
188
|
return `${crushed}\n${ccrMarker(hash)}`;
|
|
181
189
|
}
|
|
182
190
|
// ---------- Message-array walker ----------------------------------------------
|
|
@@ -203,7 +211,7 @@ function resolveRetrieveCommand(p) {
|
|
|
203
211
|
* ORIGINAL content, and crush is deterministic, so the reused value is exactly
|
|
204
212
|
* what crushField would recompute; the original was already stashed on the
|
|
205
213
|
* first (miss) crush, so skipping re-stash is safe for retrieve. */
|
|
206
|
-
function crushAndApply(obj, key, stash, thresholdBytes, stats, memo) {
|
|
214
|
+
function crushAndApply(obj, key, stash, thresholdBytes, stats, memo, seenHashes) {
|
|
207
215
|
const content = obj[key];
|
|
208
216
|
if (typeof content !== 'string')
|
|
209
217
|
return;
|
|
@@ -225,13 +233,13 @@ function crushAndApply(obj, key, stash, thresholdBytes, stats, memo) {
|
|
|
225
233
|
stats.memoHits++;
|
|
226
234
|
}
|
|
227
235
|
else {
|
|
228
|
-
replacement = crushField(content, stash, thresholdBytes);
|
|
236
|
+
replacement = crushField(content, stash, thresholdBytes, seenHashes);
|
|
229
237
|
stats.crushFieldCalls++;
|
|
230
238
|
memo.set(k, replacement);
|
|
231
239
|
}
|
|
232
240
|
}
|
|
233
241
|
else {
|
|
234
|
-
replacement = crushField(content, stash, thresholdBytes);
|
|
242
|
+
replacement = crushField(content, stash, thresholdBytes, seenHashes);
|
|
235
243
|
stats.crushFieldCalls++;
|
|
236
244
|
}
|
|
237
245
|
if (replacement === null) {
|
|
@@ -247,30 +255,18 @@ function crushAndApply(obj, key, stash, thresholdBytes, stats, memo) {
|
|
|
247
255
|
* - text part → `.text`
|
|
248
256
|
* - tool part → `.state.output` (only when state.status === 'completed';
|
|
249
257
|
* an 'error' state's `.error` is precious — left alone). */
|
|
250
|
-
function processPart(part, stash, thresholdBytes, stats, memo) {
|
|
258
|
+
function processPart(part, stash, thresholdBytes, stats, memo, seenHashes) {
|
|
251
259
|
if (!part || typeof part !== 'object')
|
|
252
260
|
return;
|
|
253
261
|
const p = part;
|
|
254
262
|
if (p.type === 'text' && typeof p.text === 'string') {
|
|
255
|
-
crushAndApply(p, 'text', stash, thresholdBytes, stats, memo);
|
|
263
|
+
crushAndApply(p, 'text', stash, thresholdBytes, stats, memo, seenHashes);
|
|
256
264
|
return;
|
|
257
265
|
}
|
|
258
266
|
if (p.type === 'tool' && p.state && typeof p.state === 'object') {
|
|
259
267
|
const state = p.state;
|
|
260
268
|
if (state.status === 'completed' && typeof state.output === 'string') {
|
|
261
|
-
|
|
262
|
-
// already stashed once; crushing it again creates an infinite
|
|
263
|
-
// marker→retrieve→same marker loop.
|
|
264
|
-
// The tool name / command may live on p.input.command (tool_use
|
|
265
|
-
// part) or on p.name / p.tool (tool_result part) depending on
|
|
266
|
-
// the opencode message format version.
|
|
267
|
-
const cmd = resolveRetrieveCommand(p);
|
|
268
|
-
if (cmd && cmd.includes('greprag retrieve')) {
|
|
269
|
-
stats.partsSkipped++;
|
|
270
|
-
}
|
|
271
|
-
else {
|
|
272
|
-
crushAndApply(state, 'output', stash, thresholdBytes, stats, memo);
|
|
273
|
-
}
|
|
269
|
+
crushAndApply(state, 'output', stash, thresholdBytes, stats, memo, seenHashes);
|
|
274
270
|
}
|
|
275
271
|
}
|
|
276
272
|
}
|
|
@@ -285,15 +281,37 @@ function crushMessages(messages, opts) {
|
|
|
285
281
|
crushFieldCalls: 0, memoHits: 0,
|
|
286
282
|
};
|
|
287
283
|
const thresholdBytes = opts.thresholdBytes ?? exports.DEFAULT_THRESHOLD_BYTES;
|
|
284
|
+
const seenHashes = opts.seenHashes ?? new Set();
|
|
288
285
|
if (!Array.isArray(messages))
|
|
289
286
|
return stats;
|
|
290
287
|
for (const msg of messages) {
|
|
291
288
|
const parts = msg && typeof msg === 'object' ? msg.parts : null;
|
|
292
289
|
if (!Array.isArray(parts))
|
|
293
290
|
continue;
|
|
291
|
+
let lastToolName = '';
|
|
294
292
|
for (const part of parts) {
|
|
295
293
|
try {
|
|
296
|
-
|
|
294
|
+
const p = part;
|
|
295
|
+
// Track the last tool_use command to skip crushing its result
|
|
296
|
+
if (p && typeof p === 'object' && (p.type === 'tool_use' || p.type === 'tool' && p.state === undefined)) {
|
|
297
|
+
const input = p.input;
|
|
298
|
+
const cmd = input && typeof input.command === 'string' ? input.command : '';
|
|
299
|
+
const name = typeof p.name === 'string' ? p.name : '';
|
|
300
|
+
lastToolName = cmd || name;
|
|
301
|
+
}
|
|
302
|
+
if (lastToolName && lastToolName.includes('greprag retrieve')) {
|
|
303
|
+
// Check if this is a tool_result for the greprag retrieve command
|
|
304
|
+
if (p && typeof p === 'object' && p.type === 'tool') {
|
|
305
|
+
stats.partsSkipped++;
|
|
306
|
+
continue;
|
|
307
|
+
}
|
|
308
|
+
// Also skip text parts immediately following (optional)
|
|
309
|
+
if (p && typeof p === 'object' && p.type === 'tool_result' && typeof p.content === 'string') {
|
|
310
|
+
stats.partsSkipped++;
|
|
311
|
+
continue;
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
processPart(part, opts.stash, thresholdBytes, stats, opts.memo, seenHashes);
|
|
297
315
|
}
|
|
298
316
|
catch {
|
|
299
317
|
// per-part swallow — a crush/stash failure must never break the turn
|
|
@@ -22,18 +22,18 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
22
22
|
mod
|
|
23
23
|
));
|
|
24
24
|
|
|
25
|
-
//
|
|
25
|
+
// src/opencode-plugin.ts
|
|
26
26
|
var crypto5 = __toESM(require("crypto"));
|
|
27
27
|
var fs7 = __toESM(require("fs"));
|
|
28
28
|
var os2 = __toESM(require("os"));
|
|
29
29
|
var path7 = __toESM(require("path"));
|
|
30
30
|
|
|
31
|
-
//
|
|
31
|
+
// src/opencode-plugin-helpers.ts
|
|
32
32
|
var crypto = __toESM(require("crypto"));
|
|
33
33
|
var fs = __toESM(require("fs"));
|
|
34
34
|
var path = __toESM(require("path"));
|
|
35
35
|
|
|
36
|
-
//
|
|
36
|
+
// src/proc.ts
|
|
37
37
|
var import_child_process = require("child_process");
|
|
38
38
|
function safeExecSync(command, options) {
|
|
39
39
|
return (0, import_child_process.execSync)(command, { windowsHide: true, ...options });
|
|
@@ -45,7 +45,7 @@ function safeSpawn(command, argsOrOptions, maybeOptions) {
|
|
|
45
45
|
return (0, import_child_process.spawn)(command, { windowsHide: true, ...argsOrOptions });
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
-
//
|
|
48
|
+
// src/opencode-plugin-helpers.ts
|
|
49
49
|
var HOME = process.env.HOME || process.env.USERPROFILE || "";
|
|
50
50
|
function readAnchorFile(filePath) {
|
|
51
51
|
try {
|
|
@@ -272,7 +272,7 @@ async function buildRecapBody(apiUrl, apiKey, anchor, now = /* @__PURE__ */ new
|
|
|
272
272
|
return parts.join("\n");
|
|
273
273
|
}
|
|
274
274
|
|
|
275
|
-
//
|
|
275
|
+
// src/crush/crush-types.ts
|
|
276
276
|
function estimateTokens(text) {
|
|
277
277
|
return Math.ceil(text.length / 4);
|
|
278
278
|
}
|
|
@@ -292,7 +292,7 @@ function makePassthrough(content, sourceType, reason, units = 0) {
|
|
|
292
292
|
};
|
|
293
293
|
}
|
|
294
294
|
|
|
295
|
-
//
|
|
295
|
+
// src/crush/adaptive-sizer.ts
|
|
296
296
|
function fnv1a(s, seed) {
|
|
297
297
|
let h = (2166136261 ^ seed) >>> 0;
|
|
298
298
|
for (let i = 0; i < s.length; i++) {
|
|
@@ -394,7 +394,7 @@ function computeOptimalK(items, bias, minK, maxK) {
|
|
|
394
394
|
return Math.max(minK, Math.min(k, effectiveMax));
|
|
395
395
|
}
|
|
396
396
|
|
|
397
|
-
//
|
|
397
|
+
// src/crush/crush-keywords.ts
|
|
398
398
|
var ERROR_KEYWORDS = [
|
|
399
399
|
"error",
|
|
400
400
|
"exception",
|
|
@@ -467,7 +467,7 @@ function classifyImportance(line) {
|
|
|
467
467
|
return null;
|
|
468
468
|
}
|
|
469
469
|
|
|
470
|
-
//
|
|
470
|
+
// src/crush/search-compressor.ts
|
|
471
471
|
var DEFAULT_SEARCH_CONFIG = {
|
|
472
472
|
maxMatchesPerFile: 5,
|
|
473
473
|
alwaysKeepFirst: true,
|
|
@@ -630,7 +630,7 @@ function crushSearch(content, query = "", config = {}) {
|
|
|
630
630
|
};
|
|
631
631
|
}
|
|
632
632
|
|
|
633
|
-
//
|
|
633
|
+
// src/crush/log-compressor.ts
|
|
634
634
|
var DEFAULT_LOG_CONFIG = {
|
|
635
635
|
maxErrors: 10,
|
|
636
636
|
errorContextLines: 3,
|
|
@@ -941,7 +941,7 @@ function crushLog(content, config = {}) {
|
|
|
941
941
|
};
|
|
942
942
|
}
|
|
943
943
|
|
|
944
|
-
//
|
|
944
|
+
// src/crush/json-detectors.ts
|
|
945
945
|
function classifyArray(items) {
|
|
946
946
|
if (items.length === 0)
|
|
947
947
|
return "empty";
|
|
@@ -1101,7 +1101,7 @@ function detectErrorItems(items) {
|
|
|
1101
1101
|
return out;
|
|
1102
1102
|
}
|
|
1103
1103
|
|
|
1104
|
-
//
|
|
1104
|
+
// src/crush/json-crusher.ts
|
|
1105
1105
|
var DEFAULT_JSON_CONFIG = {
|
|
1106
1106
|
minItemsToAnalyze: 10,
|
|
1107
1107
|
maxItemsAfterCrush: 15,
|
|
@@ -1312,7 +1312,7 @@ function crushJson(content, config = {}) {
|
|
|
1312
1312
|
};
|
|
1313
1313
|
}
|
|
1314
1314
|
|
|
1315
|
-
//
|
|
1315
|
+
// src/crush/code-compressor.ts
|
|
1316
1316
|
var DEFAULT_CODE_CONFIG = {
|
|
1317
1317
|
minLines: 8,
|
|
1318
1318
|
maxBodyLines: 3
|
|
@@ -1599,7 +1599,8 @@ function crushCode(content, config = {}) {
|
|
|
1599
1599
|
};
|
|
1600
1600
|
}
|
|
1601
1601
|
|
|
1602
|
-
//
|
|
1602
|
+
// src/opencode-plugin-crush.ts
|
|
1603
|
+
var import_crypto = require("crypto");
|
|
1603
1604
|
var CCR_MARKER_HASH_LEN = 16;
|
|
1604
1605
|
function ccrMarker(hash) {
|
|
1605
1606
|
return `<<ccr:${hash.slice(0, CCR_MARKER_HASH_LEN)}>>`;
|
|
@@ -1645,13 +1646,16 @@ function runEngine(type, content) {
|
|
|
1645
1646
|
return crushLog(content);
|
|
1646
1647
|
}
|
|
1647
1648
|
}
|
|
1648
|
-
function crushField(content, stash, thresholdBytes = DEFAULT_THRESHOLD_BYTES) {
|
|
1649
|
+
function crushField(content, stash, thresholdBytes = DEFAULT_THRESHOLD_BYTES, seenHashes) {
|
|
1649
1650
|
if (typeof content !== "string")
|
|
1650
1651
|
return null;
|
|
1651
1652
|
if (CCR_MARKER_RE.test(content))
|
|
1652
1653
|
return null;
|
|
1653
1654
|
if (Buffer.byteLength(content, "utf8") < thresholdBytes)
|
|
1654
1655
|
return null;
|
|
1656
|
+
const contentHash = (0, import_crypto.createHash)("sha256").update(content, "utf8").digest("hex").slice(0, CCR_MARKER_HASH_LEN);
|
|
1657
|
+
if (seenHashes?.has(contentHash))
|
|
1658
|
+
return null;
|
|
1655
1659
|
const type = classifyContent(content);
|
|
1656
1660
|
const result = runEngine(type, content);
|
|
1657
1661
|
if (result.stats.passthrough)
|
|
@@ -1661,19 +1665,11 @@ function crushField(content, stash, thresholdBytes = DEFAULT_THRESHOLD_BYTES) {
|
|
|
1661
1665
|
if (finalTokens >= estimateTokens(content))
|
|
1662
1666
|
return null;
|
|
1663
1667
|
const hash = stash(content, type);
|
|
1668
|
+
seenHashes?.add(hash);
|
|
1664
1669
|
return `${crushed}
|
|
1665
1670
|
${ccrMarker(hash)}`;
|
|
1666
1671
|
}
|
|
1667
|
-
function
|
|
1668
|
-
const input = p.input;
|
|
1669
|
-
if (input && typeof input.command === "string")
|
|
1670
|
-
return input.command;
|
|
1671
|
-
const toolName = typeof p.name === "string" && p.name || typeof p.tool === "string" && p.tool || typeof p.toolName === "string" && p.toolName;
|
|
1672
|
-
if (toolName)
|
|
1673
|
-
return toolName;
|
|
1674
|
-
return "";
|
|
1675
|
-
}
|
|
1676
|
-
function crushAndApply(obj, key, stash, thresholdBytes, stats, memo) {
|
|
1672
|
+
function crushAndApply(obj, key, stash, thresholdBytes, stats, memo, seenHashes) {
|
|
1677
1673
|
const content = obj[key];
|
|
1678
1674
|
if (typeof content !== "string")
|
|
1679
1675
|
return;
|
|
@@ -1694,12 +1690,12 @@ function crushAndApply(obj, key, stash, thresholdBytes, stats, memo) {
|
|
|
1694
1690
|
replacement = memo.get(k) ?? null;
|
|
1695
1691
|
stats.memoHits++;
|
|
1696
1692
|
} else {
|
|
1697
|
-
replacement = crushField(content, stash, thresholdBytes);
|
|
1693
|
+
replacement = crushField(content, stash, thresholdBytes, seenHashes);
|
|
1698
1694
|
stats.crushFieldCalls++;
|
|
1699
1695
|
memo.set(k, replacement);
|
|
1700
1696
|
}
|
|
1701
1697
|
} else {
|
|
1702
|
-
replacement = crushField(content, stash, thresholdBytes);
|
|
1698
|
+
replacement = crushField(content, stash, thresholdBytes, seenHashes);
|
|
1703
1699
|
stats.crushFieldCalls++;
|
|
1704
1700
|
}
|
|
1705
1701
|
if (replacement === null) {
|
|
@@ -1711,23 +1707,18 @@ function crushAndApply(obj, key, stash, thresholdBytes, stats, memo) {
|
|
|
1711
1707
|
stats.partsCrushed++;
|
|
1712
1708
|
stats.bytesAfter += Buffer.byteLength(replacement, "utf8");
|
|
1713
1709
|
}
|
|
1714
|
-
function processPart(part, stash, thresholdBytes, stats, memo) {
|
|
1710
|
+
function processPart(part, stash, thresholdBytes, stats, memo, seenHashes) {
|
|
1715
1711
|
if (!part || typeof part !== "object")
|
|
1716
1712
|
return;
|
|
1717
1713
|
const p = part;
|
|
1718
1714
|
if (p.type === "text" && typeof p.text === "string") {
|
|
1719
|
-
crushAndApply(p, "text", stash, thresholdBytes, stats, memo);
|
|
1715
|
+
crushAndApply(p, "text", stash, thresholdBytes, stats, memo, seenHashes);
|
|
1720
1716
|
return;
|
|
1721
1717
|
}
|
|
1722
1718
|
if (p.type === "tool" && p.state && typeof p.state === "object") {
|
|
1723
1719
|
const state = p.state;
|
|
1724
1720
|
if (state.status === "completed" && typeof state.output === "string") {
|
|
1725
|
-
|
|
1726
|
-
if (cmd && cmd.includes("greprag retrieve")) {
|
|
1727
|
-
stats.partsSkipped++;
|
|
1728
|
-
} else {
|
|
1729
|
-
crushAndApply(state, "output", stash, thresholdBytes, stats, memo);
|
|
1730
|
-
}
|
|
1721
|
+
crushAndApply(state, "output", stash, thresholdBytes, stats, memo, seenHashes);
|
|
1731
1722
|
}
|
|
1732
1723
|
}
|
|
1733
1724
|
}
|
|
@@ -1742,15 +1733,34 @@ function crushMessages(messages, opts) {
|
|
|
1742
1733
|
memoHits: 0
|
|
1743
1734
|
};
|
|
1744
1735
|
const thresholdBytes = opts.thresholdBytes ?? DEFAULT_THRESHOLD_BYTES;
|
|
1736
|
+
const seenHashes = opts.seenHashes ?? /* @__PURE__ */ new Set();
|
|
1745
1737
|
if (!Array.isArray(messages))
|
|
1746
1738
|
return stats;
|
|
1747
1739
|
for (const msg of messages) {
|
|
1748
1740
|
const parts = msg && typeof msg === "object" ? msg.parts : null;
|
|
1749
1741
|
if (!Array.isArray(parts))
|
|
1750
1742
|
continue;
|
|
1743
|
+
let lastToolName = "";
|
|
1751
1744
|
for (const part of parts) {
|
|
1752
1745
|
try {
|
|
1753
|
-
|
|
1746
|
+
const p = part;
|
|
1747
|
+
if (p && typeof p === "object" && (p.type === "tool_use" || p.type === "tool" && p.state === void 0)) {
|
|
1748
|
+
const input = p.input;
|
|
1749
|
+
const cmd = input && typeof input.command === "string" ? input.command : "";
|
|
1750
|
+
const name = typeof p.name === "string" ? p.name : "";
|
|
1751
|
+
lastToolName = cmd || name;
|
|
1752
|
+
}
|
|
1753
|
+
if (lastToolName && lastToolName.includes("greprag retrieve")) {
|
|
1754
|
+
if (p && typeof p === "object" && p.type === "tool") {
|
|
1755
|
+
stats.partsSkipped++;
|
|
1756
|
+
continue;
|
|
1757
|
+
}
|
|
1758
|
+
if (p && typeof p === "object" && p.type === "tool_result" && typeof p.content === "string") {
|
|
1759
|
+
stats.partsSkipped++;
|
|
1760
|
+
continue;
|
|
1761
|
+
}
|
|
1762
|
+
}
|
|
1763
|
+
processPart(part, opts.stash, thresholdBytes, stats, opts.memo, seenHashes);
|
|
1754
1764
|
} catch {
|
|
1755
1765
|
stats.partsSkipped++;
|
|
1756
1766
|
}
|
|
@@ -1759,7 +1769,7 @@ function crushMessages(messages, opts) {
|
|
|
1759
1769
|
return stats;
|
|
1760
1770
|
}
|
|
1761
1771
|
|
|
1762
|
-
//
|
|
1772
|
+
// src/commands/os-primer-reminder.ts
|
|
1763
1773
|
function buildOsPrimer(env) {
|
|
1764
1774
|
const spawnEntry = env?.platform === "codex" ? "codex-chip-spawn" : env?.platform === "opencode" ? "chip-bootloader" : "chip-spawn";
|
|
1765
1775
|
return [
|
|
@@ -1779,7 +1789,7 @@ var osPrimerModule = {
|
|
|
1779
1789
|
reminder: () => null
|
|
1780
1790
|
};
|
|
1781
1791
|
|
|
1782
|
-
//
|
|
1792
|
+
// src/session-id.ts
|
|
1783
1793
|
function armMonitorCommand(short, ownerPid, assistant = false, mechanic = false) {
|
|
1784
1794
|
const owner = ownerPid ? ` --owner-pid ${ownerPid}` : "";
|
|
1785
1795
|
const role = mechanic ? " --mechanic" : assistant ? " --assistant" : "";
|
|
@@ -1787,7 +1797,7 @@ function armMonitorCommand(short, ownerPid, assistant = false, mechanic = false)
|
|
|
1787
1797
|
return `while true; do ${watch}; case $? in 0|64) break;; esac; sleep 1; done`;
|
|
1788
1798
|
}
|
|
1789
1799
|
|
|
1790
|
-
//
|
|
1800
|
+
// src/commands/inbox-primer-reminder.ts
|
|
1791
1801
|
function buildInboxPrimer(env) {
|
|
1792
1802
|
const codex = env.platform === "codex";
|
|
1793
1803
|
const opencode = env.platform === "opencode";
|
|
@@ -1825,7 +1835,7 @@ var inboxPrimerModule = {
|
|
|
1825
1835
|
reminder: () => null
|
|
1826
1836
|
};
|
|
1827
1837
|
|
|
1828
|
-
//
|
|
1838
|
+
// src/commands/load-primer-reminder.ts
|
|
1829
1839
|
var LOAD_PRIMER = [
|
|
1830
1840
|
"[greprag load \u2014 on-demand doctrine. greprag ships its own methods inside the CLI; you never need a `.md` file or a CLAUDE.md entry to use them.]",
|
|
1831
1841
|
"\u2022 `greprag load` \u2192 browse the catalog (every doctrine entry + its one-line purpose).",
|
|
@@ -1877,7 +1887,7 @@ var codexChipSpawnPointerModule = {
|
|
|
1877
1887
|
reminder: () => null
|
|
1878
1888
|
};
|
|
1879
1889
|
|
|
1880
|
-
//
|
|
1890
|
+
// src/commands/email-primer-reminder.ts
|
|
1881
1891
|
var EMAIL_PRIMER = [
|
|
1882
1892
|
"[greprag email \u2014 the agent's REAL mailbox (actual inbound + outbound SMTP), distinct from `greprag send` (internal session mesh, never real email).]",
|
|
1883
1893
|
'\u2022 SEND real mail: `greprag email send --to <addr> --subject "s" (--body "t" | --body-file <f|->)` \u2014 from your <handle>@greprag.com. Flags: --html-file (rich body) \xB7 --attach (repeatable) \xB7 --cc/--bcc \xB7 --reply-to \xB7 --from-name \xB7 --from <your-own-handle> (server rejects any address that isn\'t yours \u2014 no forging).',
|
|
@@ -1894,7 +1904,7 @@ var emailPrimerModule = {
|
|
|
1894
1904
|
reminder: () => null
|
|
1895
1905
|
};
|
|
1896
1906
|
|
|
1897
|
-
//
|
|
1907
|
+
// src/commands/corpus-reminder.ts
|
|
1898
1908
|
function buildCorpusAnnounce(names) {
|
|
1899
1909
|
if (!names || names.length === 0)
|
|
1900
1910
|
return null;
|
|
@@ -1914,7 +1924,7 @@ var corpusAnnounceModule = {
|
|
|
1914
1924
|
reminder: () => null
|
|
1915
1925
|
};
|
|
1916
1926
|
|
|
1917
|
-
//
|
|
1927
|
+
// src/commands/doc-pointer-reminder.ts
|
|
1918
1928
|
var ANNOUNCE_CAP = 20;
|
|
1919
1929
|
function buildDocPointerAnnounce(pointers) {
|
|
1920
1930
|
if (!pointers || pointers.length === 0)
|
|
@@ -1946,7 +1956,7 @@ var docPointerAnnounceModule = {
|
|
|
1946
1956
|
reminder: () => null
|
|
1947
1957
|
};
|
|
1948
1958
|
|
|
1949
|
-
//
|
|
1959
|
+
// src/commands/setup-reminder.ts
|
|
1950
1960
|
function setupDetect(env) {
|
|
1951
1961
|
return env.setupWarning ? { tier: "nudge" } : { tier: "silent" };
|
|
1952
1962
|
}
|
|
@@ -1957,7 +1967,7 @@ var setupWarningModule = {
|
|
|
1957
1967
|
reminder: () => null
|
|
1958
1968
|
};
|
|
1959
1969
|
|
|
1960
|
-
//
|
|
1970
|
+
// src/commands/assistant-reminder.ts
|
|
1961
1971
|
function assistantDetect(env) {
|
|
1962
1972
|
return env.assistantDoctrine ? { tier: "ambient" } : { tier: "silent" };
|
|
1963
1973
|
}
|
|
@@ -1968,7 +1978,7 @@ var assistantDoctrineModule = {
|
|
|
1968
1978
|
reminder: () => null
|
|
1969
1979
|
};
|
|
1970
1980
|
|
|
1971
|
-
//
|
|
1981
|
+
// src/commands/memory-reflex.ts
|
|
1972
1982
|
function buildMemoryAnnounce() {
|
|
1973
1983
|
return [
|
|
1974
1984
|
"[greprag memory \u2014 this project remembers. Every past session (decisions, bugs, what was discussed, who did what) is captured and searchable.]",
|
|
@@ -1982,7 +1992,7 @@ var memoryPrimerModule = {
|
|
|
1982
1992
|
reminder: () => null
|
|
1983
1993
|
};
|
|
1984
1994
|
|
|
1985
|
-
//
|
|
1995
|
+
// src/commands/arm-reminder.ts
|
|
1986
1996
|
function armDetect(env) {
|
|
1987
1997
|
if (env.armed)
|
|
1988
1998
|
return { tier: "silent" };
|
|
@@ -2012,11 +2022,11 @@ var watcherArmModule = {
|
|
|
2012
2022
|
reminder: (d, env) => buildArmReminder(d, env)
|
|
2013
2023
|
};
|
|
2014
2024
|
|
|
2015
|
-
//
|
|
2025
|
+
// src/commands/state-trigger.ts
|
|
2016
2026
|
var STRESS_ELEVATED = 1;
|
|
2017
2027
|
var STRESS_HIGH = 2;
|
|
2018
2028
|
|
|
2019
|
-
//
|
|
2029
|
+
// src/commands/friction-reminder.ts
|
|
2020
2030
|
function quoteForCommand(value) {
|
|
2021
2031
|
return value.replace(/[\r\n]+/g, " ").replace(/"/g, '\\"').trim();
|
|
2022
2032
|
}
|
|
@@ -2081,7 +2091,7 @@ var mechanicFrictionModule = {
|
|
|
2081
2091
|
}
|
|
2082
2092
|
};
|
|
2083
2093
|
|
|
2084
|
-
//
|
|
2094
|
+
// src/commands/coordinate-gate.ts
|
|
2085
2095
|
var RISKY_PATTERNS = [
|
|
2086
2096
|
{ kind: "merge", label: "gh pr merge", re: /^gh\s+pr\s+merge\b/ },
|
|
2087
2097
|
{ kind: "deploy", label: "wrangler deploy", re: /^(?:npx\s+)?wrangler\s+deploy\b/ },
|
|
@@ -2198,7 +2208,7 @@ function buildCoordinateDirective(trigger, peers, myShort, alias) {
|
|
|
2198
2208
|
return `COORDINATE before ${trigger.label}: ${peers.length} peer${plural} live in this repo (${list}). Ping before proceeding. Codex peers: use codex_app.list_threads and codex_app.send_message_to_thread. GrepRAG watcher/cross-harness peers: greprag send "heads up, about to ${trigger.label}" --to ${handle}@greprag.com/<8hex> --from-session ${myShort}`;
|
|
2199
2209
|
}
|
|
2200
2210
|
|
|
2201
|
-
//
|
|
2211
|
+
// src/commands/collision-reminder.ts
|
|
2202
2212
|
var collisionMatchModule = {
|
|
2203
2213
|
id: "collision",
|
|
2204
2214
|
source: "command",
|
|
@@ -2223,7 +2233,7 @@ var collisionMatchModule = {
|
|
|
2223
2233
|
}
|
|
2224
2234
|
};
|
|
2225
2235
|
|
|
2226
|
-
//
|
|
2236
|
+
// src/commands/version-reminder.ts
|
|
2227
2237
|
function buildVersionAnnounce(current, latest) {
|
|
2228
2238
|
return [
|
|
2229
2239
|
`[greprag \u2014 a new release is out: v${latest} (you are on v${current}).]`,
|
|
@@ -2264,7 +2274,7 @@ var versionUpgradeModule = {
|
|
|
2264
2274
|
reminder: () => null
|
|
2265
2275
|
};
|
|
2266
2276
|
|
|
2267
|
-
//
|
|
2277
|
+
// src/commands/enrichment-health-reminder.ts
|
|
2268
2278
|
function buildEnrichmentHealthAnnounce(down) {
|
|
2269
2279
|
if (!down || !down.errorClass)
|
|
2270
2280
|
return null;
|
|
@@ -2283,7 +2293,7 @@ var enrichmentHealthModule = {
|
|
|
2283
2293
|
reminder: () => null
|
|
2284
2294
|
};
|
|
2285
2295
|
|
|
2286
|
-
//
|
|
2296
|
+
// src/commands/skill-gain-reminder.ts
|
|
2287
2297
|
function buildSkillGainAnnounce(gains) {
|
|
2288
2298
|
if (!gains || gains.landed.length === 0)
|
|
2289
2299
|
return null;
|
|
@@ -2302,7 +2312,7 @@ var skillGainAnnounceModule = {
|
|
|
2302
2312
|
reminder: () => null
|
|
2303
2313
|
};
|
|
2304
2314
|
|
|
2305
|
-
//
|
|
2315
|
+
// src/commands/skill-mirror-reminder.ts
|
|
2306
2316
|
var SKILL_ACTIVATION_MANIFEST_MAX_CHARS = 64e3;
|
|
2307
2317
|
function renderEntry(skill) {
|
|
2308
2318
|
const description = skill.triggerDescription.trim().replace(/\r\n?/g, "\n");
|
|
@@ -2355,7 +2365,7 @@ var skillMirrorAnnounceModule = {
|
|
|
2355
2365
|
reminder: () => null
|
|
2356
2366
|
};
|
|
2357
2367
|
|
|
2358
|
-
//
|
|
2368
|
+
// src/commands/procedure-reminder.ts
|
|
2359
2369
|
function buildProcedureAnnounce(lines) {
|
|
2360
2370
|
const active = (lines ?? []).map((s) => s.trim()).filter(Boolean);
|
|
2361
2371
|
if (!active.length)
|
|
@@ -2373,7 +2383,7 @@ var procedureAnnounceModule = {
|
|
|
2373
2383
|
reminder: () => null
|
|
2374
2384
|
};
|
|
2375
2385
|
|
|
2376
|
-
//
|
|
2386
|
+
// src/commands/loadout-reminder.ts
|
|
2377
2387
|
function matchLoadouts(promptText, equipped) {
|
|
2378
2388
|
const prompt = (promptText || "").toLowerCase();
|
|
2379
2389
|
if (!prompt.trim() || !equipped || equipped.length === 0)
|
|
@@ -2412,7 +2422,7 @@ var loadoutRegistrarModule = {
|
|
|
2412
2422
|
reminder: (d) => buildLoadoutReminder(d.detail?.matched || [])
|
|
2413
2423
|
};
|
|
2414
2424
|
|
|
2415
|
-
//
|
|
2425
|
+
// src/commands/delivery-reminder.ts
|
|
2416
2426
|
function coordinationLine(platform) {
|
|
2417
2427
|
if (platform === "codex") {
|
|
2418
2428
|
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. Delivery owner: rename this task `DEPLOY: <existing title>`; transfer the prefix on handoff; remove the prefix when delivery is done.";
|
|
@@ -2444,7 +2454,7 @@ var deliveryControlModule = {
|
|
|
2444
2454
|
reminder: () => null
|
|
2445
2455
|
};
|
|
2446
2456
|
|
|
2447
|
-
//
|
|
2457
|
+
// src/commands/reminder-registry.ts
|
|
2448
2458
|
var REGISTRY = [
|
|
2449
2459
|
osPrimerModule,
|
|
2450
2460
|
// grepragOS constitution — the frame every other primer hangs off; boots FIRST
|
|
@@ -2539,7 +2549,7 @@ function collectAnnounces(env, registry = REGISTRY) {
|
|
|
2539
2549
|
return out;
|
|
2540
2550
|
}
|
|
2541
2551
|
|
|
2542
|
-
//
|
|
2552
|
+
// src/commands/opencode-interrupt.ts
|
|
2543
2553
|
var opencodeRegistry = harnessModules("opencode");
|
|
2544
2554
|
var OPENCODE_QUOTA_WAITLIST_ANNOUNCE = [
|
|
2545
2555
|
"[GrepRAG quota decision rule]",
|
|
@@ -2578,11 +2588,11 @@ function getOpenCodeReminders(env) {
|
|
|
2578
2588
|
return collectReminders(env, opencodeRegistry);
|
|
2579
2589
|
}
|
|
2580
2590
|
|
|
2581
|
-
//
|
|
2591
|
+
// src/procedure.ts
|
|
2582
2592
|
var path2 = __toESM(require("path"));
|
|
2583
2593
|
var fs2 = __toESM(require("fs"));
|
|
2584
2594
|
|
|
2585
|
-
//
|
|
2595
|
+
// src/delivery-lifecycle.ts
|
|
2586
2596
|
var DELIVERY_LIFECYCLE_VERBS = [
|
|
2587
2597
|
"commit",
|
|
2588
2598
|
"merge",
|
|
@@ -2595,7 +2605,7 @@ function isDeliveryLifecycleVerb(verb) {
|
|
|
2595
2605
|
return DELIVERY_LIFECYCLE_SET.has((verb || "").trim().toLowerCase());
|
|
2596
2606
|
}
|
|
2597
2607
|
|
|
2598
|
-
//
|
|
2608
|
+
// src/procedure.ts
|
|
2599
2609
|
var PROCEDURE_STORE_VERSION = "2";
|
|
2600
2610
|
function stateDir() {
|
|
2601
2611
|
const home = process.env.HOME || process.env.USERPROFILE || "";
|
|
@@ -2836,10 +2846,10 @@ function activeProcedureAnnounces(store) {
|
|
|
2836
2846
|
return lines;
|
|
2837
2847
|
}
|
|
2838
2848
|
|
|
2839
|
-
//
|
|
2849
|
+
// src/procedure-runtime.ts
|
|
2840
2850
|
var crypto4 = __toESM(require("crypto"));
|
|
2841
2851
|
|
|
2842
|
-
//
|
|
2852
|
+
// src/project-anchor.ts
|
|
2843
2853
|
var path3 = __toESM(require("path"));
|
|
2844
2854
|
var fs3 = __toESM(require("fs"));
|
|
2845
2855
|
var crypto2 = __toESM(require("crypto"));
|
|
@@ -3021,7 +3031,7 @@ function readAnchor2(cwd) {
|
|
|
3021
3031
|
};
|
|
3022
3032
|
}
|
|
3023
3033
|
|
|
3024
|
-
//
|
|
3034
|
+
// src/procedure-watch.ts
|
|
3025
3035
|
var path4 = __toESM(require("path"));
|
|
3026
3036
|
var fs4 = __toESM(require("fs"));
|
|
3027
3037
|
var TIER1_LEARN_TRIGGERS = [
|
|
@@ -3082,7 +3092,7 @@ function openWatchIfIdle(projectId, verb, phase, shadowRunId) {
|
|
|
3082
3092
|
return true;
|
|
3083
3093
|
}
|
|
3084
3094
|
|
|
3085
|
-
//
|
|
3095
|
+
// src/procedure-shadow.ts
|
|
3086
3096
|
var crypto3 = __toESM(require("crypto"));
|
|
3087
3097
|
var fs5 = __toESM(require("fs"));
|
|
3088
3098
|
var path5 = __toESM(require("path"));
|
|
@@ -3148,7 +3158,7 @@ function recordMissingLifecycleShadowTrigger(params) {
|
|
|
3148
3158
|
});
|
|
3149
3159
|
}
|
|
3150
3160
|
|
|
3151
|
-
//
|
|
3161
|
+
// src/procedure-runtime.ts
|
|
3152
3162
|
function extractLatestOpenCodeProcedurePrompt(messages) {
|
|
3153
3163
|
let userCount = 0;
|
|
3154
3164
|
let latest = null;
|
|
@@ -3234,7 +3244,7 @@ function runProcedurePromptCheck(params) {
|
|
|
3234
3244
|
}
|
|
3235
3245
|
}
|
|
3236
3246
|
|
|
3237
|
-
//
|
|
3247
|
+
// src/archive/glyph-font.ts
|
|
3238
3248
|
var GLYPH_W = 8;
|
|
3239
3249
|
var GLYPH_H = 8;
|
|
3240
3250
|
var FIRST_CODE = 32;
|
|
@@ -3358,7 +3368,7 @@ function signatureForRows(bytes) {
|
|
|
3358
3368
|
return bytes.map((b) => (b & 255).toString(16).padStart(2, "0")).join("");
|
|
3359
3369
|
}
|
|
3360
3370
|
|
|
3361
|
-
//
|
|
3371
|
+
// src/archive/png-codec.ts
|
|
3362
3372
|
var zlib = __toESM(require("zlib"));
|
|
3363
3373
|
var PNG_SIGNATURE = Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]);
|
|
3364
3374
|
var crcTable = null;
|
|
@@ -3500,7 +3510,7 @@ function decodePng(buf) {
|
|
|
3500
3510
|
return { width, height, pixels };
|
|
3501
3511
|
}
|
|
3502
3512
|
|
|
3503
|
-
//
|
|
3513
|
+
// src/archive/page-renderer.ts
|
|
3504
3514
|
var PAGE_SIZE = 1568;
|
|
3505
3515
|
var CELL_W = GLYPH_W;
|
|
3506
3516
|
var CELL_H = 10;
|
|
@@ -3626,7 +3636,7 @@ function verifyRoundTrip(page) {
|
|
|
3626
3636
|
return `length mismatch: rendered ${a.length} decoded ${b.length}`;
|
|
3627
3637
|
}
|
|
3628
3638
|
|
|
3629
|
-
//
|
|
3639
|
+
// src/opencode-plugin-png.ts
|
|
3630
3640
|
var CCR_MARKER_HASH_LEN2 = 16;
|
|
3631
3641
|
function ccrPngMarker(hash) {
|
|
3632
3642
|
return `<<ccr:${hash.slice(0, CCR_MARKER_HASH_LEN2)}>>`;
|
|
@@ -3816,7 +3826,7 @@ function recodeMessagesToPng(messages, opts) {
|
|
|
3816
3826
|
return stats;
|
|
3817
3827
|
}
|
|
3818
3828
|
|
|
3819
|
-
//
|
|
3829
|
+
// src/skill-activation-manifest.ts
|
|
3820
3830
|
var fs6 = __toESM(require("fs"));
|
|
3821
3831
|
var path6 = __toESM(require("path"));
|
|
3822
3832
|
var MAX_NATIVE_SKILL_FILES = 1500;
|
|
@@ -3917,7 +3927,7 @@ function activationFromApiRows(params) {
|
|
|
3917
3927
|
return buildMirroredSkillActivation(entries, readNativeSkillNames(params));
|
|
3918
3928
|
}
|
|
3919
3929
|
|
|
3920
|
-
//
|
|
3930
|
+
// src/opencode-plugin.ts
|
|
3921
3931
|
var DEBUG_LOG_PATH = path7.join(os2.homedir(), ".greprag", "opencode-plugin-debug.log");
|
|
3922
3932
|
var _debugLogReady = false;
|
|
3923
3933
|
function dlogInit() {
|
|
@@ -4498,6 +4508,7 @@ function grepragBinCached() {
|
|
|
4498
4508
|
return _cachedGrepragBin;
|
|
4499
4509
|
}
|
|
4500
4510
|
var _crushShapeLogged = false;
|
|
4511
|
+
var _crushSeenHashes;
|
|
4501
4512
|
function inlineCrushEnabled() {
|
|
4502
4513
|
const v = process.env.GREPRAG_OPENCODE_CRUSH;
|
|
4503
4514
|
return v === "true" || v === "1";
|
|
@@ -4740,7 +4751,8 @@ ALWAYS pass \`--from-session ${sid82}\` when you run \`greprag send\`, so recipi
|
|
|
4740
4751
|
const thresholdEnv = parseInt(process.env.GREPRAG_OPENCODE_CRUSH_MIN_BYTES || "", 10);
|
|
4741
4752
|
const stats = crushMessages(msgs, {
|
|
4742
4753
|
stash: makeCcrStash(),
|
|
4743
|
-
thresholdBytes: Number.isFinite(thresholdEnv) && thresholdEnv > 0 ? thresholdEnv : void 0
|
|
4754
|
+
thresholdBytes: Number.isFinite(thresholdEnv) && thresholdEnv > 0 ? thresholdEnv : void 0,
|
|
4755
|
+
seenHashes: _crushSeenHashes ?? (_crushSeenHashes = /* @__PURE__ */ new Set())
|
|
4744
4756
|
});
|
|
4745
4757
|
if (stats.partsCrushed > 0 || stats.partsReverted > 0) {
|
|
4746
4758
|
dlog(
|
package/dist/opencode-plugin.js
CHANGED
|
@@ -792,6 +792,9 @@ function grepragBinCached() {
|
|
|
792
792
|
* crusher's assumptions. See the chip report: live propagation + shape are
|
|
793
793
|
* the two things only a real opencode restart can verify. */
|
|
794
794
|
let _crushShapeLogged = false;
|
|
795
|
+
/** Per-session set of hashes already stashed — prevents re-crushing content
|
|
796
|
+
* that was already compressed once (e.g. retrieved via greprag retrieve). */
|
|
797
|
+
let _crushSeenHashes;
|
|
795
798
|
/** GREPRAG_OPENCODE_CRUSH gate — opt-in, default OFF for safe rollout. */
|
|
796
799
|
function inlineCrushEnabled() {
|
|
797
800
|
const v = process.env.GREPRAG_OPENCODE_CRUSH;
|
|
@@ -1115,6 +1118,7 @@ const GrepRAGMemoryPlugin = async (ctx) => {
|
|
|
1115
1118
|
const stats = (0, opencode_plugin_crush_1.crushMessages)(msgs, {
|
|
1116
1119
|
stash: makeCcrStash(),
|
|
1117
1120
|
thresholdBytes: Number.isFinite(thresholdEnv) && thresholdEnv > 0 ? thresholdEnv : undefined,
|
|
1121
|
+
seenHashes: _crushSeenHashes ?? (_crushSeenHashes = new Set()),
|
|
1118
1122
|
});
|
|
1119
1123
|
if (stats.partsCrushed > 0 || stats.partsReverted > 0) {
|
|
1120
1124
|
dlog(`messages.transform: crushed=${stats.partsCrushed} reverted=${stats.partsReverted} ` +
|