@wrongstack/core 0.89.1 → 0.89.3
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-B8F2ORwg.d.ts → agent-bridge-DbVe1dHT.d.ts} +1 -1
- package/dist/{agent-subagent-runner-CQaLFNnA.d.ts → agent-subagent-runner-C6eqID1t.d.ts} +433 -433
- package/dist/{events-DzyLtja6.d.ts → brain-s9DyD_Vf.d.ts} +179 -92
- package/dist/{compactor-CJq7LQev.d.ts → compactor-DXLxLcmU.d.ts} +2 -2
- package/dist/{config-_DZ7dN-T.d.ts → config-84VaZpH6.d.ts} +45 -38
- package/dist/{context-ToHAp4-U.d.ts → context-CNRYfhUv.d.ts} +1 -1
- package/dist/coordination/index.d.ts +16 -17
- package/dist/coordination/index.js +25 -37
- package/dist/coordination/index.js.map +1 -1
- package/dist/defaults/index.d.ts +31 -33
- package/dist/defaults/index.js +476 -206
- package/dist/defaults/index.js.map +1 -1
- package/dist/{director-state-CgIc30qi.d.ts → director-state-BfeCUbmk.d.ts} +1 -1
- package/dist/execution/index.d.ts +18 -19
- package/dist/execution/index.js +23 -45
- package/dist/execution/index.js.map +1 -1
- package/dist/extension/index.d.ts +9 -10
- package/dist/extension/index.js +8 -6
- package/dist/extension/index.js.map +1 -1
- package/dist/{index-Ca_lOmKl.d.ts → index-CqrroYcU.d.ts} +13 -15
- package/dist/{index-Dx-CnrDN.d.ts → index-D3Nax3YU.d.ts} +9 -10
- package/dist/index.d.ts +184 -174
- package/dist/index.js +973 -349
- package/dist/index.js.map +1 -1
- package/dist/infrastructure/index.d.ts +9 -9
- package/dist/infrastructure/index.js +4 -2
- package/dist/infrastructure/index.js.map +1 -1
- package/dist/kernel/index.d.ts +14 -16
- package/dist/kernel/index.js.map +1 -1
- package/dist/{logger-B72yyPc6.d.ts → logger-B63L5bTg.d.ts} +1 -1
- package/dist/{logger-C_27pj9i.d.ts → logger-B9J5puGM.d.ts} +1 -1
- package/dist/{mcp-servers-Dck3T85_.d.ts → mcp-servers-D3E5ixAR.d.ts} +3 -3
- package/dist/{mode-CHo2XtHs.d.ts → mode-ARA3HrkY.d.ts} +1 -1
- package/dist/models/index.d.ts +5 -5
- package/dist/models/index.js +8 -6
- package/dist/models/index.js.map +1 -1
- package/dist/{models-registry-Be3osGt5.d.ts → models-registry-B6_KfS65.d.ts} +1 -1
- package/dist/{models-registry-Boz639EI.d.ts → models-registry-DU64QxQa.d.ts} +1 -1
- package/dist/{multi-agent-coordinator-Da9nd8Ic.d.ts → multi-agent-coordinator-DHNrjPaA.d.ts} +2 -2
- package/dist/{null-fleet-bus-CHJOXv3t.d.ts → null-fleet-bus-BzzciAc4.d.ts} +32 -31
- package/dist/observability/index.d.ts +3 -3
- package/dist/{observability-CoSNZdhX.d.ts → observability-D-HZN_mF.d.ts} +1 -1
- package/dist/{parallel-eternal-engine-DyMCj2Pw.d.ts → parallel-eternal-engine-CTpcrb9O.d.ts} +33 -33
- package/dist/{path-resolver-TjBlRKyH.d.ts → path-resolver-B7hgMAVe.d.ts} +3 -3
- package/dist/{permission-14CChMmO.d.ts → permission-BDv7z0mk.d.ts} +7 -2
- package/dist/{permission-policy-gW5htOo1.d.ts → permission-policy-dF74EpDp.d.ts} +2 -2
- package/dist/{system-prompt-C0rLCeyn.d.ts → pipeline-C1Ad9OjI.d.ts} +73 -73
- package/dist/{plan-templates-D9UhwoGh.d.ts → plan-templates-CNphsz0n.d.ts} +79 -11
- package/dist/{provider-runner-BEPWwkxH.d.ts → provider-runner-cqvlB_oS.d.ts} +5 -5
- package/dist/{retry-policy-DSu6O6rD.d.ts → retry-policy-BcmuT_V0.d.ts} +2 -2
- package/dist/sdd/index.d.ts +12 -33
- package/dist/sdd/index.js +21 -31
- package/dist/sdd/index.js.map +1 -1
- package/dist/{secret-scrubber-yGBFQYju.d.ts → secret-vault-DrOhc2i5.d.ts} +7 -7
- package/dist/security/index.d.ts +4 -5
- package/dist/security/index.js +4 -2
- package/dist/security/index.js.map +1 -1
- package/dist/{selector-11-fm95U.d.ts → selector-C7wcdqMA.d.ts} +1 -1
- package/dist/{session-event-bridge-D0u-x576.d.ts → session-event-bridge-IVzs2GpE.d.ts} +1 -1
- package/dist/{session-reader-BQU-toaN.d.ts → session-reader-DDz1Ek4V.d.ts} +2 -2
- package/dist/{skill-BJeF2DwY.d.ts → skill-BJxzIyyN.d.ts} +1 -1
- package/dist/skills/index.d.ts +1 -1
- package/dist/skills/index.js +3 -9
- package/dist/skills/index.js.map +1 -1
- package/dist/storage/index.d.ts +132 -12
- package/dist/storage/index.js +834 -159
- package/dist/storage/index.js.map +1 -1
- package/dist/{task-graph-CikNdRTG.d.ts → task-graph-DJBqO0EY.d.ts} +1 -1
- package/dist/types/index.d.ts +25 -27
- package/dist/types/index.js +19 -31
- package/dist/types/index.js.map +1 -1
- package/dist/utils/expect-defined.d.ts +7 -0
- package/dist/utils/expect-defined.js +11 -0
- package/dist/utils/expect-defined.js.map +1 -0
- package/dist/utils/index.d.ts +6 -20
- package/dist/utils/index.js +11 -41
- package/dist/utils/index.js.map +1 -1
- package/dist/{wstack-paths-BQMvEllz.d.ts → wstack-paths-_lqjzErq.d.ts} +1 -1
- package/package.json +5 -1
- package/dist/memory-CEXuo7sz.d.ts +0 -16
- package/dist/secret-scrubber-3MHDDAtm.d.ts +0 -6
package/dist/defaults/index.js
CHANGED
|
@@ -5,18 +5,13 @@ import * as path3 from 'path';
|
|
|
5
5
|
import { isAbsolute, resolve } from 'path';
|
|
6
6
|
import * as fs5 from 'fs';
|
|
7
7
|
import * as os from 'os';
|
|
8
|
+
import { hostname } from 'os';
|
|
8
9
|
import { execFile } from 'child_process';
|
|
9
10
|
import { promisify } from 'util';
|
|
10
11
|
import { EventEmitter } from 'events';
|
|
11
12
|
|
|
12
13
|
var __defProp = Object.defineProperty;
|
|
13
14
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
14
|
-
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
15
|
-
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
16
|
-
}) : x)(function(x) {
|
|
17
|
-
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
18
|
-
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
19
|
-
});
|
|
20
15
|
var __esm = (fn, res) => function __init() {
|
|
21
16
|
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
22
17
|
};
|
|
@@ -294,16 +289,18 @@ function formatCtx(ctx) {
|
|
|
294
289
|
}
|
|
295
290
|
}
|
|
296
291
|
|
|
297
|
-
// src/
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
// src/utils/message-invariants.ts
|
|
301
|
-
function expectDefined(value) {
|
|
292
|
+
// src/utils/expect-defined.ts
|
|
293
|
+
function expectDefined(value, label) {
|
|
302
294
|
if (value === null || value === void 0) {
|
|
303
295
|
throw new Error("Expected value to be defined");
|
|
304
296
|
}
|
|
305
297
|
return value;
|
|
306
298
|
}
|
|
299
|
+
|
|
300
|
+
// src/storage/session-store.ts
|
|
301
|
+
init_atomic_write();
|
|
302
|
+
|
|
303
|
+
// src/utils/message-invariants.ts
|
|
307
304
|
function repairToolUseAdjacency(messages) {
|
|
308
305
|
const removedToolUses = [];
|
|
309
306
|
const removedToolResults = [];
|
|
@@ -396,12 +393,6 @@ function isEmptyMessage(msg) {
|
|
|
396
393
|
}
|
|
397
394
|
|
|
398
395
|
// src/storage/session-store.ts
|
|
399
|
-
function expectDefined2(value) {
|
|
400
|
-
if (value === null || value === void 0) {
|
|
401
|
-
throw new Error("Expected value to be defined");
|
|
402
|
-
}
|
|
403
|
-
return value;
|
|
404
|
-
}
|
|
405
396
|
function sanitizeModel(model) {
|
|
406
397
|
return model.replace(/[^a-zA-Z0-9_-]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "").slice(0, 40);
|
|
407
398
|
}
|
|
@@ -1112,7 +1103,7 @@ var FileSessionWriter = class {
|
|
|
1112
1103
|
let targetCheckpointLine = -1;
|
|
1113
1104
|
let afterTarget = false;
|
|
1114
1105
|
for (let i = 0; i < lines.length; i++) {
|
|
1115
|
-
const line =
|
|
1106
|
+
const line = expectDefined(lines[i]);
|
|
1116
1107
|
if (!line.trim()) continue;
|
|
1117
1108
|
let event;
|
|
1118
1109
|
try {
|
|
@@ -1408,11 +1399,235 @@ function mergeAdjacentText(blocks) {
|
|
|
1408
1399
|
return out;
|
|
1409
1400
|
}
|
|
1410
1401
|
|
|
1411
|
-
// src/
|
|
1402
|
+
// src/types/memory.ts
|
|
1403
|
+
var MEMORY_TYPE_LABELS = {
|
|
1404
|
+
fact: "Fact",
|
|
1405
|
+
decision: "Decision",
|
|
1406
|
+
convention: "Convention",
|
|
1407
|
+
preference: "Preference",
|
|
1408
|
+
reference: "Reference",
|
|
1409
|
+
anti_pattern: "Anti-pattern"
|
|
1410
|
+
};
|
|
1411
|
+
|
|
1412
|
+
// src/storage/memory-backend.ts
|
|
1412
1413
|
init_atomic_write();
|
|
1414
|
+
var TYPE_PRIORITY_RE = /^\[(\w+)\|(\w+)\]\s+/;
|
|
1415
|
+
var TAG_RE = /#([\w-]+)/g;
|
|
1416
|
+
function formatMetadata(entry) {
|
|
1417
|
+
const parts = [];
|
|
1418
|
+
if (entry.type && entry.priority) {
|
|
1419
|
+
parts.push(`[${entry.type}|${entry.priority}]`);
|
|
1420
|
+
} else if (entry.type) {
|
|
1421
|
+
parts.push(`[${entry.type}]`);
|
|
1422
|
+
} else if (entry.priority) {
|
|
1423
|
+
parts.push(`[${entry.priority}]`);
|
|
1424
|
+
}
|
|
1425
|
+
if (entry.tags && entry.tags.length > 0) {
|
|
1426
|
+
parts.push(entry.tags.map((t) => `#${t}`).join(" "));
|
|
1427
|
+
}
|
|
1428
|
+
return parts.length > 0 ? ` ${parts.join(" ")}` : "";
|
|
1429
|
+
}
|
|
1430
|
+
function lineToEntry(line, scope) {
|
|
1431
|
+
const trimmed = line.trim();
|
|
1432
|
+
if (!trimmed.startsWith("- [")) return null;
|
|
1433
|
+
const tsMatch = trimmed.match(/^-\s*\[([^\]]+)\]/);
|
|
1434
|
+
if (!tsMatch) return null;
|
|
1435
|
+
const ts = tsMatch[1] ?? "";
|
|
1436
|
+
let rest = trimmed.slice(tsMatch[0].length).trim();
|
|
1437
|
+
let type;
|
|
1438
|
+
let priority;
|
|
1439
|
+
const tpMatch = rest.match(TYPE_PRIORITY_RE);
|
|
1440
|
+
if (tpMatch) {
|
|
1441
|
+
const a = tpMatch[1] ?? "";
|
|
1442
|
+
const b = tpMatch[2] ?? "";
|
|
1443
|
+
if (isMemoryType(a)) {
|
|
1444
|
+
type = a;
|
|
1445
|
+
priority = isPriority(b) ? b : void 0;
|
|
1446
|
+
} else if (isPriority(a)) {
|
|
1447
|
+
priority = a;
|
|
1448
|
+
}
|
|
1449
|
+
rest = rest.slice(tpMatch[0].length).trim();
|
|
1450
|
+
}
|
|
1451
|
+
const idMatch = rest.match(/^mem_\d+_\w+\s+/);
|
|
1452
|
+
let text;
|
|
1453
|
+
if (idMatch) {
|
|
1454
|
+
text = rest.slice(idMatch[0].length).trim();
|
|
1455
|
+
} else {
|
|
1456
|
+
text = rest.trim();
|
|
1457
|
+
}
|
|
1458
|
+
const tags = [];
|
|
1459
|
+
let tagMatch;
|
|
1460
|
+
TAG_RE.lastIndex = 0;
|
|
1461
|
+
while ((tagMatch = TAG_RE.exec(text)) !== null) {
|
|
1462
|
+
tags.push(tagMatch[1] ?? "");
|
|
1463
|
+
}
|
|
1464
|
+
const cleanText = text.replace(TAG_RE, "").replace(/\s{2,}/g, " ").trim();
|
|
1465
|
+
if (!cleanText) return null;
|
|
1466
|
+
return {
|
|
1467
|
+
scope,
|
|
1468
|
+
text: cleanText,
|
|
1469
|
+
ts,
|
|
1470
|
+
type,
|
|
1471
|
+
priority,
|
|
1472
|
+
tags: tags.length > 0 ? tags : void 0
|
|
1473
|
+
};
|
|
1474
|
+
}
|
|
1475
|
+
function isMemoryType(s) {
|
|
1476
|
+
return s in MEMORY_TYPE_LABELS;
|
|
1477
|
+
}
|
|
1478
|
+
function isPriority(s) {
|
|
1479
|
+
return s === "critical" || s === "high" || s === "medium" || s === "low";
|
|
1480
|
+
}
|
|
1481
|
+
var FileMemoryBackend = class {
|
|
1482
|
+
kind = "file";
|
|
1483
|
+
files;
|
|
1484
|
+
constructor(opts) {
|
|
1485
|
+
this.files = {
|
|
1486
|
+
"project-agents": opts.paths.inProjectAgentsFile,
|
|
1487
|
+
"project-memory": opts.paths.projectMemory,
|
|
1488
|
+
"user-memory": opts.paths.globalMemory
|
|
1489
|
+
};
|
|
1490
|
+
}
|
|
1491
|
+
resolveFile(filePath, scope) {
|
|
1492
|
+
return filePath || this.files[scope];
|
|
1493
|
+
}
|
|
1494
|
+
async remember(scope, entry, filePath) {
|
|
1495
|
+
const file = this.resolveFile(filePath, scope);
|
|
1496
|
+
await ensureDir(path3.dirname(file));
|
|
1497
|
+
let existing = "";
|
|
1498
|
+
try {
|
|
1499
|
+
existing = await fsp.readFile(file, "utf8");
|
|
1500
|
+
} catch {
|
|
1501
|
+
}
|
|
1502
|
+
const id = `mem_${Date.now()}_${randomUUID().slice(0, 8)}`;
|
|
1503
|
+
const meta = formatMetadata(entry);
|
|
1504
|
+
const line = `
|
|
1505
|
+
- [${entry.ts}] ${id}${meta} ${entry.text.replace(/\n/g, " ")}
|
|
1506
|
+
`;
|
|
1507
|
+
const next = existing.trim() ? existing.replace(/\n+$/, "") + line : `# WrongStack Memory
|
|
1508
|
+
${line}`;
|
|
1509
|
+
await atomicWrite(file, next);
|
|
1510
|
+
}
|
|
1511
|
+
async forget(scope, query, filePath) {
|
|
1512
|
+
const file = this.resolveFile(filePath, scope);
|
|
1513
|
+
let existing;
|
|
1514
|
+
try {
|
|
1515
|
+
existing = await fsp.readFile(file, "utf8");
|
|
1516
|
+
} catch {
|
|
1517
|
+
return 0;
|
|
1518
|
+
}
|
|
1519
|
+
const needle = query.toLowerCase();
|
|
1520
|
+
const idMatcher = /mem_\d+_\w+/;
|
|
1521
|
+
let removed = 0;
|
|
1522
|
+
const lines = existing.split("\n").filter((line) => {
|
|
1523
|
+
const trimmed = line.trim();
|
|
1524
|
+
if (!trimmed.startsWith("- ")) return true;
|
|
1525
|
+
if (idMatcher.test(query)) {
|
|
1526
|
+
const entryIdMatch = /mem_\d+_\w+/.exec(trimmed);
|
|
1527
|
+
if (entryIdMatch && entryIdMatch[0] === query) {
|
|
1528
|
+
removed++;
|
|
1529
|
+
return false;
|
|
1530
|
+
}
|
|
1531
|
+
}
|
|
1532
|
+
if (trimmed.toLowerCase().includes(needle)) {
|
|
1533
|
+
removed++;
|
|
1534
|
+
return false;
|
|
1535
|
+
}
|
|
1536
|
+
return true;
|
|
1537
|
+
});
|
|
1538
|
+
if (removed > 0) {
|
|
1539
|
+
if (lines.length === 0 || lines.length === 1 && !lines[0]?.trim()) {
|
|
1540
|
+
await atomicWrite(file, "");
|
|
1541
|
+
} else {
|
|
1542
|
+
await atomicWrite(file, lines.join("\n"));
|
|
1543
|
+
}
|
|
1544
|
+
}
|
|
1545
|
+
return removed;
|
|
1546
|
+
}
|
|
1547
|
+
async readAll(scope, filePath) {
|
|
1548
|
+
const file = this.resolveFile(filePath, scope);
|
|
1549
|
+
try {
|
|
1550
|
+
return await fsp.readFile(file, "utf8");
|
|
1551
|
+
} catch {
|
|
1552
|
+
return "";
|
|
1553
|
+
}
|
|
1554
|
+
}
|
|
1555
|
+
async list(scope, filePath, limit) {
|
|
1556
|
+
const raw = await this.readAll(scope, filePath);
|
|
1557
|
+
if (!raw.trim()) return [];
|
|
1558
|
+
const entries = parseEntries(raw, scope);
|
|
1559
|
+
return limit ? entries.slice(0, limit) : entries;
|
|
1560
|
+
}
|
|
1561
|
+
async search(scope, query, filePath, limit) {
|
|
1562
|
+
const entries = await this.list(scope, filePath);
|
|
1563
|
+
const needle = query.toLowerCase().split(/\s+/);
|
|
1564
|
+
const scored = entries.map((e) => {
|
|
1565
|
+
const words = e.text.toLowerCase().split(/\s+/);
|
|
1566
|
+
let score = 0;
|
|
1567
|
+
for (const n of needle) {
|
|
1568
|
+
if (words.some((w) => w.includes(n))) score += 1;
|
|
1569
|
+
if (e.tags?.some((t) => t.toLowerCase().includes(n))) score += 2;
|
|
1570
|
+
}
|
|
1571
|
+
return { entry: e, score };
|
|
1572
|
+
});
|
|
1573
|
+
scored.sort((a, b) => b.score - a.score);
|
|
1574
|
+
const matched = scored.filter((s) => s.score > 0).map((s) => s.entry);
|
|
1575
|
+
return limit ? matched.slice(0, limit) : matched;
|
|
1576
|
+
}
|
|
1577
|
+
async clear(scope, filePath) {
|
|
1578
|
+
const file = this.resolveFile(filePath, scope);
|
|
1579
|
+
await atomicWrite(file, "");
|
|
1580
|
+
}
|
|
1581
|
+
async consolidate(scope, filePath) {
|
|
1582
|
+
const file = this.resolveFile(filePath, scope);
|
|
1583
|
+
let existing;
|
|
1584
|
+
try {
|
|
1585
|
+
existing = await fsp.readFile(file, "utf8");
|
|
1586
|
+
} catch {
|
|
1587
|
+
return 0;
|
|
1588
|
+
}
|
|
1589
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1590
|
+
let removed = 0;
|
|
1591
|
+
const lines = existing.split("\n").filter((line) => {
|
|
1592
|
+
const trimmed = line.trim();
|
|
1593
|
+
if (!trimmed.startsWith("- ")) return true;
|
|
1594
|
+
const norm = trimmed.replace(/\[[^\]]+\]/g, "").replace(/\bmem_\d+_\w+\s*/, "").replace(/#[\w-]+/g, "").replace(/\s+/g, " ").trim().toLowerCase();
|
|
1595
|
+
if (seen.has(norm)) {
|
|
1596
|
+
removed++;
|
|
1597
|
+
return false;
|
|
1598
|
+
}
|
|
1599
|
+
seen.add(norm);
|
|
1600
|
+
return true;
|
|
1601
|
+
});
|
|
1602
|
+
const next = lines.join("\n");
|
|
1603
|
+
const backup = `${file}.bak.${Date.now()}`;
|
|
1604
|
+
try {
|
|
1605
|
+
await fsp.copyFile(file, backup);
|
|
1606
|
+
} catch {
|
|
1607
|
+
}
|
|
1608
|
+
try {
|
|
1609
|
+
await atomicWrite(file, next);
|
|
1610
|
+
} catch {
|
|
1611
|
+
return 0;
|
|
1612
|
+
}
|
|
1613
|
+
return removed;
|
|
1614
|
+
}
|
|
1615
|
+
};
|
|
1616
|
+
function parseEntries(raw, scope = "project-memory") {
|
|
1617
|
+
const entries = [];
|
|
1618
|
+
for (const line of raw.split("\n")) {
|
|
1619
|
+
const entry = lineToEntry(line, scope);
|
|
1620
|
+
if (entry) entries.push(entry);
|
|
1621
|
+
}
|
|
1622
|
+
return entries.reverse();
|
|
1623
|
+
}
|
|
1624
|
+
|
|
1625
|
+
// src/storage/memory-store.ts
|
|
1413
1626
|
var MAX_BYTES_TOTAL = 32e3;
|
|
1414
1627
|
var DefaultMemoryStore = class {
|
|
1415
1628
|
files;
|
|
1629
|
+
events;
|
|
1630
|
+
backend;
|
|
1416
1631
|
/**
|
|
1417
1632
|
* Per-scope serialization queue. `remember` / `forget` / `consolidate` /
|
|
1418
1633
|
* `clear` are read-modify-write against a single file; without a lock,
|
|
@@ -1429,12 +1644,29 @@ var DefaultMemoryStore = class {
|
|
|
1429
1644
|
writeChain = /* @__PURE__ */ new Map();
|
|
1430
1645
|
/** Last write error per scope — surfaced as warnings on the next readAll(). */
|
|
1431
1646
|
writeErrors = /* @__PURE__ */ new Map();
|
|
1647
|
+
/**
|
|
1648
|
+
* When the global root is a temporary directory (opencode, CI sandboxes),
|
|
1649
|
+
* memory files are also mirrored to the project tree so they survive
|
|
1650
|
+
* session cleanup. The primary path stays in the temp root for isolation;
|
|
1651
|
+
* this backup ensures memory is never lost.
|
|
1652
|
+
*/
|
|
1653
|
+
persistBackup;
|
|
1654
|
+
backupDir;
|
|
1432
1655
|
constructor(opts) {
|
|
1433
1656
|
this.files = {
|
|
1434
1657
|
"project-agents": opts.paths.inProjectAgentsFile,
|
|
1435
1658
|
"project-memory": opts.paths.projectMemory,
|
|
1436
1659
|
"user-memory": opts.paths.globalMemory
|
|
1437
1660
|
};
|
|
1661
|
+
this.events = opts.events;
|
|
1662
|
+
this.backend = opts.backend ?? new FileMemoryBackend({ paths: opts.paths });
|
|
1663
|
+
const root = opts.paths.globalRoot.toLowerCase();
|
|
1664
|
+
this.persistBackup = /[/\\](tmp|temp|cache)[/\\]/.test(root);
|
|
1665
|
+
this.backupDir = this.persistBackup ? opts.paths.inProjectAgentsFile.replace(/AGENTS\.md$/, "memory-persist") : "";
|
|
1666
|
+
}
|
|
1667
|
+
/** Expose the backend for plugin introspection and advanced queries. */
|
|
1668
|
+
getBackend() {
|
|
1669
|
+
return this.backend;
|
|
1438
1670
|
}
|
|
1439
1671
|
async runSerialized(scope, work) {
|
|
1440
1672
|
const prior = this.writeChain.get(scope) ?? Promise.resolve();
|
|
@@ -1461,7 +1693,7 @@ var DefaultMemoryStore = class {
|
|
|
1461
1693
|
if (writeErr2) {
|
|
1462
1694
|
parts.push(`> \u26A0\uFE0F Memory write error (${labelOf(scope)}): ${writeErr2.message}`);
|
|
1463
1695
|
}
|
|
1464
|
-
const body = await this.
|
|
1696
|
+
const body = await this.backend.readAll(scope, this.files[scope]);
|
|
1465
1697
|
if (body.trim()) parts.push(`## ${labelOf(scope)}
|
|
1466
1698
|
|
|
1467
1699
|
${body.trim()}`);
|
|
@@ -1469,117 +1701,214 @@ ${body.trim()}`);
|
|
|
1469
1701
|
return parts.join("\n\n");
|
|
1470
1702
|
}
|
|
1471
1703
|
async read(scope) {
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1704
|
+
return this.backend.readAll(scope, this.files[scope]);
|
|
1705
|
+
}
|
|
1706
|
+
/**
|
|
1707
|
+
* List entries from a scope, newest first. Delegates to the backend
|
|
1708
|
+
* so graph/semantic backends can return enriched or filtered results.
|
|
1709
|
+
*/
|
|
1710
|
+
async list(scope = "project-memory", limit) {
|
|
1711
|
+
return this.backend.list(scope, this.files[scope], limit);
|
|
1712
|
+
}
|
|
1713
|
+
/**
|
|
1714
|
+
* Find memories related to the given text via graph traversal.
|
|
1715
|
+
* Falls back to content search when no graph backend is available.
|
|
1716
|
+
*/
|
|
1717
|
+
async findRelated(text, scope = "project-memory", limit = 5) {
|
|
1718
|
+
if (this.backend.findRelated) {
|
|
1719
|
+
return this.backend.findRelated(scope, this.files[scope], text, limit);
|
|
1476
1720
|
}
|
|
1721
|
+
return this.search(text, scope, limit);
|
|
1477
1722
|
}
|
|
1478
|
-
async
|
|
1723
|
+
async search(query, scope = "project-memory", limit) {
|
|
1724
|
+
return this.backend.search(scope, query, this.files[scope], limit);
|
|
1725
|
+
}
|
|
1726
|
+
async remember(text, scope = "project-memory", metadata) {
|
|
1727
|
+
const ts = (/* @__PURE__ */ new Date()).toISOString();
|
|
1479
1728
|
return this.runSerialized(scope, async () => {
|
|
1480
|
-
const
|
|
1481
|
-
await
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
`;
|
|
1492
|
-
const next = existing.trim() ? existing.replace(/\n+$/, "") + entry : `# WrongStack Memory
|
|
1493
|
-
${entry}`;
|
|
1494
|
-
await atomicWrite(file, next);
|
|
1495
|
-
const buf = Buffer.byteLength(next, "utf8");
|
|
1496
|
-
if (buf > MAX_BYTES_TOTAL) {
|
|
1497
|
-
await this.consolidateUnsafe(scope);
|
|
1729
|
+
const entry = { scope, text, ts, ...metadata };
|
|
1730
|
+
await this.backend.remember(scope, entry, this.files[scope]);
|
|
1731
|
+
const raw = await this.backend.readAll(scope, this.files[scope]);
|
|
1732
|
+
if (Buffer.byteLength(raw, "utf8") > MAX_BYTES_TOTAL) {
|
|
1733
|
+
const removed = await this.backend.consolidate(scope, this.files[scope]);
|
|
1734
|
+
if (removed > 0) {
|
|
1735
|
+
this.events?.emit("memory.consolidated", {
|
|
1736
|
+
scope,
|
|
1737
|
+
removed
|
|
1738
|
+
});
|
|
1739
|
+
}
|
|
1498
1740
|
}
|
|
1741
|
+
await this.mirrorBackup(scope);
|
|
1742
|
+
this.events?.emit("memory.remembered", {
|
|
1743
|
+
scope,
|
|
1744
|
+
text,
|
|
1745
|
+
ts,
|
|
1746
|
+
type: entry.type,
|
|
1747
|
+
tags: entry.tags,
|
|
1748
|
+
priority: entry.priority
|
|
1749
|
+
});
|
|
1499
1750
|
});
|
|
1500
1751
|
}
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
const
|
|
1513
|
-
const
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
const
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
if (
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1752
|
+
/**
|
|
1753
|
+
* Score and rank memories by relevance to the current context.
|
|
1754
|
+
* Returns entries with score >= MIN_RELEVANCE_SCORE, sorted highest first.
|
|
1755
|
+
*/
|
|
1756
|
+
async scoreRelevant(ctx, scope = "project-memory", limit = 8) {
|
|
1757
|
+
const all = await this.list(scope);
|
|
1758
|
+
if (all.length === 0) return [];
|
|
1759
|
+
const taskWords = ctx.currentTask.toLowerCase().split(/\s+/).filter((w) => w.length > 2);
|
|
1760
|
+
const skillWords = (ctx.activeSkills ?? []).flatMap((s) => s.split("-"));
|
|
1761
|
+
const toolWords = (ctx.toolNames ?? []).flatMap((t) => t.toLowerCase().split("_"));
|
|
1762
|
+
const now = Date.now();
|
|
1763
|
+
const scored = [];
|
|
1764
|
+
for (const entry of all) {
|
|
1765
|
+
let score = 0;
|
|
1766
|
+
const reasons = [];
|
|
1767
|
+
const textLower = entry.text.toLowerCase();
|
|
1768
|
+
const tagsLower = (entry.tags ?? []).map((t) => t.toLowerCase());
|
|
1769
|
+
let taskHits = 0;
|
|
1770
|
+
for (const w of taskWords) {
|
|
1771
|
+
if (textLower.includes(w)) {
|
|
1772
|
+
taskHits++;
|
|
1773
|
+
score += 2;
|
|
1774
|
+
}
|
|
1775
|
+
if (tagsLower.some((t) => t.includes(w))) {
|
|
1776
|
+
taskHits++;
|
|
1777
|
+
score += 3;
|
|
1527
1778
|
}
|
|
1528
1779
|
}
|
|
1529
|
-
if (
|
|
1530
|
-
|
|
1531
|
-
|
|
1780
|
+
if (taskHits > 0) reasons.push(`task match (${taskHits})`);
|
|
1781
|
+
let skillHits = 0;
|
|
1782
|
+
for (const w of skillWords) {
|
|
1783
|
+
if (w.length > 2 && (textLower.includes(w) || tagsLower.some((t) => t.includes(w)))) {
|
|
1784
|
+
skillHits++;
|
|
1785
|
+
}
|
|
1786
|
+
}
|
|
1787
|
+
score += skillHits;
|
|
1788
|
+
if (skillHits > 0) reasons.push(`skill match (${skillHits})`);
|
|
1789
|
+
for (const w of toolWords) {
|
|
1790
|
+
if (w.length > 2 && (textLower.includes(w) || tagsLower.some((t) => t.includes(w)))) {
|
|
1791
|
+
score += 1;
|
|
1792
|
+
reasons.push(`tool mention: ${w}`);
|
|
1793
|
+
}
|
|
1794
|
+
}
|
|
1795
|
+
switch (entry.priority) {
|
|
1796
|
+
case "critical":
|
|
1797
|
+
score += 5;
|
|
1798
|
+
reasons.push("critical");
|
|
1799
|
+
break;
|
|
1800
|
+
case "high":
|
|
1801
|
+
score += 3;
|
|
1802
|
+
reasons.push("high priority");
|
|
1803
|
+
break;
|
|
1804
|
+
case "medium":
|
|
1805
|
+
score += 1;
|
|
1806
|
+
break;
|
|
1807
|
+
case "low":
|
|
1808
|
+
score -= 2;
|
|
1809
|
+
reasons.push("low priority");
|
|
1810
|
+
break;
|
|
1811
|
+
}
|
|
1812
|
+
switch (entry.type) {
|
|
1813
|
+
case "decision":
|
|
1814
|
+
score += 2;
|
|
1815
|
+
reasons.push("decision");
|
|
1816
|
+
break;
|
|
1817
|
+
case "convention":
|
|
1818
|
+
score += 2;
|
|
1819
|
+
reasons.push("convention");
|
|
1820
|
+
break;
|
|
1821
|
+
case "anti_pattern":
|
|
1822
|
+
score += 3;
|
|
1823
|
+
reasons.push("anti-pattern");
|
|
1824
|
+
break;
|
|
1825
|
+
case "preference":
|
|
1826
|
+
score += 1;
|
|
1827
|
+
reasons.push("preference");
|
|
1828
|
+
break;
|
|
1829
|
+
}
|
|
1830
|
+
const ageDays = (now - new Date(entry.ts).getTime()) / (1e3 * 60 * 60 * 24);
|
|
1831
|
+
if (ageDays < 1) score += 1;
|
|
1832
|
+
else if (ageDays > 30) score -= 1;
|
|
1833
|
+
if (entry.confidence !== void 0 && entry.confidence < 0.5) {
|
|
1834
|
+
score -= 2;
|
|
1835
|
+
reasons.push("low confidence");
|
|
1836
|
+
}
|
|
1837
|
+
if (entry.lastAccessed) {
|
|
1838
|
+
const hoursSinceAccess = (now - new Date(entry.lastAccessed).getTime()) / (1e3 * 60 * 60);
|
|
1839
|
+
if (hoursSinceAccess < 1) score -= 1;
|
|
1840
|
+
}
|
|
1841
|
+
if (score > 0) {
|
|
1842
|
+
scored.push({
|
|
1843
|
+
...entry,
|
|
1844
|
+
score,
|
|
1845
|
+
matchReason: reasons.join(", ") || "keyword match"
|
|
1846
|
+
});
|
|
1532
1847
|
}
|
|
1533
|
-
return true;
|
|
1534
|
-
});
|
|
1535
|
-
if (removed > 0) {
|
|
1536
|
-
await atomicWrite(file, lines.join("\n"));
|
|
1537
1848
|
}
|
|
1538
|
-
|
|
1849
|
+
scored.sort((a, b) => b.score - a.score);
|
|
1850
|
+
const threshold = 2;
|
|
1851
|
+
const relevant = scored.filter(
|
|
1852
|
+
(s) => s.score >= threshold || s.priority === "critical" || s.priority === "high"
|
|
1853
|
+
);
|
|
1854
|
+
return relevant.slice(0, Math.min(limit, 15));
|
|
1539
1855
|
}
|
|
1540
|
-
async
|
|
1541
|
-
return this.runSerialized(scope, async () =>
|
|
1856
|
+
async forget(query, scope = "project-memory") {
|
|
1857
|
+
return this.runSerialized(scope, async () => {
|
|
1858
|
+
const removed = await this.backend.forget(scope, query, this.files[scope]);
|
|
1859
|
+
if (removed > 0) {
|
|
1860
|
+
this.events?.emit("memory.forgotten", {
|
|
1861
|
+
scope,
|
|
1862
|
+
query,
|
|
1863
|
+
removed
|
|
1864
|
+
});
|
|
1865
|
+
await this.mirrorBackup(scope);
|
|
1866
|
+
}
|
|
1867
|
+
return removed;
|
|
1868
|
+
});
|
|
1542
1869
|
}
|
|
1543
|
-
async
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
const trimmed = line.trim();
|
|
1554
|
-
if (!trimmed.startsWith("- ")) return true;
|
|
1555
|
-
const norm = trimmed.replace(/\[[^\]]+\]/, "").replace(/\bmem_\d+_\w+\s*/, "").trim().toLowerCase();
|
|
1556
|
-
if (seen.has(norm)) return false;
|
|
1557
|
-
seen.add(norm);
|
|
1558
|
-
return true;
|
|
1870
|
+
async consolidate(scope) {
|
|
1871
|
+
return this.runSerialized(scope, async () => {
|
|
1872
|
+
const removed = await this.backend.consolidate(scope, this.files[scope]);
|
|
1873
|
+
if (removed > 0) {
|
|
1874
|
+
this.events?.emit("memory.consolidated", {
|
|
1875
|
+
scope,
|
|
1876
|
+
removed
|
|
1877
|
+
});
|
|
1878
|
+
await this.mirrorBackup(scope);
|
|
1879
|
+
}
|
|
1559
1880
|
});
|
|
1560
|
-
const next = lines.join("\n");
|
|
1561
|
-
const backup = `${file}.bak.${Date.now()}`;
|
|
1562
|
-
try {
|
|
1563
|
-
await fsp.copyFile(file, backup);
|
|
1564
|
-
} catch {
|
|
1565
|
-
}
|
|
1566
|
-
try {
|
|
1567
|
-
await atomicWrite(file, next);
|
|
1568
|
-
} catch {
|
|
1569
|
-
return;
|
|
1570
|
-
}
|
|
1571
1881
|
}
|
|
1572
1882
|
async clear(scope) {
|
|
1573
1883
|
if (scope) {
|
|
1574
|
-
await this.runSerialized(scope, async () =>
|
|
1884
|
+
await this.runSerialized(scope, async () => {
|
|
1885
|
+
await this.backend.clear(scope, this.files[scope]);
|
|
1886
|
+
this.events?.emit("memory.cleared", { scope });
|
|
1887
|
+
await this.mirrorBackup(scope);
|
|
1888
|
+
});
|
|
1575
1889
|
return;
|
|
1576
1890
|
}
|
|
1577
1891
|
await Promise.all(
|
|
1578
1892
|
["project-agents", "project-memory", "user-memory"].map(
|
|
1579
|
-
(s) => this.runSerialized(s, async () =>
|
|
1893
|
+
(s) => this.runSerialized(s, async () => {
|
|
1894
|
+
await this.backend.clear(s, this.files[s]);
|
|
1895
|
+
this.events?.emit("memory.cleared", { scope: s });
|
|
1896
|
+
await this.mirrorBackup(s);
|
|
1897
|
+
})
|
|
1580
1898
|
)
|
|
1581
1899
|
);
|
|
1582
1900
|
}
|
|
1901
|
+
/** Mirror current memory content to the persistent backup directory. */
|
|
1902
|
+
async mirrorBackup(scope) {
|
|
1903
|
+
if (!this.persistBackup || scope === "project-agents") return;
|
|
1904
|
+
try {
|
|
1905
|
+
const content = await this.backend.readAll(scope, this.files[scope]);
|
|
1906
|
+
const { writeFile: writeFile4, mkdir: mkdir6 } = await import('fs/promises');
|
|
1907
|
+
await mkdir6(this.backupDir, { recursive: true });
|
|
1908
|
+
await writeFile4(`${this.backupDir}/${scope}.md`, content, "utf8");
|
|
1909
|
+
} catch {
|
|
1910
|
+
}
|
|
1911
|
+
}
|
|
1583
1912
|
};
|
|
1584
1913
|
function labelOf(scope) {
|
|
1585
1914
|
switch (scope) {
|
|
@@ -2295,12 +2624,6 @@ function compileUserRegex(pattern, flags) {
|
|
|
2295
2624
|
}
|
|
2296
2625
|
|
|
2297
2626
|
// src/storage/session-reader.ts
|
|
2298
|
-
function expectDefined3(value) {
|
|
2299
|
-
if (value === null || value === void 0) {
|
|
2300
|
-
throw new Error("Expected value to be defined");
|
|
2301
|
-
}
|
|
2302
|
-
return value;
|
|
2303
|
-
}
|
|
2304
2627
|
var DefaultSessionReader = class {
|
|
2305
2628
|
store;
|
|
2306
2629
|
constructor(opts) {
|
|
@@ -2362,7 +2685,7 @@ var DefaultSessionReader = class {
|
|
|
2362
2685
|
continue;
|
|
2363
2686
|
}
|
|
2364
2687
|
for (let i = 0; i < data.events.length; i++) {
|
|
2365
|
-
const ev =
|
|
2688
|
+
const ev = expectDefined(data.events[i]);
|
|
2366
2689
|
if (allowedTypes && !allowedTypes.has(ev.type)) continue;
|
|
2367
2690
|
const text = eventText(ev);
|
|
2368
2691
|
if (text === null) continue;
|
|
@@ -2811,7 +3134,10 @@ function attachTodosCheckpoint(state, filePath, sessionId) {
|
|
|
2811
3134
|
let pending = null;
|
|
2812
3135
|
let writeChain = Promise.resolve();
|
|
2813
3136
|
const enqueueWrite = (todos) => {
|
|
2814
|
-
writeChain = writeChain.then(() => saveTodosCheckpoint(filePath, sessionId, todos))
|
|
3137
|
+
writeChain = writeChain.then(() => saveTodosCheckpoint(filePath, sessionId, todos)).catch((err) => {
|
|
3138
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
3139
|
+
console.error(`[TodosCheckpoint] save failed for session ${sessionId}: ${msg}`);
|
|
3140
|
+
});
|
|
2815
3141
|
return writeChain;
|
|
2816
3142
|
};
|
|
2817
3143
|
const flush = () => {
|
|
@@ -3115,7 +3441,7 @@ async function acquireDirectorStateLock(lockPath, processId = process.pid) {
|
|
|
3115
3441
|
}
|
|
3116
3442
|
const lock = {
|
|
3117
3443
|
pid: processId,
|
|
3118
|
-
hostname:
|
|
3444
|
+
hostname: hostname(),
|
|
3119
3445
|
startedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
3120
3446
|
};
|
|
3121
3447
|
await atomicWrite(lockPath, JSON.stringify(lock), { mode: 384 });
|
|
@@ -3641,12 +3967,6 @@ function getDangerousCapabilities(toolOrCaps) {
|
|
|
3641
3967
|
init_atomic_write();
|
|
3642
3968
|
|
|
3643
3969
|
// src/utils/glob-match.ts
|
|
3644
|
-
function expectDefined4(value) {
|
|
3645
|
-
if (value === null || value === void 0) {
|
|
3646
|
-
throw new Error("Expected value to be defined");
|
|
3647
|
-
}
|
|
3648
|
-
return value;
|
|
3649
|
-
}
|
|
3650
3970
|
function escapeRegex(s) {
|
|
3651
3971
|
return s.replace(/[.+^${}()|\\]/g, "\\$&");
|
|
3652
3972
|
}
|
|
@@ -3658,7 +3978,7 @@ function getCachedGlob(pattern) {
|
|
|
3658
3978
|
if (COMPILED_GLOB_CACHE.size >= CACHE_MAX_SIZE) {
|
|
3659
3979
|
const keys = [...COMPILED_GLOB_CACHE.keys()];
|
|
3660
3980
|
for (let i = 0; i < Math.floor(CACHE_MAX_SIZE / 4); i++) {
|
|
3661
|
-
COMPILED_GLOB_CACHE.delete(
|
|
3981
|
+
COMPILED_GLOB_CACHE.delete(expectDefined(keys[i]));
|
|
3662
3982
|
}
|
|
3663
3983
|
}
|
|
3664
3984
|
const re = compileGlob(pattern);
|
|
@@ -4523,12 +4843,6 @@ function parseDescription(raw) {
|
|
|
4523
4843
|
}
|
|
4524
4844
|
|
|
4525
4845
|
// src/utils/json-repair.ts
|
|
4526
|
-
function expectDefined5(value) {
|
|
4527
|
-
if (value === null || value === void 0) {
|
|
4528
|
-
throw new Error("Expected value to be defined");
|
|
4529
|
-
}
|
|
4530
|
-
return value;
|
|
4531
|
-
}
|
|
4532
4846
|
function completePartialObject(s) {
|
|
4533
4847
|
if (!s.trim().startsWith("{")) return s;
|
|
4534
4848
|
if (tryParse(s).ok) return s;
|
|
@@ -4540,7 +4854,7 @@ function completePartialObject(s) {
|
|
|
4540
4854
|
let contentEnd = 0;
|
|
4541
4855
|
let stringBraceDepth = 0;
|
|
4542
4856
|
for (let i = 0; i < s.length; i++) {
|
|
4543
|
-
const ch =
|
|
4857
|
+
const ch = expectDefined(s[i]);
|
|
4544
4858
|
if (inString) {
|
|
4545
4859
|
contentEnd = i + 1;
|
|
4546
4860
|
if (escaped) {
|
|
@@ -4926,12 +5240,6 @@ var DefaultProviderRunner = class {
|
|
|
4926
5240
|
};
|
|
4927
5241
|
|
|
4928
5242
|
// src/utils/token-estimate.ts
|
|
4929
|
-
function expectDefined6(value) {
|
|
4930
|
-
if (value === null || value === void 0) {
|
|
4931
|
-
throw new Error("Expected value to be defined");
|
|
4932
|
-
}
|
|
4933
|
-
return value;
|
|
4934
|
-
}
|
|
4935
5243
|
var RoughTokenEstimate = (text, charsPerToken = 3.5) => Math.max(1, Math.ceil(text.length / charsPerToken));
|
|
4936
5244
|
var ESTIMATE_CACHE = /* @__PURE__ */ new Map();
|
|
4937
5245
|
var ESTIMATE_CACHE_MAX_SIZE = 1e4;
|
|
@@ -4941,7 +5249,7 @@ function getCachedEstimate(key, compute) {
|
|
|
4941
5249
|
if (ESTIMATE_CACHE.size >= ESTIMATE_CACHE_MAX_SIZE) {
|
|
4942
5250
|
const keys = [...ESTIMATE_CACHE.keys()];
|
|
4943
5251
|
for (let i = 0; i < Math.floor(ESTIMATE_CACHE_MAX_SIZE / 4); i++) {
|
|
4944
|
-
ESTIMATE_CACHE.delete(
|
|
5252
|
+
ESTIMATE_CACHE.delete(expectDefined(keys[i]));
|
|
4945
5253
|
}
|
|
4946
5254
|
}
|
|
4947
5255
|
const estimate = compute();
|
|
@@ -5434,12 +5742,6 @@ var IntelligentCompactor = class {
|
|
|
5434
5742
|
};
|
|
5435
5743
|
|
|
5436
5744
|
// src/models/llm-selector.ts
|
|
5437
|
-
function expectDefined7(value) {
|
|
5438
|
-
if (value === null || value === void 0) {
|
|
5439
|
-
throw new Error("Expected value to be defined");
|
|
5440
|
-
}
|
|
5441
|
-
return value;
|
|
5442
|
-
}
|
|
5443
5745
|
var DEFAULT_SYSTEM_PROMPT = `You are a context pruning assistant. Given a conversation history and a token budget, decide which message ranges are worth keeping verbatim and which should be collapsed into summaries.
|
|
5444
5746
|
|
|
5445
5747
|
Output a JSON object with this structure:
|
|
@@ -5480,7 +5782,7 @@ function formatMessages(messages, maxChars = 8e3) {
|
|
|
5480
5782
|
const lines = [];
|
|
5481
5783
|
let used = 0;
|
|
5482
5784
|
for (let i = 0; i < messages.length; i++) {
|
|
5483
|
-
const m =
|
|
5785
|
+
const m = expectDefined(messages[i]);
|
|
5484
5786
|
const role = m.role.padEnd(10, " ");
|
|
5485
5787
|
let text;
|
|
5486
5788
|
if (typeof m.content === "string") {
|
|
@@ -5545,7 +5847,7 @@ IMPORTANT: Total conversation (${totalTokens} tokens) exceeds budget (${effectiv
|
|
|
5545
5847
|
let tokenCount = 0;
|
|
5546
5848
|
let startIdx = 0;
|
|
5547
5849
|
for (let i = messages.length - 1; i >= 0; i--) {
|
|
5548
|
-
const m =
|
|
5850
|
+
const m = expectDefined(messages[i]);
|
|
5549
5851
|
const cost = typeof m.content === "string" ? Math.ceil(m.content.length / 4) : m.content.reduce(
|
|
5550
5852
|
(acc, b) => acc + (b.type === "text" ? Math.ceil(b.text.length / 4) : Math.ceil(JSON.stringify(b).length / 4)),
|
|
5551
5853
|
0
|
|
@@ -6152,12 +6454,6 @@ function createToolOutputSerializer(opts = {}) {
|
|
|
6152
6454
|
}
|
|
6153
6455
|
|
|
6154
6456
|
// src/execution/tool-executor.ts
|
|
6155
|
-
function expectDefined8(value) {
|
|
6156
|
-
if (value === null || value === void 0) {
|
|
6157
|
-
throw new Error("Expected value to be defined");
|
|
6158
|
-
}
|
|
6159
|
-
return value;
|
|
6160
|
-
}
|
|
6161
6457
|
var ToolExecutor = class {
|
|
6162
6458
|
constructor(registry, opts) {
|
|
6163
6459
|
this.registry = registry;
|
|
@@ -6564,7 +6860,7 @@ function hasMalformedArguments(input) {
|
|
|
6564
6860
|
function extractMalformedRaw(input) {
|
|
6565
6861
|
if (!hasMalformedArguments(input)) return void 0;
|
|
6566
6862
|
const obj = input;
|
|
6567
|
-
const value = obj[
|
|
6863
|
+
const value = obj[expectDefined(Object.keys(obj)[0])];
|
|
6568
6864
|
if (value === void 0 || value === null) return void 0;
|
|
6569
6865
|
if (typeof value === "string") return value;
|
|
6570
6866
|
try {
|
|
@@ -7722,15 +8018,7 @@ function makeAgentSubagentRunner(opts) {
|
|
|
7722
8018
|
let budgetError = null;
|
|
7723
8019
|
const onBudgetError = (err) => {
|
|
7724
8020
|
if (err instanceof BudgetThresholdSignal) {
|
|
7725
|
-
|
|
7726
|
-
if (decision === "stop") {
|
|
7727
|
-
budgetError = new BudgetExceededError(err.kind, err.limit, err.used);
|
|
7728
|
-
aborter.abort();
|
|
7729
|
-
}
|
|
7730
|
-
}).catch(() => {
|
|
7731
|
-
budgetError = new BudgetExceededError(err.kind, err.limit, err.used);
|
|
7732
|
-
aborter.abort();
|
|
7733
|
-
});
|
|
8021
|
+
budgetError = err;
|
|
7734
8022
|
return;
|
|
7735
8023
|
}
|
|
7736
8024
|
aborter.abort();
|
|
@@ -7838,15 +8126,23 @@ function makeAgentSubagentRunner(opts) {
|
|
|
7838
8126
|
}
|
|
7839
8127
|
if (budgetError) {
|
|
7840
8128
|
if ("decision" in budgetError) {
|
|
7841
|
-
|
|
7842
|
-
|
|
8129
|
+
try {
|
|
8130
|
+
const decision = await budgetError.decision;
|
|
8131
|
+
if (decision === "stop") {
|
|
8132
|
+
budgetError = new BudgetExceededError(
|
|
8133
|
+
budgetError.kind,
|
|
8134
|
+
budgetError.limit,
|
|
8135
|
+
budgetError.used
|
|
8136
|
+
);
|
|
8137
|
+
} else {
|
|
8138
|
+
budgetError = null;
|
|
8139
|
+
}
|
|
8140
|
+
} catch {
|
|
7843
8141
|
budgetError = new BudgetExceededError(
|
|
7844
8142
|
budgetError.kind,
|
|
7845
8143
|
budgetError.limit,
|
|
7846
8144
|
budgetError.used
|
|
7847
8145
|
);
|
|
7848
|
-
} else {
|
|
7849
|
-
budgetError = null;
|
|
7850
8146
|
}
|
|
7851
8147
|
}
|
|
7852
8148
|
if (budgetError) throw budgetError;
|
|
@@ -11342,12 +11638,6 @@ var DefaultMultiAgentCoordinator = class _DefaultMultiAgentCoordinator extends E
|
|
|
11342
11638
|
};
|
|
11343
11639
|
|
|
11344
11640
|
// src/execution/parallel-eternal-engine.ts
|
|
11345
|
-
function expectDefined9(value) {
|
|
11346
|
-
if (value === null || value === void 0) {
|
|
11347
|
-
throw new Error("Expected value to be defined");
|
|
11348
|
-
}
|
|
11349
|
-
return value;
|
|
11350
|
-
}
|
|
11351
11641
|
var GOAL_COMPLETE_MARKER2 = /^\s*\[goal[_\s-]?complete\]\s*$/im;
|
|
11352
11642
|
var ParallelEternalEngine = class {
|
|
11353
11643
|
constructor(opts) {
|
|
@@ -11503,7 +11793,7 @@ var ParallelEternalEngine = class {
|
|
|
11503
11793
|
// Fan-out
|
|
11504
11794
|
// -------------------------------------------------------------------------
|
|
11505
11795
|
async fanOut(goal, tasks) {
|
|
11506
|
-
const coordinator =
|
|
11796
|
+
const coordinator = expectDefined(this.coordinator);
|
|
11507
11797
|
const slotCount = Math.min(this.slots, tasks.length);
|
|
11508
11798
|
const routes = this.dispatchEnabled ? await Promise.all(
|
|
11509
11799
|
tasks.slice(0, slotCount).map(
|
|
@@ -11535,7 +11825,7 @@ ${recentJournal}` : "No prior iterations.",
|
|
|
11535
11825
|
const routeInfo = [];
|
|
11536
11826
|
const spawnPromises = [];
|
|
11537
11827
|
for (let i = 0; i < slotCount; i++) {
|
|
11538
|
-
const task =
|
|
11828
|
+
const task = expectDefined(tasks[i]);
|
|
11539
11829
|
const route = routes[i] ?? null;
|
|
11540
11830
|
const subagentId = `parallel-${this.iterations}-${i}`;
|
|
11541
11831
|
const taskId = randomUUID();
|
|
@@ -12026,12 +12316,6 @@ function createMessage(type, from, payload, to) {
|
|
|
12026
12316
|
priority: "normal"
|
|
12027
12317
|
};
|
|
12028
12318
|
}
|
|
12029
|
-
function expectDefined10(value) {
|
|
12030
|
-
if (value === null || value === void 0) {
|
|
12031
|
-
throw new Error("Expected value to be defined");
|
|
12032
|
-
}
|
|
12033
|
-
return value;
|
|
12034
|
-
}
|
|
12035
12319
|
var GLOB_CHARS = /* @__PURE__ */ new Set(["*", "?", "["]);
|
|
12036
12320
|
var IS_WINDOWS = process.platform === "win32";
|
|
12037
12321
|
var SEP = IS_WINDOWS ? "\\" : "/";
|
|
@@ -12045,7 +12329,7 @@ function globToRegex(pat) {
|
|
|
12045
12329
|
let i = 0;
|
|
12046
12330
|
let re = "^";
|
|
12047
12331
|
while (i < pat.length) {
|
|
12048
|
-
const c =
|
|
12332
|
+
const c = expectDefined(pat[i]);
|
|
12049
12333
|
if (c === "*") {
|
|
12050
12334
|
if (pat[i + 1] === "*") {
|
|
12051
12335
|
re += ".*";
|
|
@@ -12084,7 +12368,7 @@ function globToRegex(pat) {
|
|
|
12084
12368
|
}
|
|
12085
12369
|
function baseDir(pat) {
|
|
12086
12370
|
let i = pat.length - 1;
|
|
12087
|
-
while (i >= 0 && !GLOB_CHARS.has(
|
|
12371
|
+
while (i >= 0 && !GLOB_CHARS.has(expectDefined(pat[i])) && pat[i] !== SEP && pat[i] !== "/") i--;
|
|
12088
12372
|
const cut = i >= 0 ? pat.lastIndexOf(SEP, i) : pat.lastIndexOf("/", i);
|
|
12089
12373
|
return cut < 0 ? "." : pat.slice(0, cut);
|
|
12090
12374
|
}
|
|
@@ -12165,6 +12449,7 @@ var CollabSession = class extends EventEmitter {
|
|
|
12165
12449
|
settled = false;
|
|
12166
12450
|
timeoutMs;
|
|
12167
12451
|
cancelled = false;
|
|
12452
|
+
_raceResolved = false;
|
|
12168
12453
|
alerts = [];
|
|
12169
12454
|
snapshotWarnings = [];
|
|
12170
12455
|
/** Tracks tool call counts per subagent for progress-based timeout decisions. */
|
|
@@ -12261,7 +12546,7 @@ var CollabSession = class extends EventEmitter {
|
|
|
12261
12546
|
* Safe to call multiple times (idempotent after first call).
|
|
12262
12547
|
*/
|
|
12263
12548
|
cancel(reason = "Director cancelled collab session") {
|
|
12264
|
-
if (this.
|
|
12549
|
+
if (this.cancelled) return;
|
|
12265
12550
|
this.cancelled = true;
|
|
12266
12551
|
if (this._timeoutTimer) {
|
|
12267
12552
|
clearTimeout(this._timeoutTimer);
|
|
@@ -12299,6 +12584,7 @@ var CollabSession = class extends EventEmitter {
|
|
|
12299
12584
|
this.subagentIds.set("critic", criticId);
|
|
12300
12585
|
const timeout = new Promise((_, reject) => {
|
|
12301
12586
|
this._timeoutTimer = setTimeout(() => {
|
|
12587
|
+
if (this._raceResolved) return;
|
|
12302
12588
|
this.cancel("Session-level timeout reached");
|
|
12303
12589
|
reject(new Error(`CollabSession timed out after ${this.timeoutMs}ms`));
|
|
12304
12590
|
}, this.timeoutMs);
|
|
@@ -12314,6 +12600,7 @@ var CollabSession = class extends EventEmitter {
|
|
|
12314
12600
|
timeout
|
|
12315
12601
|
]);
|
|
12316
12602
|
} catch (err) {
|
|
12603
|
+
this._raceResolved = true;
|
|
12317
12604
|
if (this._timeoutTimer) {
|
|
12318
12605
|
clearTimeout(this._timeoutTimer);
|
|
12319
12606
|
this._timeoutTimer = void 0;
|
|
@@ -12328,6 +12615,7 @@ var CollabSession = class extends EventEmitter {
|
|
|
12328
12615
|
}
|
|
12329
12616
|
this.snapshotWarnings = await this.checkSnapshotFreshness();
|
|
12330
12617
|
const report = this.assembleReport();
|
|
12618
|
+
this._raceResolved = true;
|
|
12331
12619
|
this.cleanup();
|
|
12332
12620
|
this.emit("session.done", report);
|
|
12333
12621
|
return report;
|
|
@@ -17035,12 +17323,6 @@ var TaskGraphStore = class {
|
|
|
17035
17323
|
};
|
|
17036
17324
|
|
|
17037
17325
|
// src/sdd/spec-builder.ts
|
|
17038
|
-
function expectDefined11(value) {
|
|
17039
|
-
if (value === null || value === void 0) {
|
|
17040
|
-
throw new Error("Expected value to be defined");
|
|
17041
|
-
}
|
|
17042
|
-
return value;
|
|
17043
|
-
}
|
|
17044
17326
|
function buildQuestioningPrompt(session, min, max) {
|
|
17045
17327
|
const answered = session.answers.length;
|
|
17046
17328
|
const remaining = Math.max(0, min - answered);
|
|
@@ -17086,7 +17368,7 @@ function buildQuestioningPrompt(session, min, max) {
|
|
|
17086
17368
|
if (answered > 0) {
|
|
17087
17369
|
lines.push("", "**Conversation so far:**");
|
|
17088
17370
|
for (let i = 0; i < answered; i++) {
|
|
17089
|
-
const a =
|
|
17371
|
+
const a = expectDefined(session.answers[i]);
|
|
17090
17372
|
lines.push(``, `Q${i + 1}: ${a.question}`, `A${i + 1}: ${a.answer}`);
|
|
17091
17373
|
}
|
|
17092
17374
|
}
|
|
@@ -17828,12 +18110,6 @@ function truncate2(str, maxLen) {
|
|
|
17828
18110
|
}
|
|
17829
18111
|
|
|
17830
18112
|
// src/sdd/critical-path.ts
|
|
17831
|
-
function expectDefined12(value) {
|
|
17832
|
-
if (value === null || value === void 0) {
|
|
17833
|
-
throw new Error("Expected value to be defined");
|
|
17834
|
-
}
|
|
17835
|
-
return value;
|
|
17836
|
-
}
|
|
17837
18113
|
function analyzeCriticalPath(graph) {
|
|
17838
18114
|
const nodes = Array.from(graph.nodes.values());
|
|
17839
18115
|
const topoOrder = topologicalSort(graph);
|
|
@@ -17909,7 +18185,7 @@ function getTransitiveBlocked(_graph, taskId, blocksMap) {
|
|
|
17909
18185
|
const visited = /* @__PURE__ */ new Set();
|
|
17910
18186
|
const queue = [taskId];
|
|
17911
18187
|
while (queue.length > 0) {
|
|
17912
|
-
const current =
|
|
18188
|
+
const current = expectDefined(queue.shift());
|
|
17913
18189
|
const blocked = blocksMap.get(current);
|
|
17914
18190
|
if (!blocked) continue;
|
|
17915
18191
|
for (const id of blocked) {
|
|
@@ -17955,7 +18231,7 @@ function computeCriticalPath(graph, _topoOrder, blockedByMap) {
|
|
|
17955
18231
|
if (!changed) break;
|
|
17956
18232
|
}
|
|
17957
18233
|
let maxDist = 0;
|
|
17958
|
-
let maxId =
|
|
18234
|
+
let maxId = expectDefined(allIds[0]);
|
|
17959
18235
|
for (const id of allIds) {
|
|
17960
18236
|
const d = dist.get(id) ?? 0;
|
|
17961
18237
|
if (d > maxDist) {
|
|
@@ -18424,12 +18700,6 @@ var SddTaskDecomposer = class {
|
|
|
18424
18700
|
return nodes.some((n) => n.status === "blocked");
|
|
18425
18701
|
}
|
|
18426
18702
|
};
|
|
18427
|
-
function expectDefined13(value) {
|
|
18428
|
-
if (value === null || value === void 0) {
|
|
18429
|
-
throw new Error("Expected value to be defined");
|
|
18430
|
-
}
|
|
18431
|
-
return value;
|
|
18432
|
-
}
|
|
18433
18703
|
var SddParallelRun = class {
|
|
18434
18704
|
constructor(opts) {
|
|
18435
18705
|
this.opts = opts;
|
|
@@ -18578,8 +18848,8 @@ var SddParallelRun = class {
|
|
|
18578
18848
|
const successCount = results.filter((r) => r.status === "success").length;
|
|
18579
18849
|
const failCount = results.length - successCount;
|
|
18580
18850
|
for (let i = 0; i < results.length; i++) {
|
|
18581
|
-
const result =
|
|
18582
|
-
const taskId =
|
|
18851
|
+
const result = expectDefined(results[i]);
|
|
18852
|
+
const taskId = expectDefined(taskIds[i]);
|
|
18583
18853
|
if (result.status === "success") {
|
|
18584
18854
|
this.opts.tracker.updateNodeStatus(taskId, "completed");
|
|
18585
18855
|
} else {
|