@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.
Files changed (78) hide show
  1. package/dist/{agent-bridge-STJ3JwwK.d.ts → agent-bridge-PcHQl_UQ.d.ts} +1 -1
  2. package/dist/{agent-subagent-runner-CzPGP3jA.d.ts → agent-subagent-runner-SHJW7t8q.d.ts} +8 -8
  3. package/dist/{brain-Cdg77tVN.d.ts → brain-BYcK__Ym.d.ts} +1 -1
  4. package/dist/{compactor-iMZ84CXq.d.ts → compactor-C2RKEBtC.d.ts} +1 -1
  5. package/dist/{config-Du3pYYln.d.ts → config-C_ae2k86.d.ts} +79 -2
  6. package/dist/{context-dT5Ueund.d.ts → context-Dp87Bcaq.d.ts} +47 -1
  7. package/dist/coordination/index.d.ts +62 -160
  8. package/dist/coordination/index.js +566 -149
  9. package/dist/coordination/index.js.map +1 -1
  10. package/dist/defaults/index.d.ts +26 -25
  11. package/dist/defaults/index.js +366 -137
  12. package/dist/defaults/index.js.map +1 -1
  13. package/dist/execution/index.d.ts +72 -16
  14. package/dist/execution/index.js +267 -55
  15. package/dist/execution/index.js.map +1 -1
  16. package/dist/execution/prompt-enhancer.d.ts +1 -1
  17. package/dist/extension/index.d.ts +7 -6
  18. package/dist/global-mailbox-Bvrz1P3f.d.ts +664 -0
  19. package/dist/{goal-preamble-SulMTowG.d.ts → goal-preamble-CA_4yiGQ.d.ts} +9 -9
  20. package/dist/{goal-store-CABDwdFE.d.ts → goal-store-DhuJoUNG.d.ts} +1 -1
  21. package/dist/hq/index.d.ts +204 -0
  22. package/dist/hq/index.js +1931 -0
  23. package/dist/hq/index.js.map +1 -0
  24. package/dist/{index-DtCVWel4.d.ts → index-CZQ6Pwbs.d.ts} +8 -8
  25. package/dist/{index-Bms0m4oy.d.ts → index-W4VJCzHa.d.ts} +5 -5
  26. package/dist/{index-IEuxQd-E.d.ts → index-whDfTANu.d.ts} +2 -2
  27. package/dist/index.d.ts +46 -42
  28. package/dist/index.js +3472 -1651
  29. package/dist/index.js.map +1 -1
  30. package/dist/infrastructure/index.d.ts +6 -6
  31. package/dist/infrastructure/index.js +48 -21
  32. package/dist/infrastructure/index.js.map +1 -1
  33. package/dist/kernel/index.d.ts +10 -9
  34. package/dist/{pipeline-BfD2k1rT.d.ts → mailbox-types-Ct2hJq0P.d.ts} +1 -244
  35. package/dist/{mcp-servers-C2cBTxUR.d.ts → mcp-servers-DJdZiRcv.d.ts} +10 -4
  36. package/dist/models/index.d.ts +5 -5
  37. package/dist/models/index.js +4 -3
  38. package/dist/models/index.js.map +1 -1
  39. package/dist/{models-registry-BqGZNJQ-.d.ts → models-registry-C3a-2-Yd.d.ts} +1 -1
  40. package/dist/{multi-agent-coordinator-B8R43uPz.d.ts → multi-agent-coordinator-CJSpTe5O.d.ts} +1 -1
  41. package/dist/{null-fleet-bus-CnXa5oTH.d.ts → null-fleet-bus-QVshIsDx.d.ts} +6 -6
  42. package/dist/observability/index.d.ts +2 -2
  43. package/dist/{parallel-eternal-engine-DdNnw9BQ.d.ts → parallel-eternal-engine-D9y5Pkcc.d.ts} +9 -15
  44. package/dist/{path-resolver-COIMLCQL.d.ts → path-resolver-CnQ8SIfh.d.ts} +4 -3
  45. package/dist/{permission-B75JAi3-.d.ts → permission-CvYQNUqZ.d.ts} +1 -1
  46. package/dist/{permission-policy-DlR9eJAM.d.ts → permission-policy-D5Ss8j4B.d.ts} +2 -3
  47. package/dist/pipeline-l_zzFRh3.d.ts +245 -0
  48. package/dist/{plan-templates-DSIKCXZN.d.ts → plan-templates-NtPgyeJA.d.ts} +6 -5
  49. package/dist/{provider-model-resolve-BNRsNuJx.d.ts → provider-model-resolve-d5poT5y0.d.ts} +3 -3
  50. package/dist/{provider-runner-CX7iIvox.d.ts → provider-runner-gkctlQV_.d.ts} +3 -3
  51. package/dist/{retry-policy-BilV1ujH.d.ts → retry-policy-CtFhfwa8.d.ts} +1 -1
  52. package/dist/sdd/index.d.ts +9 -8
  53. package/dist/sdd/index.js +33 -3
  54. package/dist/sdd/index.js.map +1 -1
  55. package/dist/{secret-vault-gkvEZZfE.d.ts → secret-vault-BLsVmTIK.d.ts} +1 -1
  56. package/dist/security/index.d.ts +5 -5
  57. package/dist/security/index.js +39 -29
  58. package/dist/security/index.js.map +1 -1
  59. package/dist/{selector-Bc7eWtT3.d.ts → selector-CXl2_y9W.d.ts} +1 -1
  60. package/dist/{session-event-bridge-D-araDEz.d.ts → session-event-bridge-Ccud20CC.d.ts} +1 -1
  61. package/dist/{session-reader-D7Dapswh.d.ts → session-reader-ZeXQmsmE.d.ts} +1 -1
  62. package/dist/skills/index.js.map +1 -1
  63. package/dist/storage/index.d.ts +16 -12
  64. package/dist/storage/index.js +273 -100
  65. package/dist/storage/index.js.map +1 -1
  66. package/dist/tools/index.d.ts +2 -2
  67. package/dist/tools/index.js +166 -31
  68. package/dist/tools/index.js.map +1 -1
  69. package/dist/types/index.d.ts +22 -21
  70. package/dist/types/index.js +178 -70
  71. package/dist/types/index.js.map +1 -1
  72. package/dist/utils/index.d.ts +22 -3
  73. package/dist/utils/index.js +197 -25
  74. package/dist/utils/index.js.map +1 -1
  75. package/package.json +5 -1
  76. package/skills/chimera/SKILL.md +1 -1
  77. package/skills/typescript-strict/SKILL.md +3 -3
  78. package/skills/typescript-strict/SKILL.save.md +1 -1
