negotium 0.3.0 → 0.3.2

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 (61) hide show
  1. package/dist/agent-helpers.js +107 -6
  2. package/dist/agent-helpers.js.map +11 -11
  3. package/dist/background-bash.js +3 -2
  4. package/dist/background-bash.js.map +4 -4
  5. package/dist/browser-runtime.js +3 -2
  6. package/dist/browser-runtime.js.map +4 -4
  7. package/dist/chunk-s2gez3wg.js.map +1 -1
  8. package/dist/{chunk-1y2xw0xe.js → chunk-vvfwqxnh.js} +33 -3
  9. package/dist/{chunk-1y2xw0xe.js.map → chunk-vvfwqxnh.js.map} +8 -8
  10. package/dist/hosted-agent.js +34 -4
  11. package/dist/hosted-agent.js.map +8 -8
  12. package/dist/main.js +1179 -366
  13. package/dist/main.js.map +24 -21
  14. package/dist/mcp-catalog.js +2 -1
  15. package/dist/mcp-catalog.js.map +3 -3
  16. package/dist/mcp-factories.js +635 -256
  17. package/dist/mcp-factories.js.map +15 -13
  18. package/dist/mcp-servers.js +3 -1
  19. package/dist/mcp-servers.js.map +3 -3
  20. package/dist/prompts.js +8 -2
  21. package/dist/prompts.js.map +5 -5
  22. package/dist/query-runtime.js +3 -2
  23. package/dist/query-runtime.js.map +4 -4
  24. package/dist/registry.js +3 -3
  25. package/dist/registry.js.map +2 -2
  26. package/dist/rollout.js +1 -1
  27. package/dist/runtime/src/mcp/canonical-bridge-config.ts +1 -1
  28. package/dist/runtime/src/mcp/canonical-proxy-server.ts +74 -1
  29. package/dist/runtime/src/mcp/decision-server.ts +21 -0
  30. package/dist/runtime/src/mcp/factories/decision.ts +178 -0
  31. package/dist/runtime/src/mcp/factories/index.ts +6 -0
  32. package/dist/runtime/src/mcp/runtime-spec.ts +1 -0
  33. package/dist/runtime/src/node-host.ts +1 -0
  34. package/dist/runtime/src/platform/config.ts +2 -1
  35. package/dist/runtime/src/platform/mcp-catalog-policy.ts +1 -0
  36. package/dist/runtime/src/platform/mcp-config.ts +31 -1
  37. package/dist/runtime/src/prompts/builders.ts +5 -0
  38. package/dist/runtime/src/runtime/visual-html.ts +68 -2
  39. package/dist/runtime/src/storage/decisions.ts +231 -0
  40. package/dist/runtime/src/storage/storage-public.ts +2 -0
  41. package/dist/runtime/src/types.ts +13 -0
  42. package/dist/runtime/src/version.ts +1 -1
  43. package/dist/runtime-helpers.js +71 -4
  44. package/dist/runtime-helpers.js.map +5 -5
  45. package/dist/storage.js +261 -56
  46. package/dist/storage.js.map +5 -4
  47. package/dist/types/apps/negotium/src/mcp-servers.d.ts +1 -1
  48. package/dist/types/packages/core/src/mcp/canonical-bridge-config.d.ts +1 -1
  49. package/dist/types/packages/core/src/mcp/factories/decision.d.ts +16 -0
  50. package/dist/types/packages/core/src/mcp/factories/index.d.ts +1 -0
  51. package/dist/types/packages/core/src/mcp/runtime-spec.d.ts +1 -1
  52. package/dist/types/packages/core/src/platform/config.d.ts +2 -1
  53. package/dist/types/packages/core/src/platform/mcp-catalog-policy.d.ts +4 -0
  54. package/dist/types/packages/core/src/storage/decisions.d.ts +45 -0
  55. package/dist/types/packages/core/src/storage/storage-public.d.ts +2 -0
  56. package/dist/types/packages/core/src/types.d.ts +12 -0
  57. package/dist/types/packages/core/src/version.d.ts +1 -1
  58. package/dist/vault.js +3 -2
  59. package/dist/vault.js.map +4 -4
  60. package/install-browser-rs.mjs +3 -3
  61. package/package.json +2 -2
package/dist/storage.js CHANGED
@@ -2424,6 +2424,198 @@ function findLastSessionIdForAgent(entries, agent) {
2424
2424
  }
2425
2425
  return null;
2426
2426
  }
