dsh-mnemon 0.5.11 → 0.5.13
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/README.md +1 -1
- package/README.zh-CN.md +1 -1
- package/lib/client.js +108 -53
- package/lib/index.js +852 -204
- package/lib/types/src/client/extension-sdk.d.ts +1 -1
- package/lib/types/src/client/locales.d.ts +2 -4
- package/lib/types/src/client/ui-icons.d.ts +4 -0
- package/lib/types/src/host/live-config.d.ts +11 -0
- package/lib/types/src/host/plugin.d.ts +4 -3
- package/lib/types/src/host/protocol.d.ts +4 -0
- package/package.json +9 -3
package/lib/index.js
CHANGED
|
@@ -19,6 +19,10 @@ import { findMnemonCommand, mnemonNpmLauncher, nodeLauncherEnvironment } from "d
|
|
|
19
19
|
import { spawn } from "node:child_process";
|
|
20
20
|
import { StringDecoder } from "node:string_decoder";
|
|
21
21
|
import { z as z$1 } from "zod";
|
|
22
|
+
import { readFile, stat } from "node:fs/promises";
|
|
23
|
+
import { parseDocument } from "yaml";
|
|
24
|
+
import { isVolatile } from "@deepseek-ai/cosmokit";
|
|
25
|
+
import schemastery_live_default from "schemastery-live";
|
|
22
26
|
import { Remote, TypertRemoteService } from "@deepseek-ai/dsh-typert-protocol";
|
|
23
27
|
//#region src/host/view-protocol.ts
|
|
24
28
|
const MNEMON_VIEW_CHANNEL = "/dsh-mnemon-view";
|
|
@@ -85,6 +89,48 @@ const MNEMON_EMBEDDING_PROTOCOLS = [
|
|
|
85
89
|
"openai"
|
|
86
90
|
];
|
|
87
91
|
//#endregion
|
|
92
|
+
//#region src/host/view-preferences.ts
|
|
93
|
+
const schema = z.object({
|
|
94
|
+
strategyTypeId: z.string(),
|
|
95
|
+
entries: z.dict(z.object({
|
|
96
|
+
enabled: z.boolean(),
|
|
97
|
+
config: z.dict(z.any()).default({})
|
|
98
|
+
})).default({})
|
|
99
|
+
});
|
|
100
|
+
const legacySchema = z.object({ sources: z.dict(z.object({ enabled: z.boolean() })).default({}) });
|
|
101
|
+
const ENTRY_ID$1 = /^[a-zA-Z0-9][a-zA-Z0-9._:/-]{0,299}$/u;
|
|
102
|
+
const clone$2 = (value) => JSON.parse(JSON.stringify(value));
|
|
103
|
+
function record$3(value) {
|
|
104
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) throw new Error("Plugin configuration must be an object");
|
|
105
|
+
const json = JSON.stringify(value);
|
|
106
|
+
if (json.length > 65536) throw new Error("Plugin configuration exceeds 64 KiB");
|
|
107
|
+
const parsed = JSON.parse(json);
|
|
108
|
+
for (const key of Object.keys(parsed)) if ([
|
|
109
|
+
"__proto__",
|
|
110
|
+
"prototype",
|
|
111
|
+
"constructor"
|
|
112
|
+
].includes(key)) throw new Error("Unsafe plugin configuration key");
|
|
113
|
+
return parsed;
|
|
114
|
+
}
|
|
115
|
+
function preferences(value) {
|
|
116
|
+
if (value.strategyTypeId !== void 0 && !/^[a-z][a-z0-9-]{0,127}$/u.test(value.strategyTypeId)) throw new Error("Invalid Strategy type id");
|
|
117
|
+
const entries = record$3(value.entries ?? {});
|
|
118
|
+
if (Object.keys(entries).length > 64) throw new Error("At most 64 memory plugin Entries can be configured");
|
|
119
|
+
for (const [entryId, item] of Object.entries(entries)) {
|
|
120
|
+
if (!ENTRY_ID$1.test(entryId)) throw new Error("Invalid memory plugin Entry id");
|
|
121
|
+
const candidate = record$3(item);
|
|
122
|
+
if (typeof candidate.enabled !== "boolean") throw new Error("Plugin enabled must be boolean");
|
|
123
|
+
record$3(candidate.config);
|
|
124
|
+
}
|
|
125
|
+
return clone$2(value);
|
|
126
|
+
}
|
|
127
|
+
function legacyPreferences(value) {
|
|
128
|
+
const sources = value.sources ?? {};
|
|
129
|
+
if (Object.keys(sources).length > 64) throw new Error("At most 64 legacy Source Entries can be configured");
|
|
130
|
+
for (const [entryId, item] of Object.entries(sources)) if (!ENTRY_ID$1.test(entryId) || typeof item?.enabled !== "boolean") throw new Error("Invalid legacy Source Entry preference");
|
|
131
|
+
return clone$2({ sources });
|
|
132
|
+
}
|
|
133
|
+
//#endregion
|
|
88
134
|
//#region src/host/config-values.ts
|
|
89
135
|
const DEFAULT_IDLE_REVIEW_MS = 3e4;
|
|
90
136
|
const DEFAULT_RUNTIME_MEMORY_LIMIT_BYTES = 10240;
|
|
@@ -221,6 +267,8 @@ const Config = z.object({
|
|
|
221
267
|
protocol: DEFAULT_EMBEDDING_PROTOCOL
|
|
222
268
|
}),
|
|
223
269
|
memoryTopology: MemoryTopologySchema,
|
|
270
|
+
memoryView: schema,
|
|
271
|
+
legacySettingsImported: z.boolean(),
|
|
224
272
|
recallQuality: RecallQualitySchema.default({
|
|
225
273
|
policy: DEFAULT_RECALL_QUALITY_POLICY,
|
|
226
274
|
lowScoreThreshold: DEFAULT_RECALL_LOW_SCORE_THRESHOLD,
|
|
@@ -372,6 +420,7 @@ function resolveMemoryTopology(value) {
|
|
|
372
420
|
};
|
|
373
421
|
}
|
|
374
422
|
function resolveConfig(config = {}) {
|
|
423
|
+
if (config.memoryView !== void 0) preferences(config.memoryView);
|
|
375
424
|
const cliPath = optionalText(config.cliPath);
|
|
376
425
|
const legacyDataDir = optionalText(config.dataDir);
|
|
377
426
|
const legacyPacks = resolveCustomPacks(config.customPacks, legacyDataDir);
|
|
@@ -444,7 +493,7 @@ const COMPONENT_ORDER = [
|
|
|
444
493
|
];
|
|
445
494
|
const BODY_ID = /^[a-zA-Z0-9][a-zA-Z0-9_-]*$/;
|
|
446
495
|
const SQLITE_HEADER = Buffer.from("SQLite format 3\0", "binary");
|
|
447
|
-
function record$
|
|
496
|
+
function record$2(value) {
|
|
448
497
|
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
|
|
449
498
|
}
|
|
450
499
|
function utf8(bytes, label) {
|
|
@@ -487,7 +536,7 @@ function componentsForScope(scope) {
|
|
|
487
536
|
return [scope];
|
|
488
537
|
}
|
|
489
538
|
function parseManifest(value) {
|
|
490
|
-
const manifest = record$
|
|
539
|
+
const manifest = record$2(value);
|
|
491
540
|
if (manifest?.format !== "mnemonpack" || manifest.version !== 1) throw new Error("unsupported Mnemon Pack format or version");
|
|
492
541
|
if (manifest.scope !== "full" && !COMPONENT_ORDER.includes(manifest.scope)) throw new Error("Mnemon Pack scope is invalid");
|
|
493
542
|
if (typeof manifest.exportedAt !== "string") throw new Error("Mnemon Pack exportedAt is invalid");
|
|
@@ -496,11 +545,11 @@ function parseManifest(value) {
|
|
|
496
545
|
if (components.length === 0 || new Set(components).size !== components.length || components.some((component) => !COMPONENT_ORDER.includes(component))) throw new Error("Mnemon Pack components are invalid");
|
|
497
546
|
const expected = componentsForScope(manifest.scope);
|
|
498
547
|
if (components.length !== expected.length || expected.some((component) => !components.includes(component))) throw new Error("Mnemon Pack scope does not match its components");
|
|
499
|
-
const source = record$
|
|
548
|
+
const source = record$2(manifest.source);
|
|
500
549
|
if (source?.plugin !== "dsh-mnemon" || typeof source.pluginVersion !== "string") throw new Error("Mnemon Pack source is invalid");
|
|
501
550
|
if (!Array.isArray(manifest.summary)) throw new Error("Mnemon Pack summary is invalid");
|
|
502
551
|
const summary = manifest.summary.map((entry) => {
|
|
503
|
-
const item = record$
|
|
552
|
+
const item = record$2(entry);
|
|
504
553
|
const component = item?.component;
|
|
505
554
|
if (!COMPONENT_ORDER.includes(component) || !Number.isSafeInteger(item?.files) || !Number.isSafeInteger(item?.bytes) || !Number.isSafeInteger(item?.items) || Number(item?.files) < 0 || Number(item?.bytes) < 0 || Number(item?.items) < 0) throw new Error("Mnemon Pack summary entry is invalid");
|
|
506
555
|
return {
|
|
@@ -550,8 +599,8 @@ function parseArchive(base64, runtimeLimits = RUNTIME_MEMORY_LIMITS) {
|
|
|
550
599
|
if (path !== "manifest.json" && path !== "checksums.json" && !allowedPayloadPath(path)) throw new Error(`unsupported Mnemon Pack entry: ${path}`);
|
|
551
600
|
}
|
|
552
601
|
const manifest = parseManifest(json$1(files["manifest.json"], "manifest.json"));
|
|
553
|
-
const checksumValue = record$
|
|
554
|
-
const checksumFiles = record$
|
|
602
|
+
const checksumValue = record$2(json$1(files["checksums.json"], "checksums.json"));
|
|
603
|
+
const checksumFiles = record$2(checksumValue?.files);
|
|
555
604
|
if (checksumValue?.algorithm !== "sha256" || checksumFiles === void 0) throw new Error("Mnemon Pack checksums are invalid");
|
|
556
605
|
const payloadNames = names.filter((path) => path.startsWith("payload/")).sort();
|
|
557
606
|
if (Object.keys(checksumFiles).length !== payloadNames.length) throw new Error("Mnemon Pack checksum inventory does not match the payload");
|
|
@@ -574,10 +623,10 @@ function parseArchive(base64, runtimeLimits = RUNTIME_MEMORY_LIMITS) {
|
|
|
574
623
|
};
|
|
575
624
|
}
|
|
576
625
|
function parseRuntime(value, limits = RUNTIME_MEMORY_LIMITS) {
|
|
577
|
-
const source = record$
|
|
626
|
+
const source = record$2(value);
|
|
578
627
|
if (source?.version !== RUNTIME_MEMORY_VERSION || !Array.isArray(source.entries)) throw new Error("runtime memories.json is invalid");
|
|
579
628
|
const entries = source.entries.map((raw) => {
|
|
580
|
-
const entry = record$
|
|
629
|
+
const entry = record$2(raw);
|
|
581
630
|
if (typeof entry?.content !== "string" || entry.target !== "memory" && entry.target !== "user" || ![
|
|
582
631
|
"critical",
|
|
583
632
|
"normal",
|
|
@@ -608,13 +657,13 @@ function runtimeProjection(entries, target) {
|
|
|
608
657
|
return content === "" ? "" : `${content}\n`;
|
|
609
658
|
}
|
|
610
659
|
function parseDocumentIndex(value) {
|
|
611
|
-
const index = record$
|
|
660
|
+
const index = record$2(value);
|
|
612
661
|
if (index?.version !== DOCUMENTS_VERSION || !Array.isArray(index.documents)) throw new Error("Documents index.json is invalid");
|
|
613
662
|
const ids = /* @__PURE__ */ new Set();
|
|
614
663
|
return {
|
|
615
664
|
version: 1,
|
|
616
665
|
documents: index.documents.map((raw) => {
|
|
617
|
-
const item = record$
|
|
666
|
+
const item = record$2(raw);
|
|
618
667
|
if (typeof item?.id !== "string" || item.id.trim() === "" || ids.has(item.id)) throw new Error("Documents index contains an invalid or duplicate id");
|
|
619
668
|
if (typeof item.title !== "string" || typeof item.description !== "string" || item.status !== "active" && item.status !== "archived") throw new Error("Documents index contains an invalid record");
|
|
620
669
|
if (typeof item.filename !== "string" || basename(item.filename) !== item.filename || !/^[a-zA-Z0-9._-]+\.md$/u.test(item.filename)) throw new Error("Documents index contains an unsafe filename");
|
|
@@ -644,13 +693,13 @@ function parseDocumentIndex(value) {
|
|
|
644
693
|
};
|
|
645
694
|
}
|
|
646
695
|
function parseRegistry(value) {
|
|
647
|
-
const registry = record$
|
|
696
|
+
const registry = record$2(value);
|
|
648
697
|
if (registry?.version !== 1 || !Array.isArray(registry.bodies)) throw new Error("Memory Space registry is invalid");
|
|
649
698
|
const ids = /* @__PURE__ */ new Set();
|
|
650
699
|
return {
|
|
651
700
|
version: 1,
|
|
652
701
|
bodies: registry.bodies.map((raw) => {
|
|
653
|
-
const body = record$
|
|
702
|
+
const body = record$2(raw);
|
|
654
703
|
if (typeof body?.id !== "string" || !BODY_ID.test(body.id) || ids.has(body.id)) throw new Error("Memory Space registry contains an invalid or duplicate id");
|
|
655
704
|
if (typeof body.name !== "string" || body.name.trim() === "" || body.name.length > 100 || typeof body.description !== "string" || body.description.length > 1e3) throw new Error("Memory Space registry contains invalid metadata");
|
|
656
705
|
if (typeof body.createdAt !== "string" || typeof body.updatedAt !== "string") throw new Error("Memory Space registry contains invalid timestamps");
|
|
@@ -1220,14 +1269,24 @@ function canonicalWorkspacePath(workspacePath) {
|
|
|
1220
1269
|
if (!isAbsolute(workspacePath) || workspacePath.includes("\0")) throw new Error("Workspace path must be absolute");
|
|
1221
1270
|
let parent = resolve(workspacePath);
|
|
1222
1271
|
const suffix = [];
|
|
1223
|
-
for (;;)
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1272
|
+
for (;;) {
|
|
1273
|
+
let real;
|
|
1274
|
+
try {
|
|
1275
|
+
real = realpathSync.native(parent);
|
|
1276
|
+
} catch (error) {
|
|
1277
|
+
if (error.code !== "ENOENT") throw error;
|
|
1278
|
+
const next = dirname(parent);
|
|
1279
|
+
if (next === parent) throw error;
|
|
1280
|
+
suffix.unshift(parent.slice(next.length).replace(/^[/\\]+/u, ""));
|
|
1281
|
+
parent = next;
|
|
1282
|
+
continue;
|
|
1283
|
+
}
|
|
1284
|
+
if (suffix.length > 0 && !statSync(real).isDirectory()) throw Object.assign(/* @__PURE__ */ new Error(`ENOTDIR: not a directory, realpath '${parent}'`), {
|
|
1285
|
+
code: "ENOTDIR",
|
|
1286
|
+
path: parent,
|
|
1287
|
+
syscall: "realpath"
|
|
1288
|
+
});
|
|
1289
|
+
return join(real, ...suffix);
|
|
1231
1290
|
}
|
|
1232
1291
|
}
|
|
1233
1292
|
/** A rename or move selects a new directory; resolving identity never writes. */
|
|
@@ -1283,7 +1342,7 @@ function safeBytes(path) {
|
|
|
1283
1342
|
function readJson(path) {
|
|
1284
1343
|
return JSON.parse(readFileSync(path, "utf8"));
|
|
1285
1344
|
}
|
|
1286
|
-
function record$
|
|
1345
|
+
function record$1(value) {
|
|
1287
1346
|
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
|
|
1288
1347
|
}
|
|
1289
1348
|
function missing(kind, path) {
|
|
@@ -1301,9 +1360,9 @@ function runtimeArea(root) {
|
|
|
1301
1360
|
const source = join(path, "memories.json");
|
|
1302
1361
|
if (!existsSync(source)) return missing("runtime", path);
|
|
1303
1362
|
try {
|
|
1304
|
-
const file = record$
|
|
1363
|
+
const file = record$1(readJson(source));
|
|
1305
1364
|
if (file === void 0 || !Array.isArray(file.entries)) throw new Error("memories.json is not a valid runtime-memory source");
|
|
1306
|
-
const entries = file.entries.map(record$
|
|
1365
|
+
const entries = file.entries.map(record$1).filter((entry) => entry !== void 0);
|
|
1307
1366
|
const userEntries = entries.filter((entry) => entry.target === "user").length;
|
|
1308
1367
|
const memoryEntries = entries.filter((entry) => entry.target === "memory").length;
|
|
1309
1368
|
const projectionsHealthy = existsSync(join(path, "USER.md")) && existsSync(join(path, "MEMORY.md"));
|
|
@@ -1338,8 +1397,8 @@ function memorySpacesArea(root) {
|
|
|
1338
1397
|
if (!existsSync(path)) return missing("memory-bodies", path);
|
|
1339
1398
|
try {
|
|
1340
1399
|
const registryPath = join(path, ".dsh-memory-bodies.json");
|
|
1341
|
-
const registry = existsSync(registryPath) ? record$
|
|
1342
|
-
const bodies = Array.isArray(registry?.bodies) ? registry.bodies.map(record$
|
|
1400
|
+
const registry = existsSync(registryPath) ? record$1(readJson(registryPath)) : void 0;
|
|
1401
|
+
const bodies = Array.isArray(registry?.bodies) ? registry.bodies.map(record$1).filter((body) => body !== void 0) : [];
|
|
1343
1402
|
const databaseCount = readdirSync(path, { withFileTypes: true }).filter((entry) => entry.isDirectory() && existsSync(join(path, entry.name, "mnemon.db"))).length;
|
|
1344
1403
|
const activeCount = bodies.filter((body) => body.active === true).length;
|
|
1345
1404
|
const invalidRegistry = existsSync(registryPath) && (registry?.version !== 1 || !Array.isArray(registry.bodies));
|
|
@@ -1374,9 +1433,9 @@ function documentsArea(root) {
|
|
|
1374
1433
|
const indexPath = join(path, "index.json");
|
|
1375
1434
|
if (!existsSync(indexPath)) return missing("documents", path);
|
|
1376
1435
|
try {
|
|
1377
|
-
const index = record$
|
|
1436
|
+
const index = record$1(readJson(indexPath));
|
|
1378
1437
|
if (index === void 0 || !Array.isArray(index.documents)) throw new Error("index.json is not a valid Documents index");
|
|
1379
|
-
const documents = index.documents.map(record$
|
|
1438
|
+
const documents = index.documents.map(record$1).filter((document) => document !== void 0);
|
|
1380
1439
|
const active = documents.filter((document) => document.status === "active").length;
|
|
1381
1440
|
const archived = documents.filter((document) => document.status === "archived").length;
|
|
1382
1441
|
return {
|
|
@@ -1412,9 +1471,9 @@ function stateArea(root) {
|
|
|
1412
1471
|
let providerConnections = 0;
|
|
1413
1472
|
let providerServices = 0;
|
|
1414
1473
|
if (existsSync(providerRegistry)) try {
|
|
1415
|
-
const registry = record$
|
|
1474
|
+
const registry = record$1(readJson(providerRegistry));
|
|
1416
1475
|
providerConnections = Array.isArray(registry?.bodies) ? registry.bodies.length : 0;
|
|
1417
|
-
providerServices = record$
|
|
1476
|
+
providerServices = record$1(registry?.services) === void 0 ? 0 : Object.keys(record$1(registry?.services)).length;
|
|
1418
1477
|
} catch {}
|
|
1419
1478
|
return {
|
|
1420
1479
|
kind: "state",
|
|
@@ -2723,13 +2782,13 @@ async function startGuardedReview(host, parent, toolNames, start, published) {
|
|
|
2723
2782
|
}
|
|
2724
2783
|
//#endregion
|
|
2725
2784
|
//#region src/host/review-checkpoint.ts
|
|
2726
|
-
function record
|
|
2785
|
+
function record(value) {
|
|
2727
2786
|
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : {};
|
|
2728
2787
|
}
|
|
2729
2788
|
function textContent(content, toolResult = false) {
|
|
2730
2789
|
if (!Array.isArray(content)) return "";
|
|
2731
2790
|
return content.map((block) => {
|
|
2732
|
-
const value = record
|
|
2791
|
+
const value = record(block);
|
|
2733
2792
|
if (value.type === "text" && typeof value.text === "string") return value.text;
|
|
2734
2793
|
if (toolResult && value.type === "tool-result" && value.isError !== true) return textContent(value.content);
|
|
2735
2794
|
return "";
|
|
@@ -2754,8 +2813,8 @@ function reviewCheckpoint(session, maxChars) {
|
|
|
2754
2813
|
"assistant/message",
|
|
2755
2814
|
"tool/result"
|
|
2756
2815
|
].includes(event.type)) continue;
|
|
2757
|
-
const message = record
|
|
2758
|
-
const source = record
|
|
2816
|
+
const message = record(event.data.message);
|
|
2817
|
+
const source = record(message.source);
|
|
2759
2818
|
if (event.type === "user/message" && source.kind !== "user") continue;
|
|
2760
2819
|
const text = textContent(message.content, event.type === "tool/result");
|
|
2761
2820
|
if (!text) continue;
|
|
@@ -2871,7 +2930,7 @@ var IdleReviewError = class extends Error {
|
|
|
2871
2930
|
};
|
|
2872
2931
|
function reviewReceipt(receipt) {
|
|
2873
2932
|
if (!mutationResultCommitted(receipt.value)) return void 0;
|
|
2874
|
-
const value = object$
|
|
2933
|
+
const value = object$6(receipt.value);
|
|
2875
2934
|
const args = optionalObject(receipt.arguments);
|
|
2876
2935
|
const document = optionalObject(value.document);
|
|
2877
2936
|
return {
|
|
@@ -3131,7 +3190,7 @@ function assertDshOutputValue(schema, candidate, path = "result") {
|
|
|
3131
3190
|
default: throw new Error(`${path} uses unsupported schema type ${JSON.stringify(value.type)}`);
|
|
3132
3191
|
}
|
|
3133
3192
|
}
|
|
3134
|
-
function object$
|
|
3193
|
+
function object$6(value) {
|
|
3135
3194
|
if (typeof value !== "object" || value === null || Array.isArray(value)) throw new Error("memory subagent returned an invalid structured result");
|
|
3136
3195
|
return value;
|
|
3137
3196
|
}
|
|
@@ -3484,7 +3543,7 @@ var MnemonSubagentCoordinator = class {
|
|
|
3484
3543
|
if (!isSubagent(execution.agent)) throw new Error("Mnemon subagent result tools are restricted to delegated children");
|
|
3485
3544
|
execution.signal.throwIfAborted();
|
|
3486
3545
|
assertDshOutputValue(RESULT_TOOL_INPUT_SCHEMA, args);
|
|
3487
|
-
const request = object$
|
|
3546
|
+
const request = object$6(args);
|
|
3488
3547
|
const submit = this.resultRequests.get(String(request.requestId));
|
|
3489
3548
|
if (this.disposed || submit === void 0) throw new Error("Mnemon subagent result request is unknown or no longer active");
|
|
3490
3549
|
return submit(request.result, execution);
|
|
@@ -3615,7 +3674,7 @@ var MnemonSubagentCoordinator = class {
|
|
|
3615
3674
|
].join("\n\n");
|
|
3616
3675
|
const schema = providerPlacementSchema(prepared.candidates.map((candidate) => candidate.id));
|
|
3617
3676
|
const { provider, runId, result } = await this.delegate(parent, "placement", "Choose Memory Space provider", prompt, [], schema, signal, "spawn", PROVIDER_PLACEMENT_PERSONA);
|
|
3618
|
-
const value = object$
|
|
3677
|
+
const value = object$6(result.structured);
|
|
3619
3678
|
return source.read("finalize-placement", {
|
|
3620
3679
|
prepared,
|
|
3621
3680
|
selection: {
|
|
@@ -3633,13 +3692,13 @@ var MnemonSubagentCoordinator = class {
|
|
|
3633
3692
|
const service = this.sourceFor(parent, "memory-spaces");
|
|
3634
3693
|
const prompt = `Generate concise metadata from these bounded Provider-native samples now:\n\n${(await Promise.all(selected.map((id) => service.read("metadata-sample", { memoryBodyId: id }, signal)))).map(metadataSampleText).join("\n\n")}`;
|
|
3635
3694
|
const { provider, runId, result } = await this.delegate(parent, "metadata-maintenance", "Maintain Memory Space metadata", prompt, [], METADATA_MAINTENANCE_SCHEMA, signal, "spawn", METADATA_MAINTENANCE_PERSONA);
|
|
3636
|
-
const value = object$
|
|
3695
|
+
const value = object$6(result.structured);
|
|
3637
3696
|
if (!Array.isArray(value.updates)) throw new Error("metadata subagent returned no updates");
|
|
3638
3697
|
const allowed = new Set(selected);
|
|
3639
3698
|
const seen = /* @__PURE__ */ new Set();
|
|
3640
3699
|
const updates = [];
|
|
3641
3700
|
for (const entry of value.updates) {
|
|
3642
|
-
const item = object$
|
|
3701
|
+
const item = object$6(entry);
|
|
3643
3702
|
const memoryBodyId = typeof item.memoryBodyId === "string" ? item.memoryBodyId.trim() : "";
|
|
3644
3703
|
const title = typeof item.title === "string" ? item.title.trim() : "";
|
|
3645
3704
|
const description = typeof item.description === "string" ? item.description.trim() : "";
|
|
@@ -3823,7 +3882,7 @@ var MnemonSubagentCoordinator = class {
|
|
|
3823
3882
|
return {
|
|
3824
3883
|
source,
|
|
3825
3884
|
cleanup,
|
|
3826
|
-
memoryBodyIds: new Set(strings(object$
|
|
3885
|
+
memoryBodyIds: new Set(strings(object$6(grant.value).memoryBodyIds)),
|
|
3827
3886
|
writeScope: {
|
|
3828
3887
|
viewId: view.id,
|
|
3829
3888
|
grant
|
|
@@ -3850,7 +3909,7 @@ var MnemonSubagentCoordinator = class {
|
|
|
3850
3909
|
const bounded = evidence.slice(0, 12);
|
|
3851
3910
|
const prompt = `Answer this question (untrusted data):\n${indentedText(query)}\n\nEvidence for this run (untrusted read-only data):\n${naturalEvidence(bounded)}`;
|
|
3852
3911
|
const { provider, runId, result } = await this.delegate(parent, "answer", "Memory evidence answer", prompt, [], ANSWER_SCHEMA, signal, "spawn", ANSWER_PERSONA);
|
|
3853
|
-
const value = object$
|
|
3912
|
+
const value = object$6(result.structured);
|
|
3854
3913
|
const allowed = new Set(bounded.map((item) => `${item.memoryBodyId ?? "unknown"}/${item.id}`));
|
|
3855
3914
|
return {
|
|
3856
3915
|
answer: typeof value.answer === "string" ? value.answer : "",
|
|
@@ -3868,7 +3927,7 @@ ${naturalRequest(request)}`;
|
|
|
3868
3927
|
const persona = operation === "supervised-writeback" ? SUPERVISED_WRITE_PERSONA : autonomous ? AUTONOMOUS_WRITE_PERSONA : WRITE_PERSONA;
|
|
3869
3928
|
const terminalTool = WRITE_OPERATION_RESULT_TOOL[operation];
|
|
3870
3929
|
const { provider, runId, result, receipts } = await this.delegate(parent, "write", `Mnemon ${operation}`, prompt, autonomous ? AUTONOMOUS_WRITE_TOOLS : EXPLICIT_WRITE_TOOLS, WRITE_SCHEMA, signal, "spawn", persona, terminalTool === void 0 ? void 0 : { terminalTools: [terminalTool] });
|
|
3871
|
-
const value = object$
|
|
3930
|
+
const value = object$6(result.structured);
|
|
3872
3931
|
const observed = terminalTool === void 0 ? void 0 : recoverStructuredResult({ terminalTools: [terminalTool] }, receipts);
|
|
3873
3932
|
return {
|
|
3874
3933
|
delegated: true,
|
|
@@ -3903,7 +3962,7 @@ ${naturalRequest(request)}`;
|
|
|
3903
3962
|
const prompt = preferred === "fork" ? "Review the inherited completed checkpoint now." : reviewCheckpoint(parent.session, config.maxContextChars);
|
|
3904
3963
|
const persona = preferred === "fork" ? REVIEW_PERSONA : REVIEW_PERSONA.replaceAll("inherited", "supplied bounded");
|
|
3905
3964
|
const { provider, runId, result } = await this.delegate(parent, "review", "Mnemon idle checkpoint review", prompt, REVIEW_TOOLS, WRITE_SCHEMA, signal, preferred, persona, { terminalTools: ["mnemon_runtime_memory", "mnemon_document_create"] });
|
|
3906
|
-
const value = object$
|
|
3965
|
+
const value = object$6(result.structured);
|
|
3907
3966
|
return {
|
|
3908
3967
|
delegated: true,
|
|
3909
3968
|
runId,
|
|
@@ -3965,12 +4024,12 @@ ${naturalRequest(request)}`;
|
|
|
3965
4024
|
const cleanup = graph.source("memory-spaces", agentScope(parent, graph.config)).forInstance(identity.sourceInstanceKey).forGeneration(lease.generation);
|
|
3966
4025
|
const grant = authority?.context.view.readGrants.find((grant) => grant.sourceInstanceKey === identity.sourceInstanceKey && grant.schema === "dsh-mnemon.memory-spaces/v1");
|
|
3967
4026
|
if (authority !== void 0 && grant === void 0) throw new Error("document archive requires a Memory Space namespace grant");
|
|
3968
|
-
const allowed = grant === void 0 ? void 0 : new Set(strings(object$
|
|
4027
|
+
const allowed = grant === void 0 ? void 0 : new Set(strings(object$6(grant.value).memoryBodyIds));
|
|
3969
4028
|
const eligible = (body) => body.active && body.providerEnabled !== false && body.provider.capabilities.remember && body.provider.capabilities.forget && body.provider.capabilities.writeMode === "exact" && (allowed === void 0 || allowed.has(body.id));
|
|
3970
4029
|
const bodies = (await memoryService.read("body-directory", null, signal)).items.filter(eligible);
|
|
3971
4030
|
if (bodies.length === 0) throw new Error("document archive requires an existing active Memory Space with exact writes and safe forget");
|
|
3972
4031
|
const { provider, runId, result } = await this.delegate(parent, "document-archive", "Plan managed document archive", documentArchivePrompt(document, source, bodies), [], DOCUMENT_ARCHIVE_SCHEMA, signal, "spawn", DOCUMENT_ARCHIVE_PERSONA);
|
|
3973
|
-
const value = object$
|
|
4032
|
+
const value = object$6(result.structured);
|
|
3974
4033
|
const summary = typeof value.summary === "string" ? value.summary.trim() : "";
|
|
3975
4034
|
if (value.action !== "planned") throw new Error(summary || "document archive planning failed");
|
|
3976
4035
|
if (summary === "" || summary.length > 1e3) throw new Error("document archive summary must contain 1–1000 characters");
|
|
@@ -4145,13 +4204,13 @@ ${chunk.context}
|
|
|
4145
4204
|
provider = delegated.provider;
|
|
4146
4205
|
runId = delegated.runId;
|
|
4147
4206
|
}
|
|
4148
|
-
const value = object$
|
|
4207
|
+
const value = object$6(delegated.result.structured);
|
|
4149
4208
|
if (value.action !== "planned") throw new Error(typeof value.summary === "string" && value.summary !== "" ? value.summary : "runtime memory archival routing failed");
|
|
4150
4209
|
if (!Array.isArray(value.routes) || value.routes.length === 0) throw new Error("runtime memory migration returned no routes");
|
|
4151
4210
|
const allowedIndexes = new Set(chunk.indexes);
|
|
4152
4211
|
const proposed = /* @__PURE__ */ new Map();
|
|
4153
4212
|
for (const candidate of value.routes) {
|
|
4154
|
-
const route = object$
|
|
4213
|
+
const route = object$6(candidate);
|
|
4155
4214
|
const memoryBodyId = typeof route.memoryBodyId === "string" ? route.memoryBodyId.trim() : "";
|
|
4156
4215
|
if (memoryBodyId === "" || !eligibleById.has(memoryBodyId)) throw new Error(`runtime memory migration selected an invalid Memory Space: ${memoryBodyId || "(empty)"}`);
|
|
4157
4216
|
if (!Array.isArray(route.sourceIndexes) || route.sourceIndexes.length === 0) throw new Error("runtime memory migration route must contain source indexes");
|
|
@@ -4299,10 +4358,10 @@ ${pendingMutationContext(plan)}
|
|
|
4299
4358
|
|
|
4300
4359
|
${runtimeSnapshotContext("user", plan.entries)}`;
|
|
4301
4360
|
const { provider, runId, result } = await context.model("compaction", "Consolidate local user profile", prompt, USER_COMPACTION_SCHEMA, USER_COMPACTION_PERSONA);
|
|
4302
|
-
const value = object$
|
|
4361
|
+
const value = object$6(result.structured);
|
|
4303
4362
|
if (value.action !== "compacted") throw new Error(typeof value.summary === "string" && value.summary !== "" ? value.summary : "USER.md compaction failed");
|
|
4304
4363
|
const compactedEntries = Array.isArray(value.compactedEntries) ? value.compactedEntries.map((entry) => {
|
|
4305
|
-
const item = object$
|
|
4364
|
+
const item = object$6(entry);
|
|
4306
4365
|
if (typeof item.content !== "string" || ![
|
|
4307
4366
|
"critical",
|
|
4308
4367
|
"normal",
|
|
@@ -4515,7 +4574,7 @@ This is the only completion channel for this run. Do not finish with a plain-tex
|
|
|
4515
4574
|
"failed",
|
|
4516
4575
|
"partial",
|
|
4517
4576
|
"unknown"
|
|
4518
|
-
].includes(String(object$
|
|
4577
|
+
].includes(String(object$6(structured).action))) throw new Error(`memory review reported ${object$6(structured).action}`);
|
|
4519
4578
|
completed = {
|
|
4520
4579
|
provider,
|
|
4521
4580
|
runId: activeRun.id,
|
|
@@ -4680,7 +4739,7 @@ const MNEMON_ACTIVITY_SCHEMA = "dsh-mnemon.activity/v1";
|
|
|
4680
4739
|
const MAX_ITEMS = 8;
|
|
4681
4740
|
const MAX_TITLE = 160;
|
|
4682
4741
|
const MAX_EXCERPT = 500;
|
|
4683
|
-
function object$
|
|
4742
|
+
function object$5(value) {
|
|
4684
4743
|
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
|
|
4685
4744
|
}
|
|
4686
4745
|
function bounded(value, maximum) {
|
|
@@ -4690,7 +4749,7 @@ function bounded(value, maximum) {
|
|
|
4690
4749
|
return normalized.length <= maximum ? normalized : normalized.slice(0, maximum - 1) + "…";
|
|
4691
4750
|
}
|
|
4692
4751
|
function item(value, index) {
|
|
4693
|
-
const entry = object$
|
|
4752
|
+
const entry = object$5(value);
|
|
4694
4753
|
if (entry === void 0) return void 0;
|
|
4695
4754
|
const content = bounded(entry.content ?? entry.text ?? entry.excerpt, MAX_EXCERPT);
|
|
4696
4755
|
const explicitTitle = bounded(entry.title ?? entry.label ?? entry.name ?? entry.memoryBodyName, MAX_TITLE);
|
|
@@ -4704,7 +4763,7 @@ function item(value, index) {
|
|
|
4704
4763
|
};
|
|
4705
4764
|
}
|
|
4706
4765
|
function resultItems(value) {
|
|
4707
|
-
const root = object$
|
|
4766
|
+
const root = object$5(value);
|
|
4708
4767
|
if (root === void 0) return [];
|
|
4709
4768
|
const candidates = [
|
|
4710
4769
|
root.results,
|
|
@@ -4723,8 +4782,8 @@ function resultItems(value) {
|
|
|
4723
4782
|
return items;
|
|
4724
4783
|
}
|
|
4725
4784
|
function writeItem(argsValue, operationId) {
|
|
4726
|
-
const outer = object$
|
|
4727
|
-
const input = object$
|
|
4785
|
+
const outer = object$5(argsValue) ?? {};
|
|
4786
|
+
const input = object$5(outer.input) ?? outer;
|
|
4728
4787
|
const content = bounded(input.content ?? input.description ?? input.reason ?? input.summary, MAX_EXCERPT);
|
|
4729
4788
|
const explicitTitle = bounded(input.title ?? input.name, MAX_TITLE);
|
|
4730
4789
|
const identity = bounded(input.id ?? input.memoryBodyId ?? input.targetMemoryBodyId ?? input.sourceId, 300);
|
|
@@ -4737,7 +4796,7 @@ function writeItem(argsValue, operationId) {
|
|
|
4737
4796
|
};
|
|
4738
4797
|
}
|
|
4739
4798
|
function reference(argsValue, key) {
|
|
4740
|
-
return bounded(object$
|
|
4799
|
+
return bounded(object$5(argsValue)?.[key], 600);
|
|
4741
4800
|
}
|
|
4742
4801
|
function memoryReadPresentation(sourceTypeId, operationId, referenceKey) {
|
|
4743
4802
|
return (args, value) => ({
|
|
@@ -4756,12 +4815,12 @@ function memoryWritePresentation(sourceTypeId, operationId, referenceKey) {
|
|
|
4756
4815
|
operationId,
|
|
4757
4816
|
...sourceTypeId === void 0 ? {} : { sourceTypeId },
|
|
4758
4817
|
...referenceKey === void 0 || reference(args, referenceKey) === void 0 ? {} : { reference: reference(args, referenceKey) },
|
|
4759
|
-
committed: mutationResultCommitted(value) || operationId === "mutate" && object$
|
|
4818
|
+
committed: mutationResultCommitted(value) || operationId === "mutate" && object$5(value)?.success === true,
|
|
4760
4819
|
item: writeItem(args, operationId)
|
|
4761
4820
|
});
|
|
4762
4821
|
}
|
|
4763
4822
|
function validItem(value) {
|
|
4764
|
-
const entry = object$
|
|
4823
|
+
const entry = object$5(value);
|
|
4765
4824
|
return entry !== void 0 && bounded(entry.id, 300) === entry.id && bounded(entry.title, MAX_TITLE) === entry.title && (entry.excerpt === void 0 || bounded(entry.excerpt, MAX_EXCERPT) === entry.excerpt);
|
|
4766
4825
|
}
|
|
4767
4826
|
function cleanItem(value) {
|
|
@@ -4774,7 +4833,7 @@ function cleanItem(value) {
|
|
|
4774
4833
|
}
|
|
4775
4834
|
/** Fail closed on arbitrary third-party/session metadata. */
|
|
4776
4835
|
function parseMnemonActivityMeta(value, callId, toolName) {
|
|
4777
|
-
const meta = object$
|
|
4836
|
+
const meta = object$5(value);
|
|
4778
4837
|
if (meta?.schema !== "dsh-mnemon.activity/v1" || meta.kind !== "read" && meta.kind !== "write") return {};
|
|
4779
4838
|
const operationId = bounded(meta.operationId, 300);
|
|
4780
4839
|
const sourceTypeId = bounded(meta.sourceTypeId, 128);
|
|
@@ -5156,24 +5215,22 @@ function createPluginMessage(text, form) {
|
|
|
5156
5215
|
text
|
|
5157
5216
|
}],
|
|
5158
5217
|
source: {
|
|
5159
|
-
kind:
|
|
5160
|
-
plugin: MNEMON_PLUGIN_SOURCE,
|
|
5218
|
+
kind: MNEMON_PLUGIN_SOURCE,
|
|
5161
5219
|
form
|
|
5162
5220
|
}
|
|
5163
5221
|
});
|
|
5164
5222
|
}
|
|
5165
|
-
function
|
|
5166
|
-
return
|
|
5223
|
+
function isMnemonMessageSource(source) {
|
|
5224
|
+
if (typeof source !== "object" || source === null) return false;
|
|
5225
|
+
const { kind, plugin } = source;
|
|
5226
|
+
return kind === "dsh-mnemon" || kind === `plugin:dsh-mnemon` || kind === "plugin" && plugin === "dsh-mnemon";
|
|
5167
5227
|
}
|
|
5168
5228
|
/**
|
|
5169
5229
|
* Whether an event is a durable user message this plugin produced.
|
|
5170
5230
|
*/
|
|
5171
5231
|
function isOwnUserMessageEvent(event) {
|
|
5172
5232
|
if (event?.type !== "user/message") return false;
|
|
5173
|
-
|
|
5174
|
-
if (typeof source !== "object" || source === null) return false;
|
|
5175
|
-
const { kind, plugin } = source;
|
|
5176
|
-
return kind === "plugin" && plugin === "dsh-mnemon";
|
|
5233
|
+
return isMnemonMessageSource(event.data.source);
|
|
5177
5234
|
}
|
|
5178
5235
|
function eventTurn(event) {
|
|
5179
5236
|
return typeof event.data.turn === "number" ? event.data.turn : void 0;
|
|
@@ -5396,10 +5453,7 @@ var MnemonAgentLifecycle = class {
|
|
|
5396
5453
|
if (!this.config.lifecycleEnabled) return decision;
|
|
5397
5454
|
if (this.config.writeEnabled && this.config.writebackMode === "guided") this.recordTurnMessages(payload.turn, decision.messages);
|
|
5398
5455
|
if (payload.step !== 1) return decision;
|
|
5399
|
-
if (decision.messages.some((message) =>
|
|
5400
|
-
const source = sourceOf(message);
|
|
5401
|
-
return source.kind === "plugin" && source.plugin === "dsh-mnemon";
|
|
5402
|
-
})) return decision;
|
|
5456
|
+
if (decision.messages.some((message) => isMnemonMessageSource(message.source))) return decision;
|
|
5403
5457
|
if (decision.messages.length === 0) return decision;
|
|
5404
5458
|
const snapshot = this.memorySnapshotMessage();
|
|
5405
5459
|
const withSnapshot = (messages) => snapshot === void 0 ? messages : [...messages, snapshot];
|
|
@@ -6706,7 +6760,7 @@ var VersionUpdateManager = class {
|
|
|
6706
6760
|
};
|
|
6707
6761
|
//#endregion
|
|
6708
6762
|
//#region src/host/rpc.ts
|
|
6709
|
-
function object$
|
|
6763
|
+
function object$4(value) {
|
|
6710
6764
|
if (typeof value !== "object" || value === null || Array.isArray(value)) throw new Error("payload must be an object");
|
|
6711
6765
|
return value;
|
|
6712
6766
|
}
|
|
@@ -6855,7 +6909,7 @@ async function assisted(runtime, lifecycle, typeId, operation, input, signal, ta
|
|
|
6855
6909
|
...signal === void 0 ? {} : { signal }
|
|
6856
6910
|
});
|
|
6857
6911
|
return {
|
|
6858
|
-
...object$
|
|
6912
|
+
...object$4(result.value),
|
|
6859
6913
|
revision: result.revision
|
|
6860
6914
|
};
|
|
6861
6915
|
} finally {
|
|
@@ -6924,7 +6978,7 @@ async function assisted(runtime, lifecycle, typeId, operation, input, signal, ta
|
|
|
6924
6978
|
function createReadHandler(input, lifecycle, versions) {
|
|
6925
6979
|
return async (endpoint, rawPayload, signal) => {
|
|
6926
6980
|
try {
|
|
6927
|
-
const payload = object$
|
|
6981
|
+
const payload = object$4(rawPayload);
|
|
6928
6982
|
if (endpoint === "versions") {
|
|
6929
6983
|
if (versions === void 0) throw new Error("version checks are unavailable");
|
|
6930
6984
|
return success$1(await versions.check());
|
|
@@ -6944,7 +6998,7 @@ function createReadHandler(input, lifecycle, versions) {
|
|
|
6944
6998
|
if (lifecycle === void 0 || payload.operation !== "agent-search") throw new Error("Read-only Host assistance is unavailable");
|
|
6945
6999
|
const source = (await catalog(runtime, lifecycle)).sources.find((item) => item.sourceInstanceKey === payload.sourceInstanceKey);
|
|
6946
7000
|
if (source === void 0 || !source.assistance.includes("agent-search")) throw new Error("Host assistance is not available for this Source instance");
|
|
6947
|
-
const value = await assisted(runtime, lifecycle, source.sourceTypeId, "agent-search", object$
|
|
7001
|
+
const value = await assisted(runtime, lifecycle, source.sourceTypeId, "agent-search", object$4(payload.input), signal);
|
|
6948
7002
|
return success$1({
|
|
6949
7003
|
revision: (await catalog(runtime)).sources.find((item) => item.sourceInstanceKey === source.sourceInstanceKey)?.revision ?? source.revision,
|
|
6950
7004
|
value
|
|
@@ -7037,9 +7091,9 @@ function createActivationHandler(input) {
|
|
|
7037
7091
|
return async (endpoint, rawPayload, signal) => {
|
|
7038
7092
|
try {
|
|
7039
7093
|
if (endpoint === "source-assistance") {
|
|
7040
|
-
const payload = object$
|
|
7094
|
+
const payload = object$4(rawPayload);
|
|
7041
7095
|
if (payload.operation !== "activation" || payload.confirmed !== true) throw new Error("Unsupported activation operation");
|
|
7042
|
-
const fields = object$
|
|
7096
|
+
const fields = object$4(payload.input);
|
|
7043
7097
|
if (Object.keys(fields).some((key) => key !== "memoryBodyId" && key !== "active") || typeof fields.active !== "boolean" || typeof fields.memoryBodyId !== "string") throw new Error("Activation accepts only a Memory Space id and boolean state");
|
|
7044
7098
|
const runtime = scoped(input, payload);
|
|
7045
7099
|
requireWritable(runtime);
|
|
@@ -7062,7 +7116,7 @@ function createActivationHandler(input) {
|
|
|
7062
7116
|
}
|
|
7063
7117
|
}
|
|
7064
7118
|
if (endpoint !== "body") return badRequest$1("unknown activation endpoint: " + endpoint);
|
|
7065
|
-
const payload = object$
|
|
7119
|
+
const payload = object$4(rawPayload);
|
|
7066
7120
|
const unexpected = Object.keys(payload).filter((field) => !ACTIVATION_FIELDS.has(field));
|
|
7067
7121
|
if (unexpected.length > 0) return badRequest$1("unsupported activation fields: " + unexpected.join(", "));
|
|
7068
7122
|
if (typeof payload.memoryBodyId !== "string" || payload.memoryBodyId.trim() === "") return badRequest$1("memoryBodyId must be a non-empty string");
|
|
@@ -7081,7 +7135,7 @@ function createActivationHandler(input) {
|
|
|
7081
7135
|
function createWriteHandler(input, lifecycle, versions) {
|
|
7082
7136
|
return async (endpoint, rawPayload, signal) => {
|
|
7083
7137
|
try {
|
|
7084
|
-
const payload = object$
|
|
7138
|
+
const payload = object$4(rawPayload);
|
|
7085
7139
|
if (endpoint === "version-update") {
|
|
7086
7140
|
if (versions === void 0) throw new Error("version updates are unavailable");
|
|
7087
7141
|
if (!input.config.writeEnabled) throw new Error("dsh-mnemon is configured read-only (writeEnabled: false)");
|
|
@@ -7115,12 +7169,12 @@ function createWriteHandler(input, lifecycle, versions) {
|
|
|
7115
7169
|
const operation = String(payload.operation ?? "");
|
|
7116
7170
|
if (source === void 0 || !source.assistance.includes(operation)) throw new Error("Host assistance is not available for this Source instance");
|
|
7117
7171
|
if (operation !== "agent-search" && (payload.confirmed !== true || payload.expectedRevision !== source.revision)) throw new Error("Host assistance requires confirmation of the current Source revision");
|
|
7118
|
-
const value = await assisted(runtime, lifecycle, source.sourceTypeId, operation, object$
|
|
7172
|
+
const value = await assisted(runtime, lifecycle, source.sourceTypeId, operation, object$4(payload.input), signal, {
|
|
7119
7173
|
sourceInstanceKey: source.sourceInstanceKey,
|
|
7120
7174
|
expectedRevision: source.revision
|
|
7121
7175
|
});
|
|
7122
7176
|
if (source.sourceTypeId === "runtime") return success$1({
|
|
7123
|
-
revision: object$
|
|
7177
|
+
revision: object$4(value).revision,
|
|
7124
7178
|
value
|
|
7125
7179
|
});
|
|
7126
7180
|
return success$1({
|
|
@@ -7164,7 +7218,7 @@ function createWriteHandler(input, lifecycle, versions) {
|
|
|
7164
7218
|
function createPackHandler(input) {
|
|
7165
7219
|
return async (endpoint, rawPayload) => {
|
|
7166
7220
|
try {
|
|
7167
|
-
const payload = object$
|
|
7221
|
+
const payload = object$4(rawPayload);
|
|
7168
7222
|
const runtime = scoped(input, payload);
|
|
7169
7223
|
const manager = runtime.graph.packs;
|
|
7170
7224
|
if (endpoint === "target") return success$1(manager.target());
|
|
@@ -7233,7 +7287,7 @@ function descriptor(settings, namespace) {
|
|
|
7233
7287
|
return {
|
|
7234
7288
|
status: "ready",
|
|
7235
7289
|
value: namespace === "mnemon" && displayModeOf(view.value) === "buildin" ? {
|
|
7236
|
-
...object$
|
|
7290
|
+
...object$3(view.value),
|
|
7237
7291
|
displayMode: "builtin"
|
|
7238
7292
|
} : view.value,
|
|
7239
7293
|
base: view.base,
|
|
@@ -7244,7 +7298,7 @@ function descriptor(settings, namespace) {
|
|
|
7244
7298
|
applies: view.applies
|
|
7245
7299
|
};
|
|
7246
7300
|
}
|
|
7247
|
-
function object$
|
|
7301
|
+
function object$3(value) {
|
|
7248
7302
|
if (typeof value !== "object" || value === null || Array.isArray(value)) throw new Error("payload must be an object");
|
|
7249
7303
|
return value;
|
|
7250
7304
|
}
|
|
@@ -7315,14 +7369,14 @@ function createSettingsHandler(settings) {
|
|
|
7315
7369
|
return async (endpoint, rawPayload) => {
|
|
7316
7370
|
let namespace = MNEMON_SETTINGS_NAMESPACE;
|
|
7317
7371
|
try {
|
|
7318
|
-
const payload = object$
|
|
7372
|
+
const payload = object$3(rawPayload);
|
|
7319
7373
|
namespace = namespaceOf(payload);
|
|
7320
7374
|
if (endpoint === "get") return success(descriptor(settings, namespace));
|
|
7321
7375
|
if (endpoint !== "mutate") return badRequest(`unknown settings endpoint: ${endpoint}`);
|
|
7322
7376
|
if (!settings.writable) throw new Error("DSH settings are read-only");
|
|
7323
7377
|
if (!Array.isArray(payload.ops) || payload.ops.length === 0 || payload.ops.length > 16) throw new Error("ops must contain 1..16 settings edits");
|
|
7324
7378
|
const ops = payload.ops.map((raw) => {
|
|
7325
|
-
const op = object$
|
|
7379
|
+
const op = object$3(raw);
|
|
7326
7380
|
const path = Array.isArray(op.path) && op.path.length > 0 ? op.path.map((segment) => String(segment)) : [];
|
|
7327
7381
|
if (!mutablePath(namespace, path)) throw new Error(`unsupported ${namespace} settings field: ${path.join(".")}`);
|
|
7328
7382
|
if (op.op === "unset") return {
|
|
@@ -8304,49 +8358,527 @@ function registerMnemonSubagentTokenUsageProjection(ctx) {
|
|
|
8304
8358
|
});
|
|
8305
8359
|
}
|
|
8306
8360
|
//#endregion
|
|
8307
|
-
//#region src/host/
|
|
8308
|
-
|
|
8309
|
-
|
|
8310
|
-
|
|
8311
|
-
|
|
8312
|
-
|
|
8313
|
-
|
|
8314
|
-
|
|
8315
|
-
|
|
8316
|
-
|
|
8361
|
+
//#region src/host/live-config.ts
|
|
8362
|
+
function plain(value) {
|
|
8363
|
+
if (isVolatile(value)) return plain(value.get());
|
|
8364
|
+
if (Array.isArray(value)) return value.map(plain);
|
|
8365
|
+
if (value === null || typeof value !== "object") return value;
|
|
8366
|
+
const prototype = Object.getPrototypeOf(value);
|
|
8367
|
+
if (prototype !== Object.prototype && prototype !== null) return value;
|
|
8368
|
+
return Object.fromEntries(Object.entries(value).map(([key, child]) => [key, plain(child)]));
|
|
8369
|
+
}
|
|
8370
|
+
/** Read a detached configuration snapshot from either DSH generation. */
|
|
8371
|
+
function plainHostConfig(value = {}) {
|
|
8372
|
+
return plain(value);
|
|
8373
|
+
}
|
|
8374
|
+
function liveConfig() {
|
|
8375
|
+
const schema = new schemastery_live_default(Config.toJSON());
|
|
8376
|
+
schema.dict = Object.fromEntries(Object.entries(schema.dict ?? {}).map(([key, field]) => [key, key === "remoteAccess" ? field : field.volatile()]));
|
|
8377
|
+
const standard = schema["~standard"];
|
|
8378
|
+
Object.defineProperty(schema, "~standard", { value: {
|
|
8379
|
+
...standard,
|
|
8380
|
+
validate(value) {
|
|
8381
|
+
const parsed = standard.validate(value);
|
|
8382
|
+
if ("then" in parsed) throw new TypeError("Mnemon configuration validation must be synchronous");
|
|
8383
|
+
if (parsed.issues) return parsed;
|
|
8384
|
+
try {
|
|
8385
|
+
resolveConfig(plainHostConfig(parsed.value));
|
|
8386
|
+
return parsed;
|
|
8387
|
+
} catch (error) {
|
|
8388
|
+
return { issues: [{ message: error instanceof Error ? error.message : String(error) }] };
|
|
8389
|
+
}
|
|
8390
|
+
}
|
|
8391
|
+
} });
|
|
8392
|
+
return schema;
|
|
8393
|
+
}
|
|
8394
|
+
/** Profile Config for live forms; transport authority retains normal remounts. */
|
|
8395
|
+
const LiveConfig = liveConfig();
|
|
8396
|
+
//#endregion
|
|
8397
|
+
//#region src/host/legacy-settings-import.ts
|
|
8398
|
+
const UNSAFE_KEYS = /* @__PURE__ */ new Set([
|
|
8399
|
+
"__proto__",
|
|
8400
|
+
"prototype",
|
|
8401
|
+
"constructor"
|
|
8402
|
+
]);
|
|
8317
8403
|
const ENTRY_ID = /^[a-zA-Z0-9][a-zA-Z0-9._:/-]{0,299}$/u;
|
|
8318
|
-
const
|
|
8319
|
-
const
|
|
8320
|
-
|
|
8321
|
-
|
|
8322
|
-
|
|
8323
|
-
|
|
8324
|
-
|
|
8325
|
-
|
|
8326
|
-
"
|
|
8327
|
-
|
|
8328
|
-
|
|
8329
|
-
].includes(key)) throw new Error("Unsafe plugin configuration key");
|
|
8330
|
-
return parsed;
|
|
8404
|
+
const STRATEGY_ID = /^[a-z][a-z0-9-]{0,127}$/u;
|
|
8405
|
+
const VIEW_NAMESPACE = /^mnemon-view(?:-[a-f0-9]{16})?$/u;
|
|
8406
|
+
const LEGACY_NAMESPACE = /^mnemon-plugins(?:-[a-f0-9]{16})?$/u;
|
|
8407
|
+
function object$2(value, label) {
|
|
8408
|
+
if (value === null || typeof value !== "object" || Array.isArray(value) || ![Object.prototype, null].includes(Object.getPrototypeOf(value))) throw new Error(`${label} must be a plain object`);
|
|
8409
|
+
for (const key of Reflect.ownKeys(value)) {
|
|
8410
|
+
if (typeof key !== "string" || UNSAFE_KEYS.has(key)) throw new Error(`${label} contains an unsafe key`);
|
|
8411
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
8412
|
+
if (!descriptor.enumerable || !Object.hasOwn(descriptor, "value")) throw new Error(`${label} must contain only data properties`);
|
|
8413
|
+
}
|
|
8414
|
+
return value;
|
|
8331
8415
|
}
|
|
8332
|
-
|
|
8333
|
-
|
|
8334
|
-
|
|
8335
|
-
if (
|
|
8336
|
-
|
|
8337
|
-
|
|
8338
|
-
|
|
8339
|
-
|
|
8340
|
-
|
|
8416
|
+
/** Copy JSON data without invoking getters, serializers or prototype methods. */
|
|
8417
|
+
function copy(value, label, ancestors = /* @__PURE__ */ new Set(), depth = 0) {
|
|
8418
|
+
if (value === null || typeof value === "string" || typeof value === "boolean") return value;
|
|
8419
|
+
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
8420
|
+
if (typeof value !== "object" || value === null) throw new Error(`${label} must contain only JSON data`);
|
|
8421
|
+
if (depth > 64 || ancestors.has(value)) throw new Error(`${label} contains cyclic or excessively nested data`);
|
|
8422
|
+
ancestors.add(value);
|
|
8423
|
+
try {
|
|
8424
|
+
if (Array.isArray(value)) {
|
|
8425
|
+
if (Object.getPrototypeOf(value) !== Array.prototype) throw new Error(`${label} must contain plain arrays`);
|
|
8426
|
+
if (Reflect.ownKeys(value).length !== value.length + 1) throw new Error(`${label} contains a sparse or extended array`);
|
|
8427
|
+
return Array.from({ length: value.length }, (_, index) => {
|
|
8428
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, String(index));
|
|
8429
|
+
if (!descriptor || !descriptor.enumerable || !Object.hasOwn(descriptor, "value")) throw new Error(`${label} must contain only data properties`);
|
|
8430
|
+
return copy(descriptor.value, label, ancestors, depth + 1);
|
|
8431
|
+
});
|
|
8432
|
+
}
|
|
8433
|
+
return Object.fromEntries(Object.entries(object$2(value, label)).map(([key, item]) => [key, copy(item, label, ancestors, depth + 1)]));
|
|
8434
|
+
} finally {
|
|
8435
|
+
ancestors.delete(value);
|
|
8341
8436
|
}
|
|
8342
|
-
return clone(value);
|
|
8343
8437
|
}
|
|
8344
|
-
function
|
|
8345
|
-
|
|
8346
|
-
|
|
8347
|
-
|
|
8348
|
-
|
|
8438
|
+
function copiedObject(value, label) {
|
|
8439
|
+
object$2(value, label);
|
|
8440
|
+
return copy(value, label);
|
|
8441
|
+
}
|
|
8442
|
+
/** Inspect validated copies only; never evaluate expressions or invoke getters. */
|
|
8443
|
+
function containsExpression(value) {
|
|
8444
|
+
return value !== null && typeof value === "object" && (Object.hasOwn(value, "__jsExpr") || Object.values(value).some(containsExpression));
|
|
8445
|
+
}
|
|
8446
|
+
function fields(value, allowed, label) {
|
|
8447
|
+
if (Object.keys(value).some((key) => !allowed.includes(key))) throw new Error(`${label} contains unsupported fields`);
|
|
8448
|
+
}
|
|
8449
|
+
function interaction(value, label, allowed) {
|
|
8450
|
+
const result = copiedObject(value, label);
|
|
8451
|
+
fields(result, allowed, label);
|
|
8452
|
+
if (Object.values(result).some((item) => typeof item !== "boolean")) throw new Error(`${label} preferences must be boolean`);
|
|
8453
|
+
return result;
|
|
8454
|
+
}
|
|
8455
|
+
function entryId(value, label) {
|
|
8456
|
+
if (typeof value !== "string" || !ENTRY_ID.test(value) || UNSAFE_KEYS.has(value)) throw new Error(`${label} contains an invalid Entry id`);
|
|
8457
|
+
}
|
|
8458
|
+
function view(value, label) {
|
|
8459
|
+
const result = copiedObject(value, label);
|
|
8460
|
+
fields(result, ["strategyTypeId", "entries"], label);
|
|
8461
|
+
if (Object.hasOwn(result, "strategyTypeId") && (typeof result.strategyTypeId !== "string" || !STRATEGY_ID.test(result.strategyTypeId))) throw new Error(`${label} contains an invalid Strategy type id`);
|
|
8462
|
+
const entries = {};
|
|
8463
|
+
if (Object.hasOwn(result, "entries")) {
|
|
8464
|
+
const values = object$2(result.entries, `${label}.entries`);
|
|
8465
|
+
if (Object.keys(values).length > 64) throw new Error(`${label} contains too many Entries`);
|
|
8466
|
+
for (const [id, raw] of Object.entries(values)) {
|
|
8467
|
+
entryId(id, label);
|
|
8468
|
+
const item = copiedObject(raw, `${label}.entries`);
|
|
8469
|
+
fields(item, ["enabled", "config"], `${label}.entries`);
|
|
8470
|
+
if (typeof item.enabled !== "boolean") throw new Error(`${label} Entry enabled must be boolean`);
|
|
8471
|
+
const config = Object.hasOwn(item, "config") ? copiedObject(item.config, `${label} Entry config`) : {};
|
|
8472
|
+
if (JSON.stringify(config).length > 65536) throw new Error(`${label} Entry config exceeds 64 KiB`);
|
|
8473
|
+
entries[id] = {
|
|
8474
|
+
enabled: item.enabled,
|
|
8475
|
+
config
|
|
8476
|
+
};
|
|
8477
|
+
}
|
|
8478
|
+
}
|
|
8479
|
+
return {
|
|
8480
|
+
...typeof result.strategyTypeId === "string" ? { strategyTypeId: result.strategyTypeId } : {},
|
|
8481
|
+
...Object.hasOwn(result, "entries") ? { entries } : {}
|
|
8482
|
+
};
|
|
8483
|
+
}
|
|
8484
|
+
function sources(value, label, sourceEntryIds, diagnostics) {
|
|
8485
|
+
const result = copiedObject(value, label);
|
|
8486
|
+
fields(result, ["sources"], label);
|
|
8487
|
+
const values = Object.hasOwn(result, "sources") ? object$2(result.sources, `${label}.sources`) : {};
|
|
8488
|
+
if (Object.keys(values).length > 64) throw new Error(`${label} contains too many Source Entries`);
|
|
8489
|
+
const entries = {};
|
|
8490
|
+
for (const [id, raw] of Object.entries(values)) {
|
|
8491
|
+
entryId(id, label);
|
|
8492
|
+
const item = copiedObject(raw, `${label}.sources`);
|
|
8493
|
+
fields(item, ["enabled"], `${label}.sources`);
|
|
8494
|
+
if (typeof item.enabled !== "boolean") throw new Error(`${label} Source enabled must be boolean`);
|
|
8495
|
+
if (!sourceEntryIds.has(id)) {
|
|
8496
|
+
diagnostics.push(`Skipped legacy Source preference for ${id}: the current profile does not declare it as a Source.`);
|
|
8497
|
+
continue;
|
|
8498
|
+
}
|
|
8499
|
+
entries[id] = {
|
|
8500
|
+
enabled: item.enabled,
|
|
8501
|
+
config: {}
|
|
8502
|
+
};
|
|
8503
|
+
}
|
|
8504
|
+
return entries;
|
|
8505
|
+
}
|
|
8506
|
+
function applyEntryOverrides(entries, overrides, sourceEntryIds, diagnostics) {
|
|
8507
|
+
if (!Array.isArray(overrides)) throw new Error("Explicit Entry overrides must be an array");
|
|
8508
|
+
const matching = /* @__PURE__ */ new Map();
|
|
8509
|
+
for (const raw of overrides) {
|
|
8510
|
+
const row = object$2(raw, "Explicit Entry override");
|
|
8511
|
+
entryId(row.id, "Explicit Entry override");
|
|
8512
|
+
if (!Object.hasOwn(entries, row.id)) continue;
|
|
8513
|
+
const previous = matching.get(row.id) ?? {};
|
|
8514
|
+
matching.set(row.id, {
|
|
8515
|
+
...previous,
|
|
8516
|
+
...row.disabled === void 0 ? {} : { disabled: row.disabled },
|
|
8517
|
+
...row.config === void 0 ? {} : { config: row.config }
|
|
8518
|
+
});
|
|
8519
|
+
}
|
|
8520
|
+
for (const [id, row] of matching) {
|
|
8521
|
+
if (row.disabled !== void 0 && typeof row.disabled !== "boolean") {
|
|
8522
|
+
delete entries[id];
|
|
8523
|
+
diagnostics.push(`Skipped legacy View preference for ${id}: its explicit disabled value is not boolean.`);
|
|
8524
|
+
continue;
|
|
8525
|
+
}
|
|
8526
|
+
if (row.config !== void 0 && !sourceEntryIds.has(id)) {
|
|
8527
|
+
const config = copiedObject(row.config, "Explicit Entry config");
|
|
8528
|
+
if (containsExpression(config)) {
|
|
8529
|
+
delete entries[id];
|
|
8530
|
+
diagnostics.push(`Skipped legacy View preference for ${id}: its explicit config contains an expression.`);
|
|
8531
|
+
continue;
|
|
8532
|
+
}
|
|
8533
|
+
entries[id].config = config;
|
|
8534
|
+
}
|
|
8535
|
+
if (typeof row.disabled === "boolean") entries[id].enabled = !row.disabled;
|
|
8536
|
+
}
|
|
8349
8537
|
}
|
|
8538
|
+
/**
|
|
8539
|
+
* Recover only the canonical root and the exact owning profile's old namespaces.
|
|
8540
|
+
* This does not read files, edit profile rows, validate plugin domains or commit.
|
|
8541
|
+
* Malformed relevant input rejects the complete plan without an import marker.
|
|
8542
|
+
*/
|
|
8543
|
+
function planLegacySettingsImport(options) {
|
|
8544
|
+
const diagnostics = [];
|
|
8545
|
+
try {
|
|
8546
|
+
const rawCurrent = object$2(options.currentOverride, "Current config override");
|
|
8547
|
+
if (rawCurrent.legacySettingsImported === true) return {
|
|
8548
|
+
patch: {},
|
|
8549
|
+
diagnostics
|
|
8550
|
+
};
|
|
8551
|
+
if (options.entryId !== "mnemon") throw new Error("Legacy settings belong to the canonical mnemon Entry; another root Entry is ambiguous.");
|
|
8552
|
+
if (!VIEW_NAMESPACE.test(options.viewNamespace) || !LEGACY_NAMESPACE.test(options.legacyNamespace) || options.legacyNamespace !== options.viewNamespace.replace(/^mnemon-view/u, "mnemon-plugins")) throw new Error("Legacy settings namespaces must identify the same exact profile.");
|
|
8553
|
+
const sections = object$2(options.sections, "Legacy settings document");
|
|
8554
|
+
for (const key of Object.keys(sections)) if (key.startsWith("mnemon-view-") && !VIEW_NAMESPACE.test(key) || key.startsWith("mnemon-plugins-") && !LEGACY_NAMESPACE.test(key)) throw new Error("Legacy settings document contains an invalid Mnemon namespace.");
|
|
8555
|
+
const relevant = [
|
|
8556
|
+
"mnemon",
|
|
8557
|
+
"mnemon-ui",
|
|
8558
|
+
options.viewNamespace,
|
|
8559
|
+
options.legacyNamespace
|
|
8560
|
+
];
|
|
8561
|
+
if (!relevant.some((key) => Object.hasOwn(sections, key))) return {
|
|
8562
|
+
patch: {},
|
|
8563
|
+
diagnostics
|
|
8564
|
+
};
|
|
8565
|
+
for (const key of relevant) if (Object.hasOwn(sections, key) && containsExpression(copiedObject(sections[key], key))) throw new Error(`${key} contains an expression; legacy settings must contain only literal data.`);
|
|
8566
|
+
const current = copiedObject(rawCurrent, "Current config override");
|
|
8567
|
+
if (Object.hasOwn(current, "legacySettingsImported") && typeof current.legacySettingsImported !== "boolean") throw new Error("Current import marker must be boolean");
|
|
8568
|
+
const root = Object.hasOwn(sections, "mnemon") ? copiedObject(sections.mnemon, "mnemon") : {};
|
|
8569
|
+
if (Object.hasOwn(root, "memoryView") || Object.hasOwn(root, "legacySettingsImported")) throw new Error("Legacy mnemon contains reserved migration fields");
|
|
8570
|
+
const oldInteraction = Object.hasOwn(root, "conversationInteraction") ? interaction(root.conversationInteraction, "mnemon.conversationInteraction", [
|
|
8571
|
+
"toolviews",
|
|
8572
|
+
"turnBar",
|
|
8573
|
+
"saveAction"
|
|
8574
|
+
]) : {};
|
|
8575
|
+
const oldUi = Object.hasOwn(sections, "mnemon-ui") ? interaction(sections["mnemon-ui"], "mnemon-ui", ["turnBar", "saveAction"]) : {};
|
|
8576
|
+
const currentInteraction = Object.hasOwn(current, "conversationInteraction") ? interaction(current.conversationInteraction, "Current conversationInteraction", [
|
|
8577
|
+
"toolviews",
|
|
8578
|
+
"turnBar",
|
|
8579
|
+
"saveAction"
|
|
8580
|
+
]) : {};
|
|
8581
|
+
const patch = Object.fromEntries(Object.entries(root).filter(([key]) => key !== "conversationInteraction" && !Object.hasOwn(current, key)));
|
|
8582
|
+
const inheritedInteraction = {
|
|
8583
|
+
...oldInteraction,
|
|
8584
|
+
...oldUi
|
|
8585
|
+
};
|
|
8586
|
+
if (Object.keys(inheritedInteraction).some((key) => !Object.hasOwn(currentInteraction, key))) patch.conversationInteraction = {
|
|
8587
|
+
...inheritedInteraction,
|
|
8588
|
+
...currentInteraction
|
|
8589
|
+
};
|
|
8590
|
+
const currentView = Object.hasOwn(current, "memoryView") ? view(current.memoryView, "Current memoryView") : {};
|
|
8591
|
+
if (Object.hasOwn(sections, options.viewNamespace) || Object.hasOwn(sections, options.legacyNamespace)) {
|
|
8592
|
+
if (!Array.isArray(options.sourceEntryIds)) throw new Error("Source Entry ids must be an array");
|
|
8593
|
+
for (const id of options.sourceEntryIds) entryId(id, "Source Entry ids");
|
|
8594
|
+
const sourceEntryIds = new Set(options.sourceEntryIds);
|
|
8595
|
+
const oldSources = Object.hasOwn(sections, options.legacyNamespace) ? sources(sections[options.legacyNamespace], options.legacyNamespace, sourceEntryIds, diagnostics) : {};
|
|
8596
|
+
const oldView = Object.hasOwn(sections, options.viewNamespace) ? view(sections[options.viewNamespace], options.viewNamespace) : {};
|
|
8597
|
+
const entries = {
|
|
8598
|
+
...oldSources,
|
|
8599
|
+
...oldView.entries
|
|
8600
|
+
};
|
|
8601
|
+
applyEntryOverrides(entries, options.entryOverrides, sourceEntryIds, diagnostics);
|
|
8602
|
+
const migratedView = {
|
|
8603
|
+
...oldView,
|
|
8604
|
+
entries,
|
|
8605
|
+
...currentView
|
|
8606
|
+
};
|
|
8607
|
+
if (!Object.hasOwn(currentView, "entries") || !Object.hasOwn(currentView, "strategyTypeId") && oldView.strategyTypeId !== void 0) patch.memoryView = migratedView;
|
|
8608
|
+
}
|
|
8609
|
+
patch.legacySettingsImported = true;
|
|
8610
|
+
return {
|
|
8611
|
+
patch,
|
|
8612
|
+
diagnostics
|
|
8613
|
+
};
|
|
8614
|
+
} catch (error) {
|
|
8615
|
+
diagnostics.push(error instanceof Error ? error.message : "Legacy settings import could not be planned");
|
|
8616
|
+
return {
|
|
8617
|
+
patch: {},
|
|
8618
|
+
diagnostics
|
|
8619
|
+
};
|
|
8620
|
+
}
|
|
8621
|
+
}
|
|
8622
|
+
//#endregion
|
|
8623
|
+
//#region src/host/settings-service.ts
|
|
8624
|
+
const pendingNativeImports = /* @__PURE__ */ new WeakSet();
|
|
8625
|
+
const clone$1 = (value) => structuredClone(value);
|
|
8626
|
+
const object$1 = (value) => value !== null && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
8627
|
+
function profileYaml(source) {
|
|
8628
|
+
const document = parseDocument(source, { customTags: [{
|
|
8629
|
+
tag: "tag:yaml.org,2002:js",
|
|
8630
|
+
resolve: (value) => ({ __jsExpr: value })
|
|
8631
|
+
}] });
|
|
8632
|
+
if (document.errors.length > 0 || document.warnings.length > 0) throw new Error("Invalid or unsupported legacy/profile YAML; retained backup was not changed");
|
|
8633
|
+
return document.toJS({ maxAliasCount: 100 });
|
|
8634
|
+
}
|
|
8635
|
+
/** A local facade preserves Mnemon's wire namespaces; DSH owns all persistence. */
|
|
8636
|
+
var ProfileMnemonSettings = class {
|
|
8637
|
+
ctx;
|
|
8638
|
+
input;
|
|
8639
|
+
registrations = /* @__PURE__ */ new Map();
|
|
8640
|
+
listeners = /* @__PURE__ */ new Set();
|
|
8641
|
+
revisions = /* @__PURE__ */ new Map();
|
|
8642
|
+
owner;
|
|
8643
|
+
forms;
|
|
8644
|
+
editor;
|
|
8645
|
+
closed = false;
|
|
8646
|
+
importing;
|
|
8647
|
+
nativeImportPending;
|
|
8648
|
+
constructor(ctx, input) {
|
|
8649
|
+
this.ctx = ctx;
|
|
8650
|
+
this.input = input;
|
|
8651
|
+
this.forms = ctx.settings;
|
|
8652
|
+
this.owner = ctx.fiber;
|
|
8653
|
+
this.editor = ctx.get("configEditor");
|
|
8654
|
+
const profile = ctx.get("profileContext");
|
|
8655
|
+
const root = ctx.root ?? ctx;
|
|
8656
|
+
if (profile?.home !== void 0 && existsSync(join(profile.home, "settings.yaml"))) pendingNativeImports.add(root);
|
|
8657
|
+
this.nativeImportPending = pendingNativeImports.has(root);
|
|
8658
|
+
const owner = this.owner;
|
|
8659
|
+
const validate = (candidate) => {
|
|
8660
|
+
const config = plainHostConfig(candidate);
|
|
8661
|
+
for (const registration of this.registrations.values()) {
|
|
8662
|
+
if (registration.legacy) continue;
|
|
8663
|
+
const value = this.resolve(registration, config);
|
|
8664
|
+
registration.validate?.(value);
|
|
8665
|
+
}
|
|
8666
|
+
};
|
|
8667
|
+
ctx.on("internal/config", function(_raw, next) {
|
|
8668
|
+
const candidate = next();
|
|
8669
|
+
if (this === owner) validate(candidate);
|
|
8670
|
+
return candidate;
|
|
8671
|
+
}, { prepend: true });
|
|
8672
|
+
ctx.on("loader/volatile-update", ((paths) => {
|
|
8673
|
+
if (this.closed) return;
|
|
8674
|
+
for (const registration of this.registrations.values()) {
|
|
8675
|
+
if (registration.legacy) continue;
|
|
8676
|
+
if (!paths.some((path) => registration.field === void 0 ? path.length === 0 || !["memoryView", "legacySettingsImported"].includes(path[0]) : path.length === 0 || path[0] === registration.field)) continue;
|
|
8677
|
+
const value = this.resolve(registration);
|
|
8678
|
+
for (const listener of this.listeners) try {
|
|
8679
|
+
listener(registration.namespace, value);
|
|
8680
|
+
} catch (error) {
|
|
8681
|
+
console.warn("dsh-mnemon: committed settings listener failed", error);
|
|
8682
|
+
}
|
|
8683
|
+
}
|
|
8684
|
+
}));
|
|
8685
|
+
ctx.effect(() => {
|
|
8686
|
+
const disposePresentation = owner === void 0 ? void 0 : this.forms.configure({ auto: false }, owner);
|
|
8687
|
+
return () => {
|
|
8688
|
+
this.closed = true;
|
|
8689
|
+
this.listeners.clear();
|
|
8690
|
+
this.revisions.clear();
|
|
8691
|
+
disposePresentation?.();
|
|
8692
|
+
};
|
|
8693
|
+
}, "dsh-mnemon: profile settings");
|
|
8694
|
+
}
|
|
8695
|
+
get writable() {
|
|
8696
|
+
const entry = this.owner?.entry;
|
|
8697
|
+
return !this.closed && this.forms.writable && entry !== void 0 && this.editor?.entries().includes(entry) === true;
|
|
8698
|
+
}
|
|
8699
|
+
onUpdated(listener) {
|
|
8700
|
+
this.listeners.add(listener);
|
|
8701
|
+
return () => {
|
|
8702
|
+
this.listeners.delete(listener);
|
|
8703
|
+
};
|
|
8704
|
+
}
|
|
8705
|
+
resolve(registration, config = plainHostConfig(this.owner?.config ?? this.input)) {
|
|
8706
|
+
const value = registration.legacy ? registration.base : registration.field === void 0 ? config : config[registration.field];
|
|
8707
|
+
return registration.schema(object$1(value));
|
|
8708
|
+
}
|
|
8709
|
+
register(namespace, schema, options) {
|
|
8710
|
+
if (this.registrations.has(namespace)) throw new Error(`Mnemon settings already registered: ${namespace}`);
|
|
8711
|
+
if (typeof schema !== "function") throw new Error("Mnemon settings require a schema");
|
|
8712
|
+
const field = namespace === "mnemon-ui" ? "conversationInteraction" : /^mnemon-view(?:-[a-f0-9]{16})?$/u.test(namespace) ? "memoryView" : void 0;
|
|
8713
|
+
const legacy = /^mnemon-plugins(?:-[a-f0-9]{16})?$/u.test(namespace);
|
|
8714
|
+
if (namespace !== "mnemon" && field === void 0 && !legacy) throw new Error("Unsupported Mnemon settings namespace");
|
|
8715
|
+
const registration = {
|
|
8716
|
+
namespace,
|
|
8717
|
+
...field === void 0 ? {} : { field },
|
|
8718
|
+
legacy,
|
|
8719
|
+
schema,
|
|
8720
|
+
base: clone$1(options.base ?? {}),
|
|
8721
|
+
...options.validate === void 0 ? {} : { validate: options.validate }
|
|
8722
|
+
};
|
|
8723
|
+
const value = this.resolve(registration);
|
|
8724
|
+
options.validate?.(value);
|
|
8725
|
+
this.registrations.set(namespace, registration);
|
|
8726
|
+
return { get: () => this.resolve(registration) };
|
|
8727
|
+
}
|
|
8728
|
+
nativeDescriptor() {
|
|
8729
|
+
if (this.closed || this.owner?.entry === void 0 || !this.editor?.entries().includes(this.owner.entry)) return void 0;
|
|
8730
|
+
const descriptor = this.forms.describe().find((item) => item.ns === this.owner?.entry?.options.id);
|
|
8731
|
+
if (descriptor !== void 0) {
|
|
8732
|
+
this.revisions.set(descriptor.revision, clone$1({
|
|
8733
|
+
ns: descriptor.ns,
|
|
8734
|
+
revision: descriptor.revision,
|
|
8735
|
+
applies: descriptor.applies,
|
|
8736
|
+
value: descriptor.value,
|
|
8737
|
+
base: descriptor.base,
|
|
8738
|
+
user: descriptor.user
|
|
8739
|
+
}));
|
|
8740
|
+
if (this.revisions.size > 64) this.revisions.delete(this.revisions.keys().next().value);
|
|
8741
|
+
}
|
|
8742
|
+
return descriptor;
|
|
8743
|
+
}
|
|
8744
|
+
unchanged(previous, current, registration, operations) {
|
|
8745
|
+
const project = (value) => {
|
|
8746
|
+
if (registration.field !== void 0) return object$1(value)[registration.field];
|
|
8747
|
+
const { memoryView: _view, legacySettingsImported: _imported, conversationInteraction, ...core } = object$1(value);
|
|
8748
|
+
return operations.some((operation) => operation.path[0] === "conversationInteraction") ? {
|
|
8749
|
+
...core,
|
|
8750
|
+
conversationInteraction
|
|
8751
|
+
} : core;
|
|
8752
|
+
};
|
|
8753
|
+
const signature = (descriptor) => canonicalMemoryJson(JSON.parse(JSON.stringify([
|
|
8754
|
+
project(descriptor.value) ?? null,
|
|
8755
|
+
project(descriptor.base) ?? null,
|
|
8756
|
+
project(descriptor.user) ?? null
|
|
8757
|
+
])));
|
|
8758
|
+
return signature(previous) === signature(current);
|
|
8759
|
+
}
|
|
8760
|
+
describe(options) {
|
|
8761
|
+
const raw = this.nativeDescriptor();
|
|
8762
|
+
if (raw === void 0) return [];
|
|
8763
|
+
const descriptor = options?.redactSecrets ? this.forms.describe(options).find((item) => item.ns === this.owner?.entry?.options.id) : raw;
|
|
8764
|
+
if (descriptor === void 0) return [];
|
|
8765
|
+
return [...this.registrations.values()].map((registration) => {
|
|
8766
|
+
const project = (value) => registration.legacy ? {} : registration.field === void 0 ? value : object$1(value)[registration.field];
|
|
8767
|
+
return {
|
|
8768
|
+
ns: registration.namespace,
|
|
8769
|
+
value: project(descriptor.value) ?? {},
|
|
8770
|
+
base: project(descriptor.base) ?? {},
|
|
8771
|
+
user: project(descriptor.user) ?? {},
|
|
8772
|
+
revision: descriptor.revision,
|
|
8773
|
+
applies: "live"
|
|
8774
|
+
};
|
|
8775
|
+
});
|
|
8776
|
+
}
|
|
8777
|
+
async mutate(namespace, operations, expectedRevision) {
|
|
8778
|
+
const registration = this.registrations.get(namespace);
|
|
8779
|
+
if (registration === void 0 || registration.legacy) throw new Error("Unsupported Mnemon settings namespace");
|
|
8780
|
+
if (!this.writable) throw new Error("DSH settings are read-only");
|
|
8781
|
+
const translated = operations.map((operation) => ({
|
|
8782
|
+
...operation,
|
|
8783
|
+
path: [...registration.field === void 0 ? [] : [registration.field], ...operation.path]
|
|
8784
|
+
}));
|
|
8785
|
+
let revision = expectedRevision;
|
|
8786
|
+
const previous = revision === void 0 ? void 0 : this.revisions.get(revision);
|
|
8787
|
+
for (let attempt = 0;; attempt += 1) {
|
|
8788
|
+
if (!this.writable) throw new Error("DSH settings are read-only");
|
|
8789
|
+
try {
|
|
8790
|
+
await this.forms.mutate(this.owner.entry.options.id, translated, revision);
|
|
8791
|
+
return;
|
|
8792
|
+
} catch (error) {
|
|
8793
|
+
if (attempt >= 2 || previous === void 0 || typeof error !== "object" || error === null || !("code" in error) || error.code !== "SETTINGS_CONFLICT") throw error;
|
|
8794
|
+
if (!this.writable) throw new Error("DSH settings are read-only");
|
|
8795
|
+
const current = this.nativeDescriptor();
|
|
8796
|
+
if (current === void 0 || !this.unchanged(previous, current, registration, operations)) throw error;
|
|
8797
|
+
revision = current.revision;
|
|
8798
|
+
}
|
|
8799
|
+
}
|
|
8800
|
+
}
|
|
8801
|
+
/** Read only the retained backup; ConfigEditor preserves all other patch rows. */
|
|
8802
|
+
async importLegacy(sourceEntryIds) {
|
|
8803
|
+
if (this.importing !== void 0) return this.importing;
|
|
8804
|
+
this.importing = this.performImport(sourceEntryIds).finally(() => {
|
|
8805
|
+
this.importing = void 0;
|
|
8806
|
+
});
|
|
8807
|
+
return this.importing;
|
|
8808
|
+
}
|
|
8809
|
+
async performImport(sourceEntryIds) {
|
|
8810
|
+
const profile = this.ctx.get("profileContext");
|
|
8811
|
+
const entry = this.owner?.entry;
|
|
8812
|
+
if (!this.writable || profile?.home === void 0 || entry === void 0) return;
|
|
8813
|
+
if (this.nativeImportPending) {
|
|
8814
|
+
console.warn("dsh-mnemon: DSH is importing settings.yaml; restart once to recover retained Mnemon UI and plugin preferences");
|
|
8815
|
+
return;
|
|
8816
|
+
}
|
|
8817
|
+
if (plainHostConfig(this.owner?.config ?? this.input).legacySettingsImported) return;
|
|
8818
|
+
const backup = join(profile.home, "settings.yaml.imported");
|
|
8819
|
+
let text;
|
|
8820
|
+
try {
|
|
8821
|
+
if ((await stat(backup)).size > 1048576) throw new Error("Legacy settings backup exceeds the import limit");
|
|
8822
|
+
text = await readFile(backup, "utf8");
|
|
8823
|
+
} catch (error) {
|
|
8824
|
+
if (typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT") return;
|
|
8825
|
+
throw error;
|
|
8826
|
+
}
|
|
8827
|
+
const sections = profileYaml(text);
|
|
8828
|
+
const viewNamespace = [...this.registrations.keys()].find((namespace) => namespace.startsWith("mnemon-view"));
|
|
8829
|
+
const legacyNamespace = [...this.registrations.keys()].find((namespace) => namespace.startsWith("mnemon-plugins"));
|
|
8830
|
+
const plan = () => {
|
|
8831
|
+
const configuration = this.editor.configuration().find((item) => item.entry === entry);
|
|
8832
|
+
if (configuration === void 0) throw new Error("Mnemon profile entry is no longer editable");
|
|
8833
|
+
const document = profileYaml(readFileSync(this.editor.documentPath, "utf8"));
|
|
8834
|
+
const entryOverrides = Array.isArray(document) ? document.flatMap((value) => {
|
|
8835
|
+
const row = object$1(value);
|
|
8836
|
+
if (typeof row.id !== "string") return [];
|
|
8837
|
+
const entries = this.editor.entries().filter((candidate) => candidate.options.id === row.id);
|
|
8838
|
+
if (entries.length > 1) throw new Error("Legacy settings import requires unambiguous profile Entry ids");
|
|
8839
|
+
return [{
|
|
8840
|
+
id: entries[0]?.id ?? row.id,
|
|
8841
|
+
..."disabled" in row ? { disabled: row.disabled } : {},
|
|
8842
|
+
..."config" in row ? { config: row.config } : {}
|
|
8843
|
+
}];
|
|
8844
|
+
}) : [];
|
|
8845
|
+
return planLegacySettingsImport({
|
|
8846
|
+
entryId: entry.options.id,
|
|
8847
|
+
viewNamespace,
|
|
8848
|
+
legacyNamespace,
|
|
8849
|
+
sections,
|
|
8850
|
+
currentOverride: configuration.override,
|
|
8851
|
+
entryOverrides,
|
|
8852
|
+
sourceEntryIds
|
|
8853
|
+
});
|
|
8854
|
+
};
|
|
8855
|
+
const preview = plan();
|
|
8856
|
+
if (Object.keys(preview.patch).length === 0) {
|
|
8857
|
+
if (preview.diagnostics.length > 0) console.warn("dsh-mnemon: legacy settings were not imported; retained backup requires review");
|
|
8858
|
+
return;
|
|
8859
|
+
}
|
|
8860
|
+
if (this.closed) return;
|
|
8861
|
+
await this.editor.edit(entry, (current) => {
|
|
8862
|
+
if (this.closed) throw new Error("Mnemon settings are disposed");
|
|
8863
|
+
const next = plan();
|
|
8864
|
+
return {
|
|
8865
|
+
...current,
|
|
8866
|
+
...next.patch
|
|
8867
|
+
};
|
|
8868
|
+
});
|
|
8869
|
+
}
|
|
8870
|
+
};
|
|
8871
|
+
function createHostSettings(ctx, config) {
|
|
8872
|
+
return typeof ctx.settings.register === "function" ? ctx.settings : new ProfileMnemonSettings(ctx, config);
|
|
8873
|
+
}
|
|
8874
|
+
function subscribeSettings(ctx, settings, listener) {
|
|
8875
|
+
return settings instanceof ProfileMnemonSettings ? settings.onUpdated(listener) : ctx.on("settings/updated", listener);
|
|
8876
|
+
}
|
|
8877
|
+
//#endregion
|
|
8878
|
+
//#region src/host/plugin-management.ts
|
|
8879
|
+
const PACKAGE$1 = /^(?:@[a-z0-9._-]+\/)?dsh-mnemon-(source|strategy)-[a-z0-9._-]+$/u;
|
|
8880
|
+
const hash = (value) => createHash("sha256").update(canonicalMemoryJson(value)).digest("hex");
|
|
8881
|
+
const clone = (value) => JSON.parse(JSON.stringify(value));
|
|
8350
8882
|
function contributionRoles(snapshot, entryId) {
|
|
8351
8883
|
const roles = /* @__PURE__ */ new Set();
|
|
8352
8884
|
if (snapshot.sources.some((value) => value.provenance.entryId === entryId)) roles.add("source");
|
|
@@ -8436,6 +8968,7 @@ function orderPlugins(values) {
|
|
|
8436
8968
|
var MemoryPluginManagement = class {
|
|
8437
8969
|
ctx;
|
|
8438
8970
|
engine;
|
|
8971
|
+
settingsService;
|
|
8439
8972
|
settingsNamespace;
|
|
8440
8973
|
settings;
|
|
8441
8974
|
legacySettings;
|
|
@@ -8445,21 +8978,23 @@ var MemoryPluginManagement = class {
|
|
|
8445
8978
|
restoreError;
|
|
8446
8979
|
discoveryWarnings = [];
|
|
8447
8980
|
changingEntries = false;
|
|
8448
|
-
|
|
8981
|
+
restorePending = false;
|
|
8982
|
+
constructor(ctx, engine, settingsService = ctx.settings) {
|
|
8449
8983
|
this.ctx = ctx;
|
|
8450
8984
|
this.engine = engine;
|
|
8985
|
+
this.settingsService = settingsService;
|
|
8451
8986
|
const loader = this.loader();
|
|
8452
|
-
const anchor = loader?.config?.baseUrl ?? loader?.context?.baseUrl;
|
|
8987
|
+
const anchor = loader?.config?.baseUrl ?? loader?.ctx?.baseUrl ?? loader?.context?.baseUrl;
|
|
8453
8988
|
const suffix = anchor ? `-${hash(anchor).slice(0, 16)}` : "";
|
|
8454
8989
|
this.settingsNamespace = `${MNEMON_VIEW_SETTINGS_NAMESPACE}${suffix}`;
|
|
8455
|
-
this.settings =
|
|
8990
|
+
this.settings = settingsService.register(this.settingsNamespace, schema, {
|
|
8456
8991
|
base: { entries: {} },
|
|
8457
8992
|
applies: "live",
|
|
8458
8993
|
validate: (value) => {
|
|
8459
8994
|
preferences(value);
|
|
8460
8995
|
}
|
|
8461
8996
|
});
|
|
8462
|
-
this.legacySettings =
|
|
8997
|
+
this.legacySettings = settingsService.register(`mnemon-plugins${suffix}`, legacySchema, {
|
|
8463
8998
|
base: { sources: {} },
|
|
8464
8999
|
applies: "live",
|
|
8465
9000
|
validate: (value) => {
|
|
@@ -8467,8 +9002,8 @@ var MemoryPluginManagement = class {
|
|
|
8467
9002
|
}
|
|
8468
9003
|
});
|
|
8469
9004
|
}
|
|
8470
|
-
resolveConfig(config) {
|
|
8471
|
-
const selected =
|
|
9005
|
+
resolveConfig(config, view = this.settings.get()) {
|
|
9006
|
+
const selected = view.strategyTypeId;
|
|
8472
9007
|
return selected === void 0 ? config : {
|
|
8473
9008
|
...config,
|
|
8474
9009
|
memoryTopology: {
|
|
@@ -8478,36 +9013,61 @@ var MemoryPluginManagement = class {
|
|
|
8478
9013
|
};
|
|
8479
9014
|
}
|
|
8480
9015
|
start() {
|
|
8481
|
-
const schedule = () =>
|
|
8482
|
-
const hasSavedState = Object.keys(this.settings.get().entries ?? {}).length > 0 || Object.keys(this.legacySettings.get().sources ?? {}).length > 0;
|
|
8483
|
-
if (this.closed || this.changingEntries || this.timer || !hasSavedState) return;
|
|
8484
|
-
this.timer = setTimeout(() => {
|
|
8485
|
-
this.timer = void 0;
|
|
8486
|
-
this.exclusive(() => this.restore()).catch((error) => {
|
|
8487
|
-
this.restoreError = error instanceof Error ? error.message : String(error);
|
|
8488
|
-
});
|
|
8489
|
-
}, 0);
|
|
8490
|
-
};
|
|
9016
|
+
const schedule = () => this.scheduleRestore();
|
|
8491
9017
|
const stops = [
|
|
8492
9018
|
this.ctx.on("loader/entry-init", schedule),
|
|
8493
9019
|
this.ctx.on("loader/partial-dispose", schedule),
|
|
8494
|
-
this.ctx.on("
|
|
9020
|
+
this.ctx.on("app-boot/config-reload", () => this.scheduleRestore(true)),
|
|
9021
|
+
subscribeSettings(this.ctx, this.settingsService, (namespace) => {
|
|
8495
9022
|
if (namespace === this.settingsNamespace || namespace === `mnemon-plugins${this.settingsNamespace.slice(11)}`) schedule();
|
|
8496
|
-
})
|
|
9023
|
+
})
|
|
8497
9024
|
];
|
|
8498
9025
|
schedule();
|
|
8499
9026
|
return () => {
|
|
8500
9027
|
this.closed = true;
|
|
9028
|
+
this.restorePending = false;
|
|
8501
9029
|
clearTimeout(this.timer);
|
|
8502
9030
|
for (const stop of stops.reverse()) stop();
|
|
8503
9031
|
};
|
|
8504
9032
|
}
|
|
9033
|
+
scheduleRestore(profileReload = false) {
|
|
9034
|
+
const hasSavedState = Object.keys(this.settings.get().entries ?? {}).length > 0 || Object.keys(this.legacySettings.get().sources ?? {}).length > 0;
|
|
9035
|
+
if (this.closed || !profileReload && this.changingEntries || !hasSavedState) return;
|
|
9036
|
+
this.restorePending = true;
|
|
9037
|
+
if (this.changingEntries || this.timer) return;
|
|
9038
|
+
this.timer = setTimeout(() => {
|
|
9039
|
+
this.timer = void 0;
|
|
9040
|
+
this.enqueueRestore();
|
|
9041
|
+
}, 0);
|
|
9042
|
+
}
|
|
9043
|
+
enqueueRestore() {
|
|
9044
|
+
if (this.closed || this.changingEntries || !this.restorePending) return;
|
|
9045
|
+
clearTimeout(this.timer);
|
|
9046
|
+
this.timer = void 0;
|
|
9047
|
+
this.restorePending = false;
|
|
9048
|
+
this.exclusive(async () => {
|
|
9049
|
+
try {
|
|
9050
|
+
await this.restore();
|
|
9051
|
+
} catch (error) {
|
|
9052
|
+
this.restoreError = error instanceof Error ? error.message : String(error);
|
|
9053
|
+
}
|
|
9054
|
+
}).catch(() => {});
|
|
9055
|
+
}
|
|
9056
|
+
/** A response must not race the deferred restore after profile reconciliation. */
|
|
9057
|
+
async settled() {
|
|
9058
|
+
do {
|
|
9059
|
+
this.enqueueRestore();
|
|
9060
|
+
const pending = this.queue;
|
|
9061
|
+
await pending;
|
|
9062
|
+
if (pending === this.queue && !this.restorePending) return;
|
|
9063
|
+
} while (!this.closed);
|
|
9064
|
+
}
|
|
8505
9065
|
loader() {
|
|
8506
9066
|
const candidate = this.ctx.get("loader");
|
|
8507
9067
|
return candidate && typeof candidate.entries === "function" ? candidate : void 0;
|
|
8508
9068
|
}
|
|
8509
9069
|
settingsRevision() {
|
|
8510
|
-
return this.
|
|
9070
|
+
return this.settingsService.describe({ redactSecrets: true }).find((value) => value.ns === this.settingsNamespace)?.revision ?? 0;
|
|
8511
9071
|
}
|
|
8512
9072
|
async managed() {
|
|
8513
9073
|
const loader = this.loader();
|
|
@@ -8552,7 +9112,7 @@ var MemoryPluginManagement = class {
|
|
|
8552
9112
|
config: editor === void 0 ? {} : memoryStrategyConfigurationValues(editor, entry.options.config),
|
|
8553
9113
|
enabled: !entry.disabled,
|
|
8554
9114
|
active,
|
|
8555
|
-
writable: this.
|
|
9115
|
+
writable: this.settingsService.writable && !ancestorDisabled && (entry.options.disabled === void 0 || typeof entry.options.disabled === "boolean"),
|
|
8556
9116
|
...ancestorDisabled ? { diagnostic: "This Entry is disabled by its parent." } : !entry.disabled && !active ? { diagnostic: "This Entry is enabled but has not registered a memory contribution." } : {}
|
|
8557
9117
|
};
|
|
8558
9118
|
const item = {
|
|
@@ -8583,7 +9143,7 @@ var MemoryPluginManagement = class {
|
|
|
8583
9143
|
`mnemon-plugins${this.settingsNamespace.slice(11)}`
|
|
8584
9144
|
]);
|
|
8585
9145
|
return hash({
|
|
8586
|
-
settings: this.
|
|
9146
|
+
settings: this.settingsService.describe({ redactSecrets: true }).filter((value) => namespaces.has(value.ns)).map((value) => [value.ns, value.revision]),
|
|
8587
9147
|
contribution: this.engine.contributionSnapshot().revision,
|
|
8588
9148
|
entries: items.map(({ entry, value, descriptor }) => ({
|
|
8589
9149
|
id: entry.id,
|
|
@@ -8595,8 +9155,10 @@ var MemoryPluginManagement = class {
|
|
|
8595
9155
|
});
|
|
8596
9156
|
}
|
|
8597
9157
|
async catalog() {
|
|
8598
|
-
await this.
|
|
9158
|
+
await this.settled();
|
|
9159
|
+
const pending = this.queue;
|
|
8599
9160
|
const items = await this.managed();
|
|
9161
|
+
if (pending !== this.queue || this.restorePending) return this.catalog();
|
|
8600
9162
|
const values = items.map((item) => clone(item.value));
|
|
8601
9163
|
const snapshot = this.engine.contributionSnapshot();
|
|
8602
9164
|
const managedIds = new Set(items.map((item) => item.entry.id));
|
|
@@ -8655,7 +9217,7 @@ var MemoryPluginManagement = class {
|
|
|
8655
9217
|
}
|
|
8656
9218
|
return {
|
|
8657
9219
|
revision: this.revision(items),
|
|
8658
|
-
writable: this.
|
|
9220
|
+
writable: this.settingsService.writable && this.loader() !== void 0,
|
|
8659
9221
|
entries: orderPlugins(values),
|
|
8660
9222
|
diagnostics: [...this.discoveryWarnings, ...this.restoreError === void 0 ? [] : [this.restoreError]]
|
|
8661
9223
|
};
|
|
@@ -8737,7 +9299,7 @@ var MemoryPluginManagement = class {
|
|
|
8737
9299
|
return captureMemoryContributionSnapshot(candidate);
|
|
8738
9300
|
}
|
|
8739
9301
|
async preview(config, scope, request, signal) {
|
|
8740
|
-
await this.
|
|
9302
|
+
await this.settled();
|
|
8741
9303
|
const items = await this.managed();
|
|
8742
9304
|
const value = await this.evaluateSnapshot(this.proposal(items, request), config, scope, request.strategyTypeId, signal);
|
|
8743
9305
|
if (request.expectedRevision !== this.revision(items)) throw new Error("Memory plugin configuration changed during preview; refresh and retry.");
|
|
@@ -8762,8 +9324,9 @@ var MemoryPluginManagement = class {
|
|
|
8762
9324
|
}
|
|
8763
9325
|
}
|
|
8764
9326
|
async apply(config, scope, request, signal) {
|
|
9327
|
+
await this.settled();
|
|
8765
9328
|
return this.exclusive(async () => {
|
|
8766
|
-
if (!this.
|
|
9329
|
+
if (!this.settingsService.writable || !this.loader()) throw new Error("Memory plugin configuration is read-only");
|
|
8767
9330
|
const items = await this.managed();
|
|
8768
9331
|
const choices = this.validateRequest(items, request);
|
|
8769
9332
|
const expectedSettingsRevision = this.settingsRevision();
|
|
@@ -8775,19 +9338,38 @@ var MemoryPluginManagement = class {
|
|
|
8775
9338
|
...request.entries
|
|
8776
9339
|
}
|
|
8777
9340
|
});
|
|
8778
|
-
|
|
8779
|
-
|
|
8780
|
-
|
|
8781
|
-
|
|
8782
|
-
|
|
8783
|
-
|
|
8784
|
-
|
|
8785
|
-
|
|
8786
|
-
|
|
8787
|
-
|
|
8788
|
-
|
|
8789
|
-
|
|
9341
|
+
let committedRevision;
|
|
9342
|
+
await this.updateEntries(items, choices, {
|
|
9343
|
+
validate: () => this.evaluateSnapshot(this.engine.contributionSnapshot(), config, scope, request.strategyTypeId, signal),
|
|
9344
|
+
persist: async () => {
|
|
9345
|
+
await this.settingsService.mutate(this.settingsNamespace, [{
|
|
9346
|
+
op: "set",
|
|
9347
|
+
path: ["strategyTypeId"],
|
|
9348
|
+
value: next.strategyTypeId
|
|
9349
|
+
}, {
|
|
9350
|
+
op: "set",
|
|
9351
|
+
path: ["entries"],
|
|
9352
|
+
value: next.entries
|
|
9353
|
+
}], expectedSettingsRevision);
|
|
9354
|
+
committedRevision = this.settingsRevision();
|
|
9355
|
+
},
|
|
9356
|
+
compensate: async () => {
|
|
9357
|
+
if (hash(preferences(this.settings.get())) !== hash(next)) throw new Error("Memory plugin settings changed before rollback; refresh and inspect the saved configuration.");
|
|
9358
|
+
await this.settingsService.mutate(this.settingsNamespace, [previous.strategyTypeId === void 0 ? {
|
|
9359
|
+
op: "unset",
|
|
9360
|
+
path: ["strategyTypeId"]
|
|
9361
|
+
} : {
|
|
9362
|
+
op: "set",
|
|
9363
|
+
path: ["strategyTypeId"],
|
|
9364
|
+
value: previous.strategyTypeId
|
|
9365
|
+
}, {
|
|
9366
|
+
op: "set",
|
|
9367
|
+
path: ["entries"],
|
|
9368
|
+
value: previous.entries
|
|
9369
|
+
}], committedRevision);
|
|
9370
|
+
}
|
|
8790
9371
|
}, signal);
|
|
9372
|
+
this.restoreError = void 0;
|
|
8791
9373
|
});
|
|
8792
9374
|
}
|
|
8793
9375
|
async restore() {
|
|
@@ -8814,55 +9396,99 @@ var MemoryPluginManagement = class {
|
|
|
8814
9396
|
this.restoreError = void 0;
|
|
8815
9397
|
}
|
|
8816
9398
|
async updateEntries(items, choices, commit, signal) {
|
|
8817
|
-
const
|
|
8818
|
-
|
|
8819
|
-
|
|
8820
|
-
|
|
8821
|
-
|
|
8822
|
-
|
|
8823
|
-
})
|
|
8824
|
-
const
|
|
9399
|
+
const previous = items.map((item) => ({
|
|
9400
|
+
item,
|
|
9401
|
+
disabled: item.entry.options.disabled ?? null,
|
|
9402
|
+
config: clone(item.entry.options.config ?? {}),
|
|
9403
|
+
enabled: item.value.enabled,
|
|
9404
|
+
active: item.value.active
|
|
9405
|
+
}));
|
|
9406
|
+
const touched = /* @__PURE__ */ new Set();
|
|
9407
|
+
const replay = async (current) => {
|
|
9408
|
+
for (const item of items) if (!current.some((value) => value.entry.id === item.entry.id)) throw new Error("Memory plugin Entry disappeared during configuration: " + item.entry.id);
|
|
9409
|
+
const ordered = current.filter((item) => choices.has(item.entry.id)).sort((left, right) => Number(choices.get(left.entry.id).enabled) - Number(choices.get(right.entry.id).enabled));
|
|
9410
|
+
for (const item of ordered) {
|
|
9411
|
+
signal?.throwIfAborted();
|
|
9412
|
+
if (this.closed) throw new Error("Memory plugin management service is disposed");
|
|
9413
|
+
const desired = choices.get(item.entry.id);
|
|
9414
|
+
const actual = {
|
|
9415
|
+
enabled: !item.entry.disabled,
|
|
9416
|
+
config: item.editor === void 0 ? {} : memoryStrategyConfigurationValues(item.editor, item.entry.options.config)
|
|
9417
|
+
};
|
|
9418
|
+
const active = contributionRoles(this.engine.contributionSnapshot(), item.entry.id).length > 0;
|
|
9419
|
+
if (hash(desired) === hash(actual) && active === desired.enabled) continue;
|
|
9420
|
+
touched.add(item.entry.id);
|
|
9421
|
+
await item.entry.update(item.editor === void 0 ? { disabled: !desired.enabled } : {
|
|
9422
|
+
disabled: !desired.enabled,
|
|
9423
|
+
config: clone(desired.config)
|
|
9424
|
+
});
|
|
9425
|
+
await item.entry.fiber?.await?.();
|
|
9426
|
+
const registered = contributionRoles(this.engine.contributionSnapshot(), item.entry.id).length > 0;
|
|
9427
|
+
if (item.entry.disabled === desired.enabled || registered !== desired.enabled) throw new Error("Cordis did not register the requested memory plugin state: " + item.entry.id);
|
|
9428
|
+
}
|
|
9429
|
+
};
|
|
9430
|
+
let persisted = false;
|
|
8825
9431
|
this.changingEntries = true;
|
|
8826
9432
|
try {
|
|
8827
9433
|
await this.engine.batch(async () => {
|
|
8828
9434
|
try {
|
|
8829
|
-
|
|
8830
|
-
signal?.throwIfAborted();
|
|
8831
|
-
if (this.closed) throw new Error("Memory plugin management service is disposed");
|
|
8832
|
-
const desired = choices.get(item.entry.id);
|
|
8833
|
-
restored.push({
|
|
8834
|
-
item,
|
|
8835
|
-
disabled: item.entry.options.disabled ?? null,
|
|
8836
|
-
config: clone(item.entry.options.config ?? {})
|
|
8837
|
-
});
|
|
8838
|
-
await item.entry.update(item.editor === void 0 ? { disabled: !desired.enabled } : {
|
|
8839
|
-
disabled: !desired.enabled,
|
|
8840
|
-
config: clone(desired.config)
|
|
8841
|
-
});
|
|
8842
|
-
await item.entry.fiber?.await?.();
|
|
8843
|
-
const active = contributionRoles(this.engine.contributionSnapshot(), item.entry.id).length > 0;
|
|
8844
|
-
if (item.entry.disabled === desired.enabled || active !== desired.enabled) throw new Error("Cordis did not register the requested memory plugin state: " + item.entry.id);
|
|
8845
|
-
}
|
|
9435
|
+
await replay(items);
|
|
8846
9436
|
signal?.throwIfAborted();
|
|
8847
9437
|
if (this.closed) throw new Error("Memory plugin management service is disposed");
|
|
8848
|
-
|
|
9438
|
+
if (commit !== void 0) {
|
|
9439
|
+
await commit.validate();
|
|
9440
|
+
await commit.persist();
|
|
9441
|
+
persisted = true;
|
|
9442
|
+
const entries = new Map(Array.from(this.loader()?.entries() ?? []).map((entry) => [entry.id, entry]));
|
|
9443
|
+
await replay(items.flatMap((item) => {
|
|
9444
|
+
const entry = entries.get(item.entry.id);
|
|
9445
|
+
return entry === void 0 ? [] : [{
|
|
9446
|
+
...item,
|
|
9447
|
+
entry
|
|
9448
|
+
}];
|
|
9449
|
+
}));
|
|
9450
|
+
await commit.validate();
|
|
9451
|
+
}
|
|
8849
9452
|
} catch (error) {
|
|
8850
9453
|
const failures = [];
|
|
8851
|
-
|
|
8852
|
-
await
|
|
8853
|
-
disabled: previous.disabled,
|
|
8854
|
-
config: previous.config
|
|
8855
|
-
});
|
|
8856
|
-
await previous.item.entry.fiber?.await?.();
|
|
9454
|
+
if (persisted) try {
|
|
9455
|
+
await commit.compensate();
|
|
8857
9456
|
} catch (rollback) {
|
|
8858
9457
|
failures.push(rollback);
|
|
8859
9458
|
}
|
|
8860
|
-
|
|
9459
|
+
const current = new Map(Array.from(this.loader()?.entries() ?? []).map((entry) => [entry.id, entry]));
|
|
9460
|
+
for (const before of previous.reverse()) {
|
|
9461
|
+
const entry = current.get(before.item.entry.id);
|
|
9462
|
+
if (!(entry === void 0 || hash({
|
|
9463
|
+
disabled: entry.options.disabled ?? null,
|
|
9464
|
+
config: entry.options.config ?? {}
|
|
9465
|
+
}) !== hash({
|
|
9466
|
+
disabled: before.disabled,
|
|
9467
|
+
config: before.config
|
|
9468
|
+
}) || !entry.disabled !== before.enabled || contributionRoles(this.engine.contributionSnapshot(), before.item.entry.id).length > 0 !== before.active) && !touched.has(before.item.entry.id)) continue;
|
|
9469
|
+
try {
|
|
9470
|
+
if (entry === void 0) throw new Error("Memory plugin Entry is unavailable for rollback: " + before.item.entry.id);
|
|
9471
|
+
await entry.update(before.item.editor === void 0 ? { disabled: before.disabled } : {
|
|
9472
|
+
disabled: before.disabled,
|
|
9473
|
+
config: before.config
|
|
9474
|
+
});
|
|
9475
|
+
await entry.fiber?.await?.();
|
|
9476
|
+
if (!entry.disabled !== before.enabled || contributionRoles(this.engine.contributionSnapshot(), entry.id).length > 0 !== before.active) throw new Error("Cordis did not restore the previous memory plugin state: " + entry.id);
|
|
9477
|
+
} catch (rollback) {
|
|
9478
|
+
failures.push(rollback);
|
|
9479
|
+
}
|
|
9480
|
+
}
|
|
9481
|
+
if (failures.length) {
|
|
9482
|
+
this.restorePending = false;
|
|
9483
|
+
this.restoreError = "Plugin change failed and rollback was incomplete; inspect DSH plugin state.";
|
|
9484
|
+
throw new AggregateError([error, ...failures], this.restoreError);
|
|
9485
|
+
}
|
|
8861
9486
|
throw error;
|
|
8862
9487
|
}
|
|
8863
9488
|
});
|
|
8864
9489
|
} finally {
|
|
8865
9490
|
this.changingEntries = false;
|
|
9491
|
+
if (this.restorePending) this.scheduleRestore(true);
|
|
8866
9492
|
}
|
|
8867
9493
|
}
|
|
8868
9494
|
exclusive(operation) {
|
|
@@ -9437,19 +10063,21 @@ function optionalWorkspaceRegistry(ctx) {
|
|
|
9437
10063
|
};
|
|
9438
10064
|
}
|
|
9439
10065
|
/** DSH owns assembly; this Host only wires scope, phases and user preferences. */
|
|
9440
|
-
function apply(rawContext,
|
|
10066
|
+
function apply(rawContext, rawConfig = {}) {
|
|
9441
10067
|
const ctx = rawContext;
|
|
10068
|
+
const config = plainHostConfig(rawConfig);
|
|
10069
|
+
const hostSettings = createHostSettings(ctx, rawConfig);
|
|
9442
10070
|
registerMnemonSubagentTokenUsageProjection(ctx);
|
|
9443
10071
|
const extensions = provideMemoryRuntime(ctx);
|
|
9444
|
-
const memoryPlugins = new MemoryPluginManagement(ctx, extensions);
|
|
10072
|
+
const memoryPlugins = new MemoryPluginManagement(ctx, extensions, hostSettings);
|
|
9445
10073
|
const pluginInstallation = new MemoryPluginInstallation(ctx);
|
|
9446
|
-
const effectiveConfig = (value) => memoryPlugins.resolveConfig(resolveConfig(value));
|
|
10074
|
+
const effectiveConfig = (value) => memoryPlugins.resolveConfig(resolveConfig(value), hostSettings instanceof ProfileMnemonSettings ? value.memoryView ?? { entries: {} } : void 0);
|
|
9447
10075
|
const prepared = /* @__PURE__ */ new Map();
|
|
9448
10076
|
const disposePrepared = () => {
|
|
9449
10077
|
for (const candidate of prepared.values()) candidate.graph.dispose();
|
|
9450
10078
|
prepared.clear();
|
|
9451
10079
|
};
|
|
9452
|
-
const settings =
|
|
10080
|
+
const settings = hostSettings.register("mnemon", Config, {
|
|
9453
10081
|
base: config,
|
|
9454
10082
|
applies: "live",
|
|
9455
10083
|
validate: (value) => {
|
|
@@ -9458,6 +10086,10 @@ function apply(rawContext, config = {}) {
|
|
|
9458
10086
|
graph: createRuntimeGraph(effectiveConfig(value), void 0, extensions),
|
|
9459
10087
|
token: Symbol("prepared-runtime")
|
|
9460
10088
|
};
|
|
10089
|
+
if (hostSettings instanceof ProfileMnemonSettings) {
|
|
10090
|
+
candidate.graph.dispose();
|
|
10091
|
+
return;
|
|
10092
|
+
}
|
|
9461
10093
|
prepared.set(value, candidate);
|
|
9462
10094
|
queueMicrotask(() => {
|
|
9463
10095
|
if (prepared.get(value)?.token !== candidate.token) return;
|
|
@@ -9471,7 +10103,8 @@ function apply(rawContext, config = {}) {
|
|
|
9471
10103
|
if (initialCandidate !== void 0) prepared.delete(initialSettings);
|
|
9472
10104
|
const runtime = new LiveMnemonRuntime(initialCandidate?.graph ?? createRuntimeGraph(effectiveConfig(initialSettings), void 0, extensions), optionalWorkspaceRegistry(ctx), ctx.agents, extensions);
|
|
9473
10105
|
const resolved = runtime.config;
|
|
9474
|
-
ctx.
|
|
10106
|
+
ctx.effect(() => subscribeSettings(ctx, hostSettings, (namespace, value) => {
|
|
10107
|
+
const next = value;
|
|
9475
10108
|
if (namespace === memoryPlugins.settingsNamespace) {
|
|
9476
10109
|
runtime.swap(createRuntimeGraph(effectiveConfig(settings.get()), void 0, extensions));
|
|
9477
10110
|
return;
|
|
@@ -9481,9 +10114,9 @@ function apply(rawContext, config = {}) {
|
|
|
9481
10114
|
if (candidate !== void 0) prepared.delete(next);
|
|
9482
10115
|
disposePrepared();
|
|
9483
10116
|
runtime.swap(candidate?.graph ?? createRuntimeGraph(effectiveConfig(next), void 0, extensions));
|
|
9484
|
-
}));
|
|
10117
|
+
}), "dsh-mnemon: live runtime settings");
|
|
9485
10118
|
ctx.effect(() => memoryPlugins.start(), "dsh-mnemon: plugin graph settings");
|
|
9486
|
-
|
|
10119
|
+
hostSettings.register("mnemon-ui", InteractionConfig, {
|
|
9487
10120
|
base: resolveInteractionConfig(resolved.conversationInteraction),
|
|
9488
10121
|
applies: "live"
|
|
9489
10122
|
});
|
|
@@ -9491,7 +10124,7 @@ function apply(rawContext, config = {}) {
|
|
|
9491
10124
|
let disposed = false;
|
|
9492
10125
|
const migrate = () => {
|
|
9493
10126
|
if (disposed) return;
|
|
9494
|
-
migrateLegacyDisplayMode(
|
|
10127
|
+
migrateLegacyDisplayMode(hostSettings).catch((error) => {
|
|
9495
10128
|
console.warn("dsh-mnemon: could not persist the builtin displayMode migration", error);
|
|
9496
10129
|
});
|
|
9497
10130
|
};
|
|
@@ -9504,6 +10137,21 @@ function apply(rawContext, config = {}) {
|
|
|
9504
10137
|
unsubscribe();
|
|
9505
10138
|
};
|
|
9506
10139
|
}, "dsh-mnemon: canonical displayMode migration");
|
|
10140
|
+
if (hostSettings instanceof ProfileMnemonSettings) ctx.effect(() => {
|
|
10141
|
+
let disposed = false;
|
|
10142
|
+
const loader = ctx.get("loader");
|
|
10143
|
+
Promise.resolve(loader?.await?.()).then(async () => {
|
|
10144
|
+
if (disposed) return;
|
|
10145
|
+
const catalog = await memoryPlugins.catalog();
|
|
10146
|
+
if (disposed) return;
|
|
10147
|
+
await hostSettings.importLegacy(catalog.entries.filter((entry) => entry.roles.includes("source")).map((entry) => entry.entryId));
|
|
10148
|
+
}).catch((error) => {
|
|
10149
|
+
console.warn("dsh-mnemon: could not recover retained legacy settings", error);
|
|
10150
|
+
});
|
|
10151
|
+
return () => {
|
|
10152
|
+
disposed = true;
|
|
10153
|
+
};
|
|
10154
|
+
}, "dsh-mnemon: retained settings migration");
|
|
9507
10155
|
const coordinator = new MnemonSubagentCoordinator(ctx.subagents, runtime, ctx, () => {
|
|
9508
10156
|
const taskAgentModel = runtime.config.taskAgentModel;
|
|
9509
10157
|
if (taskAgentModel.mode !== "fixed") return void 0;
|
|
@@ -9532,7 +10180,7 @@ function apply(rawContext, config = {}) {
|
|
|
9532
10180
|
if (webContext.connection === void 0) return;
|
|
9533
10181
|
const managementAuthority = resolved.remoteAccess === "trusted-host" ? "trusted-host" : "loopback";
|
|
9534
10182
|
const rpc = registerRpc(webContext.connection, runtime, lifecycle, void 0, managementAuthority);
|
|
9535
|
-
const settings = registerSettingsRpc(webContext.connection,
|
|
10183
|
+
const settings = registerSettingsRpc(webContext.connection, hostSettings, managementAuthority);
|
|
9536
10184
|
const view = registerViewRpc(webContext.connection, runtime, extensions, memoryPlugins, lifecycle, managementAuthority, pluginInstallation);
|
|
9537
10185
|
if (Context.is(webContext)) new MnemonRemoteService(webContext, {
|
|
9538
10186
|
...rpc,
|
|
@@ -9544,4 +10192,4 @@ function apply(rawContext, config = {}) {
|
|
|
9544
10192
|
});
|
|
9545
10193
|
}
|
|
9546
10194
|
//#endregion
|
|
9547
|
-
export { Config, apply, inject, name, provide };
|
|
10195
|
+
export { LiveConfig as Config, apply, inject, name, provide };
|