@@ -5,15 +5,7 @@ import * as os from 'os';
5
5
  import { hostname } from 'os';
6
6
  import 'fs';
7
7
 
8
- // src/utils/expect-defined.ts
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 (!msg || msg.role !== "assistant") return ids;
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 (!msg || msg.role !== "user") return ids;
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 = (open6, close) => (s) => COLOR ? `\x1B[${open6}m${s}\x1B[${close}m` : s;
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
- let stat7;
620
- try {
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
- return Array.from(seen.values());
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 raw = await fsp.readFile(this.filePath, "utf8");
1505
- const lines = raw.split("\n");
1506
- const kept = [];
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 targetCheckpointLine = -1;
1509
- let afterTarget = false;
1510
- for (let i = 0; i < lines.length; i++) {
1511
- const line = expectDefined(lines[i]);
1512
- if (!line.trim()) continue;
1513
- let event;
1514
- try {
1515
- event = JSON.parse(line);
1516
- } catch {
1517
- kept.push(line);
1518
- continue;
1519
- }
1520
- if (event.type === "checkpoint") {
1521
- if (event.promptIndex === targetPromptIndex) {
1522
- targetCheckpointLine = kept.length;
1523
- afterTarget = true;
1524
- } else if (event.promptIndex > targetPromptIndex) {
1525
- afterTarget = true;
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
- if (event.promptIndex !== void 0 && event.promptIndex > targetPromptIndex) {
1529
- removedCount++;
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
- const truncated = kept.join("\n");
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.writeFile(tmpPath, truncated + "\n", "utf8");
1591
+ const src = await fsp.open(this.filePath, "r", 384);
1543
1592
  try {
1544
- await this.handle.close();
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, filePath, limit) {
2860
+ async search(scope, query, _filePath, limit) {
2754
2861
  await this.loadGraph(scope);
2755
2862
  const needle = query.toLowerCase().split(/\s+/);
2756
- const all = await this.list(scope, filePath);
2757
- const scored = all.map((entry) => {
2758
- const words = entry.text.toLowerCase().split(/\s+/);
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
- return { entry, score };
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.filter((s) => s.score > 0).map((s) => s.entry);
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 || !provider.complete) return;
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 && op.text.trim()) {
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 all = await this.load(sessionId);
4791
+ const fp = path2.join(dir, entry.name);
4680
4792
  out.push({
4681
4793
  sessionId,
4682
- entryCount: all.length,
4683
- path: path2.join(dir, entry.name)
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 raw = await fsp.readFile(this.filePath, "utf8").catch(() => "{}");
5498
- const registry = JSON.parse(raw);
5499
- const entry = registry[this.currentSessionId];
5500
- if (entry) {
5501
- entry.lastHeartbeatAt = (/* @__PURE__ */ new Date()).toISOString();
5502
- if (entry.status !== "closing") {
5503
- const hasRunning = (entry.agents ?? []).some(
5504
- (a) => a.status === "running" || a.status === "streaming"
5505
- );
5506
- entry.status = hasRunning ? "active" : "idle";
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
- const tmp = `${this.filePath}.${randomUUID().slice(0, 8)}.tmp`;
5609
- await fsp.writeFile(tmp, JSON.stringify(registry, null, 2), "utf8");
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
- const tmp = `${this.filePath}.${randomUUID().slice(0, 8)}.tmp`;
5615
- await fsp.writeFile(tmp, JSON.stringify(registry, null, 2), "utf8");
5616
- await fsp.rename(tmp, this.filePath);
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 (err) {
7796
+ } catch (_err) {
7624
7797
  }
7625
7798
  },
7626
7799
  async appendBatch(events) {