2427
+ // ../../packages/core/src/storage/decisions.ts
2428
+ var exports_decisions = {};
2429
+ __export(exports_decisions, {
2430
+ writeDecisions: () => writeDecisions,
2431
+ writeDecisionGraphSvg: () => writeDecisionGraphSvg,
2432
+ validateDecisionGraph: () => validateDecisionGraph,
2433
+ updateDecisions: () => updateDecisions,
2434
+ renderDecisionList: () => renderDecisionList,
2435
+ readDecisions: () => readDecisions,
2436
+ getDecisionGraphSvgPath: () => getDecisionGraphSvgPath,
2437
+ getDecisionFilePath: () => getDecisionFilePath,
2438
+ deleteDecisions: () => deleteDecisions,
2439
+ decisionScopeKey: () => decisionScopeKey,
2440
+ createDecisions: () => createDecisions,
2441
+ DECISION_STATUS_VALUES: () => DECISION_STATUS_VALUES
2442
+ });
2443
+ import { existsSync as existsSync4, mkdirSync as mkdirSync6, readFileSync as readFileSync4, renameSync as renameSync4, writeFileSync as writeFileSync5 } from "fs";
2444
+ import { dirname as dirname5, join as join5 } from "path";
2445
+ var DECISION_STATUS_VALUES = [
2446
+ "proposed",
2447
+ "accepted",
2448
+ "executed",
2449
+ "rejected",
2450
+ "superseded"
2451
+ ];
2452
+ function safeDecisionScopeKey(scopeKey) {
2453
+ const safe = sanitizeFileName(scopeKey);
2454
+ if (!safe || safe === "." || safe === "..") {
2455
+ throw new Error(`decisions: refusing unsafe scope key: ${scopeKey}`);
2456
+ }
2457
+ return safe;
2458
+ }
2459
+ function decisionScopeKey(opts) {
2460
+ return opts.topicId?.trim() || opts.session || "default";
2461
+ }
2462
+ function getDecisionFilePath(userId, scopeKey) {
2463
+ return join5(resolveStorageDataDir(), "decisions", `${safeDecisionScopeKey(scopeKey)}.json`);
2464
+ }
2465
+ function getDecisionGraphSvgPath(userId, scopeKey) {
2466
+ return join5(resolveStorageDataDir(), "decision-renders", safeDecisionScopeKey(scopeKey), "latest.svg");
2467
+ }
2468
+ function writeDecisionGraphSvg(userId, scopeKey, svg) {
2469
+ const path = getDecisionGraphSvgPath(userId, scopeKey);
2470
+ mkdirSync6(dirname5(path), { recursive: true });
2471
+ const tmp = `${path}.${process.pid}.tmp`;
2472
+ writeFileSync5(tmp, svg, "utf-8");
2473
+ renameSync4(tmp, path);
2474
+ return path;
2475
+ }
2476
+ function readDecisions(userId, scopeKey) {
2477
+ const path = getDecisionFilePath(userId, scopeKey);
2478
+ if (!existsSync4(path))
2479
+ return [];
2480
+ try {
2481
+ const parsed = JSON.parse(readFileSync4(path, "utf-8"));
2482
+ return Array.isArray(parsed?.decisions) ? parsed.decisions : [];
2483
+ } catch (error) {
2484
+ logger.warn({ err: error, path }, "decisions: failed to read decision store");
2485
+ return [];
2486
+ }
2487
+ }
2488
+ function writeDecisions(userId, scopeKey, decisions) {
2489
+ const path = getDecisionFilePath(userId, scopeKey);
2490
+ mkdirSync6(dirname5(path), { recursive: true });
2491
+ const payload = { version: 1, decisions };
2492
+ const tmp = `${path}.${process.pid}.tmp`;
2493
+ writeFileSync5(tmp, JSON.stringify(payload, null, 2), "utf-8");
2494
+ renameSync4(tmp, path);
2495
+ }
2496
+ function nextDecisionId(decisions) {
2497
+ let max = 0;
2498
+ for (const decision of decisions) {
2499
+ const id = Number(decision.id);
2500
+ if (Number.isInteger(id) && id > max)
2501
+ max = id;
2502
+ }
2503
+ return max + 1;
2504
+ }
2505
+ function normalizedIds(ids) {
2506
+ if (!ids)
2507
+ return;
2508
+ const unique = [...new Set(ids.map((id) => id.trim()).filter(Boolean))];
2509
+ return unique.length > 0 ? unique : undefined;
2510
+ }
2511
+ function validateDecisionGraph(decisions) {
2512
+ const ids = new Set(decisions.map((decision) => decision.id));
2513
+ for (const decision of decisions) {
2514
+ for (const upstream of decision.causedBy ?? []) {
2515
+ if (!ids.has(upstream)) {
2516
+ throw new Error(`Decision #${decision.id} references missing decision #${upstream}.`);
2517
+ }
2518
+ if (upstream === decision.id) {
2519
+ throw new Error(`Decision #${decision.id} cannot cause itself.`);
2520
+ }
2521
+ }
2522
+ }
2523
+ const visiting = new Set;
2524
+ const visited = new Set;
2525
+ const byId = new Map(decisions.map((decision) => [decision.id, decision]));
2526
+ const visit = (id) => {
2527
+ if (visited.has(id))
2528
+ return;
2529
+ if (visiting.has(id))
2530
+ throw new Error(`Decision graph contains a cycle at #${id}.`);
2531
+ visiting.add(id);
2532
+ for (const upstream of byId.get(id)?.causedBy ?? [])
2533
+ visit(upstream);
2534
+ visiting.delete(id);
2535
+ visited.add(id);
2536
+ };
2537
+ for (const id of ids)
2538
+ visit(id);
2539
+ }
2540
+ function createDecisions(decisions, inputs) {
2541
+ const out = [...decisions];
2542
+ const created = [];
2543
+ let id = nextDecisionId(out);
2544
+ for (const input of inputs) {
2545
+ const decision = {
2546
+ id: String(id++),
2547
+ action: input.action.trim(),
2548
+ reasoning: input.reasoning.trim(),
2549
+ agent: input.agent,
2550
+ status: input.status ?? "accepted",
2551
+ timestamp: input.timestamp ?? Date.now(),
2552
+ ...input.model ? { model: input.model } : {},
2553
+ ...normalizedIds(input.causedBy) ? { causedBy: normalizedIds(input.causedBy) } : {}
2554
+ };
2555
+ out.push(decision);
2556
+ created.push(decision);
2557
+ }
2558
+ validateDecisionGraph(out);
2559
+ return { decisions: out, created };
2560
+ }
2561
+ function updateDecisions(decisions, updates) {
2562
+ const out = decisions.map((decision) => ({
2563
+ ...decision,
2564
+ ...decision.causedBy ? { causedBy: [...decision.causedBy] } : {}
2565
+ }));
2566
+ const byId = new Map(out.map((decision) => [decision.id, decision]));
2567
+ const missing = [];
2568
+ for (const update of updates) {
2569
+ const decision = byId.get(update.id);
2570
+ if (!decision) {
2571
+ missing.push(update.id);
2572
+ continue;
2573
+ }
2574
+ if (update.action !== undefined)
2575
+ decision.action = update.action.trim();
2576
+ if (update.reasoning !== undefined)
2577
+ decision.reasoning = update.reasoning.trim();
2578
+ if (update.status !== undefined)
2579
+ decision.status = update.status;
2580
+ if (update.causedBy !== undefined) {
2581
+ const ids = normalizedIds(update.causedBy);
2582
+ if (ids)
2583
+ decision.causedBy = ids;
2584
+ else
2585
+ delete decision.causedBy;
2586
+ }
2587
+ }
2588
+ validateDecisionGraph(out);
2589
+ return { decisions: out, missing };
2590
+ }
2591
+ function deleteDecisions(decisions, opts) {
2592
+ if (opts.all)
2593
+ return { decisions: [], removed: decisions.length };
2594
+ const ids = new Set(opts.ids ?? []);
2595
+ const kept = decisions.filter((decision) => !ids.has(decision.id)).map((decision) => {
2596
+ const causedBy = decision.causedBy?.filter((id) => !ids.has(id));
2597
+ const next = { ...decision };
2598
+ if (causedBy && causedBy.length > 0)
2599
+ next.causedBy = causedBy;
2600
+ else
2601
+ delete next.causedBy;
2602
+ return next;
2603
+ });
2604
+ return { decisions: kept, removed: decisions.length - kept.length };
2605
+ }
2606
+ function renderDecisionList(decisions) {
2607
+ if (decisions.length === 0)
2608
+ return "Decisions (0 recorded)";
2609
+ return [
2610
+ `Decisions (${decisions.length} recorded)`,
2611
+ ...decisions.map((decision) => {
2612
+ const causes = decision.causedBy?.length ? ` <- ${decision.causedBy.map((id) => `#${id}`).join(", ")}` : "";
2613
+ return `[${decision.status}] #${decision.id} ${decision.action}${causes}
2614
+ ${decision.reasoning}`;
2615
+ })
2616
+ ].join(`
2617
+ `);
2618
+ }
2427
2619
  // ../../packages/core/src/storage/forum/index.ts
