@wrongstack/core 0.89.1 → 0.104.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 (87) hide show
  1. package/dist/{agent-bridge-B8F2ORwg.d.ts → agent-bridge-mOxbpFcg.d.ts} +1 -1
  2. package/dist/{agent-subagent-runner-CQaLFNnA.d.ts → agent-subagent-runner-DukQLUcS.d.ts} +433 -433
  3. package/dist/{events-DzyLtja6.d.ts → brain-Dfv4Y82E.d.ts} +179 -92
  4. package/dist/{compactor-CJq7LQev.d.ts → compactor-DXLxLcmU.d.ts} +2 -2
  5. package/dist/{config-_DZ7dN-T.d.ts → config-BSU-6vah.d.ts} +45 -38
  6. package/dist/{context-ToHAp4-U.d.ts → context-CNRYfhUv.d.ts} +1 -1
  7. package/dist/coordination/index.d.ts +16 -17
  8. package/dist/coordination/index.js +128 -37
  9. package/dist/coordination/index.js.map +1 -1
  10. package/dist/defaults/index.d.ts +34 -35
  11. package/dist/defaults/index.js +752 -218
  12. package/dist/defaults/index.js.map +1 -1
  13. package/dist/{director-state-CgIc30qi.d.ts → director-state-BfeCUbmk.d.ts} +1 -1
  14. package/dist/execution/index.d.ts +65 -370
  15. package/dist/execution/index.js +446 -53
  16. package/dist/execution/index.js.map +1 -1
  17. package/dist/extension/index.d.ts +9 -10
  18. package/dist/extension/index.js +8 -6
  19. package/dist/extension/index.js.map +1 -1
  20. package/dist/goal-preamble-CI8lxeY1.d.ts +378 -0
  21. package/dist/{goal-store-DvWLNu52.d.ts → goal-store-ht0VmR1A.d.ts} +63 -21
  22. package/dist/{index-Ca_lOmKl.d.ts → index-BWRN6wOb.d.ts} +13 -15
  23. package/dist/{index-Dx-CnrDN.d.ts → index-DIKEcfgC.d.ts} +9 -10
  24. package/dist/index.d.ts +188 -176
  25. package/dist/index.js +1508 -407
  26. package/dist/index.js.map +1 -1
  27. package/dist/infrastructure/index.d.ts +9 -9
  28. package/dist/infrastructure/index.js +4 -2
  29. package/dist/infrastructure/index.js.map +1 -1
  30. package/dist/kernel/index.d.ts +14 -16
  31. package/dist/kernel/index.js.map +1 -1
  32. package/dist/{logger-B72yyPc6.d.ts → logger-B63L5bTg.d.ts} +1 -1
  33. package/dist/{logger-C_27pj9i.d.ts → logger-B9J5puGM.d.ts} +1 -1
  34. package/dist/{mcp-servers-Dck3T85_.d.ts → mcp-servers-CXCsANdY.d.ts} +3 -3
  35. package/dist/{mode-CHo2XtHs.d.ts → mode-ARA3HrkY.d.ts} +1 -1
  36. package/dist/models/index.d.ts +5 -5
  37. package/dist/models/index.js +8 -6
  38. package/dist/models/index.js.map +1 -1
  39. package/dist/{models-registry-Be3osGt5.d.ts → models-registry-B6_KfS65.d.ts} +1 -1
  40. package/dist/{models-registry-Boz639EI.d.ts → models-registry-DU64QxQa.d.ts} +1 -1
  41. package/dist/{multi-agent-coordinator-Da9nd8Ic.d.ts → multi-agent-coordinator-51LvnXkD.d.ts} +2 -2
  42. package/dist/{null-fleet-bus-CHJOXv3t.d.ts → null-fleet-bus-D09hMzFQ.d.ts} +32 -31
  43. package/dist/observability/index.d.ts +3 -3
  44. package/dist/{observability-CoSNZdhX.d.ts → observability-D-HZN_mF.d.ts} +1 -1
  45. package/dist/{parallel-eternal-engine-DyMCj2Pw.d.ts → parallel-eternal-engine-CUtmM_0V.d.ts} +54 -35
  46. package/dist/{path-resolver-TjBlRKyH.d.ts → path-resolver-DDJiMAtX.d.ts} +3 -3
  47. package/dist/{permission-14CChMmO.d.ts → permission-BDv7z0mk.d.ts} +7 -2
  48. package/dist/{permission-policy-gW5htOo1.d.ts → permission-policy-dF74EpDp.d.ts} +2 -2
  49. package/dist/{system-prompt-C0rLCeyn.d.ts → pipeline-BqiA_UMr.d.ts} +73 -73
  50. package/dist/{plan-templates-D9UhwoGh.d.ts → plan-templates-BdDxl9cI.d.ts} +79 -11
  51. package/dist/{provider-runner-BEPWwkxH.d.ts → provider-runner-BUunikwY.d.ts} +5 -5
  52. package/dist/{retry-policy-DSu6O6rD.d.ts → retry-policy-BcmuT_V0.d.ts} +2 -2
  53. package/dist/sdd/index.d.ts +17 -33
  54. package/dist/sdd/index.js +145 -36
  55. package/dist/sdd/index.js.map +1 -1
  56. package/dist/{secret-scrubber-yGBFQYju.d.ts → secret-vault-DrOhc2i5.d.ts} +7 -7
  57. package/dist/security/index.d.ts +4 -5
  58. package/dist/security/index.js +4 -2
  59. package/dist/security/index.js.map +1 -1
  60. package/dist/{selector-11-fm95U.d.ts → selector-C7wcdqMA.d.ts} +1 -1
  61. package/dist/{session-event-bridge-D0u-x576.d.ts → session-event-bridge-BpJ5trO9.d.ts} +2 -2
  62. package/dist/{session-reader-BQU-toaN.d.ts → session-reader-DDz1Ek4V.d.ts} +2 -2
  63. package/dist/{skill-BJeF2DwY.d.ts → skill-Bj6Ezqb8.d.ts} +1 -1
  64. package/dist/skills/index.d.ts +1 -1
  65. package/dist/skills/index.js +3 -9
  66. package/dist/skills/index.js.map +1 -1
  67. package/dist/spec-TBi3Jr6T.d.ts +78 -0
  68. package/dist/storage/index.d.ts +145 -13
  69. package/dist/storage/index.js +990 -172
  70. package/dist/storage/index.js.map +1 -1
  71. package/dist/task-format-vGOIftmK.d.ts +23 -0
  72. package/dist/task-graph-u1q9Jkyk.d.ts +84 -0
  73. package/dist/types/index.d.ts +27 -28
  74. package/dist/types/index.js +19 -31
  75. package/dist/types/index.js.map +1 -1
  76. package/dist/utils/expect-defined.d.ts +7 -0
  77. package/dist/utils/expect-defined.js +11 -0
  78. package/dist/utils/expect-defined.js.map +1 -0
  79. package/dist/utils/index.d.ts +8 -20
  80. package/dist/utils/index.js +120 -41
  81. package/dist/utils/index.js.map +1 -1
  82. package/dist/{wstack-paths-BQMvEllz.d.ts → wstack-paths-_lqjzErq.d.ts} +1 -1
  83. package/package.json +5 -1
  84. package/skills/tech-stack/SKILL.md +177 -0
  85. package/dist/memory-CEXuo7sz.d.ts +0 -16
  86. package/dist/secret-scrubber-3MHDDAtm.d.ts +0 -6
  87. package/dist/task-graph-CikNdRTG.d.ts +0 -161
@@ -2,13 +2,15 @@ import { randomBytes, randomUUID, createHash } from 'crypto';
2
2
  import * as fsp from 'fs/promises';
3
3
  import * as path2 from 'path';
4
4
  import * as os from 'os';
5
+ import { hostname } from 'os';
5
6
 
