@wrongstack/core 0.267.0 → 0.269.0
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/{agent-bridge-STJ3JwwK.d.ts → agent-bridge-PcHQl_UQ.d.ts} +1 -1
- package/dist/{agent-subagent-runner-CzPGP3jA.d.ts → agent-subagent-runner-SHJW7t8q.d.ts} +8 -8
- package/dist/{brain-Cdg77tVN.d.ts → brain-BYcK__Ym.d.ts} +1 -1
- package/dist/{compactor-iMZ84CXq.d.ts → compactor-C2RKEBtC.d.ts} +1 -1
- package/dist/{config-Du3pYYln.d.ts → config-C_ae2k86.d.ts} +79 -2
- package/dist/{context-dT5Ueund.d.ts → context-Dp87Bcaq.d.ts} +47 -1
- package/dist/coordination/index.d.ts +62 -160
- package/dist/coordination/index.js +566 -149
- package/dist/coordination/index.js.map +1 -1
- package/dist/defaults/index.d.ts +26 -25
- package/dist/defaults/index.js +366 -137
- package/dist/defaults/index.js.map +1 -1
- package/dist/execution/index.d.ts +72 -16
- package/dist/execution/index.js +267 -55
- package/dist/execution/index.js.map +1 -1
- package/dist/execution/prompt-enhancer.d.ts +1 -1
- package/dist/extension/index.d.ts +7 -6
- package/dist/global-mailbox-Bvrz1P3f.d.ts +664 -0
- package/dist/{goal-preamble-SulMTowG.d.ts → goal-preamble-CA_4yiGQ.d.ts} +9 -9
- package/dist/{goal-store-CABDwdFE.d.ts → goal-store-DhuJoUNG.d.ts} +1 -1
- package/dist/hq/index.d.ts +204 -0
- package/dist/hq/index.js +1931 -0
- package/dist/hq/index.js.map +1 -0
- package/dist/{index-DtCVWel4.d.ts → index-CZQ6Pwbs.d.ts} +8 -8
- package/dist/{index-Bms0m4oy.d.ts → index-W4VJCzHa.d.ts} +5 -5
- package/dist/{index-IEuxQd-E.d.ts → index-whDfTANu.d.ts} +2 -2
- package/dist/index.d.ts +46 -42
- package/dist/index.js +3472 -1651
- package/dist/index.js.map +1 -1
- package/dist/infrastructure/index.d.ts +6 -6
- package/dist/infrastructure/index.js +48 -21
- package/dist/infrastructure/index.js.map +1 -1
- package/dist/kernel/index.d.ts +10 -9
- package/dist/{pipeline-BfD2k1rT.d.ts → mailbox-types-Ct2hJq0P.d.ts} +1 -244
- package/dist/{mcp-servers-C2cBTxUR.d.ts → mcp-servers-DJdZiRcv.d.ts} +10 -4
- package/dist/models/index.d.ts +5 -5
- package/dist/models/index.js +4 -3
- package/dist/models/index.js.map +1 -1
- package/dist/{models-registry-BqGZNJQ-.d.ts → models-registry-C3a-2-Yd.d.ts} +1 -1
- package/dist/{multi-agent-coordinator-B8R43uPz.d.ts → multi-agent-coordinator-CJSpTe5O.d.ts} +1 -1
- package/dist/{null-fleet-bus-CnXa5oTH.d.ts → null-fleet-bus-QVshIsDx.d.ts} +6 -6
- package/dist/observability/index.d.ts +2 -2
- package/dist/{parallel-eternal-engine-DdNnw9BQ.d.ts → parallel-eternal-engine-D9y5Pkcc.d.ts} +9 -15
- package/dist/{path-resolver-COIMLCQL.d.ts → path-resolver-CnQ8SIfh.d.ts} +4 -3
- package/dist/{permission-B75JAi3-.d.ts → permission-CvYQNUqZ.d.ts} +1 -1
- package/dist/{permission-policy-DlR9eJAM.d.ts → permission-policy-D5Ss8j4B.d.ts} +2 -3
- package/dist/pipeline-l_zzFRh3.d.ts +245 -0
- package/dist/{plan-templates-DSIKCXZN.d.ts → plan-templates-NtPgyeJA.d.ts} +6 -5
- package/dist/{provider-model-resolve-BNRsNuJx.d.ts → provider-model-resolve-d5poT5y0.d.ts} +3 -3
- package/dist/{provider-runner-CX7iIvox.d.ts → provider-runner-gkctlQV_.d.ts} +3 -3
- package/dist/{retry-policy-BilV1ujH.d.ts → retry-policy-CtFhfwa8.d.ts} +1 -1
- package/dist/sdd/index.d.ts +9 -8
- package/dist/sdd/index.js +33 -3
- package/dist/sdd/index.js.map +1 -1
- package/dist/{secret-vault-gkvEZZfE.d.ts → secret-vault-BLsVmTIK.d.ts} +1 -1
- package/dist/security/index.d.ts +5 -5
- package/dist/security/index.js +39 -29
- package/dist/security/index.js.map +1 -1
- package/dist/{selector-Bc7eWtT3.d.ts → selector-CXl2_y9W.d.ts} +1 -1
- package/dist/{session-event-bridge-D-araDEz.d.ts → session-event-bridge-Ccud20CC.d.ts} +1 -1
- package/dist/{session-reader-D7Dapswh.d.ts → session-reader-ZeXQmsmE.d.ts} +1 -1
- package/dist/skills/index.js.map +1 -1
- package/dist/storage/index.d.ts +16 -12
- package/dist/storage/index.js +273 -100
- package/dist/storage/index.js.map +1 -1
- package/dist/tools/index.d.ts +2 -2
- package/dist/tools/index.js +166 -31
- package/dist/tools/index.js.map +1 -1
- package/dist/types/index.d.ts +22 -21
- package/dist/types/index.js +178 -70
- package/dist/types/index.js.map +1 -1
- package/dist/utils/index.d.ts +22 -3
- package/dist/utils/index.js +197 -25
- package/dist/utils/index.js.map +1 -1
- package/package.json +5 -1
- package/skills/chimera/SKILL.md +1 -1
- package/skills/typescript-strict/SKILL.md +3 -3
- package/skills/typescript-strict/SKILL.save.md +1 -1
package/dist/storage/index.js
CHANGED
|
@@ -5,15 +5,7 @@ import * as os from 'os';
|
|
|
5
5
|
import { hostname } from 'os';
|
|
6
6
|
import 'fs';
|
|
7
7
|
|
|
8
|
-
// src/
|
|
9
|
-
function expectDefined(value, label) {
|
|
10
|
-
if (value === null || value === void 0) {
|
|
11
|
-
const err = new Error("Expected value to be defined");
|
|
12
|
-
err.name = "ExpectDefinedError";
|
|
13
|
-
throw err;
|
|
14
|
-
}
|
|
15
|
-
return value;
|
|
16
|
-
}
|
|
8
|
+
// src/storage/session-store.ts
|
|
17
9
|
async function atomicWrite(targetPath, content, opts = {}) {
|
|
18
10
|
const dir = path2.dirname(targetPath);
|
|
19
11
|
await fsp.mkdir(dir, { recursive: true });
|
|
@@ -127,6 +119,16 @@ async function renameWithRetry(from, to) {
|
|
|
127
119
|
throw lastErr;
|
|
128
120
|
}
|
|
129
121
|
|
|
122
|
+
// src/utils/expect-defined.ts
|
|
123
|
+
function expectDefined(value, label) {
|
|
124
|
+
if (value === null || value === void 0) {
|
|
125
|
+
const err = new Error("Expected value to be defined");
|
|
126
|
+
err.name = "ExpectDefinedError";
|
|
127
|
+
throw err;
|
|
128
|
+
}
|
|
129
|
+
return value;
|
|
130
|
+
}
|
|
131
|
+
|
|
130
132
|
// src/utils/message-invariants.ts
|
|
131
133
|
function repairToolUseAdjacency(messages) {
|
|
132
134
|
const removedToolUses = [];
|
|
@@ -189,7 +191,7 @@ function hasToolResult(msg) {
|
|
|
189
191
|
}
|
|
190
192
|
function toolUseIds(msg) {
|
|
191
193
|
const ids = /* @__PURE__ */ new Set();
|
|
192
|
-
if (
|
|
194
|
+
if (msg?.role !== "assistant") return ids;
|
|
193
195
|
for (const block of contentBlocks(msg)) {
|
|
194
196
|
if (block.type === "tool_use") ids.add(block.id);
|
|
195
197
|
}
|
|
@@ -197,7 +199,7 @@ function toolUseIds(msg) {
|
|
|
197
199
|
}
|
|
198
200
|
function toolResultIds(msg) {
|
|
199
201
|
const ids = /* @__PURE__ */ new Set();
|
|
200
|
-
if (
|
|
202
|
+
if (msg?.role !== "user") return ids;
|
|
201
203
|
for (const block of contentBlocks(msg)) {
|
|
202
204
|
if (block.type === "tool_result") ids.add(block.tool_use_id);
|
|
203
205
|
}
|
|
@@ -237,7 +239,7 @@ function envFlag(value) {
|
|
|
237
239
|
return !/^(0|false|no|off)$/i.test(value.trim());
|
|
238
240
|
}
|
|
239
241
|
var COLOR = isColorTty();
|
|
240
|
-
var wrap = (
|
|
242
|
+
var wrap = (open7, close) => (s) => COLOR ? `\x1B[${open7}m${s}\x1B[${close}m` : s;
|
|
241
243
|
var color = {
|
|
242
244
|
reset: wrap("0", "0"),
|
|
243
245
|
bold: wrap("1", "22"),
|
|
@@ -455,6 +457,7 @@ var DefaultSessionStore = class _DefaultSessionStore {
|
|
|
455
457
|
* processes. When the limit is reached, the oldest entry is evicted.
|
|
456
458
|
*/
|
|
457
459
|
_loadCache = /* @__PURE__ */ new Map();
|
|
460
|
+
_indexCache = null;
|
|
458
461
|
static LOAD_CACHE_MAX_ENTRIES = 50;
|
|
459
462
|
constructor(opts) {
|
|
460
463
|
this.dir = opts.dir;
|
|
@@ -616,16 +619,13 @@ var DefaultSessionStore = class _DefaultSessionStore {
|
|
|
616
619
|
let errorMsg;
|
|
617
620
|
let cacheHit = false;
|
|
618
621
|
try {
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
const s = await fsp.stat(file);
|
|
622
|
-
stat7 = { mtimeMs: s.mtimeMs, size: s.size };
|
|
623
|
-
} catch (err) {
|
|
624
|
-
throw err;
|
|
625
|
-
}
|
|
622
|
+
const s = await fsp.stat(file);
|
|
623
|
+
const stat7 = { mtimeMs: s.mtimeMs, size: s.size };
|
|
626
624
|
const cached = this._loadCache.get(id);
|
|
627
625
|
if (cached && cached.mtimeMs === stat7.mtimeMs && cached.size === stat7.size) {
|
|
628
626
|
cacheHit = true;
|
|
627
|
+
this._loadCache.delete(id);
|
|
628
|
+
this._loadCache.set(id, cached);
|
|
629
629
|
return cached.data;
|
|
630
630
|
}
|
|
631
631
|
const raw = await fsp.readFile(file, "utf8");
|
|
@@ -711,6 +711,7 @@ var DefaultSessionStore = class _DefaultSessionStore {
|
|
|
711
711
|
await ensureDir(this.dir);
|
|
712
712
|
const line = JSON.stringify(summary) + "\n";
|
|
713
713
|
await fsp.appendFile(this.indexFile, line, "utf8");
|
|
714
|
+
this._indexCache = null;
|
|
714
715
|
this.indexAppendCount++;
|
|
715
716
|
if (this.indexAppendCount >= _DefaultSessionStore.COMPACT_EVERY) {
|
|
716
717
|
await this.compactIndex();
|
|
@@ -725,6 +726,7 @@ var DefaultSessionStore = class _DefaultSessionStore {
|
|
|
725
726
|
await ensureDir(this.dir);
|
|
726
727
|
const line = JSON.stringify({ action: "delete", id }) + "\n";
|
|
727
728
|
await fsp.appendFile(this.indexFile, line, "utf8");
|
|
729
|
+
this._indexCache = null;
|
|
728
730
|
this.indexAppendCount++;
|
|
729
731
|
} catch {
|
|
730
732
|
}
|
|
@@ -744,6 +746,7 @@ var DefaultSessionStore = class _DefaultSessionStore {
|
|
|
744
746
|
const lines = entries.map((s) => JSON.stringify(s)).join("\n") + "\n";
|
|
745
747
|
await fsp.writeFile(tmp, lines, "utf8");
|
|
746
748
|
await fsp.rename(tmp, this.indexFile);
|
|
749
|
+
this._indexCache = null;
|
|
747
750
|
} catch (err) {
|
|
748
751
|
outcome = "failure";
|
|
749
752
|
errorMsg = toErrorMessage(err);
|
|
@@ -757,10 +760,22 @@ var DefaultSessionStore = class _DefaultSessionStore {
|
|
|
757
760
|
* Returns empty array when the index doesn't exist or is corrupt.
|
|
758
761
|
*/
|
|
759
762
|
async readIndex() {
|
|
763
|
+
let stat7;
|
|
764
|
+
try {
|
|
765
|
+
const s = await fsp.stat(this.indexFile);
|
|
766
|
+
stat7 = { mtimeMs: s.mtimeMs, size: s.size };
|
|
767
|
+
} catch {
|
|
768
|
+
this._indexCache = null;
|
|
769
|
+
return [];
|
|
770
|
+
}
|
|
771
|
+
if (this._indexCache !== null && this._indexCache.mtimeMs === stat7.mtimeMs && this._indexCache.size === stat7.size) {
|
|
772
|
+
return [...this._indexCache.summaries];
|
|
773
|
+
}
|
|
760
774
|
let raw;
|
|
761
775
|
try {
|
|
762
776
|
raw = await fsp.readFile(this.indexFile, "utf8");
|
|
763
777
|
} catch {
|
|
778
|
+
this._indexCache = null;
|
|
764
779
|
return [];
|
|
765
780
|
}
|
|
766
781
|
const deleted = /* @__PURE__ */ new Set();
|
|
@@ -780,7 +795,9 @@ var DefaultSessionStore = class _DefaultSessionStore {
|
|
|
780
795
|
} catch {
|
|
781
796
|
}
|
|
782
797
|
}
|
|
783
|
-
|
|
798
|
+
const summaries = Array.from(seen.values());
|
|
799
|
+
this._indexCache = { ...stat7, summaries };
|
|
800
|
+
return [...summaries];
|
|
784
801
|
}
|
|
785
802
|
/**
|
|
786
803
|
* Rebuild the index from disk by scanning all sessions and writing a
|
|
@@ -794,6 +811,7 @@ var DefaultSessionStore = class _DefaultSessionStore {
|
|
|
794
811
|
const lines = valid.map((s) => JSON.stringify(s)).join("\n") + "\n";
|
|
795
812
|
await fsp.writeFile(tmp, lines, "utf8");
|
|
796
813
|
await fsp.rename(tmp, this.indexFile);
|
|
814
|
+
this._indexCache = null;
|
|
797
815
|
return valid.length;
|
|
798
816
|
}
|
|
799
817
|
/** Recursively collect session IDs from date-shard subdirectories.
|
|
@@ -1493,6 +1511,12 @@ var FileSessionWriter = class _FileSessionWriter {
|
|
|
1493
1511
|
files
|
|
1494
1512
|
});
|
|
1495
1513
|
}
|
|
1514
|
+
/**
|
|
1515
|
+
* Truncate the session file to the checkpoint with the given promptIndex,
|
|
1516
|
+
* removing all events that follow it. Uses a single-pass byte-offset scan
|
|
1517
|
+
* so post-checkpoint content is never read or parsed — O(1) memory instead
|
|
1518
|
+
* of O(N) JSON.parse calls over the full file.
|
|
1519
|
+
*/
|
|
1496
1520
|
async truncateToCheckpoint(targetPromptIndex) {
|
|
1497
1521
|
if (!this.filePath) return 0;
|
|
1498
1522
|
if (this.flushTimer) {
|
|
@@ -1501,51 +1525,118 @@ var FileSessionWriter = class _FileSessionWriter {
|
|
|
1501
1525
|
}
|
|
1502
1526
|
await this.flushBuffer();
|
|
1503
1527
|
await this.writeChain;
|
|
1504
|
-
const
|
|
1505
|
-
|
|
1506
|
-
|
|
1528
|
+
const CHUNK_SIZE = 65536;
|
|
1529
|
+
let fd;
|
|
1530
|
+
let fileOffset = 0;
|
|
1531
|
+
let lineStartOffset = 0;
|
|
1532
|
+
let checkpointByteOffset = -1;
|
|
1507
1533
|
let removedCount = 0;
|
|
1508
|
-
let
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1534
|
+
let targetCheckpointSeen = false;
|
|
1535
|
+
try {
|
|
1536
|
+
fd = await fsp.open(this.filePath, "r", 384);
|
|
1537
|
+
while (true) {
|
|
1538
|
+
const buf = Buffer.alloc(CHUNK_SIZE);
|
|
1539
|
+
const { bytesRead } = await fd.read(buf, 0, CHUNK_SIZE, fileOffset);
|
|
1540
|
+
if (bytesRead === 0) break;
|
|
1541
|
+
let chunkPos = 0;
|
|
1542
|
+
while (chunkPos < bytesRead) {
|
|
1543
|
+
const idx = buf.indexOf("\n", chunkPos);
|
|
1544
|
+
if (idx === -1) {
|
|
1545
|
+
lineStartOffset = fileOffset + chunkPos;
|
|
1546
|
+
break;
|
|
1547
|
+
}
|
|
1548
|
+
if (checkpointByteOffset !== -1) {
|
|
1549
|
+
removedCount++;
|
|
1550
|
+
} else {
|
|
1551
|
+
const lineBytes = buf.subarray(chunkPos, idx);
|
|
1552
|
+
const line = new TextDecoder("utf-8", { fatal: false }).decode(lineBytes);
|
|
1553
|
+
if (line.trim()) {
|
|
1554
|
+
try {
|
|
1555
|
+
const event = JSON.parse(line);
|
|
1556
|
+
if (event.type === "checkpoint") {
|
|
1557
|
+
if (event.promptIndex === targetPromptIndex) {
|
|
1558
|
+
checkpointByteOffset = lineStartOffset;
|
|
1559
|
+
targetCheckpointSeen = true;
|
|
1560
|
+
} else if (event.promptIndex !== void 0 && event.promptIndex > targetPromptIndex) {
|
|
1561
|
+
checkpointByteOffset = lineStartOffset;
|
|
1562
|
+
}
|
|
1563
|
+
} else if (targetCheckpointSeen && event.promptIndex !== void 0 && event.promptIndex > targetPromptIndex) {
|
|
1564
|
+
removedCount++;
|
|
1565
|
+
} else if (targetCheckpointSeen && event.promptIndex === void 0) {
|
|
1566
|
+
removedCount++;
|
|
1567
|
+
} else if (!targetCheckpointSeen && event.promptIndex === void 0) {
|
|
1568
|
+
removedCount++;
|
|
1569
|
+
} else if (!targetCheckpointSeen && event.promptIndex !== void 0 && event.promptIndex > targetPromptIndex) {
|
|
1570
|
+
removedCount++;
|
|
1571
|
+
}
|
|
1572
|
+
} catch {
|
|
1573
|
+
}
|
|
1574
|
+
}
|
|
1575
|
+
}
|
|
1576
|
+
chunkPos = idx + 1;
|
|
1577
|
+
lineStartOffset = fileOffset + chunkPos;
|
|
1526
1578
|
}
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
} else if (event.promptIndex === void 0) {
|
|
1531
|
-
if (!afterTarget || targetCheckpointLine === -1) {
|
|
1532
|
-
kept.push(line);
|
|
1533
|
-
} else {
|
|
1534
|
-
removedCount++;
|
|
1579
|
+
fileOffset += bytesRead;
|
|
1580
|
+
if (chunkPos >= bytesRead) {
|
|
1581
|
+
lineStartOffset = fileOffset;
|
|
1535
1582
|
}
|
|
1536
|
-
} else {
|
|
1537
|
-
kept.push(line);
|
|
1538
1583
|
}
|
|
1584
|
+
} finally {
|
|
1585
|
+
await fd?.close();
|
|
1539
1586
|
}
|
|
1540
|
-
|
|
1587
|
+
if (checkpointByteOffset === -1) return 0;
|
|
1588
|
+
await this.writeChain;
|
|
1589
|
+
await this.handle.close();
|
|
1541
1590
|
const tmpPath = `${this.filePath}.rewind.tmp`;
|
|
1542
|
-
await fsp.
|
|
1591
|
+
const src = await fsp.open(this.filePath, "r", 384);
|
|
1543
1592
|
try {
|
|
1544
|
-
await
|
|
1593
|
+
const statResult = await src.stat();
|
|
1594
|
+
const totalSize = statResult.size;
|
|
1595
|
+
const prefixBytes = checkpointByteOffset;
|
|
1596
|
+
let newlineAfterCheckpoint = prefixBytes;
|
|
1597
|
+
if (prefixBytes < totalSize) {
|
|
1598
|
+
const probeBuf = Buffer.alloc(Math.min(CHUNK_SIZE, totalSize - prefixBytes));
|
|
1599
|
+
const { bytesRead: probeRead } = await src.read(probeBuf, 0, probeBuf.length, prefixBytes);
|
|
1600
|
+
if (probeRead > 0) {
|
|
1601
|
+
const nl = probeBuf.indexOf("\n");
|
|
1602
|
+
newlineAfterCheckpoint = nl !== -1 ? prefixBytes + nl + 1 : totalSize;
|
|
1603
|
+
}
|
|
1604
|
+
} else {
|
|
1605
|
+
newlineAfterCheckpoint = totalSize;
|
|
1606
|
+
}
|
|
1607
|
+
const writeFd = await fsp.open(tmpPath, "w", 384);
|
|
1608
|
+
try {
|
|
1609
|
+
let copied = 0;
|
|
1610
|
+
let readOffset = 0;
|
|
1611
|
+
while (readOffset < newlineAfterCheckpoint) {
|
|
1612
|
+
const toCopy = Math.min(CHUNK_SIZE, newlineAfterCheckpoint - readOffset);
|
|
1613
|
+
const copyBuf = Buffer.alloc(toCopy);
|
|
1614
|
+
const { bytesRead: r } = await src.read(copyBuf, 0, toCopy, readOffset);
|
|
1615
|
+
if (r === 0) break;
|
|
1616
|
+
await writeFd.write(copyBuf, 0, r);
|
|
1617
|
+
readOffset += r;
|
|
1618
|
+
copied += r;
|
|
1619
|
+
}
|
|
1620
|
+
const raw = await fsp.readFile(this.filePath);
|
|
1621
|
+
const tail = raw.subarray(newlineAfterCheckpoint).toString("utf8");
|
|
1622
|
+
for (const line of tail.split("\n")) {
|
|
1623
|
+
if (!line.trim()) continue;
|
|
1624
|
+
try {
|
|
1625
|
+
JSON.parse(line);
|
|
1626
|
+
} catch {
|
|
1627
|
+
await writeFd.write(`${line}
|
|
1628
|
+
`, void 0, "utf8");
|
|
1629
|
+
}
|
|
1630
|
+
}
|
|
1631
|
+
} finally {
|
|
1632
|
+
await writeFd.close();
|
|
1633
|
+
}
|
|
1634
|
+
await src.close();
|
|
1545
1635
|
await fsp.rename(tmpPath, this.filePath);
|
|
1546
1636
|
this.handle = await fsp.open(this.filePath, "a", 384);
|
|
1547
1637
|
} catch (err) {
|
|
1548
1638
|
await fsp.unlink(tmpPath).catch(() => void 0);
|
|
1639
|
+
this.handle = await fsp.open(this.filePath, "a", 384).catch(() => this.handle);
|
|
1549
1640
|
throw err;
|
|
1550
1641
|
}
|
|
1551
1642
|
await this.append({
|
|
@@ -1938,6 +2029,7 @@ var MEMORY_TYPE_LABELS = {
|
|
|
1938
2029
|
// src/storage/memory-backend.ts
|
|
1939
2030
|
var TYPE_PRIORITY_RE = /^\[(\w+)\|(\w+)\]\s+/;
|
|
1940
2031
|
var TAG_RE = /#([\w-]+)/g;
|
|
2032
|
+
var MAX_MEMORY_CONSOLIDATE_BACKUPS = 5;
|
|
1941
2033
|
function formatMetadata(entry) {
|
|
1942
2034
|
const parts = [];
|
|
1943
2035
|
if (entry.type && entry.priority) {
|
|
@@ -2130,6 +2222,7 @@ ${line}`;
|
|
|
2130
2222
|
const backup = `${file}.bak.${Date.now()}`;
|
|
2131
2223
|
try {
|
|
2132
2224
|
await fsp.copyFile(file, backup);
|
|
2225
|
+
await pruneConsolidateBackups(file);
|
|
2133
2226
|
} catch {
|
|
2134
2227
|
}
|
|
2135
2228
|
try {
|
|
@@ -2140,6 +2233,20 @@ ${line}`;
|
|
|
2140
2233
|
return removed;
|
|
2141
2234
|
}
|
|
2142
2235
|
};
|
|
2236
|
+
async function pruneConsolidateBackups(file) {
|
|
2237
|
+
const dir = path2.dirname(file);
|
|
2238
|
+
const base = path2.basename(file);
|
|
2239
|
+
const prefix = `${base}.bak.`;
|
|
2240
|
+
const backups = (await fsp.readdir(dir)).filter((name) => name.startsWith(prefix)).sort().reverse();
|
|
2241
|
+
await Promise.all(
|
|
2242
|
+
backups.slice(MAX_MEMORY_CONSOLIDATE_BACKUPS).map(async (name) => {
|
|
2243
|
+
try {
|
|
2244
|
+
await fsp.unlink(path2.join(dir, name));
|
|
2245
|
+
} catch {
|
|
2246
|
+
}
|
|
2247
|
+
})
|
|
2248
|
+
);
|
|
2249
|
+
}
|
|
2143
2250
|
function parseEntries(raw, scope = "project-memory") {
|
|
2144
2251
|
const entries = [];
|
|
2145
2252
|
for (const line of raw.split("\n")) {
|
|
@@ -2750,27 +2857,25 @@ var GraphMemoryBackend = class {
|
|
|
2750
2857
|
enriched.sort((a, b) => b.ts.localeCompare(a.ts));
|
|
2751
2858
|
return limit ? enriched.slice(0, limit) : enriched;
|
|
2752
2859
|
}
|
|
2753
|
-
async search(scope, query,
|
|
2860
|
+
async search(scope, query, _filePath, limit) {
|
|
2754
2861
|
await this.loadGraph(scope);
|
|
2755
2862
|
const needle = query.toLowerCase().split(/\s+/);
|
|
2756
|
-
const
|
|
2757
|
-
const
|
|
2758
|
-
|
|
2863
|
+
const scored = [];
|
|
2864
|
+
for (const node of this.nodes.values()) {
|
|
2865
|
+
if (node.entry.scope !== scope) continue;
|
|
2866
|
+
const words = node.entry.text.toLowerCase().split(/\s+/);
|
|
2759
2867
|
let score = 0;
|
|
2760
2868
|
for (const n of needle) {
|
|
2761
2869
|
if (words.some((w) => w.includes(n))) score += 1;
|
|
2762
|
-
if (entry.tags?.some((t) => t.toLowerCase().includes(n))) score += 2;
|
|
2763
|
-
}
|
|
2764
|
-
const node = this.nodes.get(this.nodeId(entry));
|
|
2765
|
-
if (node) {
|
|
2766
|
-
if (node.priority === "critical") score += 3;
|
|
2767
|
-
else if (node.priority === "high") score += 2;
|
|
2768
|
-
score += node.count * 0.5;
|
|
2870
|
+
if (node.entry.tags?.some((t) => t.toLowerCase().includes(n))) score += 2;
|
|
2769
2871
|
}
|
|
2770
|
-
|
|
2771
|
-
|
|
2872
|
+
if (node.priority === "critical") score += 3;
|
|
2873
|
+
else if (node.priority === "high") score += 2;
|
|
2874
|
+
score += node.count * 0.5;
|
|
2875
|
+
if (score > 0) scored.push({ entry: node.entry, score });
|
|
2876
|
+
}
|
|
2772
2877
|
scored.sort((a, b) => b.score - a.score);
|
|
2773
|
-
const matched = scored.
|
|
2878
|
+
const matched = scored.map((s) => s.entry);
|
|
2774
2879
|
return limit ? matched.slice(0, limit) : matched;
|
|
2775
2880
|
}
|
|
2776
2881
|
async clear(scope, filePath) {
|
|
@@ -2954,7 +3059,7 @@ var SessionMemoryConsolidator = class {
|
|
|
2954
3059
|
if (!result.finalText || result.finalText.trim().length < 20) return;
|
|
2955
3060
|
if (result.iterations < this.minIterations) return;
|
|
2956
3061
|
const provider = this.provider ?? ctx.provider;
|
|
2957
|
-
if (!provider
|
|
3062
|
+
if (!provider?.complete) return;
|
|
2958
3063
|
try {
|
|
2959
3064
|
const existingEntries = await this.memoryStore.list("project-memory", this.maxExistingEntries);
|
|
2960
3065
|
const prompt = buildConsolidationPrompt(
|
|
@@ -2997,7 +3102,7 @@ var SessionMemoryConsolidator = class {
|
|
|
2997
3102
|
break;
|
|
2998
3103
|
}
|
|
2999
3104
|
case "edit": {
|
|
3000
|
-
if (op.query && op.text
|
|
3105
|
+
if (op.query && op.text?.trim()) {
|
|
3001
3106
|
await this.memoryStore.forget(op.query);
|
|
3002
3107
|
await this.memoryStore.remember(op.text.trim(), void 0, {
|
|
3003
3108
|
type: op.type,
|
|
@@ -3298,6 +3403,9 @@ var DEFAULT_CONTEXT_CONFIG = Object.freeze({
|
|
|
3298
3403
|
preserveK: 10,
|
|
3299
3404
|
eliseThreshold: 2e3
|
|
3300
3405
|
});
|
|
3406
|
+
var DEFAULT_AUTONOMY_CONFIG = Object.freeze({
|
|
3407
|
+
autoProceedDelayMs: 45e3
|
|
3408
|
+
});
|
|
3301
3409
|
var DEFAULT_SESSION_LOGGING_CONFIG = Object.freeze({
|
|
3302
3410
|
auditLevel: "standard",
|
|
3303
3411
|
sampling: {
|
|
@@ -3341,15 +3449,19 @@ var BEHAVIOR_DEFAULTS = {
|
|
|
3341
3449
|
plugins: true,
|
|
3342
3450
|
memory: true,
|
|
3343
3451
|
modelsRegistry: true,
|
|
3344
|
-
skills: true
|
|
3452
|
+
skills: true,
|
|
3453
|
+
tokenSavingMode: "off",
|
|
3454
|
+
allowOutsideProjectRoot: true
|
|
3345
3455
|
},
|
|
3456
|
+
mcpServers: {},
|
|
3346
3457
|
indexing: {
|
|
3347
3458
|
onSessionStart: true,
|
|
3348
3459
|
onEdit: true,
|
|
3349
3460
|
watchExternal: true,
|
|
3350
3461
|
debounceMs: 400
|
|
3351
3462
|
},
|
|
3352
|
-
session: { ...DEFAULT_SESSION_LOGGING_CONFIG }
|
|
3463
|
+
session: { ...DEFAULT_SESSION_LOGGING_CONFIG },
|
|
3464
|
+
autonomy: { autoProceedDelayMs: DEFAULT_AUTONOMY_CONFIG.autoProceedDelayMs }
|
|
3353
3465
|
};
|
|
3354
3466
|
function envBool(v) {
|
|
3355
3467
|
return !/^(0|false|no|off)$/i.test(v.trim());
|
|
@@ -4676,11 +4788,11 @@ var ReplayLogStore = class {
|
|
|
4676
4788
|
if (!entry.isFile() || !entry.name.endsWith(".replay.jsonl")) continue;
|
|
4677
4789
|
const base = entry.name.slice(0, -".replay.jsonl".length);
|
|
4678
4790
|
const sessionId = prefix ? `${prefix}/${base}` : base;
|
|
4679
|
-
const
|
|
4791
|
+
const fp = path2.join(dir, entry.name);
|
|
4680
4792
|
out.push({
|
|
4681
4793
|
sessionId,
|
|
4682
|
-
entryCount:
|
|
4683
|
-
path:
|
|
4794
|
+
entryCount: await this.countEntries(fp),
|
|
4795
|
+
path: fp
|
|
4684
4796
|
});
|
|
4685
4797
|
}
|
|
4686
4798
|
};
|
|
@@ -4691,6 +4803,33 @@ var ReplayLogStore = class {
|
|
|
4691
4803
|
filePath(sessionId) {
|
|
4692
4804
|
return sessionScopedPath(this.dir, sessionId, ".replay.jsonl");
|
|
4693
4805
|
}
|
|
4806
|
+
async countEntries(filePath) {
|
|
4807
|
+
const handle = await fsp.open(filePath, "r");
|
|
4808
|
+
const buffer = Buffer.allocUnsafe(64 * 1024);
|
|
4809
|
+
let count = 0;
|
|
4810
|
+
let hasNonWhitespace = false;
|
|
4811
|
+
try {
|
|
4812
|
+
while (true) {
|
|
4813
|
+
const { bytesRead } = await handle.read(buffer, 0, buffer.length, null);
|
|
4814
|
+
if (bytesRead === 0) break;
|
|
4815
|
+
for (let i = 0; i < bytesRead; i++) {
|
|
4816
|
+
const ch = buffer[i];
|
|
4817
|
+
if (ch === 10) {
|
|
4818
|
+
if (hasNonWhitespace) count++;
|
|
4819
|
+
hasNonWhitespace = false;
|
|
4820
|
+
continue;
|
|
4821
|
+
}
|
|
4822
|
+
if (ch !== 13 && ch !== 32 && ch !== 9) {
|
|
4823
|
+
hasNonWhitespace = true;
|
|
4824
|
+
}
|
|
4825
|
+
}
|
|
4826
|
+
}
|
|
4827
|
+
} finally {
|
|
4828
|
+
await handle.close();
|
|
4829
|
+
}
|
|
4830
|
+
if (hasNonWhitespace) count++;
|
|
4831
|
+
return count;
|
|
4832
|
+
}
|
|
4694
4833
|
async readAll(sessionId) {
|
|
4695
4834
|
const fp = this.filePath(sessionId);
|
|
4696
4835
|
try {
|
|
@@ -5342,6 +5481,8 @@ var HEARTBEAT_INTERVAL_MS = 5e3;
|
|
|
5342
5481
|
var STALE_TIMEOUT_MS = 3e4;
|
|
5343
5482
|
var CLOSING_GRACE_MS = 15e3;
|
|
5344
5483
|
var STALE_LOCK_MS = 1e4;
|
|
5484
|
+
var STALE_TMP_MS = 6e4;
|
|
5485
|
+
var MAX_STALE_TMP_FILES = 20;
|
|
5345
5486
|
function pidAlive(pid) {
|
|
5346
5487
|
try {
|
|
5347
5488
|
process.kill(pid, 0);
|
|
@@ -5494,25 +5635,24 @@ var SessionRegistry = class {
|
|
|
5494
5635
|
async heartbeat() {
|
|
5495
5636
|
if (!this.currentSessionId) return;
|
|
5496
5637
|
try {
|
|
5497
|
-
const
|
|
5498
|
-
const
|
|
5499
|
-
|
|
5500
|
-
|
|
5501
|
-
|
|
5502
|
-
|
|
5503
|
-
|
|
5504
|
-
|
|
5505
|
-
|
|
5506
|
-
|
|
5507
|
-
|
|
5508
|
-
await this.writeAtomic(registry);
|
|
5509
|
-
} else if (this.lastEntry) {
|
|
5510
|
-
await this.atomicUpdate((reg) => {
|
|
5511
|
-
if (!reg[this.currentSessionId] && this.lastEntry) {
|
|
5512
|
-
reg[this.currentSessionId] = { ...this.lastEntry, lastHeartbeatAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
5638
|
+
const sessionId = this.currentSessionId;
|
|
5639
|
+
const nowIso = (/* @__PURE__ */ new Date()).toISOString();
|
|
5640
|
+
await this.atomicUpdate((registry) => {
|
|
5641
|
+
const entry = registry[sessionId];
|
|
5642
|
+
if (entry) {
|
|
5643
|
+
entry.lastHeartbeatAt = nowIso;
|
|
5644
|
+
if (entry.status !== "closing") {
|
|
5645
|
+
const hasRunning = (entry.agents ?? []).some(
|
|
5646
|
+
(a) => a.status === "running" || a.status === "streaming"
|
|
5647
|
+
);
|
|
5648
|
+
entry.status = hasRunning ? "active" : "idle";
|
|
5513
5649
|
}
|
|
5514
|
-
|
|
5515
|
-
|
|
5650
|
+
return;
|
|
5651
|
+
}
|
|
5652
|
+
if (this.lastEntry) {
|
|
5653
|
+
registry[sessionId] = { ...this.lastEntry, lastHeartbeatAt: nowIso };
|
|
5654
|
+
}
|
|
5655
|
+
});
|
|
5516
5656
|
} catch {
|
|
5517
5657
|
}
|
|
5518
5658
|
}
|
|
@@ -5605,15 +5745,48 @@ var SessionRegistry = class {
|
|
|
5605
5745
|
}
|
|
5606
5746
|
}
|
|
5607
5747
|
async writeAtomicLocked(registry) {
|
|
5608
|
-
|
|
5609
|
-
await
|
|
5610
|
-
await fsp.rename(tmp, this.filePath);
|
|
5748
|
+
await this.pruneStaleTempFiles();
|
|
5749
|
+
await this.writeAtomicFile(registry);
|
|
5611
5750
|
}
|
|
5612
5751
|
/** Legacy write without lock — used by heartbeat for performance. */
|
|
5613
5752
|
async writeAtomic(registry) {
|
|
5614
|
-
|
|
5615
|
-
await
|
|
5616
|
-
|
|
5753
|
+
await this.pruneStaleTempFiles();
|
|
5754
|
+
await this.writeAtomicFile(registry);
|
|
5755
|
+
}
|
|
5756
|
+
async writeAtomicFile(registry) {
|
|
5757
|
+
const tmp = path2.join(
|
|
5758
|
+
path2.dirname(this.filePath),
|
|
5759
|
+
`.${path2.basename(this.filePath)}.${randomUUID().slice(0, 8)}.tmp`
|
|
5760
|
+
);
|
|
5761
|
+
try {
|
|
5762
|
+
await fsp.writeFile(tmp, JSON.stringify(registry, null, 2), "utf8");
|
|
5763
|
+
await fsp.rename(tmp, this.filePath);
|
|
5764
|
+
} catch (err) {
|
|
5765
|
+
await fsp.unlink(tmp).catch(() => void 0);
|
|
5766
|
+
throw err;
|
|
5767
|
+
}
|
|
5768
|
+
}
|
|
5769
|
+
async pruneStaleTempFiles() {
|
|
5770
|
+
try {
|
|
5771
|
+
const dir = path2.dirname(this.filePath);
|
|
5772
|
+
const base = path2.basename(this.filePath);
|
|
5773
|
+
const now = Date.now();
|
|
5774
|
+
const stale = [];
|
|
5775
|
+
for (const name of await fsp.readdir(dir)) {
|
|
5776
|
+
const isTemp = (name.startsWith(`${base}.`) || name.startsWith(`.${base}.`)) && name.endsWith(".tmp");
|
|
5777
|
+
if (!isTemp) continue;
|
|
5778
|
+
const stat7 = await fsp.stat(path2.join(dir, name)).catch(() => null);
|
|
5779
|
+
if (!stat7) continue;
|
|
5780
|
+
if (now - stat7.mtimeMs > STALE_TMP_MS) stale.push({ name, mtimeMs: stat7.mtimeMs });
|
|
5781
|
+
}
|
|
5782
|
+
stale.sort((a, b) => b.mtimeMs - a.mtimeMs);
|
|
5783
|
+
await Promise.all(
|
|
5784
|
+
stale.slice(MAX_STALE_TMP_FILES).map(async ({ name }) => {
|
|
5785
|
+
await fsp.unlink(path2.join(dir, name)).catch(() => void 0);
|
|
5786
|
+
})
|
|
5787
|
+
);
|
|
5788
|
+
} catch {
|
|
5789
|
+
}
|
|
5617
5790
|
}
|
|
5618
5791
|
};
|
|
5619
5792
|
var _instance = null;
|
|
@@ -7620,7 +7793,7 @@ function createSessionEventBridge(writer, level = "standard", options = {}) {
|
|
|
7620
7793
|
if (!shouldSample(event)) return;
|
|
7621
7794
|
try {
|
|
7622
7795
|
await target.append(event);
|
|
7623
|
-
} catch (
|
|
7796
|
+
} catch (_err) {
|
|
7624
7797
|
}
|
|
7625
7798
|
},
|
|
7626
7799
|
async appendBatch(events) {
|