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.
- package/dist/agent-helpers.js +107 -6
- package/dist/agent-helpers.js.map +11 -11
- package/dist/background-bash.js +3 -2
- package/dist/background-bash.js.map +4 -4
- package/dist/browser-runtime.js +3 -2
- package/dist/browser-runtime.js.map +4 -4
- package/dist/chunk-s2gez3wg.js.map +1 -1
- package/dist/{chunk-1y2xw0xe.js → chunk-vvfwqxnh.js} +33 -3
- package/dist/{chunk-1y2xw0xe.js.map → chunk-vvfwqxnh.js.map} +8 -8
- package/dist/hosted-agent.js +34 -4
- package/dist/hosted-agent.js.map +8 -8
- package/dist/main.js +1179 -366
- package/dist/main.js.map +24 -21
- package/dist/mcp-catalog.js +2 -1
- package/dist/mcp-catalog.js.map +3 -3
- package/dist/mcp-factories.js +635 -256
- package/dist/mcp-factories.js.map +15 -13
- package/dist/mcp-servers.js +3 -1
- package/dist/mcp-servers.js.map +3 -3
- package/dist/prompts.js +8 -2
- package/dist/prompts.js.map +5 -5
- package/dist/query-runtime.js +3 -2
- package/dist/query-runtime.js.map +4 -4
- package/dist/registry.js +3 -3
- package/dist/registry.js.map +2 -2
- package/dist/rollout.js +1 -1
- package/dist/runtime/src/mcp/canonical-bridge-config.ts +1 -1
- package/dist/runtime/src/mcp/canonical-proxy-server.ts +74 -1
- package/dist/runtime/src/mcp/decision-server.ts +21 -0
- package/dist/runtime/src/mcp/factories/decision.ts +178 -0
- package/dist/runtime/src/mcp/factories/index.ts +6 -0
- package/dist/runtime/src/mcp/runtime-spec.ts +1 -0
- package/dist/runtime/src/node-host.ts +1 -0
- package/dist/runtime/src/platform/config.ts +2 -1
- package/dist/runtime/src/platform/mcp-catalog-policy.ts +1 -0
- package/dist/runtime/src/platform/mcp-config.ts +31 -1
- package/dist/runtime/src/prompts/builders.ts +5 -0
- package/dist/runtime/src/runtime/visual-html.ts +68 -2
- package/dist/runtime/src/storage/decisions.ts +231 -0
- package/dist/runtime/src/storage/storage-public.ts +2 -0
- package/dist/runtime/src/types.ts +13 -0
- package/dist/runtime/src/version.ts +1 -1
- package/dist/runtime-helpers.js +71 -4
- package/dist/runtime-helpers.js.map +5 -5
- package/dist/storage.js +261 -56
- package/dist/storage.js.map +5 -4
- package/dist/types/apps/negotium/src/mcp-servers.d.ts +1 -1
- package/dist/types/packages/core/src/mcp/canonical-bridge-config.d.ts +1 -1
- package/dist/types/packages/core/src/mcp/factories/decision.d.ts +16 -0
- package/dist/types/packages/core/src/mcp/factories/index.d.ts +1 -0
- package/dist/types/packages/core/src/mcp/runtime-spec.d.ts +1 -1
- package/dist/types/packages/core/src/platform/config.d.ts +2 -1
- package/dist/types/packages/core/src/platform/mcp-catalog-policy.d.ts +4 -0
- package/dist/types/packages/core/src/storage/decisions.d.ts +45 -0
- package/dist/types/packages/core/src/storage/storage-public.d.ts +2 -0
- package/dist/types/packages/core/src/types.d.ts +12 -0
- package/dist/types/packages/core/src/version.d.ts +1 -1
- package/dist/vault.js +3 -2
- package/dist/vault.js.map +4 -4
- package/install-browser-rs.mjs +3 -3
- 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
|
|
3250
|
+
mkdirSync as mkdirSync7,
|
|
3059
3251
|
openSync as openSync2,
|
|
3060
3252
|
readdirSync as readdirSync2,
|
|
3061
|
-
readFileSync as
|
|
3253
|
+
readFileSync as readFileSync5,
|
|
3062
3254
|
statSync as statSync3,
|
|
3063
3255
|
unlinkSync as unlinkSync5,
|
|
3064
|
-
writeFileSync as
|
|
3256
|
+
writeFileSync as writeFileSync6
|
|
3065
3257
|
} from "fs";
|
|
3066
|
-
import { dirname as
|
|
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
|
|
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
|
|
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
|
|
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 =
|
|
3092
|
-
return
|
|
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 =
|
|
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
|
-
|
|
3165
|
-
|
|
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
|
-
|
|
3362
|
+
mkdirSync7(pendingAskDir(record.userId), { recursive: true });
|
|
3171
3363
|
let fd = null;
|
|
3172
3364
|
try {
|
|
3173
3365
|
fd = openSync2(path, "wx");
|
|
3174
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
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 =
|
|
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
|
|
3423
|
-
import { dirname as
|
|
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
|
|
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 (!
|
|
3632
|
+
if (!existsSync5(path))
|
|
3441
3633
|
return [];
|
|
3442
3634
|
try {
|
|
3443
|
-
const parsed = JSON.parse(
|
|
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
|
-
|
|
3644
|
+
mkdirSync8(dirname7(path), { recursive: true });
|
|
3453
3645
|
const payload = { version: 1, tasks };
|
|
3454
3646
|
const tmp = `${path}.${process.pid}.tmp`;
|
|
3455
|
-
|
|
3456
|
-
|
|
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
|
|
3559
|
-
import { join as
|
|
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
|
-
|
|
3578
|
-
return
|
|
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
|
-
|
|
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
|
|
3766
|
-
import { join as
|
|
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
|
|
3855
|
-
import { basename as basename2, dirname as
|
|
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
|
|
4049
|
+
return join9(workspaceDir, "wiki");
|
|
3858
4050
|
}
|
|
3859
4051
|
function getSharedWikiDir(workspaceDir = resolveStorageWorkspaceDir()) {
|
|
3860
|
-
return workspaceDir === resolveStorageWorkspaceDir() ? resolveStorageSharedWikiDir() :
|
|
4052
|
+
return workspaceDir === resolveStorageWorkspaceDir() ? resolveStorageSharedWikiDir() : join9(workspaceDir, "wiki");
|
|
3861
4053
|
}
|
|
3862
4054
|
function findLatestSummaryFile(wikiDir, safeTopic) {
|
|
3863
|
-
const summariesDir =
|
|
3864
|
-
if (!
|
|
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(
|
|
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 ?
|
|
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 =
|
|
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 =
|
|
4072
|
+
const archiveDir = join9(wikiDir, "archive");
|
|
3881
4073
|
const archiveExistsFor = (name) => {
|
|
3882
4074
|
const safe = sanitizeTopicName(name);
|
|
3883
|
-
return
|
|
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 (
|
|
4080
|
+
if (existsSync6(target.brief)) {
|
|
3889
4081
|
return {
|
|
3890
|
-
memoryDir:
|
|
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:
|
|
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 =
|
|
3911
|
-
|
|
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 =
|
|
4115
|
+
path = join10(archiveDir, filename);
|
|
3924
4116
|
try {
|
|
3925
|
-
|
|
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 =
|
|
3969
|
-
|
|
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 =
|
|
4188
|
+
const path = join10(archiveDir, `${safeTopic}_${date}${reasonSuffix}_events${suffix}.jsonl`);
|
|
3997
4189
|
try {
|
|
3998
|
-
|
|
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=
|
|
4591
|
+
//# debugId=89A366518555705864756E2164756E21
|