2428
2620
  var exports_forum = {};
2429
2621
  __export(exports_forum, {
@@ -3055,20 +3247,20 @@ __export(exports_session_asks, {
3055
3247
  import { createHash } from "crypto";
3056
3248
  import {
3057
3249
  closeSync as closeSync2,
3058
- mkdirSync as mkdirSync6,
3250
+ mkdirSync as mkdirSync7,
3059
3251
  openSync as openSync2,
3060
3252
  readdirSync as readdirSync2,
3061
- readFileSync as readFileSync4,
3253
+ readFileSync as readFileSync5,
3062
3254
  statSync as statSync3,
3063
3255
  unlinkSync as unlinkSync5,
3064
- writeFileSync as writeFileSync5
3256
+ writeFileSync as writeFileSync6
3065
3257
  } from "fs";
3066
- import { dirname as dirname5, join as join5 } from "path";
3258
+ import { dirname as dirname6, join as join6 } from "path";
3067
3259
  var PENDING_ASK_TTL_MS = 15 * 60 * 1000;
3068
3260
  function pendingAskDir(userId) {
3069
3261
  const rawUserId = String(userId);
3070
3262
  const safeUserId = /^[A-Za-z0-9][A-Za-z0-9_.@-]{0,255}$/.test(rawUserId) && !rawUserId.includes("..") ? rawUserId : `sha256-${createHash("sha256").update(rawUserId).digest("hex")}`;
3071
- return join5(resolveStorageSessionAsksDir(), safeUserId);
3263
+ return join6(resolveStorageSessionAsksDir(), safeUserId);
3072
3264
  }
3073
3265
  var ASK_FILENAME_PREFIX = "v3-";
3074
3266
  var V2_ASK_FILENAME_PREFIX = "v2-";
@@ -3077,19 +3269,19 @@ function encodeAskKey(key) {
3077
3269
  }
3078
3270
  function pendingAskPath(key) {
3079
3271
  const digest = createHash("sha256").update(encodeAskKey(key)).digest("hex");
3080
- return join5(pendingAskDir(key.userId), `${ASK_FILENAME_PREFIX}${digest}.pending`);
3272
+ return join6(pendingAskDir(key.userId), `${ASK_FILENAME_PREFIX}${digest}.pending`);
3081
3273
  }
3082
3274
  function v2PendingAskPath(key) {
3083
3275
  const encoded = Buffer.from(encodeAskKey(key), "utf8").toString("base64url");
3084
- return join5(pendingAskDir(key.userId), `${V2_ASK_FILENAME_PREFIX}${encoded}.pending`);
3276
+ return join6(pendingAskDir(key.userId), `${V2_ASK_FILENAME_PREFIX}${encoded}.pending`);
3085
3277
  }
3086
3278
  function legacyPendingAskPath(key) {
3087
3279
  if (key.from.includes("/") || key.from.includes("\\") || key.to.includes("/") || key.to.includes("\\") || key.from.includes("\x00") || key.to.includes("\x00")) {
3088
3280
  return null;
3089
3281
  }
3090
3282
  const dir = pendingAskDir(key.userId);
3091
- const candidate = join5(dir, `${key.from}___${key.to}.pending`);
3092
- return dirname5(candidate) === dir ? candidate : null;
3283
+ const candidate = join6(dir, `${key.from}___${key.to}.pending`);
3284
+ return dirname6(candidate) === dir ? candidate : null;
3093
3285
  }
3094
3286
  function parsePendingAskFilename(fileName) {
3095
3287
  if (!fileName.endsWith(".pending"))
@@ -3110,7 +3302,7 @@ function parsePendingAskFilename(fileName) {
3110
3302
  }
3111
3303
  function readPendingAskFile(path, fallback) {
3112
3304
  try {
3113
- const raw = readFileSync4(path, "utf8").trim();
3305
+ const raw = readFileSync5(path, "utf8").trim();
3114
3306
  if (!raw)
3115
3307
  return null;
3116
3308
  if (!raw.startsWith("{")) {
@@ -3161,17 +3353,17 @@ function isStale(record, path) {
3161
3353
  }
3162
3354
  function writePendingAsk(record) {
3163
3355
  const path = pendingAskPath(record);
3164
- mkdirSync6(pendingAskDir(record.userId), { recursive: true });
3165
- writeFileSync5(path, `${JSON.stringify(record)}
3356
+ mkdirSync7(pendingAskDir(record.userId), { recursive: true });
3357
+ writeFileSync6(path, `${JSON.stringify(record)}
3166
3358
  `);
3167
3359
  }
3168
3360
  function writePendingAskIfAbsent(record) {
3169
3361
  const path = pendingAskPath(record);
3170
- mkdirSync6(pendingAskDir(record.userId), { recursive: true });
3362
+ mkdirSync7(pendingAskDir(record.userId), { recursive: true });
3171
3363
  let fd = null;
3172
3364
  try {
3173
3365
  fd = openSync2(path, "wx");
3174
- writeFileSync5(fd, `${JSON.stringify(record)}
3366
+ writeFileSync6(fd, `${JSON.stringify(record)}
3175
3367
  `);
3176
3368
  return true;
3177
3369
  } catch (error) {
@@ -3231,12 +3423,12 @@ function createPendingAsk(args) {
3231
3423
  createdAt: now,
3232
3424
  updatedAt: now
3233
3425
  };
3234
- mkdirSync6(pendingAskDir(args.userId), { recursive: true });
3426
+ mkdirSync7(pendingAskDir(args.userId), { recursive: true });
3235
3427
  for (let attempt = 0;attempt < 2; attempt++) {
3236
3428
  let fd = null;
3237
3429
  try {
3238
3430
  fd = openSync2(path, "wx");
3239
- writeFileSync5(fd, `${JSON.stringify(record)}
3431
+ writeFileSync6(fd, `${JSON.stringify(record)}
3240
3432
  `);
3241
3433
  return { ok: true, record };
3242
3434
  } catch (err) {
@@ -3329,7 +3521,7 @@ function listPendingAsksForCaller(args) {
3329
3521
  const parsed = isV3 ? { from: args.from, to: "" } : parsePendingAskFilename(fileName);
3330
3522
  if (!parsed)
3331
3523
  continue;
3332
- const path = join5(dir, fileName);
3524
+ const path = join6(dir, fileName);
3333
3525
  const record = readPendingAskFile(path, {
3334
3526
  userId: args.userId,
3335
3527
  from: parsed.from,
@@ -3371,7 +3563,7 @@ function deletePendingAsksForTopic(args) {
3371
3563
  }
3372
3564
  let deleted = 0;
3373
3565
  for (const fileName of files) {
3374
- const path = join5(dir, fileName);
3566
+ const path = join6(dir, fileName);
3375
3567
  const parsed = parsePendingAskFilename(fileName);
3376
3568
  const record = readPendingAskFile(path, {
3377
3569
  userId: args.userId,
@@ -3419,8 +3611,8 @@ __export(exports_tasks, {
3419
3611
  createTasks: () => createTasks,
3420
3612
  TASK_STATUS_VALUES: () => TASK_STATUS_VALUES
3421
3613
  });
3422
- import { existsSync as existsSync4, mkdirSync as mkdirSync7, readFileSync as readFileSync5, renameSync as renameSync4, statSync as statSync4, writeFileSync as writeFileSync6 } from "fs";
3423
- import { dirname as dirname6, join as join6 } from "path";
3614
+ import { existsSync as existsSync5, mkdirSync as mkdirSync8, readFileSync as readFileSync6, renameSync as renameSync5, statSync as statSync4, writeFileSync as writeFileSync7 } from "fs";
3615
+ import { dirname as dirname7, join as join7 } from "path";
3424
3616
  var TASK_STATUS_VALUES = ["pending", "in_progress", "completed"];
3425
3617
  function safeTaskScopeKey(scopeKey) {
3426
3618
  const safe = sanitizeFileName(scopeKey);
@@ -3433,14 +3625,14 @@ function taskScopeKey(opts) {
3433
3625
  return opts.topicId?.trim() || opts.session || "default";
3434
3626
  }
3435
3627
  function getTaskFilePath(userId, scopeKey) {
3436
- return join6(resolveStorageDataDir(), "tasks", `${safeTaskScopeKey(scopeKey)}.json`);
3628
+ return join7(resolveStorageDataDir(), "tasks", `${safeTaskScopeKey(scopeKey)}.json`);
3437
3629
  }
3438
3630
  function readTasks(userId, scopeKey) {
3439
3631
  const path = getTaskFilePath(userId, scopeKey);
3440
- if (!existsSync4(path))
3632
+ if (!existsSync5(path))
3441
3633
  return [];
3442
3634
  try {
3443
- const parsed = JSON.parse(readFileSync5(path, "utf-8"));
3635
+ const parsed = JSON.parse(readFileSync6(path, "utf-8"));
3444
3636
  return Array.isArray(parsed?.tasks) ? parsed.tasks : [];
3445
3637
  } catch (e) {
3446
3638
  logger.warn({ err: e, path }, "tasks: failed to read task store");
@@ -3449,11 +3641,11 @@ function readTasks(userId, scopeKey) {
3449
3641
  }
3450
3642
  function writeTasks(userId, scopeKey, tasks) {
3451
3643
  const path = getTaskFilePath(userId, scopeKey);
3452
- mkdirSync7(dirname6(path), { recursive: true });
3644
+ mkdirSync8(dirname7(path), { recursive: true });
3453
3645
  const payload = { version: 1, tasks };
3454
3646
  const tmp = `${path}.${process.pid}.tmp`;
3455
- writeFileSync6(tmp, JSON.stringify(payload, null, 2), "utf-8");
3456
- renameSync4(tmp, path);
3647
+ writeFileSync7(tmp, JSON.stringify(payload, null, 2), "utf-8");
3648
+ renameSync5(tmp, path);
3457
3649
  }
3458
3650
  function taskFileMtimeNs(userId, scopeKey) {
3459
3651
  try {
@@ -3555,8 +3747,8 @@ __export(exports_token_stats, {
3555
3747
  calcCost: () => calcCost
3556
3748
  });
3557
3749
  import { createHash as createHash2 } from "crypto";
3558
- import { mkdirSync as mkdirSync8, writeFileSync as writeFileSync7 } from "fs";
3559
- import { join as join7 } from "path";
3750
+ import { mkdirSync as mkdirSync9, writeFileSync as writeFileSync8 } from "fs";
3751
+ import { join as join8 } from "path";
3560
3752
  function emptyBucket() {
3561
3753
  return {
3562
3754
  inputTokens: 0,
@@ -3574,8 +3766,8 @@ function tokenStatsFileId(userId) {
3574
3766
  function queriesPath(userId) {
3575
3767
  const fileId = tokenStatsFileId(userId);
3576
3768
  const logDir = resolveStorageLogDir();
3577
- mkdirSync8(logDir, { recursive: true });
3578
- return join7(logDir, `token-queries-${fileId}.jsonl`);
3769
+ mkdirSync9(logDir, { recursive: true });
3770
+ return join8(logDir, `token-queries-${fileId}.jsonl`);
3579
3771
  }
3580
3772
  function loadRecords(userId) {
3581
3773
  try {
@@ -3656,7 +3848,7 @@ function deleteTopicStats(userId, topicId) {
3656
3848
  return true;
3657
3849
  }
3658
3850
  });
3659
- writeFileSync7(path, kept.length > 0 ? `${kept.join(`
3851
+ writeFileSync8(path, kept.length > 0 ? `${kept.join(`
3660
3852
  `)}
3661
3853
  ` : "", "utf-8");
3662
3854
  } catch (e) {
@@ -3762,8 +3954,8 @@ __export(exports_topic_archive, {
3762
3954
  archiveTopicMessages: () => archiveTopicMessages,
3763
3955
  archiveConversationEvents: () => archiveConversationEvents
3764
3956
  });
3765
- import { mkdirSync as mkdirSync9, writeFileSync as writeFileSync8 } from "fs";
3766
- import { join as join9 } from "path";
3957
+ import { mkdirSync as mkdirSync10, writeFileSync as writeFileSync9 } from "fs";
3958
+ import { join as join10 } from "path";
3767
3959
 
3768
3960
  // ../../packages/core/src/agents/memory-archive-policy.ts
3769
3961
  function countMemoryArchiveExchanges(rows) {
@@ -3851,50 +4043,50 @@ __export(exports_wiki, {
3851
4043
  getTopicMemoryFilePaths: () => getTopicMemoryFilePaths,
3852
4044
  getSharedWikiDir: () => getSharedWikiDir
3853
4045
  });
3854
- import { existsSync as existsSync5, readdirSync as readdirSync3, statSync as statSync5 } from "fs";
3855
- import { basename as basename2, dirname as dirname7, join as join8 } from "path";
4046
+ import { existsSync as existsSync6, readdirSync as readdirSync3, statSync as statSync5 } from "fs";
4047
+ import { basename as basename2, dirname as dirname8, join as join9 } from "path";
3856
4048
  function getWikiDir(_userId, workspaceDir = resolveStorageWorkspaceDir()) {
3857
- return join8(workspaceDir, "wiki");
4049
+ return join9(workspaceDir, "wiki");
3858
4050
  }
3859
4051
  function getSharedWikiDir(workspaceDir = resolveStorageWorkspaceDir()) {
3860
- return workspaceDir === resolveStorageWorkspaceDir() ? resolveStorageSharedWikiDir() : join8(workspaceDir, "wiki");
4052
+ return workspaceDir === resolveStorageWorkspaceDir() ? resolveStorageSharedWikiDir() : join9(workspaceDir, "wiki");
3861
4053
  }
3862
4054
  function findLatestSummaryFile(wikiDir, safeTopic) {
3863
- const summariesDir = join8(wikiDir, "summaries");
3864
- if (!existsSync5(summariesDir))
4055
+ const summariesDir = join9(wikiDir, "summaries");
4056
+ if (!existsSync6(summariesDir))
3865
4057
  return null;
3866
4058
  const files = readdirSync3(summariesDir).filter((f) => f.endsWith(".md") && f.match(new RegExp(`^\\d{4}-\\d{2}-\\d{2}-${safeTopic}(\\.md|~\\d+\\.md)$`)) && !f.endsWith("-sent-files.md")).sort((left, right) => {
3867
- const mtimeDelta = statSync5(join8(summariesDir, right)).mtimeMs - statSync5(join8(summariesDir, left)).mtimeMs;
4059
+ const mtimeDelta = statSync5(join9(summariesDir, right)).mtimeMs - statSync5(join9(summariesDir, left)).mtimeMs;
3868
4060
  return mtimeDelta || right.localeCompare(left, undefined, { numeric: true });
3869
4061
  });
3870
- return files.length > 0 ? join8(summariesDir, files[0]) : null;
4062
+ return files.length > 0 ? join9(summariesDir, files[0]) : null;
3871
4063
  }
3872
4064
  function getTopicMemoryFilePaths(_userId, topicName, forkOrigin, workspaceDir = resolveStorageWorkspaceDir()) {
3873
4065
  const wikiDir = getSharedWikiDir(workspaceDir);
3874
4066
  const resolveBrief = (name) => {
3875
4067
  const safe = sanitizeTopicName(name, true);
3876
- const brief = join8(wikiDir, "topic", `${safe}.md`);
4068
+ const brief = join9(wikiDir, "topic", `${safe}.md`);
3877
4069
  const latestSummary = findLatestSummaryFile(wikiDir, safe);
3878
4070
  return { brief, latestSummary };
3879
4071
  };
3880
- const archiveDir = join8(wikiDir, "archive");
4072
+ const archiveDir = join9(wikiDir, "archive");
3881
4073
  const archiveExistsFor = (name) => {
3882
4074
  const safe = sanitizeTopicName(name);
3883
- return existsSync5(archiveDir) && readdirSync3(archiveDir).some((f) => f.endsWith(".jsonl") && f.startsWith(`${safe}_`));
4075
+ return existsSync6(archiveDir) && readdirSync3(archiveDir).some((f) => f.endsWith(".jsonl") && f.startsWith(`${safe}_`));
3884
4076
  };
3885
4077
  const sourceTopic = forkOrigin ?? topicName;
3886
4078
  const hasArchive = archiveExistsFor(sourceTopic) || (forkOrigin ? archiveExistsFor(topicName) : false);
3887
4079
  const target = resolveBrief(sourceTopic);
3888
- if (existsSync5(target.brief)) {
4080
+ if (existsSync6(target.brief)) {
3889
4081
  return {
3890
- memoryDir: dirname7(target.brief),
4082
+ memoryDir: dirname8(target.brief),
3891
4083
  memoryFiles: [basename2(target.brief)],
3892
4084
  ...target.latestSummary ? { latestSummaryFile: target.latestSummary } : {},
3893
4085
  ...hasArchive ? { hasArchive: true } : {}
3894
4086
  };
3895
4087
  }
3896
4088
  return {
3897
- memoryDir: join8(wikiDir, "topic"),
4089
+ memoryDir: join9(wikiDir, "topic"),
3898
4090
  memoryFiles: [],
3899
4091
  ...target.latestSummary ? { latestSummaryFile: target.latestSummary } : {},
3900
4092
  ...hasArchive ? { hasArchive: true } : {}
@@ -3907,8 +4099,8 @@ function archiveTopicMessages(topicId, topicTitle, options = {}) {
3907
4099
  if (rows.length === 0)
3908
4100
  return null;
3909
4101
  const safeTopic = sanitizeTopicName(topicTitle, true);
3910
- const archiveDir = join9(getSharedWikiDir(), "archive");
3911
- mkdirSync9(archiveDir, { recursive: true });
4102
+ const archiveDir = join10(getSharedWikiDir(), "archive");
4103
+ mkdirSync10(archiveDir, { recursive: true });
3912
4104
  const date = new Date().toISOString().slice(0, 10);
3913
4105
  const reasonSuffix = options.reason && options.reason !== "delete" ? `_${options.reason}` : "";
3914
4106
  let filename;
@@ -3920,9 +4112,9 @@ function archiveTopicMessages(topicId, topicTitle, options = {}) {
3920
4112
  let path;
3921
4113
  while (true) {
3922
4114
  filename = `${safeTopic}_${date}${reasonSuffix}${counter === 1 ? "" : `_${counter}`}.jsonl`;
3923
- path = join9(archiveDir, filename);
4115
+ path = join10(archiveDir, filename);
3924
4116
  try {
3925
- writeFileSync8(path, body, { flag: "wx" });
4117
+ writeFileSync9(path, body, { flag: "wx" });
3926
4118
  break;
3927
4119
  } catch (err) {
3928
4120
  if (err.code !== "EEXIST")
@@ -3965,8 +4157,8 @@ function archiveConversationEvents(topicId, topicTitle, userId, options = {}) {
3965
4157
  const entries = readRawConversation(userId, topicTitle);
3966
4158
  if (entries.length === 0)
3967
4159
  return null;
3968
- const archiveDir = join9(getSharedWikiDir(), "archive");
3969
- mkdirSync9(archiveDir, { recursive: true });
4160
+ const archiveDir = join10(getSharedWikiDir(), "archive");
4161
+ mkdirSync10(archiveDir, { recursive: true });
3970
4162
  const safeTopic = sanitizeTopicName(topicTitle, true);
3971
4163
  const date = new Date().toISOString().slice(0, 10);
3972
4164
  const reasonSuffix = options.reason && options.reason !== "delete" ? `_${options.reason}` : "";
@@ -3993,9 +4185,9 @@ function archiveConversationEvents(topicId, topicTitle, userId, options = {}) {
3993
4185
  let counter = 1;
3994
4186
  while (true) {
3995
4187
  const suffix = counter === 1 ? "" : `_${counter}`;
3996
- const path = join9(archiveDir, `${safeTopic}_${date}${reasonSuffix}_events${suffix}.jsonl`);
4188
+ const path = join10(archiveDir, `${safeTopic}_${date}${reasonSuffix}_events${suffix}.jsonl`);
3997
4189
  try {
3998
- writeFileSync8(path, body, { flag: "wx" });
4190
+ writeFileSync9(path, body, { flag: "wx" });
3999
4191
  logger.info({ topicId, topicTitle, archive: path, eventCount: entries.length }, "archiveConversationEvents: archived raw conversation events");
4000
4192
  return { path, eventCount: entries.length };
4001
4193
  } catch (error) {
@@ -4182,6 +4374,8 @@ export {
4182
4374
  writeTasks,
4183
4375
  writeSentFileLog,
4184
4376
  writeLog,
4377
+ writeDecisions,
4378
+ writeDecisionGraphSvg,
4185
4379
  wikiSummaryStorageSlug,
4186
4380
  wikiSummarySlug,
4187
4381
  exports_wiki_summary_names as wikiSummaryNames,
@@ -4190,9 +4384,11 @@ export {
4190
4384
  exports_wiki as wiki,
4191
4385
  waitForRuntimeProcessLease,
4192
4386
  waitForRequiredRuntimeProcessLease,
4387
+ validateDecisionGraph,
4193
4388
  upsertTopic,
4194
4389
  updateTopicThreadId,
4195
4390
  updateTasks,
4391
+ updateDecisions,
4196
4392
  updateApiMessageUsage,
4197
4393
  updateApiMessageText,
4198
4394
  updateApiMessageSubagentCard,
@@ -4241,6 +4437,7 @@ export {
4241
4437
  replaceConversationStrict,
4242
4438
  reparentTopicChildren,
4243
4439
  renderTaskList,
4440
+ renderDecisionList,
4244
4441
  renameTopic,
4245
4442
  removeTopic,
4246
4443
  removeSentFilesForTopic,
@@ -4252,6 +4449,7 @@ export {
4252
4449
  readTasks,
4253
4450
  readSentFilesForTopic,
4254
4451
  readRawConversation,
4452
+ readDecisions,
4255
4453
  readConversation,
4256
4454
  quarantineForeignAskUserGates,
4257
4455
  quarantineAskUserGate,
@@ -4313,6 +4511,8 @@ export {
4313
4511
  getGlobalAiName,
4314
4512
  getTopicByName2 as getForumTopicByName,
4315
4513
  getDmSessionId,
4514
+ getDecisionGraphSvgPath,
4515
+ getDecisionFilePath,
4316
4516
  getConversationPath,
4317
4517
  getCommunicateThreadId,
4318
4518
  getApiTopicConfig,
@@ -4336,12 +4536,16 @@ export {
4336
4536
  deleteTasks,
4337
4537
  deletePendingAsksForTopic,
4338
4538
  deleteMessagesForTopic,
4539
+ deleteDecisions,
4339
4540
  deleteApiTopicConfig,
4340
4541
  defaultTopicSurface,
4341
4542
  defaultSurfaceScope,
4543
+ exports_decisions as decisions,
4544
+ decisionScopeKey,
4342
4545
  db2 as db,
4343
4546
  createTasks,
4344
4547
  createPendingAsk,
4548
+ createDecisions,
4345
4549
  copyMessagesForTopic,
4346
4550
  copyMessageSnapshotToTopic,
4347
4551
  exports_conversations as conversations,
@@ -4380,7 +4584,8 @@ export {
4380
4584
  PROCESS_LEASE_HEARTBEAT_MS,
4381
4585
  PENDING_ASK_TTL_MS,
4382
4586
  DEFAULT_AI_NAME,
4587
+ DECISION_STATUS_VALUES,
4383
4588
  ConversationLogDivergedError
4384
4589
  };
4385
4590
 
4386
- //# debugId=91A231DEF2CE9E1164756E2164756E21
4591
+ //# debugId=89A366518555705864756E2164756E21