6
- var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
7
- get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
8
- }) : x)(function(x) {
9
- if (typeof require !== "undefined") return require.apply(this, arguments);
10
- throw Error('Dynamic require of "' + x + '" is not supported');
11
- });
7
+ // src/utils/expect-defined.ts
8
+ function expectDefined(value, label) {
9
+ if (value === null || value === void 0) {
10
+ throw new Error("Expected value to be defined");
11
+ }
12
+ return value;
13
+ }
12
14
  async function atomicWrite(targetPath, content, opts = {}) {
13
15
  const dir = path2.dirname(targetPath);
14
16
  await fsp.mkdir(dir, { recursive: true });
@@ -118,12 +120,6 @@ async function renameWithRetry(from, to) {
118
120
  }
119
121
 
120
122
  // src/utils/message-invariants.ts
121
- function expectDefined(value) {
122
- if (value === null || value === void 0) {
123
- throw new Error("Expected value to be defined");
124
- }
125
- return value;
126
- }
127
123
  function repairToolUseAdjacency(messages) {
128
124
  const removedToolUses = [];
129
125
  const removedToolResults = [];
@@ -216,12 +212,6 @@ function isEmptyMessage(msg) {
216
212
  }
217
213
 
218
214
  // src/storage/session-store.ts
219
- function expectDefined2(value) {
220
- if (value === null || value === void 0) {
221
- throw new Error("Expected value to be defined");
222
- }
223
- return value;
224
- }
225
215
  function sanitizeModel(model) {
226
216
  return model.replace(/[^a-zA-Z0-9_-]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "").slice(0, 40);
227
217
  }
@@ -932,7 +922,7 @@ var FileSessionWriter = class {
932
922
  let targetCheckpointLine = -1;
933
923
  let afterTarget = false;
934
924
  for (let i = 0; i < lines.length; i++) {
935
- const line = expectDefined2(lines[i]);
925
+ const line = expectDefined(lines[i]);
936
926
  if (!line.trim()) continue;
937
927
  let event;
938
928
  try {
@@ -1221,9 +1211,235 @@ function mergeAdjacentText(blocks) {
1221
1211
  }
1222
1212
  return out;
1223
1213
  }
1214
+
1215
+ // src/types/memory.ts
1216
+ var MEMORY_TYPE_LABELS = {
1217
+ fact: "Fact",
1218
+ decision: "Decision",
1219
+ convention: "Convention",
1220
+ preference: "Preference",
1221
+ reference: "Reference",
1222
+ anti_pattern: "Anti-pattern"
1223
+ };
1224
+
1225
+ // src/storage/memory-backend.ts
1226
+ var TYPE_PRIORITY_RE = /^\[(\w+)\|(\w+)\]\s+/;
1227
+ var TAG_RE = /#([\w-]+)/g;
1228
+ function formatMetadata(entry) {
1229
+ const parts = [];
1230
+ if (entry.type && entry.priority) {
1231
+ parts.push(`[${entry.type}|${entry.priority}]`);
1232
+ } else if (entry.type) {
1233
+ parts.push(`[${entry.type}]`);
1234
+ } else if (entry.priority) {
1235
+ parts.push(`[${entry.priority}]`);
1236
+ }
1237
+ if (entry.tags && entry.tags.length > 0) {
1238
+ parts.push(entry.tags.map((t) => `#${t}`).join(" "));
1239
+ }
1240
+ return parts.length > 0 ? ` ${parts.join(" ")}` : "";
1241
+ }
1242
+ function lineToEntry(line, scope) {
1243
+ const trimmed = line.trim();
1244
+ if (!trimmed.startsWith("- [")) return null;
1245
+ const tsMatch = trimmed.match(/^-\s*\[([^\]]+)\]/);
1246
+ if (!tsMatch) return null;
1247
+ const ts = tsMatch[1] ?? "";
1248
+ let rest = trimmed.slice(tsMatch[0].length).trim();
1249
+ let type;
1250
+ let priority;
1251
+ const tpMatch = rest.match(TYPE_PRIORITY_RE);
1252
+ if (tpMatch) {
1253
+ const a = tpMatch[1] ?? "";
1254
+ const b = tpMatch[2] ?? "";
1255
+ if (isMemoryType(a)) {
1256
+ type = a;
1257
+ priority = isPriority(b) ? b : void 0;
1258
+ } else if (isPriority(a)) {
1259
+ priority = a;
1260
+ }
1261
+ rest = rest.slice(tpMatch[0].length).trim();
1262
+ }
1263
+ const idMatch = rest.match(/^mem_\d+_\w+\s+/);
1264
+ let text;
1265
+ if (idMatch) {
1266
+ text = rest.slice(idMatch[0].length).trim();
1267
+ } else {
1268
+ text = rest.trim();
1269
+ }
1270
+ const tags = [];
1271
+ let tagMatch;
1272
+ TAG_RE.lastIndex = 0;
1273
+ while ((tagMatch = TAG_RE.exec(text)) !== null) {
1274
+ tags.push(tagMatch[1] ?? "");
1275
+ }
1276
+ const cleanText = text.replace(TAG_RE, "").replace(/\s{2,}/g, " ").trim();
1277
+ if (!cleanText) return null;
1278
+ return {
1279
+ scope,
1280
+ text: cleanText,
1281
+ ts,
1282
+ type,
1283
+ priority,
1284
+ tags: tags.length > 0 ? tags : void 0
1285
+ };
1286
+ }
1287
+ function isMemoryType(s) {
1288
+ return s in MEMORY_TYPE_LABELS;
1289
+ }
1290
+ function isPriority(s) {
1291
+ return s === "critical" || s === "high" || s === "medium" || s === "low";
1292
+ }
1293
+ var FileMemoryBackend = class {
1294
+ kind = "file";
1295
+ files;
1296
+ constructor(opts) {
1297
+ this.files = {
1298
+ "project-agents": opts.paths.inProjectAgentsFile,
1299
+ "project-memory": opts.paths.projectMemory,
1300
+ "user-memory": opts.paths.globalMemory
1301
+ };
1302
+ }
1303
+ resolveFile(filePath, scope) {
1304
+ return filePath || this.files[scope];
1305
+ }
1306
+ async remember(scope, entry, filePath) {
1307
+ const file = this.resolveFile(filePath, scope);
1308
+ await ensureDir(path2.dirname(file));
1309
+ let existing = "";
1310
+ try {
1311
+ existing = await fsp.readFile(file, "utf8");
1312
+ } catch {
1313
+ }
1314
+ const id = `mem_${Date.now()}_${randomUUID().slice(0, 8)}`;
1315
+ const meta = formatMetadata(entry);
1316
+ const line = `
1317
+ - [${entry.ts}] ${id}${meta} ${entry.text.replace(/\n/g, " ")}
1318
+ `;
1319
+ const next = existing.trim() ? existing.replace(/\n+$/, "") + line : `# WrongStack Memory
1320
+ ${line}`;
1321
+ await atomicWrite(file, next);
1322
+ }
1323
+ async forget(scope, query, filePath) {
1324
+ const file = this.resolveFile(filePath, scope);
1325
+ let existing;
1326
+ try {
1327
+ existing = await fsp.readFile(file, "utf8");
1328
+ } catch {
1329
+ return 0;
1330
+ }
1331
+ const needle = query.toLowerCase();
1332
+ const idMatcher = /mem_\d+_\w+/;
1333
+ let removed = 0;
1334
+ const lines = existing.split("\n").filter((line) => {
1335
+ const trimmed = line.trim();
1336
+ if (!trimmed.startsWith("- ")) return true;
1337
+ if (idMatcher.test(query)) {
1338
+ const entryIdMatch = /mem_\d+_\w+/.exec(trimmed);
1339
+ if (entryIdMatch && entryIdMatch[0] === query) {
1340
+ removed++;
1341
+ return false;
1342
+ }
1343
+ }
1344
+ if (trimmed.toLowerCase().includes(needle)) {
1345
+ removed++;
1346
+ return false;
1347
+ }
1348
+ return true;
1349
+ });
1350
+ if (removed > 0) {
1351
+ if (lines.length === 0 || lines.length === 1 && !lines[0]?.trim()) {
1352
+ await atomicWrite(file, "");
1353
+ } else {
1354
+ await atomicWrite(file, lines.join("\n"));
1355
+ }
1356
+ }
1357
+ return removed;
1358
+ }
1359
+ async readAll(scope, filePath) {
1360
+ const file = this.resolveFile(filePath, scope);
1361
+ try {
1362
+ return await fsp.readFile(file, "utf8");
1363
+ } catch {
1364
+ return "";
1365
+ }
1366
+ }
1367
+ async list(scope, filePath, limit) {
1368
+ const raw = await this.readAll(scope, filePath);
1369
+ if (!raw.trim()) return [];
1370
+ const entries = parseEntries(raw, scope);
1371
+ return limit ? entries.slice(0, limit) : entries;
1372
+ }
1373
+ async search(scope, query, filePath, limit) {
1374
+ const entries = await this.list(scope, filePath);
1375
+ const needle = query.toLowerCase().split(/\s+/);
1376
+ const scored = entries.map((e) => {
1377
+ const words = e.text.toLowerCase().split(/\s+/);
1378
+ let score = 0;
1379
+ for (const n of needle) {
1380
+ if (words.some((w) => w.includes(n))) score += 1;
1381
+ if (e.tags?.some((t) => t.toLowerCase().includes(n))) score += 2;
1382
+ }
1383
+ return { entry: e, score };
1384
+ });
1385
+ scored.sort((a, b) => b.score - a.score);
1386
+ const matched = scored.filter((s) => s.score > 0).map((s) => s.entry);
1387
+ return limit ? matched.slice(0, limit) : matched;
1388
+ }
1389
+ async clear(scope, filePath) {
1390
+ const file = this.resolveFile(filePath, scope);
1391
+ await atomicWrite(file, "");
1392
+ }
1393
+ async consolidate(scope, filePath) {
1394
+ const file = this.resolveFile(filePath, scope);
1395
+ let existing;
1396
+ try {
1397
+ existing = await fsp.readFile(file, "utf8");
1398
+ } catch {
1399
+ return 0;
1400
+ }
1401
+ const seen = /* @__PURE__ */ new Set();
1402
+ let removed = 0;
1403
+ const lines = existing.split("\n").filter((line) => {
1404
+ const trimmed = line.trim();
1405
+ if (!trimmed.startsWith("- ")) return true;
1406
+ const norm = trimmed.replace(/\[[^\]]+\]/g, "").replace(/\bmem_\d+_\w+\s*/, "").replace(/#[\w-]+/g, "").replace(/\s+/g, " ").trim().toLowerCase();
1407
+ if (seen.has(norm)) {
1408
+ removed++;
1409
+ return false;
1410
+ }
1411
+ seen.add(norm);
1412
+ return true;
1413
+ });
1414
+ const next = lines.join("\n");
1415
+ const backup = `${file}.bak.${Date.now()}`;
1416
+ try {
1417
+ await fsp.copyFile(file, backup);
1418
+ } catch {
1419
+ }
1420
+ try {
1421
+ await atomicWrite(file, next);
1422
+ } catch {
1423
+ return 0;
1424
+ }
1425
+ return removed;
1426
+ }
1427
+ };
1428
+ function parseEntries(raw, scope = "project-memory") {
1429
+ const entries = [];
1430
+ for (const line of raw.split("\n")) {
1431
+ const entry = lineToEntry(line, scope);
1432
+ if (entry) entries.push(entry);
1433
+ }
1434
+ return entries.reverse();
1435
+ }
1436
+
1437
+ // src/storage/memory-store.ts
1224
1438
  var MAX_BYTES_TOTAL = 32e3;
1225
1439
  var DefaultMemoryStore = class {
1226
1440
  files;
1441
+ events;
1442
+ backend;
1227
1443
  /**
1228
1444
  * Per-scope serialization queue. `remember` / `forget` / `consolidate` /
1229
1445
  * `clear` are read-modify-write against a single file; without a lock,
@@ -1240,12 +1456,29 @@ var DefaultMemoryStore = class {
1240
1456
  writeChain = /* @__PURE__ */ new Map();
1241
1457
  /** Last write error per scope — surfaced as warnings on the next readAll(). */
1242
1458
  writeErrors = /* @__PURE__ */ new Map();
1459
+ /**
1460
+ * When the global root is a temporary directory (opencode, CI sandboxes),
1461
+ * memory files are also mirrored to the project tree so they survive
1462
+ * session cleanup. The primary path stays in the temp root for isolation;
1463
+ * this backup ensures memory is never lost.
1464
+ */
1465
+ persistBackup;
1466
+ backupDir;
1243
1467
  constructor(opts) {
1244
1468
  this.files = {
1245
1469
  "project-agents": opts.paths.inProjectAgentsFile,
1246
1470
  "project-memory": opts.paths.projectMemory,
1247
1471
  "user-memory": opts.paths.globalMemory
1248
1472
  };
1473
+ this.events = opts.events;
1474
+ this.backend = opts.backend ?? new FileMemoryBackend({ paths: opts.paths });
1475
+ const root = opts.paths.globalRoot.toLowerCase();
1476
+ this.persistBackup = /[/\\](tmp|temp|cache)[/\\]/.test(root);
1477
+ this.backupDir = this.persistBackup ? opts.paths.inProjectAgentsFile.replace(/AGENTS\.md$/, "memory-persist") : "";
1478
+ }
1479
+ /** Expose the backend for plugin introspection and advanced queries. */
1480
+ getBackend() {
1481
+ return this.backend;
1249
1482
  }
1250
1483
  async runSerialized(scope, work) {
1251
1484
  const prior = this.writeChain.get(scope) ?? Promise.resolve();
@@ -1272,7 +1505,7 @@ var DefaultMemoryStore = class {
1272
1505
  if (writeErr) {
1273
1506
  parts.push(`> \u26A0\uFE0F Memory write error (${labelOf(scope)}): ${writeErr.message}`);
1274
1507
  }
1275
- const body = await this.read(scope);
1508
+ const body = await this.backend.readAll(scope, this.files[scope]);
1276
1509
  if (body.trim()) parts.push(`## ${labelOf(scope)}
1277
1510
 
1278
1511
  ${body.trim()}`);
@@ -1280,117 +1513,214 @@ ${body.trim()}`);
1280
1513
  return parts.join("\n\n");
1281
1514
  }
1282
1515
  async read(scope) {
1283
- try {
1284
- return await fsp.readFile(this.files[scope], "utf8");
1285
- } catch {
1286
- return "";
1516
+ return this.backend.readAll(scope, this.files[scope]);
1517
+ }
1518
+ /**
1519
+ * List entries from a scope, newest first. Delegates to the backend
1520
+ * so graph/semantic backends can return enriched or filtered results.
1521
+ */
1522
+ async list(scope = "project-memory", limit) {
1523
+ return this.backend.list(scope, this.files[scope], limit);
1524
+ }
1525
+ /**
1526
+ * Find memories related to the given text via graph traversal.
1527
+ * Falls back to content search when no graph backend is available.
1528
+ */
1529
+ async findRelated(text, scope = "project-memory", limit = 5) {
1530
+ if (this.backend.findRelated) {
1531
+ return this.backend.findRelated(scope, this.files[scope], text, limit);
1287
1532
  }
1533
+ return this.search(text, scope, limit);
1288
1534
  }
1289
- async remember(text, scope = "project-memory") {
1535
+ async search(query, scope = "project-memory", limit) {
1536
+ return this.backend.search(scope, query, this.files[scope], limit);
1537
+ }
1538
+ async remember(text, scope = "project-memory", metadata) {
1539
+ const ts = (/* @__PURE__ */ new Date()).toISOString();
1290
1540
  return this.runSerialized(scope, async () => {
1291
- const file = this.files[scope];
1292
- await ensureDir(path2.dirname(file));
1293
- let existing = "";
1294
- try {
1295
- existing = await fsp.readFile(file, "utf8");
1296
- } catch {
1297
- }
1298
- const ts = (/* @__PURE__ */ new Date()).toISOString();
1299
- const id = `mem_${Date.now()}_${randomUUID().slice(0, 8)}`;
1300
- const entry = `
1301
- - [${ts}] ${id} ${text.replace(/\n/g, " ")}
1302
- `;
1303
- const next = existing.trim() ? existing.replace(/\n+$/, "") + entry : `# WrongStack Memory
1304
- ${entry}`;
1305
- await atomicWrite(file, next);
1306
- const buf = Buffer.byteLength(next, "utf8");
1307
- if (buf > MAX_BYTES_TOTAL) {
1308
- await this.consolidateUnsafe(scope);
1541
+ const entry = { scope, text, ts, ...metadata };
1542
+ await this.backend.remember(scope, entry, this.files[scope]);
1543
+ const raw = await this.backend.readAll(scope, this.files[scope]);
1544
+ if (Buffer.byteLength(raw, "utf8") > MAX_BYTES_TOTAL) {
1545
+ const removed = await this.backend.consolidate(scope, this.files[scope]);
1546
+ if (removed > 0) {
1547
+ this.events?.emit("memory.consolidated", {
1548
+ scope,
1549
+ removed
1550
+ });
1551
+ }
1309
1552
  }
1553
+ await this.mirrorBackup(scope);
1554
+ this.events?.emit("memory.remembered", {
1555
+ scope,
1556
+ text,
1557
+ ts,
1558
+ type: entry.type,
1559
+ tags: entry.tags,
1560
+ priority: entry.priority
1561
+ });
1310
1562
  });
1311
1563
  }
1312
- async forget(query, scope = "project-memory") {
1313
- return this.runSerialized(scope, async () => this.forgetUnsafe(query, scope));
1314
- }
1315
- async forgetUnsafe(query, scope) {
1316
- const file = this.files[scope];
1317
- let existing;
1318
- try {
1319
- existing = await fsp.readFile(file, "utf8");
1320
- } catch {
1321
- return 0;
1322
- }
1323
- const needle = query.toLowerCase();
1324
- const idMatcher = /mem_\d+_\w+/;
1325
- let removed = 0;
1326
- const lines = existing.split("\n").filter((line) => {
1327
- const trimmed = line.trim();
1328
- if (!trimmed.startsWith("- ")) return true;
1329
- if (idMatcher.test(query)) {
1330
- const afterBracket = trimmed.indexOf("] ");
1331
- if (afterBracket !== -1) {
1332
- const afterTs = trimmed.slice(afterBracket + 2);
1333
- const entryIdMatch = /^mem_\d+_\w+/.exec(afterTs);
1334
- if (entryIdMatch && entryIdMatch[0] === query) {
1335
- removed++;
1336
- return false;
1337
- }
1564
+ /**
1565
+ * Score and rank memories by relevance to the current context.
1566
+ * Returns entries with score >= MIN_RELEVANCE_SCORE, sorted highest first.
1567
+ */
1568
+ async scoreRelevant(ctx, scope = "project-memory", limit = 8) {
1569
+ const all = await this.list(scope);
1570
+ if (all.length === 0) return [];
1571
+ const taskWords = ctx.currentTask.toLowerCase().split(/\s+/).filter((w) => w.length > 2);
1572
+ const skillWords = (ctx.activeSkills ?? []).flatMap((s) => s.split("-"));
1573
+ const toolWords = (ctx.toolNames ?? []).flatMap((t) => t.toLowerCase().split("_"));
1574
+ const now = Date.now();
1575
+ const scored = [];
1576
+ for (const entry of all) {
1577
+ let score = 0;
1578
+ const reasons = [];
1579
+ const textLower = entry.text.toLowerCase();
1580
+ const tagsLower = (entry.tags ?? []).map((t) => t.toLowerCase());
1581
+ let taskHits = 0;
1582
+ for (const w of taskWords) {
1583
+ if (textLower.includes(w)) {
1584
+ taskHits++;
1585
+ score += 2;
1586
+ }
1587
+ if (tagsLower.some((t) => t.includes(w))) {
1588
+ taskHits++;
1589
+ score += 3;
1338
1590
  }
1339
1591
  }
1340
- if (trimmed.toLowerCase().includes(needle)) {
1341
- removed++;
1342
- return false;
1592
+ if (taskHits > 0) reasons.push(`task match (${taskHits})`);
1593
+ let skillHits = 0;
1594
+ for (const w of skillWords) {
1595
+ if (w.length > 2 && (textLower.includes(w) || tagsLower.some((t) => t.includes(w)))) {
1596
+ skillHits++;
1597
+ }
1598
+ }
1599
+ score += skillHits;
1600
+ if (skillHits > 0) reasons.push(`skill match (${skillHits})`);
1601
+ for (const w of toolWords) {
1602
+ if (w.length > 2 && (textLower.includes(w) || tagsLower.some((t) => t.includes(w)))) {
1603
+ score += 1;
1604
+ reasons.push(`tool mention: ${w}`);
1605
+ }
1606
+ }
1607
+ switch (entry.priority) {
1608
+ case "critical":
1609
+ score += 5;
1610
+ reasons.push("critical");
1611
+ break;
1612
+ case "high":
1613
+ score += 3;
1614
+ reasons.push("high priority");
1615
+ break;
1616
+ case "medium":
1617
+ score += 1;
1618
+ break;
1619
+ case "low":
1620
+ score -= 2;
1621
+ reasons.push("low priority");
1622
+ break;
1623
+ }
1624
+ switch (entry.type) {
1625
+ case "decision":
1626
+ score += 2;
1627
+ reasons.push("decision");
1628
+ break;
1629
+ case "convention":
1630
+ score += 2;
1631
+ reasons.push("convention");
1632
+ break;
1633
+ case "anti_pattern":
1634
+ score += 3;
1635
+ reasons.push("anti-pattern");
1636
+ break;
1637
+ case "preference":
1638
+ score += 1;
1639
+ reasons.push("preference");
1640
+ break;
1641
+ }
1642
+ const ageDays = (now - new Date(entry.ts).getTime()) / (1e3 * 60 * 60 * 24);
1643
+ if (ageDays < 1) score += 1;
1644
+ else if (ageDays > 30) score -= 1;
1645
+ if (entry.confidence !== void 0 && entry.confidence < 0.5) {
1646
+ score -= 2;
1647
+ reasons.push("low confidence");
1648
+ }
1649
+ if (entry.lastAccessed) {
1650
+ const hoursSinceAccess = (now - new Date(entry.lastAccessed).getTime()) / (1e3 * 60 * 60);
1651
+ if (hoursSinceAccess < 1) score -= 1;
1652
+ }
1653
+ if (score > 0) {
1654
+ scored.push({
1655
+ ...entry,
1656
+ score,
1657
+ matchReason: reasons.join(", ") || "keyword match"
1658
+ });
1343
1659
  }
1344
- return true;
1345
- });
1346
- if (removed > 0) {
1347
- await atomicWrite(file, lines.join("\n"));
1348
1660
  }
1349
- return removed;
1661
+ scored.sort((a, b) => b.score - a.score);
1662
+ const threshold = 2;
1663
+ const relevant = scored.filter(
1664
+ (s) => s.score >= threshold || s.priority === "critical" || s.priority === "high"
1665
+ );
1666
+ return relevant.slice(0, Math.min(limit, 15));
1350
1667
  }
1351
- async consolidate(scope) {
1352
- return this.runSerialized(scope, async () => this.consolidateUnsafe(scope));
1668
+ async forget(query, scope = "project-memory") {
1669
+ return this.runSerialized(scope, async () => {
1670
+ const removed = await this.backend.forget(scope, query, this.files[scope]);
1671
+ if (removed > 0) {
1672
+ this.events?.emit("memory.forgotten", {
1673
+ scope,
1674
+ query,
1675
+ removed
1676
+ });
1677
+ await this.mirrorBackup(scope);
1678
+ }
1679
+ return removed;
1680
+ });
1353
1681
  }
1354
- async consolidateUnsafe(scope) {
1355
- const file = this.files[scope];
1356
- let existing;
1357
- try {
1358
- existing = await fsp.readFile(file, "utf8");
1359
- } catch {
1360
- return;
1361
- }
1362
- const seen = /* @__PURE__ */ new Set();
1363
- const lines = existing.split("\n").filter((line) => {
1364
- const trimmed = line.trim();
1365
- if (!trimmed.startsWith("- ")) return true;
1366
- const norm = trimmed.replace(/\[[^\]]+\]/, "").replace(/\bmem_\d+_\w+\s*/, "").trim().toLowerCase();
1367
- if (seen.has(norm)) return false;
1368
- seen.add(norm);
1369
- return true;
1682
+ async consolidate(scope) {
1683
+ return this.runSerialized(scope, async () => {
1684
+ const removed = await this.backend.consolidate(scope, this.files[scope]);
1685
+ if (removed > 0) {
1686
+ this.events?.emit("memory.consolidated", {
1687
+ scope,
1688
+ removed
1689
+ });
1690
+ await this.mirrorBackup(scope);
1691
+ }
1370
1692
  });
1371
- const next = lines.join("\n");
1372
- const backup = `${file}.bak.${Date.now()}`;
1373
- try {
1374
- await fsp.copyFile(file, backup);
1375
- } catch {
1376
- }
1377
- try {
1378
- await atomicWrite(file, next);
1379
- } catch {
1380
- return;
1381
- }
1382
1693
  }
1383
1694
  async clear(scope) {
1384
1695
  if (scope) {
1385
- await this.runSerialized(scope, async () => atomicWrite(this.files[scope], ""));
1696
+ await this.runSerialized(scope, async () => {
1697
+ await this.backend.clear(scope, this.files[scope]);
1698
+ this.events?.emit("memory.cleared", { scope });
1699
+ await this.mirrorBackup(scope);
1700
+ });
1386
1701
  return;
1387
1702
  }
1388
1703
  await Promise.all(
1389
1704
  ["project-agents", "project-memory", "user-memory"].map(
1390
- (s) => this.runSerialized(s, async () => atomicWrite(this.files[s], ""))
1705
+ (s) => this.runSerialized(s, async () => {
1706
+ await this.backend.clear(s, this.files[s]);
1707
+ this.events?.emit("memory.cleared", { scope: s });
1708
+ await this.mirrorBackup(s);
1709
+ })
1391
1710
  )
1392
1711
  );
1393
1712
  }
1713
+ /** Mirror current memory content to the persistent backup directory. */
1714
+ async mirrorBackup(scope) {
1715
+ if (!this.persistBackup || scope === "project-agents") return;
1716
+ try {
1717
+ const content = await this.backend.readAll(scope, this.files[scope]);
1718
+ const { writeFile: writeFile6, mkdir: mkdir5 } = await import('fs/promises');
1719
+ await mkdir5(this.backupDir, { recursive: true });
1720
+ await writeFile6(`${this.backupDir}/${scope}.md`, content, "utf8");
1721
+ } catch {
1722
+ }
1723
+ }
1394
1724
  };
1395
1725
  function labelOf(scope) {
1396
1726
  switch (scope) {
@@ -1402,6 +1732,384 @@ function labelOf(scope) {
1402
1732
  return "User memory";
1403
1733
  }
1404
1734
  }
1735
+ var GraphMemoryBackend = class {
1736
+ kind = "graph";
1737
+ file;
1738
+ graphFile;
1739
+ // In-memory graph state — lazily loaded, saved on mutation.
1740
+ nodes = /* @__PURE__ */ new Map();
1741
+ edges = [];
1742
+ loadedScope = null;
1743
+ loaded = false;
1744
+ constructor(opts) {
1745
+ this.file = new FileMemoryBackend({ paths: opts.paths });
1746
+ this.graphFile = opts.graphPath ?? `${opts.paths.projectDir}/memory-graph.json`;
1747
+ }
1748
+ // ── Backend interface ──────────────────────────────────────────────
1749
+ async remember(scope, entry, filePath) {
1750
+ await this.file.remember(scope, entry, filePath);
1751
+ await this.loadGraph(scope);
1752
+ const nodeId = this.nodeId(entry);
1753
+ const existing = this.nodes.get(nodeId);
1754
+ if (existing) {
1755
+ existing.count++;
1756
+ existing.entry = entry;
1757
+ existing.type = entry.type;
1758
+ existing.tags = entry.tags;
1759
+ existing.priority = entry.priority;
1760
+ } else {
1761
+ this.nodes.set(nodeId, {
1762
+ id: nodeId,
1763
+ entry,
1764
+ firstSeen: entry.ts,
1765
+ count: 1,
1766
+ type: entry.type,
1767
+ tags: entry.tags,
1768
+ priority: entry.priority
1769
+ });
1770
+ for (const [, other] of this.nodes) {
1771
+ if (other.id === nodeId) continue;
1772
+ const sim = wordOverlap(entry.text, other.entry.text);
1773
+ const tagSim = sharedTags(entry.tags ?? [], other.tags ?? []);
1774
+ const weight = Math.max(sim, tagSim * 0.5);
1775
+ if (weight > 0.15) {
1776
+ this.edges.push({
1777
+ from: nodeId,
1778
+ to: other.id,
1779
+ relation: sim >= tagSim ? "similar" : "same_turn",
1780
+ weight,
1781
+ ts: entry.ts
1782
+ });
1783
+ }
1784
+ }
1785
+ }
1786
+ await this.saveGraph(scope);
1787
+ }
1788
+ async forget(scope, query, filePath) {
1789
+ const removed = await this.file.forget(scope, query, filePath);
1790
+ if (removed > 0) {
1791
+ await this.loadGraph(scope);
1792
+ const n = query.toLowerCase();
1793
+ const toRemove = [];
1794
+ for (const [id, node] of this.nodes) {
1795
+ if (node.entry.text.toLowerCase().includes(n)) {
1796
+ toRemove.push(id);
1797
+ }
1798
+ }
1799
+ for (const id of toRemove) this.nodes.delete(id);
1800
+ this.edges = this.edges.filter((e) => !toRemove.includes(e.from) && !toRemove.includes(e.to));
1801
+ await this.saveGraph(scope);
1802
+ }
1803
+ return removed;
1804
+ }
1805
+ async readAll(scope, filePath) {
1806
+ return this.file.readAll(scope, filePath);
1807
+ }
1808
+ async list(scope, filePath, limit) {
1809
+ await this.loadGraph(scope);
1810
+ const fileEntries = await this.file.list(scope, filePath);
1811
+ const nodeMap = new Map(this.nodes.entries());
1812
+ const enriched = fileEntries.map((fe) => {
1813
+ const nodeId = this.nodeId(fe);
1814
+ const node = nodeMap.get(nodeId);
1815
+ if (node) {
1816
+ return {
1817
+ ...fe,
1818
+ type: node.type ?? fe.type,
1819
+ tags: node.tags ?? fe.tags,
1820
+ priority: node.priority ?? fe.priority
1821
+ };
1822
+ }
1823
+ return fe;
1824
+ });
1825
+ const fileIds = new Set(fileEntries.map((e) => this.nodeId(e)));
1826
+ for (const [id, node] of this.nodes) {
1827
+ if (!fileIds.has(id)) {
1828
+ enriched.push(node.entry);
1829
+ }
1830
+ }
1831
+ enriched.sort((a, b) => b.ts.localeCompare(a.ts));
1832
+ return limit ? enriched.slice(0, limit) : enriched;
1833
+ }
1834
+ async search(scope, query, filePath, limit) {
1835
+ await this.loadGraph(scope);
1836
+ const needle = query.toLowerCase().split(/\s+/);
1837
+ const all = await this.list(scope, filePath);
1838
+ const scored = all.map((entry) => {
1839
+ const words = entry.text.toLowerCase().split(/\s+/);
1840
+ let score = 0;
1841
+ for (const n of needle) {
1842
+ if (words.some((w) => w.includes(n))) score += 1;
1843
+ if (entry.tags?.some((t) => t.toLowerCase().includes(n))) score += 2;
1844
+ }
1845
+ const node = this.nodes.get(this.nodeId(entry));
1846
+ if (node) {
1847
+ if (node.priority === "critical") score += 3;
1848
+ else if (node.priority === "high") score += 2;
1849
+ score += node.count * 0.5;
1850
+ }
1851
+ return { entry, score };
1852
+ });
1853
+ scored.sort((a, b) => b.score - a.score);
1854
+ const matched = scored.filter((s) => s.score > 0).map((s) => s.entry);
1855
+ return limit ? matched.slice(0, limit) : matched;
1856
+ }
1857
+ async clear(scope, filePath) {
1858
+ await this.file.clear(scope, filePath);
1859
+ this.nodes.clear();
1860
+ this.edges = [];
1861
+ this.loadedScope = scope;
1862
+ this.loaded = true;
1863
+ try {
1864
+ await fsp.unlink(this.graphFile);
1865
+ } catch {
1866
+ }
1867
+ }
1868
+ async consolidate(scope, filePath) {
1869
+ return this.file.consolidate(scope, filePath);
1870
+ }
1871
+ // ── Graph-specific queries ─────────────────────────────────────────
1872
+ /**
1873
+ * Find memories related to the given entry, ordered by edge weight.
1874
+ */
1875
+ async findRelated(scope, _filePath, entryText, limit = 5) {
1876
+ await this.loadGraph(scope);
1877
+ const targetId = this.nodeId({ scope, text: entryText, ts: "" });
1878
+ const related = this.edges.filter((e) => e.from === targetId || e.to === targetId).sort((a, b) => b.weight - a.weight).slice(0, limit);
1879
+ const result = [];
1880
+ for (const edge of related) {
1881
+ const otherId = edge.from === targetId ? edge.to : edge.from;
1882
+ const node = this.nodes.get(otherId);
1883
+ if (node) result.push(node.entry);
1884
+ }
1885
+ return result;
1886
+ }
1887
+ /**
1888
+ * Get all edges for visualization or traversal.
1889
+ */
1890
+ getGraph() {
1891
+ return {
1892
+ nodes: [...this.nodes.values()],
1893
+ edges: [...this.edges]
1894
+ };
1895
+ }
1896
+ // ── Persistence ────────────────────────────────────────────────────
1897
+ nodeId(entry) {
1898
+ const norm = entry.text.toLowerCase().trim().replace(/\s+/g, " ");
1899
+ return `${entry.scope ?? "mem"}::${simpleHash(norm)}`;
1900
+ }
1901
+ async loadGraph(scope) {
1902
+ if (this.loaded && this.loadedScope === scope) return;
1903
+ try {
1904
+ const raw = await fsp.readFile(this.graphFile, "utf8");
1905
+ const data = JSON.parse(raw);
1906
+ this.nodes = new Map(data.nodes);
1907
+ this.edges = data.edges;
1908
+ } catch {
1909
+ this.nodes = /* @__PURE__ */ new Map();
1910
+ this.edges = [];
1911
+ }
1912
+ this.loadedScope = scope;
1913
+ this.loaded = true;
1914
+ }
1915
+ async saveGraph(scope) {
1916
+ this.loadedScope = scope;
1917
+ this.loaded = true;
1918
+ try {
1919
+ const data = {
1920
+ nodes: [...this.nodes.entries()],
1921
+ edges: this.edges
1922
+ };
1923
+ await fsp.mkdir(
1924
+ this.graphFile.substring(0, this.graphFile.lastIndexOf("/")),
1925
+ { recursive: true }
1926
+ );
1927
+ const tmp = `${this.graphFile}.tmp`;
1928
+ await fsp.writeFile(tmp, JSON.stringify(data));
1929
+ await fsp.rename(tmp, this.graphFile);
1930
+ } catch {
1931
+ }
1932
+ }
1933
+ };
1934
+ function wordOverlap(a, b) {
1935
+ const wordsA = new Set(a.toLowerCase().split(/\s+/).filter((w) => w.length > 2));
1936
+ const wordsB = new Set(b.toLowerCase().split(/\s+/).filter((w) => w.length > 2));
1937
+ if (wordsA.size === 0 || wordsB.size === 0) return 0;
1938
+ let intersection = 0;
1939
+ for (const w of wordsA) {
1940
+ if (wordsB.has(w)) intersection++;
1941
+ }
1942
+ return intersection / Math.max(wordsA.size, wordsB.size);
1943
+ }
1944
+ function sharedTags(a, b) {
1945
+ if (a.length === 0 || b.length === 0) return 0;
1946
+ const setB = new Set(b);
1947
+ let shared = 0;
1948
+ for (const t of a) if (setB.has(t)) shared++;
1949
+ return shared / Math.max(a.length, b.length);
1950
+ }
1951
+ function simpleHash(s) {
1952
+ let h = 0;
1953
+ for (let i = 0; i < s.length; i++) {
1954
+ h = (h << 5) - h + s.charCodeAt(i) | 0;
1955
+ }
1956
+ return Math.abs(h).toString(36);
1957
+ }
1958
+
1959
+ // src/storage/memory-consolidator.ts
1960
+ function buildConsolidationPrompt(finalText, iterations, existingEntries) {
1961
+ const existingBlock = existingEntries.length > 0 ? `
1962
+
1963
+ Existing memory entries:
1964
+ ${existingEntries.map((e) => `- [${e.ts.slice(0, 10)}] ${e.text}`).join("\n")}` : "";
1965
+ return `You are a memory consolidator. Review the following session summary and decide what key facts, conventions, decisions, or learnings should be persisted to long-term memory.
1966
+
1967
+ Session summary (${iterations} iterations):
1968
+ ${finalText.slice(0, 3e3)}${existingBlock}
1969
+
1970
+ Return a JSON object with an "operations" array. Each operation must have an "action" field:
1971
+ - "add": create a new memory entry. Include "text", and optionally "type", "tags", "priority".
1972
+ - "edit": replace an existing entry. Include "query" (to match) and "text" (replacement).
1973
+ - "delete": remove an entry. Include "query" (to match).
1974
+
1975
+ Memory types:
1976
+ - "fact": Objective truth about the project (e.g. "uses pnpm workspaces")
1977
+ - "decision": A choice that was made (e.g. "decided to use biome over eslint")
1978
+ - "convention": A recurring pattern or standard (e.g. "commit messages use conventional format")
1979
+ - "preference": User or team preference (e.g. "prefers short variable names")
1980
+ - "reference": Pointer to a file or location (e.g. "auth logic in packages/core/src/auth/")
1981
+ - "anti_pattern": Something to avoid (e.g. "never use any in TypeScript")
1982
+
1983
+ Priority levels:
1984
+ - "critical": Must always be known (e.g. security constraints)
1985
+ - "high": Important for most tasks
1986
+ - "medium": Useful context
1987
+ - "low": Nice to know
1988
+
1989
+ Rules:
1990
+ - Only persist facts likely useful across multiple future sessions.
1991
+ - Do NOT persist task progress, temporary state, or one-off observations.
1992
+ - Prefer "add" over "edit" unless the existing entry is clearly outdated.
1993
+ - Assign a type and priority to every "add" operation.
1994
+ - Use 1-3 hashtag tags for each entry (e.g. #typescript #build).
1995
+ - Be concise \u2014 each memory entry should be one clear sentence.
1996
+
1997
+ Return ONLY valid JSON, no markdown, no explanation:
1998
+ {
1999
+ "operations": [
2000
+ {
2001
+ "action": "add",
2002
+ "text": "Project uses pnpm workspaces with TypeScript strict mode",
2003
+ "type": "convention",
2004
+ "priority": "high",
2005
+ "tags": ["pnpm", "typescript", "build"]
2006
+ },
2007
+ {
2008
+ "action": "edit",
2009
+ "query": "pnpm",
2010
+ "text": "Project uses pnpm v9+ with ESM-only modules",
2011
+ "type": "fact",
2012
+ "priority": "medium"
2013
+ },
2014
+ { "action": "delete", "query": "outdated convention" }
2015
+ ]
2016
+ }`;
2017
+ }
2018
+ var SessionMemoryConsolidator = class {
2019
+ name = "session-memory-consolidator";
2020
+ owner = "core";
2021
+ memoryStore;
2022
+ provider;
2023
+ model;
2024
+ minIterations;
2025
+ maxExistingEntries;
2026
+ constructor(opts) {
2027
+ this.memoryStore = opts.memoryStore;
2028
+ this.provider = opts.provider;
2029
+ this.model = opts.model;
2030
+ this.minIterations = opts.minIterations ?? 2;
2031
+ this.maxExistingEntries = opts.maxExistingEntries ?? 15;
2032
+ }
2033
+ afterRun = async (ctx, result) => {
2034
+ if (result.status !== "done") return;
2035
+ if (!result.finalText || result.finalText.trim().length < 20) return;
2036
+ if (result.iterations < this.minIterations) return;
2037
+ const provider = this.provider ?? ctx.provider;
2038
+ if (!provider || !provider.complete) return;
2039
+ try {
2040
+ const existingEntries = await this.memoryStore.list("project-memory", this.maxExistingEntries);
2041
+ const prompt = buildConsolidationPrompt(
2042
+ result.finalText,
2043
+ result.iterations,
2044
+ existingEntries
2045
+ );
2046
+ const signal = AbortSignal.timeout(15e3);
2047
+ const response = await provider.complete(
2048
+ {
2049
+ model: this.model ?? ctx.model,
2050
+ system: [{ type: "text", text: prompt }],
2051
+ messages: [
2052
+ { role: "user", content: "Review the session and return memory operations as JSON." }
2053
+ ],
2054
+ maxTokens: 500
2055
+ },
2056
+ { signal }
2057
+ );
2058
+ const text = response.content.filter((b) => b.type === "text").map((b) => b.text).join("").trim();
2059
+ if (!text) return;
2060
+ const jsonMatch = text.match(/\{[\s\S]*\}/);
2061
+ if (!jsonMatch) return;
2062
+ const parsed = JSON.parse(jsonMatch[0]);
2063
+ if (!Array.isArray(parsed.operations) || parsed.operations.length === 0) return;
2064
+ let added = 0;
2065
+ let edited = 0;
2066
+ let deleted = 0;
2067
+ for (const op of parsed.operations) {
2068
+ switch (op.action) {
2069
+ case "add": {
2070
+ if (op.text && op.text.trim()) {
2071
+ await this.memoryStore.remember(op.text.trim(), void 0, {
2072
+ type: op.type,
2073
+ tags: op.tags,
2074
+ priority: op.priority
2075
+ });
2076
+ added++;
2077
+ }
2078
+ break;
2079
+ }
2080
+ case "edit": {
2081
+ if (op.query && op.text && op.text.trim()) {
2082
+ await this.memoryStore.forget(op.query);
2083
+ await this.memoryStore.remember(op.text.trim(), void 0, {
2084
+ type: op.type,
2085
+ tags: op.tags,
2086
+ priority: op.priority
2087
+ });
2088
+ edited++;
2089
+ }
2090
+ break;
2091
+ }
2092
+ case "delete": {
2093
+ if (op.query) {
2094
+ const n = await this.memoryStore.forget(op.query);
2095
+ deleted += n;
2096
+ }
2097
+ break;
2098
+ }
2099
+ }
2100
+ }
2101
+ if (added > 0 || edited > 0 || deleted > 0) {
2102
+ const parts = [];
2103
+ if (added) parts.push(`${added} added`);
2104
+ if (edited) parts.push(`${edited} edited`);
2105
+ if (deleted) parts.push(`${deleted} deleted`);
2106
+ process.stderr.write(`[memory] Session consolidation: ${parts.join(", ")}
2107
+ `);
2108
+ }
2109
+ } catch {
2110
+ }
2111
+ };
2112
+ };
1405
2113
 
1406
2114
  // src/storage/config-store.ts
1407
2115
  function stripEphemeralFields(cfg) {
@@ -2097,12 +2805,6 @@ function compileUserRegex(pattern, flags) {
2097
2805
  }
2098
2806
 
2099
2807
  // src/storage/session-reader.ts
2100
- function expectDefined3(value) {
2101
- if (value === null || value === void 0) {
2102
- throw new Error("Expected value to be defined");
2103
- }
2104
- return value;
2105
- }
2106
2808
  var DefaultSessionReader = class {
2107
2809
  store;
2108
2810
  constructor(opts) {
@@ -2164,7 +2866,7 @@ var DefaultSessionReader = class {
2164
2866
  continue;
2165
2867
  }
2166
2868
  for (let i = 0; i < data.events.length; i++) {
2167
- const ev = expectDefined3(data.events[i]);
2869
+ const ev = expectDefined(data.events[i]);
2168
2870
  if (allowedTypes && !allowedTypes.has(ev.type)) continue;
2169
2871
  const text = eventText(ev);
2170
2872
  if (text === null) continue;
@@ -2377,12 +3079,6 @@ function renderPlainText(meta, events) {
2377
3079
  }
2378
3080
  return lines.join("\n");
2379
3081
  }
2380
- function expectDefined4(value) {
2381
- if (value === null || value === void 0) {
2382
- throw new Error("Expected value to be defined");
2383
- }
2384
- return value;
2385
- }
2386
3082
  var FILE_VERSION = 1;
2387
3083
  var MAX_TEXT_LENGTH = 2e3;
2388
3084
  var MAX_ANNOTATIONS = 1e3;
@@ -2475,7 +3171,7 @@ var AnnotationsStore = class {
2475
3171
  return;
2476
3172
  }
2477
3173
  const next = {
2478
- ...expectDefined4(all[idx]),
3174
+ ...expectDefined(all[idx]),
2479
3175
  resolved: true,
2480
3176
  resolvedAt: (/* @__PURE__ */ new Date()).toISOString(),
2481
3177
  resolvedBy: input.resolvedBy
@@ -2710,12 +3406,6 @@ var ReplayLogStore = class {
2710
3406
  return next;
2711
3407
  }
2712
3408
  };
2713
- function expectDefined5(value) {
2714
- if (value === null || value === void 0) {
2715
- throw new Error("Expected value to be defined");
2716
- }
2717
- return value;
2718
- }
2719
3409
  var SessionRecovery = class {
2720
3410
  constructor(dir) {
2721
3411
  this.dir = dir;
@@ -2756,7 +3446,7 @@ var SessionRecovery = class {
2756
3446
  const lines = raw.split("\n").filter((l) => l.trim());
2757
3447
  for (let i = lines.length - 1; i >= 0; i--) {
2758
3448
  try {
2759
- const ev = JSON.parse(expectDefined5(lines[i]));
3449
+ const ev = JSON.parse(expectDefined(lines[i]));
2760
3450
  if (ev.type === "in_flight_start") {
2761
3451
  return {
2762
3452
  sessionId,
@@ -2809,12 +3499,12 @@ var SessionRecovery = class {
2809
3499
  let lastCheckpointIdx = -1;
2810
3500
  for (let i = 0; i < events.length; i++) {
2811
3501
  if (events[i]?.type === "checkpoint") {
2812
- lastCheckpoint = expectDefined5(events[i]);
3502
+ lastCheckpoint = expectDefined(events[i]);
2813
3503
  lastCheckpointIdx = i;
2814
3504
  }
2815
3505
  }
2816
3506
  const pendingEvents = lastCheckpointIdx >= 0 ? events.slice(lastCheckpointIdx + 1) : events;
2817
- const lastEv = expectDefined5(events[events.length - 1]);
3507
+ const lastEv = expectDefined(events[events.length - 1]);
2818
3508
  const inFlightStart = lastEv.type === "in_flight_start" ? lastEv : null;
2819
3509
  const context = inFlightStart && inFlightStart.type === "in_flight_start" ? inFlightStart.context : null;
2820
3510
  return {
@@ -2857,12 +3547,6 @@ var SessionRecovery = class {
2857
3547
  return path2.join(this.dir, `${sessionId}.jsonl`);
2858
3548
  }
2859
3549
  };
2860
- function expectDefined6(value) {
2861
- if (value === null || value === void 0) {
2862
- throw new Error("Expected value to be defined");
2863
- }
2864
- return value;
2865
- }
2866
3550
  var GENESIS_PREV = "0".repeat(64);
2867
3551
  var DEFAULT_FSYNC_EVERY = 100;
2868
3552
  var ToolAuditLog = class {
@@ -2943,7 +3627,7 @@ var ToolAuditLog = class {
2943
3627
  }
2944
3628
  let prevHash = GENESIS_PREV;
2945
3629
  for (let i = 0; i < entries.length; i++) {
2946
- const e = expectDefined6(entries[i]);
3630
+ const e = expectDefined(entries[i]);
2947
3631
  if (e.prevHash !== prevHash) {
2948
3632
  return {
2949
3633
  ok: false,
@@ -3160,12 +3844,6 @@ var SessionAnalyzer = class {
3160
3844
  return last - first;
3161
3845
  }
3162
3846
  };
3163
- function expectDefined7(value) {
3164
- if (value === null || value === void 0) {
3165
- throw new Error("Expected value to be defined");
3166
- }
3167
- return value;
3168
- }
3169
3847
  var DefaultSessionRewinder = class {
3170
3848
  constructor(sessionsDir, projectRoot) {
3171
3849
  this.sessionsDir = sessionsDir;
@@ -3204,7 +3882,7 @@ var DefaultSessionRewinder = class {
3204
3882
  const events = parseEvents(raw);
3205
3883
  let targetIdx = -1;
3206
3884
  for (let i = 0; i < events.length; i++) {
3207
- const event = expectDefined7(events[i]);
3885
+ const event = expectDefined(events[i]);
3208
3886
  if (event.type === "checkpoint") {
3209
3887
  const checkpointEvent = event;
3210
3888
  if (checkpointEvent.promptIndex === checkpointIndex) {
@@ -3218,7 +3896,7 @@ var DefaultSessionRewinder = class {
3218
3896
  }
3219
3897
  const snapshotsToRevert = [];
3220
3898
  for (let i = targetIdx + 1; i < events.length; i++) {
3221
- const event = expectDefined7(events[i]);
3899
+ const event = expectDefined(events[i]);
3222
3900
  if (event.type === "checkpoint") {
3223
3901
  break;
3224
3902
  }
@@ -3365,7 +4043,10 @@ function attachTodosCheckpoint(state, filePath, sessionId) {
3365
4043
  let pending = null;
3366
4044
  let writeChain = Promise.resolve();
3367
4045
  const enqueueWrite = (todos) => {
3368
- writeChain = writeChain.then(() => saveTodosCheckpoint(filePath, sessionId, todos));
4046
+ writeChain = writeChain.then(() => saveTodosCheckpoint(filePath, sessionId, todos)).catch((err) => {
4047
+ const msg = err instanceof Error ? err.message : String(err);
4048
+ console.error(`[TodosCheckpoint] save failed for session ${sessionId}: ${msg}`);
4049
+ });
3369
4050
  return writeChain;
3370
4051
  };
3371
4052
  const flush = () => {
@@ -3629,6 +4310,40 @@ ${cat}:`);
3629
4310
  }
3630
4311
  return lines.join("\n");
3631
4312
  }
4313
+ function emptyTaskFile(sessionId) {
4314
+ return {
4315
+ version: 1,
4316
+ sessionId,
4317
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
4318
+ tasks: []
4319
+ };
4320
+ }
4321
+ async function loadTasks(filePath) {
4322
+ let raw;
4323
+ try {
4324
+ raw = await fsp.readFile(filePath, "utf8");
4325
+ } catch {
4326
+ return null;
4327
+ }
4328
+ try {
4329
+ const parsed = JSON.parse(raw);
4330
+ if (parsed?.version !== 1 || !Array.isArray(parsed.tasks)) return null;
4331
+ return parsed;
4332
+ } catch {
4333
+ return null;
4334
+ }
4335
+ }
4336
+ async function saveTasks(filePath, tasks) {
4337
+ try {
4338
+ tasks.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
4339
+ await atomicWrite(filePath, JSON.stringify(tasks, null, 2), { mode: 384 });
4340
+ } catch (err) {
4341
+ console.warn(
4342
+ "[task-store] save failed:",
4343
+ err instanceof Error ? err.message : String(err)
4344
+ );
4345
+ }
4346
+ }
3632
4347
  async function loadDirectorState(filePath) {
3633
4348
  let raw;
3634
4349
  try {
@@ -3663,7 +4378,7 @@ async function acquireDirectorStateLock(lockPath, processId = process.pid) {
3663
4378
  }
3664
4379
  const lock = {
3665
4380
  pid: processId,
3666
- hostname: __require("os").hostname(),
4381
+ hostname: hostname(),
3667
4382
  startedAt: (/* @__PURE__ */ new Date()).toISOString()
3668
4383
  };
3669
4384
  await atomicWrite(lockPath, JSON.stringify(lock), { mode: 384 });
@@ -3808,6 +4523,44 @@ var DirectorStateCheckpoint = class {
3808
4523
  }
3809
4524
  };
3810
4525
 
4526
+ // src/utils/term.ts
4527
+ var hasStdout = () => typeof process !== "undefined" && !!process.stdout;
4528
+ function isStdoutTTY() {
4529
+ return hasStdout() && Boolean(process.stdout.isTTY);
4530
+ }
4531
+
4532
+ // src/utils/color.ts
4533
+ var isColorTty = () => {
4534
+ if (envFlag(process.env.NO_COLOR)) return false;
4535
+ if (envFlag(process.env.FORCE_COLOR)) return true;
4536
+ return isStdoutTTY();
4537
+ };
4538
+ function envFlag(value) {
4539
+ if (value === void 0) return false;
4540
+ if (value.trim() === "") return false;
4541
+ return !/^(0|false|no|off)$/i.test(value.trim());
4542
+ }
4543
+ var COLOR = isColorTty();
4544
+ var wrap = (open5, close) => (s) => COLOR ? `\x1B[${open5}m${s}\x1B[${close}m` : s;
4545
+ var color = {
4546
+ reset: wrap("0", "0"),
4547
+ bold: wrap("1", "22"),
4548
+ dim: wrap("2", "22"),
4549
+ italic: wrap("3", "23"),
4550
+ underline: wrap("4", "24"),
4551
+ red: wrap("31", "39"),
4552
+ green: wrap("32", "39"),
4553
+ yellow: wrap("33", "39"),
4554
+ blue: wrap("34", "39"),
4555
+ magenta: wrap("35", "39"),
4556
+ cyan: wrap("36", "39"),
4557
+ gray: wrap("90", "39"),
4558
+ amber: wrap("38;5;214", "39"),
4559
+ pink: wrap("38;5;205", "39"),
4560
+ bgRed: wrap("41", "49"),
4561
+ bgGreen: wrap("42", "49")
4562
+ };
4563
+
3811
4564
  // src/types/errors.ts
3812
4565
  var ERROR_CODES = {
3813
4566
  // File system
@@ -3907,6 +4660,14 @@ function emptyGoal(goal) {
3907
4660
  journal: []
3908
4661
  };
3909
4662
  }
4663
+ function setProgress(goal, progress, note) {
4664
+ const clamped = Math.min(100, Math.max(0, progress));
4665
+ return {
4666
+ ...goal,
4667
+ progress: clamped,
4668
+ progressNote: note ?? clamped + "% complete"
4669
+ };
4670
+ }
3910
4671
  function appendJournal(goal, entry) {
3911
4672
  const iteration = goal.iterations + 1;
3912
4673
  const at = (/* @__PURE__ */ new Date()).toISOString();
@@ -3935,34 +4696,97 @@ function summarizeUsage(goal) {
3935
4696
  }
3936
4697
  return { totalCostUsd, totalInputTokens, totalOutputTokens, iterationsWithUsage };
3937
4698
  }
4699
+ var DOLLAR = "$";
3938
4700
  function formatGoal(goal, journalLimit = 10) {
3939
4701
  const lines = [];
3940
- lines.push(`Goal: ${goal.goal}`);
3941
- lines.push(`Set: ${goal.setAt}`);
3942
- lines.push(`Last activity: ${goal.lastActivityAt}`);
3943
- lines.push(`Iterations: ${goal.iterations}`);
4702
+ const displayGoal = goal.refinedGoal || goal.goal;
4703
+ lines.push(color.bold("Goal") + ": " + displayGoal);
4704
+ if (goal.refinedGoal && goal.refinedGoal !== goal.goal) {
4705
+ const snippet = goal.goal.length > 60 ? goal.goal.slice(0, 60) + "\u2026" : goal.goal;
4706
+ lines.push(color.dim(' (original: "' + snippet + '")'));
4707
+ }
4708
+ if (typeof goal.progress === "number") {
4709
+ const pct = Math.min(100, Math.max(0, Math.round(goal.progress)));
4710
+ const filled = Math.round(pct / 5);
4711
+ const empty = 20 - filled;
4712
+ const bar = color.green("\u2588".repeat(filled)) + color.dim("\u2591".repeat(empty));
4713
+ lines.push("Progress: " + bar + " " + color.bold(pct + "%"));
4714
+ if (goal.progressNote) {
4715
+ lines.push(" " + color.dim(goal.progressNote));
4716
+ }
4717
+ if (goal.progressTrend) {
4718
+ const trendIcon = goal.progressTrend === "accelerating" ? "\u{1F680}" : goal.progressTrend === "stalling" ? "\u26A0\uFE0F" : "\u27A1\uFE0F";
4719
+ lines.push(" Trend: " + trendIcon + " " + goal.progressTrend);
4720
+ }
4721
+ }
4722
+ if (goal.deliverables && goal.deliverables.length > 0) {
4723
+ lines.push("");
4724
+ lines.push(color.bold("Deliverables:"));
4725
+ for (const d of goal.deliverables) {
4726
+ const done = /^\[[x✓]\]|✅|\(done\)/i.test(d);
4727
+ const marker = done ? color.green("\u2713") : color.dim("\u25CB");
4728
+ lines.push(" " + marker + " " + d);
4729
+ }
4730
+ }
4731
+ lines.push("");
4732
+ lines.push("Set: " + goal.setAt);
4733
+ lines.push("Last activity: " + goal.lastActivityAt);
4734
+ lines.push("Iterations: " + goal.iterations);
3944
4735
  const stateLabel = goal.goalState ?? "active";
3945
- lines.push(`State: ${stateLabel}${goal.iterations > 0 ? ` (iteration #${goal.iterations})` : ""}`);
3946
- lines.push(`Engine: ${goal.engineState}`);
4736
+ lines.push("State: " + stateLabel + (goal.iterations > 0 ? " (iteration #" + goal.iterations + ")" : ""));
4737
+ lines.push("Engine: " + goal.engineState);
3947
4738
  const usage = summarizeUsage(goal);
3948
4739
  if (usage.iterationsWithUsage > 0) {
3949
- lines.push(
3950
- `Spent: $${usage.totalCostUsd.toFixed(4)} (in ${usage.totalInputTokens} / out ${usage.totalOutputTokens} tokens across ${usage.iterationsWithUsage} iterations)`
3951
- );
4740
+ const spent = "Spent: " + DOLLAR + usage.totalCostUsd.toFixed(4) + " (in " + usage.totalInputTokens + " / out " + usage.totalOutputTokens + " tokens across " + usage.iterationsWithUsage + " iterations)";
4741
+ lines.push(spent);
3952
4742
  }
3953
4743
  if (goal.journal.length > 0) {
3954
4744
  lines.push("");
3955
- lines.push(`Recent journal (last ${Math.min(journalLimit, goal.journal.length)}):`);
4745
+ lines.push("Recent journal (last " + Math.min(journalLimit, goal.journal.length) + "):");
3956
4746
  const tail = goal.journal.slice(-journalLimit);
3957
4747
  for (const e of tail) {
3958
4748
  const mark = e.status === "success" ? "\u2713" : e.status === "failure" ? "\u2717" : e.status === "aborted" ? "\u2298" : "\xB7";
3959
- const note = e.note ? ` \u2014 ${e.note}` : "";
3960
- const cost = typeof e.costUsd === "number" ? ` ($${e.costUsd.toFixed(4)})` : "";
3961
- lines.push(` #${e.iteration} ${mark} [${e.source}] ${e.task}${cost}${note}`);
4749
+ const note = e.note ? " \u2014 " + e.note : "";
4750
+ const cost = typeof e.costUsd === "number" ? " (" + DOLLAR + e.costUsd.toFixed(4) + ")" : "";
4751
+ lines.push(" #" + e.iteration + " " + mark + " [" + e.source + "] " + e.task + cost + note);
3962
4752
  }
3963
4753
  }
3964
4754
  return lines.join("\n");
3965
4755
  }
4756
+ function parseProgressFromText(text) {
4757
+ const re = /\[progress:\s*(\d{1,3})%\]\s*(?:[—\-]\s*(.+))?/i;
4758
+ const m = text.match(re);
4759
+ if (!m) return null;
4760
+ const progress = Math.min(100, Math.max(0, Number.parseInt(m[1], 10)));
4761
+ const note = m[2]?.trim() || void 0;
4762
+ return { progress, note };
4763
+ }
4764
+ function recordProgress(goal, progress, note) {
4765
+ const clamped = Math.min(100, Math.max(0, progress));
4766
+ const history = [...goal.progressHistory ?? [], { at: (/* @__PURE__ */ new Date()).toISOString(), progress: clamped, note }];
4767
+ const trimmed = history.length > 200 ? history.slice(-200) : history;
4768
+ return {
4769
+ ...goal,
4770
+ progress: clamped,
4771
+ progressNote: note ?? `${clamped}% complete`,
4772
+ progressHistory: trimmed,
4773
+ progressTrend: computeTrend(trimmed)
4774
+ };
4775
+ }
4776
+ var MAX_PROGRESS_HISTORY = 200;
4777
+ function computeTrend(history) {
4778
+ if (history.length < 3) return void 0;
4779
+ const recent = history.slice(-5);
4780
+ const deltas = [];
4781
+ for (let i = 1; i < recent.length; i++) {
4782
+ deltas.push(recent[i].progress - recent[i - 1].progress);
4783
+ }
4784
+ if (deltas.length < 2) return void 0;
4785
+ const avgDelta = deltas.reduce((a, b) => a + b, 0) / deltas.length;
4786
+ if (avgDelta > 2) return "accelerating";
4787
+ if (avgDelta < -1) return "stalling";
4788
+ return "steady";
4789
+ }
3966
4790
  var DefaultPromptStore = class {
3967
4791
  dir;
3968
4792
  constructor(paths) {
@@ -4033,12 +4857,6 @@ var DefaultPromptStore = class {
4033
4857
  };
4034
4858
  }
4035
4859
  };
4036
- function expectDefined8(value) {
4037
- if (value === null || value === void 0) {
4038
- throw new Error("Expected value to be defined");
4039
- }
4040
- return value;
4041
- }
4042
4860
  var ALL_SYNC_CATEGORIES = ["settings", "skills", "prompts", "memory", "history"];
4043
4861
  var CloudSync = class {
4044
4862
  constructor(paths, getConfig, setConfig) {
@@ -4081,8 +4899,8 @@ var CloudSync = class {
4081
4899
  const cfg = this.getConfig();
4082
4900
  if (!cfg?.enabled) return { ok: false, action: "push", categories: [], message: "Not enabled." };
4083
4901
  const parts = cfg.repo.split("/");
4084
- const owner = expectDefined8(parts[0]);
4085
- const repoName = expectDefined8(parts[1]);
4902
+ const owner = expectDefined(parts[0]);
4903
+ const repoName = expectDefined(parts[1]);
4086
4904
  const branch = "main";
4087
4905
  const baseTreeSha = this.state?.sha;
4088
4906
  const { treeEntries, rev } = await this.buildLocalTree(cfg.categories);
@@ -4134,8 +4952,8 @@ var CloudSync = class {
4134
4952
  const cfg = this.getConfig();
4135
4953
  if (!cfg?.enabled) return { ok: false, action: "pull", categories: [], message: "Not enabled." };
4136
4954
  const pullParts = cfg.repo.split("/");
4137
- const owner = expectDefined8(pullParts[0]);
4138
- const repoName = expectDefined8(pullParts[1]);
4955
+ const owner = expectDefined(pullParts[0]);
4956
+ const repoName = expectDefined(pullParts[1]);
4139
4957
  const branchData = await this.getRef(token, owner, repoName, "main");
4140
4958
  const currentSha = branchData.object.sha;
4141
4959
  const commitData = await this.getCommit(token, owner, repoName, currentSha);
@@ -4452,6 +5270,6 @@ function resolveSessionLoggingConfig(cfg) {
4452
5270
  };
4453
5271
  }
4454
5272
 
4455
- export { ALL_SYNC_CATEGORIES, AnnotationsStore, CORE_RECONSTRUCT_EVENTS, CloudSync, ConfigMigrationError, DEFAULT_CONFIG_MIGRATIONS, DefaultAttachmentStore, DefaultConfigLoader, DefaultConfigStore, DefaultMemoryStore, DefaultPromptStore, DefaultSessionReader, DefaultSessionRewinder, DefaultSessionStore, DirectorStateCheckpoint, MAX_JOURNAL_ENTRIES, QueueStore, RecoveryLock, ReplayLogStore, STANDARD_AUDIT_EVENTS, SessionAnalyzer, SessionRecovery, ToolAuditLog, addPlanItem, appendJournal, attachPlanCheckpoint, attachTodosCheckpoint, clearPlan, createSessionEventBridge, deriveTodosFromPlanItem, emptyGoal, emptyPlan, formatGoal, formatPlan, formatPlanTemplates, getPlanTemplate, goalFilePath, listPlanTemplates, loadDirectorState, loadGoal, loadPlan, loadTodosCheckpoint, removePlanItem, resolveAuditLevel, resolveSessionLoggingConfig, runConfigMigrations, saveGoal, savePlan, saveTodosCheckpoint, setPlanItemStatus, summarizeUsage };
5273
+ export { ALL_SYNC_CATEGORIES, AnnotationsStore, CORE_RECONSTRUCT_EVENTS, CloudSync, ConfigMigrationError, DEFAULT_CONFIG_MIGRATIONS, DefaultAttachmentStore, DefaultConfigLoader, DefaultConfigStore, DefaultMemoryStore, DefaultPromptStore, DefaultSessionReader, DefaultSessionRewinder, DefaultSessionStore, DirectorStateCheckpoint, FileMemoryBackend, GraphMemoryBackend, MAX_JOURNAL_ENTRIES, MAX_PROGRESS_HISTORY, QueueStore, RecoveryLock, ReplayLogStore, STANDARD_AUDIT_EVENTS, SessionAnalyzer, SessionMemoryConsolidator, SessionRecovery, ToolAuditLog, addPlanItem, appendJournal, attachPlanCheckpoint, attachTodosCheckpoint, clearPlan, createSessionEventBridge, deriveTodosFromPlanItem, emptyGoal, emptyPlan, emptyTaskFile, formatGoal, formatPlan, formatPlanTemplates, getPlanTemplate, goalFilePath, listPlanTemplates, loadDirectorState, loadGoal, loadPlan, loadTasks, loadTodosCheckpoint, parseEntries, parseProgressFromText, recordProgress, removePlanItem, resolveAuditLevel, resolveSessionLoggingConfig, runConfigMigrations, saveGoal, savePlan, saveTasks, saveTodosCheckpoint, setPlanItemStatus, setProgress, summarizeUsage };
4456
5274
  //# sourceMappingURL=index.js.map
4457
5275
  //# sourceMappingURL=index.js.map