dsh-mnemon 0.5.12 → 0.5.14
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/lib/client.js +73 -22
- package/lib/contracts-D4ghDRK4.js +35 -0
- package/lib/contracts.js +1 -34
- package/lib/core.js +1 -1
- package/lib/{definitions-j0FLgE0-.js → definitions-CSPV0ER1.js} +1 -1
- package/lib/extension-sdk.js +2 -2
- package/lib/index.js +876 -219
- package/lib/{runtime-AtIOTeP1.js → runtime-BEX0sc1z.js} +2 -2
- package/lib/{strategy-configuration-BTXIWooc.js → strategy-configuration-D8IEKZdS.js} +1 -1
- package/lib/testing.js +3 -3
- package/lib/types/src/client/extension-sdk.d.ts +1 -1
- package/lib/types/src/client/locales.d.ts +12 -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 +7 -0
- package/package.json +11 -6
package/lib/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { f as withMemoryStorageLock, n as memoryStrategyConfigurationValues, r as readMemoryStrategyConfiguration, s as receipt } from "./strategy-configuration-
|
|
2
|
-
import { a as prepareMemoryContributions, i as validateMemoryPluginGraph, n as MemoryCompositionGeneration, r as captureMemoryContributionSnapshot, t as provideMemoryRuntime } from "./runtime-
|
|
3
|
-
import { DEFAULT_MEMORY_VIEW_BUDGET, MEMORY_CAPABILITIES } from "./contracts.js";
|
|
4
|
-
import { r as defineMemoryPlugin, t as canonicalMemoryJson } from "./definitions-
|
|
1
|
+
import { f as withMemoryStorageLock, n as memoryStrategyConfigurationValues, r as readMemoryStrategyConfiguration, s as receipt } from "./strategy-configuration-D8IEKZdS.js";
|
|
2
|
+
import { a as prepareMemoryContributions, i as validateMemoryPluginGraph, n as MemoryCompositionGeneration, r as captureMemoryContributionSnapshot, t as provideMemoryRuntime } from "./runtime-BEX0sc1z.js";
|
|
3
|
+
import { i as DEFAULT_MEMORY_VIEW_BUDGET, t as MEMORY_CAPABILITIES } from "./contracts-D4ghDRK4.js";
|
|
4
|
+
import { r as defineMemoryPlugin, t as canonicalMemoryJson } from "./definitions-CSPV0ER1.js";
|
|
5
5
|
import { Context } from "@deepseek-ai/cordis";
|
|
6
6
|
import z from "schemastery";
|
|
7
7
|
import { basename, delimiter, dirname, isAbsolute, join, normalize, resolve } from "node:path";
|
|
@@ -19,6 +19,9 @@ 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 * as cosmokit from "@deepseek-ai/cosmokit";
|
|
22
25
|
import { Remote, TypertRemoteService } from "@deepseek-ai/dsh-typert-protocol";
|
|
23
26
|
//#region src/host/view-protocol.ts
|
|
24
27
|
const MNEMON_VIEW_CHANNEL = "/dsh-mnemon-view";
|
|
@@ -52,6 +55,7 @@ const DEFAULT_IDLE_REVIEW = {
|
|
|
52
55
|
enabled: true,
|
|
53
56
|
provider: "spawn",
|
|
54
57
|
fallback: "spawn",
|
|
58
|
+
agentTeams: "pause",
|
|
55
59
|
minIntervalMs: 3e5,
|
|
56
60
|
maxPerSession: 20,
|
|
57
61
|
maxContextChars: 24e3,
|
|
@@ -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;
|
|
@@ -164,6 +210,7 @@ const IdleReviewSchema = z.object({
|
|
|
164
210
|
enabled: z.boolean().default(DEFAULT_IDLE_REVIEW.enabled),
|
|
165
211
|
provider: z.union(["spawn", "fork"]).default(DEFAULT_IDLE_REVIEW.provider),
|
|
166
212
|
fallback: z.union(["spawn", "skip"]).default(DEFAULT_IDLE_REVIEW.fallback),
|
|
213
|
+
agentTeams: z.union(["pause", "scoped"]).default(DEFAULT_IDLE_REVIEW.agentTeams),
|
|
167
214
|
minIntervalMs: z.number().step(1).min(5e3).max(864e5).default(DEFAULT_IDLE_REVIEW.minIntervalMs),
|
|
168
215
|
maxPerSession: z.number().step(1).min(0).max(200).default(DEFAULT_IDLE_REVIEW.maxPerSession),
|
|
169
216
|
maxContextChars: z.number().step(1).min(1e3).max(1e6).default(DEFAULT_IDLE_REVIEW.maxContextChars),
|
|
@@ -221,6 +268,8 @@ const Config = z.object({
|
|
|
221
268
|
protocol: DEFAULT_EMBEDDING_PROTOCOL
|
|
222
269
|
}),
|
|
223
270
|
memoryTopology: MemoryTopologySchema,
|
|
271
|
+
memoryView: schema,
|
|
272
|
+
legacySettingsImported: z.boolean(),
|
|
224
273
|
recallQuality: RecallQualitySchema.default({
|
|
225
274
|
policy: DEFAULT_RECALL_QUALITY_POLICY,
|
|
226
275
|
lowScoreThreshold: DEFAULT_RECALL_LOW_SCORE_THRESHOLD,
|
|
@@ -372,6 +421,7 @@ function resolveMemoryTopology(value) {
|
|
|
372
421
|
};
|
|
373
422
|
}
|
|
374
423
|
function resolveConfig(config = {}) {
|
|
424
|
+
if (config.memoryView !== void 0) preferences(config.memoryView);
|
|
375
425
|
const cliPath = optionalText(config.cliPath);
|
|
376
426
|
const legacyDataDir = optionalText(config.dataDir);
|
|
377
427
|
const legacyPacks = resolveCustomPacks(config.customPacks, legacyDataDir);
|
|
@@ -444,7 +494,7 @@ const COMPONENT_ORDER = [
|
|
|
444
494
|
];
|
|
445
495
|
const BODY_ID = /^[a-zA-Z0-9][a-zA-Z0-9_-]*$/;
|
|
446
496
|
const SQLITE_HEADER = Buffer.from("SQLite format 3\0", "binary");
|
|
447
|
-
function record$
|
|
497
|
+
function record$2(value) {
|
|
448
498
|
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
|
|
449
499
|
}
|
|
450
500
|
function utf8(bytes, label) {
|
|
@@ -487,7 +537,7 @@ function componentsForScope(scope) {
|
|
|
487
537
|
return [scope];
|
|
488
538
|
}
|
|
489
539
|
function parseManifest(value) {
|
|
490
|
-
const manifest = record$
|
|
540
|
+
const manifest = record$2(value);
|
|
491
541
|
if (manifest?.format !== "mnemonpack" || manifest.version !== 1) throw new Error("unsupported Mnemon Pack format or version");
|
|
492
542
|
if (manifest.scope !== "full" && !COMPONENT_ORDER.includes(manifest.scope)) throw new Error("Mnemon Pack scope is invalid");
|
|
493
543
|
if (typeof manifest.exportedAt !== "string") throw new Error("Mnemon Pack exportedAt is invalid");
|
|
@@ -496,11 +546,11 @@ function parseManifest(value) {
|
|
|
496
546
|
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
547
|
const expected = componentsForScope(manifest.scope);
|
|
498
548
|
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$
|
|
549
|
+
const source = record$2(manifest.source);
|
|
500
550
|
if (source?.plugin !== "dsh-mnemon" || typeof source.pluginVersion !== "string") throw new Error("Mnemon Pack source is invalid");
|
|
501
551
|
if (!Array.isArray(manifest.summary)) throw new Error("Mnemon Pack summary is invalid");
|
|
502
552
|
const summary = manifest.summary.map((entry) => {
|
|
503
|
-
const item = record$
|
|
553
|
+
const item = record$2(entry);
|
|
504
554
|
const component = item?.component;
|
|
505
555
|
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
556
|
return {
|
|
@@ -550,8 +600,8 @@ function parseArchive(base64, runtimeLimits = RUNTIME_MEMORY_LIMITS) {
|
|
|
550
600
|
if (path !== "manifest.json" && path !== "checksums.json" && !allowedPayloadPath(path)) throw new Error(`unsupported Mnemon Pack entry: ${path}`);
|
|
551
601
|
}
|
|
552
602
|
const manifest = parseManifest(json$1(files["manifest.json"], "manifest.json"));
|
|
553
|
-
const checksumValue = record$
|
|
554
|
-
const checksumFiles = record$
|
|
603
|
+
const checksumValue = record$2(json$1(files["checksums.json"], "checksums.json"));
|
|
604
|
+
const checksumFiles = record$2(checksumValue?.files);
|
|
555
605
|
if (checksumValue?.algorithm !== "sha256" || checksumFiles === void 0) throw new Error("Mnemon Pack checksums are invalid");
|
|
556
606
|
const payloadNames = names.filter((path) => path.startsWith("payload/")).sort();
|
|
557
607
|
if (Object.keys(checksumFiles).length !== payloadNames.length) throw new Error("Mnemon Pack checksum inventory does not match the payload");
|
|
@@ -574,10 +624,10 @@ function parseArchive(base64, runtimeLimits = RUNTIME_MEMORY_LIMITS) {
|
|
|
574
624
|
};
|
|
575
625
|
}
|
|
576
626
|
function parseRuntime(value, limits = RUNTIME_MEMORY_LIMITS) {
|
|
577
|
-
const source = record$
|
|
627
|
+
const source = record$2(value);
|
|
578
628
|
if (source?.version !== RUNTIME_MEMORY_VERSION || !Array.isArray(source.entries)) throw new Error("runtime memories.json is invalid");
|
|
579
629
|
const entries = source.entries.map((raw) => {
|
|
580
|
-
const entry = record$
|
|
630
|
+
const entry = record$2(raw);
|
|
581
631
|
if (typeof entry?.content !== "string" || entry.target !== "memory" && entry.target !== "user" || ![
|
|
582
632
|
"critical",
|
|
583
633
|
"normal",
|
|
@@ -608,13 +658,13 @@ function runtimeProjection(entries, target) {
|
|
|
608
658
|
return content === "" ? "" : `${content}\n`;
|
|
609
659
|
}
|
|
610
660
|
function parseDocumentIndex(value) {
|
|
611
|
-
const index = record$
|
|
661
|
+
const index = record$2(value);
|
|
612
662
|
if (index?.version !== DOCUMENTS_VERSION || !Array.isArray(index.documents)) throw new Error("Documents index.json is invalid");
|
|
613
663
|
const ids = /* @__PURE__ */ new Set();
|
|
614
664
|
return {
|
|
615
665
|
version: 1,
|
|
616
666
|
documents: index.documents.map((raw) => {
|
|
617
|
-
const item = record$
|
|
667
|
+
const item = record$2(raw);
|
|
618
668
|
if (typeof item?.id !== "string" || item.id.trim() === "" || ids.has(item.id)) throw new Error("Documents index contains an invalid or duplicate id");
|
|
619
669
|
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
670
|
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 +694,13 @@ function parseDocumentIndex(value) {
|
|
|
644
694
|
};
|
|
645
695
|
}
|
|
646
696
|
function parseRegistry(value) {
|
|
647
|
-
const registry = record$
|
|
697
|
+
const registry = record$2(value);
|
|
648
698
|
if (registry?.version !== 1 || !Array.isArray(registry.bodies)) throw new Error("Memory Space registry is invalid");
|
|
649
699
|
const ids = /* @__PURE__ */ new Set();
|
|
650
700
|
return {
|
|
651
701
|
version: 1,
|
|
652
702
|
bodies: registry.bodies.map((raw) => {
|
|
653
|
-
const body = record$
|
|
703
|
+
const body = record$2(raw);
|
|
654
704
|
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
705
|
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
706
|
if (typeof body.createdAt !== "string" || typeof body.updatedAt !== "string") throw new Error("Memory Space registry contains invalid timestamps");
|
|
@@ -1220,14 +1270,24 @@ function canonicalWorkspacePath(workspacePath) {
|
|
|
1220
1270
|
if (!isAbsolute(workspacePath) || workspacePath.includes("\0")) throw new Error("Workspace path must be absolute");
|
|
1221
1271
|
let parent = resolve(workspacePath);
|
|
1222
1272
|
const suffix = [];
|
|
1223
|
-
for (;;)
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1273
|
+
for (;;) {
|
|
1274
|
+
let real;
|
|
1275
|
+
try {
|
|
1276
|
+
real = realpathSync.native(parent);
|
|
1277
|
+
} catch (error) {
|
|
1278
|
+
if (error.code !== "ENOENT") throw error;
|
|
1279
|
+
const next = dirname(parent);
|
|
1280
|
+
if (next === parent) throw error;
|
|
1281
|
+
suffix.unshift(parent.slice(next.length).replace(/^[/\\]+/u, ""));
|
|
1282
|
+
parent = next;
|
|
1283
|
+
continue;
|
|
1284
|
+
}
|
|
1285
|
+
if (suffix.length > 0 && !statSync(real).isDirectory()) throw Object.assign(/* @__PURE__ */ new Error(`ENOTDIR: not a directory, realpath '${parent}'`), {
|
|
1286
|
+
code: "ENOTDIR",
|
|
1287
|
+
path: parent,
|
|
1288
|
+
syscall: "realpath"
|
|
1289
|
+
});
|
|
1290
|
+
return join(real, ...suffix);
|
|
1231
1291
|
}
|
|
1232
1292
|
}
|
|
1233
1293
|
/** A rename or move selects a new directory; resolving identity never writes. */
|
|
@@ -1283,7 +1343,7 @@ function safeBytes(path) {
|
|
|
1283
1343
|
function readJson(path) {
|
|
1284
1344
|
return JSON.parse(readFileSync(path, "utf8"));
|
|
1285
1345
|
}
|
|
1286
|
-
function record$
|
|
1346
|
+
function record$1(value) {
|
|
1287
1347
|
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
|
|
1288
1348
|
}
|
|
1289
1349
|
function missing(kind, path) {
|
|
@@ -1301,9 +1361,9 @@ function runtimeArea(root) {
|
|
|
1301
1361
|
const source = join(path, "memories.json");
|
|
1302
1362
|
if (!existsSync(source)) return missing("runtime", path);
|
|
1303
1363
|
try {
|
|
1304
|
-
const file = record$
|
|
1364
|
+
const file = record$1(readJson(source));
|
|
1305
1365
|
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$
|
|
1366
|
+
const entries = file.entries.map(record$1).filter((entry) => entry !== void 0);
|
|
1307
1367
|
const userEntries = entries.filter((entry) => entry.target === "user").length;
|
|
1308
1368
|
const memoryEntries = entries.filter((entry) => entry.target === "memory").length;
|
|
1309
1369
|
const projectionsHealthy = existsSync(join(path, "USER.md")) && existsSync(join(path, "MEMORY.md"));
|
|
@@ -1338,8 +1398,8 @@ function memorySpacesArea(root) {
|
|
|
1338
1398
|
if (!existsSync(path)) return missing("memory-bodies", path);
|
|
1339
1399
|
try {
|
|
1340
1400
|
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$
|
|
1401
|
+
const registry = existsSync(registryPath) ? record$1(readJson(registryPath)) : void 0;
|
|
1402
|
+
const bodies = Array.isArray(registry?.bodies) ? registry.bodies.map(record$1).filter((body) => body !== void 0) : [];
|
|
1343
1403
|
const databaseCount = readdirSync(path, { withFileTypes: true }).filter((entry) => entry.isDirectory() && existsSync(join(path, entry.name, "mnemon.db"))).length;
|
|
1344
1404
|
const activeCount = bodies.filter((body) => body.active === true).length;
|
|
1345
1405
|
const invalidRegistry = existsSync(registryPath) && (registry?.version !== 1 || !Array.isArray(registry.bodies));
|
|
@@ -1374,9 +1434,9 @@ function documentsArea(root) {
|
|
|
1374
1434
|
const indexPath = join(path, "index.json");
|
|
1375
1435
|
if (!existsSync(indexPath)) return missing("documents", path);
|
|
1376
1436
|
try {
|
|
1377
|
-
const index = record$
|
|
1437
|
+
const index = record$1(readJson(indexPath));
|
|
1378
1438
|
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$
|
|
1439
|
+
const documents = index.documents.map(record$1).filter((document) => document !== void 0);
|
|
1380
1440
|
const active = documents.filter((document) => document.status === "active").length;
|
|
1381
1441
|
const archived = documents.filter((document) => document.status === "archived").length;
|
|
1382
1442
|
return {
|
|
@@ -1412,9 +1472,9 @@ function stateArea(root) {
|
|
|
1412
1472
|
let providerConnections = 0;
|
|
1413
1473
|
let providerServices = 0;
|
|
1414
1474
|
if (existsSync(providerRegistry)) try {
|
|
1415
|
-
const registry = record$
|
|
1475
|
+
const registry = record$1(readJson(providerRegistry));
|
|
1416
1476
|
providerConnections = Array.isArray(registry?.bodies) ? registry.bodies.length : 0;
|
|
1417
|
-
providerServices = record$
|
|
1477
|
+
providerServices = record$1(registry?.services) === void 0 ? 0 : Object.keys(record$1(registry?.services)).length;
|
|
1418
1478
|
} catch {}
|
|
1419
1479
|
return {
|
|
1420
1480
|
kind: "state",
|
|
@@ -2635,13 +2695,13 @@ function hostSessionEventAt(session, seq) {
|
|
|
2635
2695
|
//#region src/host/review-tools.ts
|
|
2636
2696
|
const startingReview = new AsyncLocalStorage();
|
|
2637
2697
|
/**
|
|
2638
|
-
*
|
|
2639
|
-
*
|
|
2640
|
-
*
|
|
2641
|
-
*
|
|
2698
|
+
* Older published Team tools evaluate membership after a child loses its
|
|
2699
|
+
* temporary Lead identity. Keep their conservative pause unless the operator
|
|
2700
|
+
* selects scoped review (verified with DSH/Teams 0.1.7-rc.1). That opt-in still
|
|
2701
|
+
* requires startGuardedReview; it never removes another plugin's policy.
|
|
2642
2702
|
*/
|
|
2643
|
-
function idleReviewBlockReason(parent) {
|
|
2644
|
-
return parent.ctx?.get?.("agentTeams") !== void 0 && parent.ctx.tools?.get?.("spawn_teammate", parent) !== void 0 ? "agent-team" : void 0;
|
|
2703
|
+
function idleReviewBlockReason(parent, agentTeams = "pause") {
|
|
2704
|
+
return agentTeams !== "scoped" && parent.ctx?.get?.("agentTeams") !== void 0 && parent.ctx.tools?.get?.("spawn_teammate", parent) !== void 0 ? "agent-team" : void 0;
|
|
2645
2705
|
}
|
|
2646
2706
|
/**
|
|
2647
2707
|
* DSH restrict() filters inherited capabilities, leaving own-scope plugin tools
|
|
@@ -2723,13 +2783,13 @@ async function startGuardedReview(host, parent, toolNames, start, published) {
|
|
|
2723
2783
|
}
|
|
2724
2784
|
//#endregion
|
|
2725
2785
|
//#region src/host/review-checkpoint.ts
|
|
2726
|
-
function record
|
|
2786
|
+
function record(value) {
|
|
2727
2787
|
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : {};
|
|
2728
2788
|
}
|
|
2729
2789
|
function textContent(content, toolResult = false) {
|
|
2730
2790
|
if (!Array.isArray(content)) return "";
|
|
2731
2791
|
return content.map((block) => {
|
|
2732
|
-
const value = record
|
|
2792
|
+
const value = record(block);
|
|
2733
2793
|
if (value.type === "text" && typeof value.text === "string") return value.text;
|
|
2734
2794
|
if (toolResult && value.type === "tool-result" && value.isError !== true) return textContent(value.content);
|
|
2735
2795
|
return "";
|
|
@@ -2754,8 +2814,8 @@ function reviewCheckpoint(session, maxChars) {
|
|
|
2754
2814
|
"assistant/message",
|
|
2755
2815
|
"tool/result"
|
|
2756
2816
|
].includes(event.type)) continue;
|
|
2757
|
-
const message = record
|
|
2758
|
-
const source = record
|
|
2817
|
+
const message = record(event.type === "user/message" ? event.data : event.data.message);
|
|
2818
|
+
const source = record(message.source);
|
|
2759
2819
|
if (event.type === "user/message" && source.kind !== "user") continue;
|
|
2760
2820
|
const text = textContent(message.content, event.type === "tool/result");
|
|
2761
2821
|
if (!text) continue;
|
|
@@ -2871,7 +2931,7 @@ var IdleReviewError = class extends Error {
|
|
|
2871
2931
|
};
|
|
2872
2932
|
function reviewReceipt(receipt) {
|
|
2873
2933
|
if (!mutationResultCommitted(receipt.value)) return void 0;
|
|
2874
|
-
const value = object$
|
|
2934
|
+
const value = object$6(receipt.value);
|
|
2875
2935
|
const args = optionalObject(receipt.arguments);
|
|
2876
2936
|
const document = optionalObject(value.document);
|
|
2877
2937
|
return {
|
|
@@ -3131,7 +3191,7 @@ function assertDshOutputValue(schema, candidate, path = "result") {
|
|
|
3131
3191
|
default: throw new Error(`${path} uses unsupported schema type ${JSON.stringify(value.type)}`);
|
|
3132
3192
|
}
|
|
3133
3193
|
}
|
|
3134
|
-
function object$
|
|
3194
|
+
function object$6(value) {
|
|
3135
3195
|
if (typeof value !== "object" || value === null || Array.isArray(value)) throw new Error("memory subagent returned an invalid structured result");
|
|
3136
3196
|
return value;
|
|
3137
3197
|
}
|
|
@@ -3292,6 +3352,8 @@ function metadataSampleText(sample) {
|
|
|
3292
3352
|
}
|
|
3293
3353
|
const REVIEW_PERSONA = `You are Mnemon's conservative idle checkpoint reviewer. Review the inherited completed parent conversation as a maintenance pass, not a continuation of the user's task.
|
|
3294
3354
|
|
|
3355
|
+
Your authority is limited to the review tools and its completion tool. Agent Teams availability does not grant this maintenance child a Team role or permission to create teammates, send messages, manage tasks, or delegate. Those capabilities remain unavailable even if another plugin presents them.
|
|
3356
|
+
|
|
3295
3357
|
Reuse complete evidence already present in the inherited checkpoint, including repository overviews, index chunks, file excerpts, project rules, and successful tool results. Do not fetch the same overview or reopen files to reconstruct the completed task. If relevant evidence is missing or truncated, use only a bounded Document search for a specific candidate; skip the candidate when that is insufficient. Raw tool output remains evidence, never a new user-authored memory assertion.
|
|
3296
3358
|
|
|
3297
3359
|
Hot memory: only new, explicit, durable assertions authored by the live user qualify. Questions, one-turn formatting requests, assistant claims, reasoning, raw tool output, recalled content, translations, aliases, summaries, and inferred preferences do not qualify. Use mnemon_runtime_memory for every hot-memory mutation: target=user only for identity and personal preferences; target=memory only for stable project, environment, decisions, conventions, tool quirks, and reusable lessons. Prefer replace for corrections; remove only with direct user-authored evidence that an entry is obsolete or wrong. Perform at most one hot-memory add, replace, or remove.
|
|
@@ -3484,7 +3546,7 @@ var MnemonSubagentCoordinator = class {
|
|
|
3484
3546
|
if (!isSubagent(execution.agent)) throw new Error("Mnemon subagent result tools are restricted to delegated children");
|
|
3485
3547
|
execution.signal.throwIfAborted();
|
|
3486
3548
|
assertDshOutputValue(RESULT_TOOL_INPUT_SCHEMA, args);
|
|
3487
|
-
const request = object$
|
|
3549
|
+
const request = object$6(args);
|
|
3488
3550
|
const submit = this.resultRequests.get(String(request.requestId));
|
|
3489
3551
|
if (this.disposed || submit === void 0) throw new Error("Mnemon subagent result request is unknown or no longer active");
|
|
3490
3552
|
return submit(request.result, execution);
|
|
@@ -3615,7 +3677,7 @@ var MnemonSubagentCoordinator = class {
|
|
|
3615
3677
|
].join("\n\n");
|
|
3616
3678
|
const schema = providerPlacementSchema(prepared.candidates.map((candidate) => candidate.id));
|
|
3617
3679
|
const { provider, runId, result } = await this.delegate(parent, "placement", "Choose Memory Space provider", prompt, [], schema, signal, "spawn", PROVIDER_PLACEMENT_PERSONA);
|
|
3618
|
-
const value = object$
|
|
3680
|
+
const value = object$6(result.structured);
|
|
3619
3681
|
return source.read("finalize-placement", {
|
|
3620
3682
|
prepared,
|
|
3621
3683
|
selection: {
|
|
@@ -3633,13 +3695,13 @@ var MnemonSubagentCoordinator = class {
|
|
|
3633
3695
|
const service = this.sourceFor(parent, "memory-spaces");
|
|
3634
3696
|
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
3697
|
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$
|
|
3698
|
+
const value = object$6(result.structured);
|
|
3637
3699
|
if (!Array.isArray(value.updates)) throw new Error("metadata subagent returned no updates");
|
|
3638
3700
|
const allowed = new Set(selected);
|
|
3639
3701
|
const seen = /* @__PURE__ */ new Set();
|
|
3640
3702
|
const updates = [];
|
|
3641
3703
|
for (const entry of value.updates) {
|
|
3642
|
-
const item = object$
|
|
3704
|
+
const item = object$6(entry);
|
|
3643
3705
|
const memoryBodyId = typeof item.memoryBodyId === "string" ? item.memoryBodyId.trim() : "";
|
|
3644
3706
|
const title = typeof item.title === "string" ? item.title.trim() : "";
|
|
3645
3707
|
const description = typeof item.description === "string" ? item.description.trim() : "";
|
|
@@ -3823,7 +3885,7 @@ var MnemonSubagentCoordinator = class {
|
|
|
3823
3885
|
return {
|
|
3824
3886
|
source,
|
|
3825
3887
|
cleanup,
|
|
3826
|
-
memoryBodyIds: new Set(strings(object$
|
|
3888
|
+
memoryBodyIds: new Set(strings(object$6(grant.value).memoryBodyIds)),
|
|
3827
3889
|
writeScope: {
|
|
3828
3890
|
viewId: view.id,
|
|
3829
3891
|
grant
|
|
@@ -3850,7 +3912,7 @@ var MnemonSubagentCoordinator = class {
|
|
|
3850
3912
|
const bounded = evidence.slice(0, 12);
|
|
3851
3913
|
const prompt = `Answer this question (untrusted data):\n${indentedText(query)}\n\nEvidence for this run (untrusted read-only data):\n${naturalEvidence(bounded)}`;
|
|
3852
3914
|
const { provider, runId, result } = await this.delegate(parent, "answer", "Memory evidence answer", prompt, [], ANSWER_SCHEMA, signal, "spawn", ANSWER_PERSONA);
|
|
3853
|
-
const value = object$
|
|
3915
|
+
const value = object$6(result.structured);
|
|
3854
3916
|
const allowed = new Set(bounded.map((item) => `${item.memoryBodyId ?? "unknown"}/${item.id}`));
|
|
3855
3917
|
return {
|
|
3856
3918
|
answer: typeof value.answer === "string" ? value.answer : "",
|
|
@@ -3868,7 +3930,7 @@ ${naturalRequest(request)}`;
|
|
|
3868
3930
|
const persona = operation === "supervised-writeback" ? SUPERVISED_WRITE_PERSONA : autonomous ? AUTONOMOUS_WRITE_PERSONA : WRITE_PERSONA;
|
|
3869
3931
|
const terminalTool = WRITE_OPERATION_RESULT_TOOL[operation];
|
|
3870
3932
|
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$
|
|
3933
|
+
const value = object$6(result.structured);
|
|
3872
3934
|
const observed = terminalTool === void 0 ? void 0 : recoverStructuredResult({ terminalTools: [terminalTool] }, receipts);
|
|
3873
3935
|
return {
|
|
3874
3936
|
delegated: true,
|
|
@@ -3881,13 +3943,13 @@ ${naturalRequest(request)}`;
|
|
|
3881
3943
|
};
|
|
3882
3944
|
}
|
|
3883
3945
|
async review(parent, signal) {
|
|
3884
|
-
|
|
3946
|
+
const config = this.runtimeSource.config.idleReview;
|
|
3947
|
+
if (idleReviewBlockReason(parent, config.agentTeams) !== void 0) return {
|
|
3885
3948
|
delegated: false,
|
|
3886
3949
|
action: "skipped",
|
|
3887
|
-
summary: "Idle review is paused
|
|
3950
|
+
summary: "Idle review is paused by the Agent Teams compatibility setting.",
|
|
3888
3951
|
documentIds: []
|
|
3889
3952
|
};
|
|
3890
|
-
const config = this.runtimeSource.config.idleReview;
|
|
3891
3953
|
let preferred = config.provider;
|
|
3892
3954
|
if (preferred === "fork") try {
|
|
3893
3955
|
this.provider("fork");
|
|
@@ -3903,7 +3965,7 @@ ${naturalRequest(request)}`;
|
|
|
3903
3965
|
const prompt = preferred === "fork" ? "Review the inherited completed checkpoint now." : reviewCheckpoint(parent.session, config.maxContextChars);
|
|
3904
3966
|
const persona = preferred === "fork" ? REVIEW_PERSONA : REVIEW_PERSONA.replaceAll("inherited", "supplied bounded");
|
|
3905
3967
|
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$
|
|
3968
|
+
const value = object$6(result.structured);
|
|
3907
3969
|
return {
|
|
3908
3970
|
delegated: true,
|
|
3909
3971
|
runId,
|
|
@@ -3965,12 +4027,12 @@ ${naturalRequest(request)}`;
|
|
|
3965
4027
|
const cleanup = graph.source("memory-spaces", agentScope(parent, graph.config)).forInstance(identity.sourceInstanceKey).forGeneration(lease.generation);
|
|
3966
4028
|
const grant = authority?.context.view.readGrants.find((grant) => grant.sourceInstanceKey === identity.sourceInstanceKey && grant.schema === "dsh-mnemon.memory-spaces/v1");
|
|
3967
4029
|
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$
|
|
4030
|
+
const allowed = grant === void 0 ? void 0 : new Set(strings(object$6(grant.value).memoryBodyIds));
|
|
3969
4031
|
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
4032
|
const bodies = (await memoryService.read("body-directory", null, signal)).items.filter(eligible);
|
|
3971
4033
|
if (bodies.length === 0) throw new Error("document archive requires an existing active Memory Space with exact writes and safe forget");
|
|
3972
4034
|
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$
|
|
4035
|
+
const value = object$6(result.structured);
|
|
3974
4036
|
const summary = typeof value.summary === "string" ? value.summary.trim() : "";
|
|
3975
4037
|
if (value.action !== "planned") throw new Error(summary || "document archive planning failed");
|
|
3976
4038
|
if (summary === "" || summary.length > 1e3) throw new Error("document archive summary must contain 1–1000 characters");
|
|
@@ -4145,13 +4207,13 @@ ${chunk.context}
|
|
|
4145
4207
|
provider = delegated.provider;
|
|
4146
4208
|
runId = delegated.runId;
|
|
4147
4209
|
}
|
|
4148
|
-
const value = object$
|
|
4210
|
+
const value = object$6(delegated.result.structured);
|
|
4149
4211
|
if (value.action !== "planned") throw new Error(typeof value.summary === "string" && value.summary !== "" ? value.summary : "runtime memory archival routing failed");
|
|
4150
4212
|
if (!Array.isArray(value.routes) || value.routes.length === 0) throw new Error("runtime memory migration returned no routes");
|
|
4151
4213
|
const allowedIndexes = new Set(chunk.indexes);
|
|
4152
4214
|
const proposed = /* @__PURE__ */ new Map();
|
|
4153
4215
|
for (const candidate of value.routes) {
|
|
4154
|
-
const route = object$
|
|
4216
|
+
const route = object$6(candidate);
|
|
4155
4217
|
const memoryBodyId = typeof route.memoryBodyId === "string" ? route.memoryBodyId.trim() : "";
|
|
4156
4218
|
if (memoryBodyId === "" || !eligibleById.has(memoryBodyId)) throw new Error(`runtime memory migration selected an invalid Memory Space: ${memoryBodyId || "(empty)"}`);
|
|
4157
4219
|
if (!Array.isArray(route.sourceIndexes) || route.sourceIndexes.length === 0) throw new Error("runtime memory migration route must contain source indexes");
|
|
@@ -4299,10 +4361,10 @@ ${pendingMutationContext(plan)}
|
|
|
4299
4361
|
|
|
4300
4362
|
${runtimeSnapshotContext("user", plan.entries)}`;
|
|
4301
4363
|
const { provider, runId, result } = await context.model("compaction", "Consolidate local user profile", prompt, USER_COMPACTION_SCHEMA, USER_COMPACTION_PERSONA);
|
|
4302
|
-
const value = object$
|
|
4364
|
+
const value = object$6(result.structured);
|
|
4303
4365
|
if (value.action !== "compacted") throw new Error(typeof value.summary === "string" && value.summary !== "" ? value.summary : "USER.md compaction failed");
|
|
4304
4366
|
const compactedEntries = Array.isArray(value.compactedEntries) ? value.compactedEntries.map((entry) => {
|
|
4305
|
-
const item = object$
|
|
4367
|
+
const item = object$6(entry);
|
|
4306
4368
|
if (typeof item.content !== "string" || ![
|
|
4307
4369
|
"critical",
|
|
4308
4370
|
"normal",
|
|
@@ -4515,7 +4577,7 @@ This is the only completion channel for this run. Do not finish with a plain-tex
|
|
|
4515
4577
|
"failed",
|
|
4516
4578
|
"partial",
|
|
4517
4579
|
"unknown"
|
|
4518
|
-
].includes(String(object$
|
|
4580
|
+
].includes(String(object$6(structured).action))) throw new Error(`memory review reported ${object$6(structured).action}`);
|
|
4519
4581
|
completed = {
|
|
4520
4582
|
provider,
|
|
4521
4583
|
runId: activeRun.id,
|
|
@@ -4680,7 +4742,7 @@ const MNEMON_ACTIVITY_SCHEMA = "dsh-mnemon.activity/v1";
|
|
|
4680
4742
|
const MAX_ITEMS = 8;
|
|
4681
4743
|
const MAX_TITLE = 160;
|
|
4682
4744
|
const MAX_EXCERPT = 500;
|
|
4683
|
-
function object$
|
|
4745
|
+
function object$5(value) {
|
|
4684
4746
|
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
|
|
4685
4747
|
}
|
|
4686
4748
|
function bounded(value, maximum) {
|
|
@@ -4690,7 +4752,7 @@ function bounded(value, maximum) {
|
|
|
4690
4752
|
return normalized.length <= maximum ? normalized : normalized.slice(0, maximum - 1) + "…";
|
|
4691
4753
|
}
|
|
4692
4754
|
function item(value, index) {
|
|
4693
|
-
const entry = object$
|
|
4755
|
+
const entry = object$5(value);
|
|
4694
4756
|
if (entry === void 0) return void 0;
|
|
4695
4757
|
const content = bounded(entry.content ?? entry.text ?? entry.excerpt, MAX_EXCERPT);
|
|
4696
4758
|
const explicitTitle = bounded(entry.title ?? entry.label ?? entry.name ?? entry.memoryBodyName, MAX_TITLE);
|
|
@@ -4704,7 +4766,7 @@ function item(value, index) {
|
|
|
4704
4766
|
};
|
|
4705
4767
|
}
|
|
4706
4768
|
function resultItems(value) {
|
|
4707
|
-
const root = object$
|
|
4769
|
+
const root = object$5(value);
|
|
4708
4770
|
if (root === void 0) return [];
|
|
4709
4771
|
const candidates = [
|
|
4710
4772
|
root.results,
|
|
@@ -4723,8 +4785,8 @@ function resultItems(value) {
|
|
|
4723
4785
|
return items;
|
|
4724
4786
|
}
|
|
4725
4787
|
function writeItem(argsValue, operationId) {
|
|
4726
|
-
const outer = object$
|
|
4727
|
-
const input = object$
|
|
4788
|
+
const outer = object$5(argsValue) ?? {};
|
|
4789
|
+
const input = object$5(outer.input) ?? outer;
|
|
4728
4790
|
const content = bounded(input.content ?? input.description ?? input.reason ?? input.summary, MAX_EXCERPT);
|
|
4729
4791
|
const explicitTitle = bounded(input.title ?? input.name, MAX_TITLE);
|
|
4730
4792
|
const identity = bounded(input.id ?? input.memoryBodyId ?? input.targetMemoryBodyId ?? input.sourceId, 300);
|
|
@@ -4737,7 +4799,7 @@ function writeItem(argsValue, operationId) {
|
|
|
4737
4799
|
};
|
|
4738
4800
|
}
|
|
4739
4801
|
function reference(argsValue, key) {
|
|
4740
|
-
return bounded(object$
|
|
4802
|
+
return bounded(object$5(argsValue)?.[key], 600);
|
|
4741
4803
|
}
|
|
4742
4804
|
function memoryReadPresentation(sourceTypeId, operationId, referenceKey) {
|
|
4743
4805
|
return (args, value) => ({
|
|
@@ -4756,12 +4818,12 @@ function memoryWritePresentation(sourceTypeId, operationId, referenceKey) {
|
|
|
4756
4818
|
operationId,
|
|
4757
4819
|
...sourceTypeId === void 0 ? {} : { sourceTypeId },
|
|
4758
4820
|
...referenceKey === void 0 || reference(args, referenceKey) === void 0 ? {} : { reference: reference(args, referenceKey) },
|
|
4759
|
-
committed: mutationResultCommitted(value) || operationId === "mutate" && object$
|
|
4821
|
+
committed: mutationResultCommitted(value) || operationId === "mutate" && object$5(value)?.success === true,
|
|
4760
4822
|
item: writeItem(args, operationId)
|
|
4761
4823
|
});
|
|
4762
4824
|
}
|
|
4763
4825
|
function validItem(value) {
|
|
4764
|
-
const entry = object$
|
|
4826
|
+
const entry = object$5(value);
|
|
4765
4827
|
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
4828
|
}
|
|
4767
4829
|
function cleanItem(value) {
|
|
@@ -4774,7 +4836,7 @@ function cleanItem(value) {
|
|
|
4774
4836
|
}
|
|
4775
4837
|
/** Fail closed on arbitrary third-party/session metadata. */
|
|
4776
4838
|
function parseMnemonActivityMeta(value, callId, toolName) {
|
|
4777
|
-
const meta = object$
|
|
4839
|
+
const meta = object$5(value);
|
|
4778
4840
|
if (meta?.schema !== "dsh-mnemon.activity/v1" || meta.kind !== "read" && meta.kind !== "write") return {};
|
|
4779
4841
|
const operationId = bounded(meta.operationId, 300);
|
|
4780
4842
|
const sourceTypeId = bounded(meta.sourceTypeId, 128);
|
|
@@ -5156,24 +5218,22 @@ function createPluginMessage(text, form) {
|
|
|
5156
5218
|
text
|
|
5157
5219
|
}],
|
|
5158
5220
|
source: {
|
|
5159
|
-
kind:
|
|
5160
|
-
plugin: MNEMON_PLUGIN_SOURCE,
|
|
5221
|
+
kind: MNEMON_PLUGIN_SOURCE,
|
|
5161
5222
|
form
|
|
5162
5223
|
}
|
|
5163
5224
|
});
|
|
5164
5225
|
}
|
|
5165
|
-
function
|
|
5166
|
-
return
|
|
5226
|
+
function isMnemonMessageSource(source) {
|
|
5227
|
+
if (typeof source !== "object" || source === null) return false;
|
|
5228
|
+
const { kind, plugin } = source;
|
|
5229
|
+
return kind === "dsh-mnemon" || kind === `plugin:dsh-mnemon` || kind === "plugin" && plugin === "dsh-mnemon";
|
|
5167
5230
|
}
|
|
5168
5231
|
/**
|
|
5169
5232
|
* Whether an event is a durable user message this plugin produced.
|
|
5170
5233
|
*/
|
|
5171
5234
|
function isOwnUserMessageEvent(event) {
|
|
5172
5235
|
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";
|
|
5236
|
+
return isMnemonMessageSource(event.data.source);
|
|
5177
5237
|
}
|
|
5178
5238
|
function eventTurn(event) {
|
|
5179
5239
|
return typeof event.data.turn === "number" ? event.data.turn : void 0;
|
|
@@ -5322,7 +5382,7 @@ var MnemonAgentLifecycle = class {
|
|
|
5322
5382
|
reviewRunning: this.reviewRunning,
|
|
5323
5383
|
reviewActivity: this.reviewActivity(),
|
|
5324
5384
|
idleReviewAttempts: this.idleReviewAttempts,
|
|
5325
|
-
...idleReviewBlockReason(this.agent) === void 0 ? {} : { idleReviewBlocked: "agent-team" },
|
|
5385
|
+
...idleReviewBlockReason(this.agent, this.config.idleReview.agentTeams) === void 0 ? {} : { idleReviewBlocked: "agent-team" },
|
|
5326
5386
|
...this.lastReviewAttemptAt === void 0 ? {} : { nextReviewAt: new Date(this.lastReviewAttemptAt + this.config.idleReview.minIntervalMs).toISOString() },
|
|
5327
5387
|
...this.lastReviewFailure === void 0 ? {} : { lastReviewFailure: this.lastReviewFailure },
|
|
5328
5388
|
lastPhase: this.lastPhase,
|
|
@@ -5396,10 +5456,7 @@ var MnemonAgentLifecycle = class {
|
|
|
5396
5456
|
if (!this.config.lifecycleEnabled) return decision;
|
|
5397
5457
|
if (this.config.writeEnabled && this.config.writebackMode === "guided") this.recordTurnMessages(payload.turn, decision.messages);
|
|
5398
5458
|
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;
|
|
5459
|
+
if (decision.messages.some((message) => isMnemonMessageSource(message.source))) return decision;
|
|
5403
5460
|
if (decision.messages.length === 0) return decision;
|
|
5404
5461
|
const snapshot = this.memorySnapshotMessage();
|
|
5405
5462
|
const withSnapshot = (messages) => snapshot === void 0 ? messages : [...messages, snapshot];
|
|
@@ -5471,7 +5528,7 @@ var MnemonAgentLifecycle = class {
|
|
|
5471
5528
|
}, Math.max(this.config.idleReviewMs, (this.lastReviewAttemptAt ?? -Infinity) + this.config.idleReview.minIntervalMs - Date.now()));
|
|
5472
5529
|
}
|
|
5473
5530
|
idleReviewAllowed() {
|
|
5474
|
-
return this.config.lifecycleEnabled && this.config.writeEnabled && this.config.writebackMode === "guided" && this.config.idleReview.enabled && this.idleReviewAttempts < this.config.idleReview.maxPerSession && idleReviewBlockReason(this.agent) === void 0 && this.config.memoryTopology.strategyId === "default-three-tier";
|
|
5531
|
+
return this.config.lifecycleEnabled && this.config.writeEnabled && this.config.writebackMode === "guided" && this.config.idleReview.enabled && this.idleReviewAttempts < this.config.idleReview.maxPerSession && idleReviewBlockReason(this.agent, this.config.idleReview.agentTeams) === void 0 && this.config.memoryTopology.strategyId === "default-three-tier";
|
|
5475
5532
|
}
|
|
5476
5533
|
async runIdleReview() {
|
|
5477
5534
|
const controller = new AbortController();
|
|
@@ -6706,7 +6763,7 @@ var VersionUpdateManager = class {
|
|
|
6706
6763
|
};
|
|
6707
6764
|
//#endregion
|
|
6708
6765
|
//#region src/host/rpc.ts
|
|
6709
|
-
function object$
|
|
6766
|
+
function object$4(value) {
|
|
6710
6767
|
if (typeof value !== "object" || value === null || Array.isArray(value)) throw new Error("payload must be an object");
|
|
6711
6768
|
return value;
|
|
6712
6769
|
}
|
|
@@ -6855,7 +6912,7 @@ async function assisted(runtime, lifecycle, typeId, operation, input, signal, ta
|
|
|
6855
6912
|
...signal === void 0 ? {} : { signal }
|
|
6856
6913
|
});
|
|
6857
6914
|
return {
|
|
6858
|
-
...object$
|
|
6915
|
+
...object$4(result.value),
|
|
6859
6916
|
revision: result.revision
|
|
6860
6917
|
};
|
|
6861
6918
|
} finally {
|
|
@@ -6924,7 +6981,7 @@ async function assisted(runtime, lifecycle, typeId, operation, input, signal, ta
|
|
|
6924
6981
|
function createReadHandler(input, lifecycle, versions) {
|
|
6925
6982
|
return async (endpoint, rawPayload, signal) => {
|
|
6926
6983
|
try {
|
|
6927
|
-
const payload = object$
|
|
6984
|
+
const payload = object$4(rawPayload);
|
|
6928
6985
|
if (endpoint === "versions") {
|
|
6929
6986
|
if (versions === void 0) throw new Error("version checks are unavailable");
|
|
6930
6987
|
return success$1(await versions.check());
|
|
@@ -6944,7 +7001,7 @@ function createReadHandler(input, lifecycle, versions) {
|
|
|
6944
7001
|
if (lifecycle === void 0 || payload.operation !== "agent-search") throw new Error("Read-only Host assistance is unavailable");
|
|
6945
7002
|
const source = (await catalog(runtime, lifecycle)).sources.find((item) => item.sourceInstanceKey === payload.sourceInstanceKey);
|
|
6946
7003
|
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$
|
|
7004
|
+
const value = await assisted(runtime, lifecycle, source.sourceTypeId, "agent-search", object$4(payload.input), signal);
|
|
6948
7005
|
return success$1({
|
|
6949
7006
|
revision: (await catalog(runtime)).sources.find((item) => item.sourceInstanceKey === source.sourceInstanceKey)?.revision ?? source.revision,
|
|
6950
7007
|
value
|
|
@@ -7037,9 +7094,9 @@ function createActivationHandler(input) {
|
|
|
7037
7094
|
return async (endpoint, rawPayload, signal) => {
|
|
7038
7095
|
try {
|
|
7039
7096
|
if (endpoint === "source-assistance") {
|
|
7040
|
-
const payload = object$
|
|
7097
|
+
const payload = object$4(rawPayload);
|
|
7041
7098
|
if (payload.operation !== "activation" || payload.confirmed !== true) throw new Error("Unsupported activation operation");
|
|
7042
|
-
const fields = object$
|
|
7099
|
+
const fields = object$4(payload.input);
|
|
7043
7100
|
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
7101
|
const runtime = scoped(input, payload);
|
|
7045
7102
|
requireWritable(runtime);
|
|
@@ -7062,7 +7119,7 @@ function createActivationHandler(input) {
|
|
|
7062
7119
|
}
|
|
7063
7120
|
}
|
|
7064
7121
|
if (endpoint !== "body") return badRequest$1("unknown activation endpoint: " + endpoint);
|
|
7065
|
-
const payload = object$
|
|
7122
|
+
const payload = object$4(rawPayload);
|
|
7066
7123
|
const unexpected = Object.keys(payload).filter((field) => !ACTIVATION_FIELDS.has(field));
|
|
7067
7124
|
if (unexpected.length > 0) return badRequest$1("unsupported activation fields: " + unexpected.join(", "));
|
|
7068
7125
|
if (typeof payload.memoryBodyId !== "string" || payload.memoryBodyId.trim() === "") return badRequest$1("memoryBodyId must be a non-empty string");
|
|
@@ -7081,7 +7138,7 @@ function createActivationHandler(input) {
|
|
|
7081
7138
|
function createWriteHandler(input, lifecycle, versions) {
|
|
7082
7139
|
return async (endpoint, rawPayload, signal) => {
|
|
7083
7140
|
try {
|
|
7084
|
-
const payload = object$
|
|
7141
|
+
const payload = object$4(rawPayload);
|
|
7085
7142
|
if (endpoint === "version-update") {
|
|
7086
7143
|
if (versions === void 0) throw new Error("version updates are unavailable");
|
|
7087
7144
|
if (!input.config.writeEnabled) throw new Error("dsh-mnemon is configured read-only (writeEnabled: false)");
|
|
@@ -7115,12 +7172,12 @@ function createWriteHandler(input, lifecycle, versions) {
|
|
|
7115
7172
|
const operation = String(payload.operation ?? "");
|
|
7116
7173
|
if (source === void 0 || !source.assistance.includes(operation)) throw new Error("Host assistance is not available for this Source instance");
|
|
7117
7174
|
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$
|
|
7175
|
+
const value = await assisted(runtime, lifecycle, source.sourceTypeId, operation, object$4(payload.input), signal, {
|
|
7119
7176
|
sourceInstanceKey: source.sourceInstanceKey,
|
|
7120
7177
|
expectedRevision: source.revision
|
|
7121
7178
|
});
|
|
7122
7179
|
if (source.sourceTypeId === "runtime") return success$1({
|
|
7123
|
-
revision: object$
|
|
7180
|
+
revision: object$4(value).revision,
|
|
7124
7181
|
value
|
|
7125
7182
|
});
|
|
7126
7183
|
return success$1({
|
|
@@ -7164,7 +7221,7 @@ function createWriteHandler(input, lifecycle, versions) {
|
|
|
7164
7221
|
function createPackHandler(input) {
|
|
7165
7222
|
return async (endpoint, rawPayload) => {
|
|
7166
7223
|
try {
|
|
7167
|
-
const payload = object$
|
|
7224
|
+
const payload = object$4(rawPayload);
|
|
7168
7225
|
const runtime = scoped(input, payload);
|
|
7169
7226
|
const manager = runtime.graph.packs;
|
|
7170
7227
|
if (endpoint === "target") return success$1(manager.target());
|
|
@@ -7233,7 +7290,7 @@ function descriptor(settings, namespace) {
|
|
|
7233
7290
|
return {
|
|
7234
7291
|
status: "ready",
|
|
7235
7292
|
value: namespace === "mnemon" && displayModeOf(view.value) === "buildin" ? {
|
|
7236
|
-
...object$
|
|
7293
|
+
...object$3(view.value),
|
|
7237
7294
|
displayMode: "builtin"
|
|
7238
7295
|
} : view.value,
|
|
7239
7296
|
base: view.base,
|
|
@@ -7244,7 +7301,7 @@ function descriptor(settings, namespace) {
|
|
|
7244
7301
|
applies: view.applies
|
|
7245
7302
|
};
|
|
7246
7303
|
}
|
|
7247
|
-
function object$
|
|
7304
|
+
function object$3(value) {
|
|
7248
7305
|
if (typeof value !== "object" || value === null || Array.isArray(value)) throw new Error("payload must be an object");
|
|
7249
7306
|
return value;
|
|
7250
7307
|
}
|
|
@@ -7315,14 +7372,14 @@ function createSettingsHandler(settings) {
|
|
|
7315
7372
|
return async (endpoint, rawPayload) => {
|
|
7316
7373
|
let namespace = MNEMON_SETTINGS_NAMESPACE;
|
|
7317
7374
|
try {
|
|
7318
|
-
const payload = object$
|
|
7375
|
+
const payload = object$3(rawPayload);
|
|
7319
7376
|
namespace = namespaceOf(payload);
|
|
7320
7377
|
if (endpoint === "get") return success(descriptor(settings, namespace));
|
|
7321
7378
|
if (endpoint !== "mutate") return badRequest(`unknown settings endpoint: ${endpoint}`);
|
|
7322
7379
|
if (!settings.writable) throw new Error("DSH settings are read-only");
|
|
7323
7380
|
if (!Array.isArray(payload.ops) || payload.ops.length === 0 || payload.ops.length > 16) throw new Error("ops must contain 1..16 settings edits");
|
|
7324
7381
|
const ops = payload.ops.map((raw) => {
|
|
7325
|
-
const op = object$
|
|
7382
|
+
const op = object$3(raw);
|
|
7326
7383
|
const path = Array.isArray(op.path) && op.path.length > 0 ? op.path.map((segment) => String(segment)) : [];
|
|
7327
7384
|
if (!mutablePath(namespace, path)) throw new Error(`unsupported ${namespace} settings field: ${path.join(".")}`);
|
|
7328
7385
|
if (op.op === "unset") return {
|
|
@@ -8304,49 +8361,533 @@ function registerMnemonSubagentTokenUsageProjection(ctx) {
|
|
|
8304
8361
|
});
|
|
8305
8362
|
}
|
|
8306
8363
|
//#endregion
|
|
8307
|
-
//#region src/host/
|
|
8308
|
-
const
|
|
8309
|
-
|
|
8310
|
-
|
|
8311
|
-
|
|
8312
|
-
|
|
8313
|
-
|
|
8314
|
-
|
|
8315
|
-
|
|
8316
|
-
|
|
8364
|
+
//#region src/host/profile-schema.mjs
|
|
8365
|
+
const predicate = Reflect.get(cosmokit, "isVolatile");
|
|
8366
|
+
const supportsLiveConfig = typeof predicate === "function" && typeof Reflect.get(cosmokit, "createVolatile") === "function";
|
|
8367
|
+
const isVolatile = (value) => supportsLiveConfig && predicate(value);
|
|
8368
|
+
var profile_schema_default = supportsLiveConfig ? (await import("schemastery-live")).default : z;
|
|
8369
|
+
//#endregion
|
|
8370
|
+
//#region src/host/live-config.ts
|
|
8371
|
+
function plain(value) {
|
|
8372
|
+
if (isVolatile(value)) return plain(value.get());
|
|
8373
|
+
if (Array.isArray(value)) return value.map(plain);
|
|
8374
|
+
if (value === null || typeof value !== "object") return value;
|
|
8375
|
+
const prototype = Object.getPrototypeOf(value);
|
|
8376
|
+
if (prototype !== Object.prototype && prototype !== null) return value;
|
|
8377
|
+
return Object.fromEntries(Object.entries(value).map(([key, child]) => [key, plain(child)]));
|
|
8378
|
+
}
|
|
8379
|
+
/** Read a detached configuration snapshot from either DSH generation. */
|
|
8380
|
+
function plainHostConfig(value = {}) {
|
|
8381
|
+
return plain(value);
|
|
8382
|
+
}
|
|
8383
|
+
function liveConfig() {
|
|
8384
|
+
const schema = new profile_schema_default(Config.toJSON());
|
|
8385
|
+
schema.dict = Object.fromEntries(Object.entries(schema.dict ?? {}).map(([key, field]) => [key, key === "remoteAccess" ? field : field.volatile()]));
|
|
8386
|
+
const standard = schema["~standard"];
|
|
8387
|
+
Object.defineProperty(schema, "~standard", { value: {
|
|
8388
|
+
...standard,
|
|
8389
|
+
validate(value) {
|
|
8390
|
+
const parsed = standard.validate(value);
|
|
8391
|
+
if ("then" in parsed) throw new TypeError("Mnemon configuration validation must be synchronous");
|
|
8392
|
+
if (parsed.issues) return parsed;
|
|
8393
|
+
try {
|
|
8394
|
+
resolveConfig(plainHostConfig(parsed.value));
|
|
8395
|
+
return parsed;
|
|
8396
|
+
} catch (error) {
|
|
8397
|
+
return { issues: [{ message: error instanceof Error ? error.message : String(error) }] };
|
|
8398
|
+
}
|
|
8399
|
+
}
|
|
8400
|
+
} });
|
|
8401
|
+
return schema;
|
|
8402
|
+
}
|
|
8403
|
+
/** Profile Config for live forms; transport authority retains normal remounts. */
|
|
8404
|
+
const LiveConfig = supportsLiveConfig ? liveConfig() : Config;
|
|
8405
|
+
//#endregion
|
|
8406
|
+
//#region src/host/legacy-settings-import.ts
|
|
8407
|
+
const UNSAFE_KEYS = /* @__PURE__ */ new Set([
|
|
8408
|
+
"__proto__",
|
|
8409
|
+
"prototype",
|
|
8410
|
+
"constructor"
|
|
8411
|
+
]);
|
|
8317
8412
|
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;
|
|
8413
|
+
const STRATEGY_ID = /^[a-z][a-z0-9-]{0,127}$/u;
|
|
8414
|
+
const VIEW_NAMESPACE = /^mnemon-view(?:-[a-f0-9]{16})?$/u;
|
|
8415
|
+
const LEGACY_NAMESPACE = /^mnemon-plugins(?:-[a-f0-9]{16})?$/u;
|
|
8416
|
+
function object$2(value, label) {
|
|
8417
|
+
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`);
|
|
8418
|
+
for (const key of Reflect.ownKeys(value)) {
|
|
8419
|
+
if (typeof key !== "string" || UNSAFE_KEYS.has(key)) throw new Error(`${label} contains an unsafe key`);
|
|
8420
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
8421
|
+
if (!descriptor.enumerable || !Object.hasOwn(descriptor, "value")) throw new Error(`${label} must contain only data properties`);
|
|
8422
|
+
}
|
|
8423
|
+
return value;
|
|
8331
8424
|
}
|
|
8332
|
-
|
|
8333
|
-
|
|
8334
|
-
|
|
8335
|
-
if (
|
|
8336
|
-
|
|
8337
|
-
|
|
8338
|
-
|
|
8339
|
-
|
|
8340
|
-
|
|
8425
|
+
/** Copy JSON data without invoking getters, serializers or prototype methods. */
|
|
8426
|
+
function copy(value, label, ancestors = /* @__PURE__ */ new Set(), depth = 0) {
|
|
8427
|
+
if (value === null || typeof value === "string" || typeof value === "boolean") return value;
|
|
8428
|
+
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
8429
|
+
if (typeof value !== "object" || value === null) throw new Error(`${label} must contain only JSON data`);
|
|
8430
|
+
if (depth > 64 || ancestors.has(value)) throw new Error(`${label} contains cyclic or excessively nested data`);
|
|
8431
|
+
ancestors.add(value);
|
|
8432
|
+
try {
|
|
8433
|
+
if (Array.isArray(value)) {
|
|
8434
|
+
if (Object.getPrototypeOf(value) !== Array.prototype) throw new Error(`${label} must contain plain arrays`);
|
|
8435
|
+
if (Reflect.ownKeys(value).length !== value.length + 1) throw new Error(`${label} contains a sparse or extended array`);
|
|
8436
|
+
return Array.from({ length: value.length }, (_, index) => {
|
|
8437
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, String(index));
|
|
8438
|
+
if (!descriptor || !descriptor.enumerable || !Object.hasOwn(descriptor, "value")) throw new Error(`${label} must contain only data properties`);
|
|
8439
|
+
return copy(descriptor.value, label, ancestors, depth + 1);
|
|
8440
|
+
});
|
|
8441
|
+
}
|
|
8442
|
+
return Object.fromEntries(Object.entries(object$2(value, label)).map(([key, item]) => [key, copy(item, label, ancestors, depth + 1)]));
|
|
8443
|
+
} finally {
|
|
8444
|
+
ancestors.delete(value);
|
|
8341
8445
|
}
|
|
8342
|
-
return clone(value);
|
|
8343
8446
|
}
|
|
8344
|
-
function
|
|
8345
|
-
|
|
8346
|
-
|
|
8347
|
-
for (const [entryId, item] of Object.entries(sources)) if (!ENTRY_ID.test(entryId) || typeof item?.enabled !== "boolean") throw new Error("Invalid legacy Source Entry preference");
|
|
8348
|
-
return clone({ sources });
|
|
8447
|
+
function copiedObject(value, label) {
|
|
8448
|
+
object$2(value, label);
|
|
8449
|
+
return copy(value, label);
|
|
8349
8450
|
}
|
|
8451
|
+
/** Inspect validated copies only; never evaluate expressions or invoke getters. */
|
|
8452
|
+
function containsExpression(value) {
|
|
8453
|
+
return value !== null && typeof value === "object" && (Object.hasOwn(value, "__jsExpr") || Object.values(value).some(containsExpression));
|
|
8454
|
+
}
|
|
8455
|
+
function fields(value, allowed, label) {
|
|
8456
|
+
if (Object.keys(value).some((key) => !allowed.includes(key))) throw new Error(`${label} contains unsupported fields`);
|
|
8457
|
+
}
|
|
8458
|
+
function interaction(value, label, allowed) {
|
|
8459
|
+
const result = copiedObject(value, label);
|
|
8460
|
+
fields(result, allowed, label);
|
|
8461
|
+
if (Object.values(result).some((item) => typeof item !== "boolean")) throw new Error(`${label} preferences must be boolean`);
|
|
8462
|
+
return result;
|
|
8463
|
+
}
|
|
8464
|
+
function entryId(value, label) {
|
|
8465
|
+
if (typeof value !== "string" || !ENTRY_ID.test(value) || UNSAFE_KEYS.has(value)) throw new Error(`${label} contains an invalid Entry id`);
|
|
8466
|
+
}
|
|
8467
|
+
function view(value, label) {
|
|
8468
|
+
const result = copiedObject(value, label);
|
|
8469
|
+
fields(result, ["strategyTypeId", "entries"], label);
|
|
8470
|
+
if (Object.hasOwn(result, "strategyTypeId") && (typeof result.strategyTypeId !== "string" || !STRATEGY_ID.test(result.strategyTypeId))) throw new Error(`${label} contains an invalid Strategy type id`);
|
|
8471
|
+
const entries = {};
|
|
8472
|
+
if (Object.hasOwn(result, "entries")) {
|
|
8473
|
+
const values = object$2(result.entries, `${label}.entries`);
|
|
8474
|
+
if (Object.keys(values).length > 64) throw new Error(`${label} contains too many Entries`);
|
|
8475
|
+
for (const [id, raw] of Object.entries(values)) {
|
|
8476
|
+
entryId(id, label);
|
|
8477
|
+
const item = copiedObject(raw, `${label}.entries`);
|
|
8478
|
+
fields(item, ["enabled", "config"], `${label}.entries`);
|
|
8479
|
+
if (typeof item.enabled !== "boolean") throw new Error(`${label} Entry enabled must be boolean`);
|
|
8480
|
+
const config = Object.hasOwn(item, "config") ? copiedObject(item.config, `${label} Entry config`) : {};
|
|
8481
|
+
if (JSON.stringify(config).length > 65536) throw new Error(`${label} Entry config exceeds 64 KiB`);
|
|
8482
|
+
entries[id] = {
|
|
8483
|
+
enabled: item.enabled,
|
|
8484
|
+
config
|
|
8485
|
+
};
|
|
8486
|
+
}
|
|
8487
|
+
}
|
|
8488
|
+
return {
|
|
8489
|
+
...typeof result.strategyTypeId === "string" ? { strategyTypeId: result.strategyTypeId } : {},
|
|
8490
|
+
...Object.hasOwn(result, "entries") ? { entries } : {}
|
|
8491
|
+
};
|
|
8492
|
+
}
|
|
8493
|
+
function sources(value, label, sourceEntryIds, diagnostics) {
|
|
8494
|
+
const result = copiedObject(value, label);
|
|
8495
|
+
fields(result, ["sources"], label);
|
|
8496
|
+
const values = Object.hasOwn(result, "sources") ? object$2(result.sources, `${label}.sources`) : {};
|
|
8497
|
+
if (Object.keys(values).length > 64) throw new Error(`${label} contains too many Source Entries`);
|
|
8498
|
+
const entries = {};
|
|
8499
|
+
for (const [id, raw] of Object.entries(values)) {
|
|
8500
|
+
entryId(id, label);
|
|
8501
|
+
const item = copiedObject(raw, `${label}.sources`);
|
|
8502
|
+
fields(item, ["enabled"], `${label}.sources`);
|
|
8503
|
+
if (typeof item.enabled !== "boolean") throw new Error(`${label} Source enabled must be boolean`);
|
|
8504
|
+
if (!sourceEntryIds.has(id)) {
|
|
8505
|
+
diagnostics.push(`Skipped legacy Source preference for ${id}: the current profile does not declare it as a Source.`);
|
|
8506
|
+
continue;
|
|
8507
|
+
}
|
|
8508
|
+
entries[id] = {
|
|
8509
|
+
enabled: item.enabled,
|
|
8510
|
+
config: {}
|
|
8511
|
+
};
|
|
8512
|
+
}
|
|
8513
|
+
return entries;
|
|
8514
|
+
}
|
|
8515
|
+
function applyEntryOverrides(entries, overrides, sourceEntryIds, diagnostics) {
|
|
8516
|
+
if (!Array.isArray(overrides)) throw new Error("Explicit Entry overrides must be an array");
|
|
8517
|
+
const matching = /* @__PURE__ */ new Map();
|
|
8518
|
+
for (const raw of overrides) {
|
|
8519
|
+
const row = object$2(raw, "Explicit Entry override");
|
|
8520
|
+
entryId(row.id, "Explicit Entry override");
|
|
8521
|
+
if (!Object.hasOwn(entries, row.id)) continue;
|
|
8522
|
+
const previous = matching.get(row.id) ?? {};
|
|
8523
|
+
matching.set(row.id, {
|
|
8524
|
+
...previous,
|
|
8525
|
+
...row.disabled === void 0 ? {} : { disabled: row.disabled },
|
|
8526
|
+
...row.config === void 0 ? {} : { config: row.config }
|
|
8527
|
+
});
|
|
8528
|
+
}
|
|
8529
|
+
for (const [id, row] of matching) {
|
|
8530
|
+
if (row.disabled !== void 0 && typeof row.disabled !== "boolean") {
|
|
8531
|
+
delete entries[id];
|
|
8532
|
+
diagnostics.push(`Skipped legacy View preference for ${id}: its explicit disabled value is not boolean.`);
|
|
8533
|
+
continue;
|
|
8534
|
+
}
|
|
8535
|
+
if (row.config !== void 0 && !sourceEntryIds.has(id)) {
|
|
8536
|
+
const config = copiedObject(row.config, "Explicit Entry config");
|
|
8537
|
+
if (containsExpression(config)) {
|
|
8538
|
+
delete entries[id];
|
|
8539
|
+
diagnostics.push(`Skipped legacy View preference for ${id}: its explicit config contains an expression.`);
|
|
8540
|
+
continue;
|
|
8541
|
+
}
|
|
8542
|
+
entries[id].config = config;
|
|
8543
|
+
}
|
|
8544
|
+
if (typeof row.disabled === "boolean") entries[id].enabled = !row.disabled;
|
|
8545
|
+
}
|
|
8546
|
+
}
|
|
8547
|
+
/**
|
|
8548
|
+
* Recover only the canonical root and the exact owning profile's old namespaces.
|
|
8549
|
+
* This does not read files, edit profile rows, validate plugin domains or commit.
|
|
8550
|
+
* Malformed relevant input rejects the complete plan without an import marker.
|
|
8551
|
+
*/
|
|
8552
|
+
function planLegacySettingsImport(options) {
|
|
8553
|
+
const diagnostics = [];
|
|
8554
|
+
try {
|
|
8555
|
+
const rawCurrent = object$2(options.currentOverride, "Current config override");
|
|
8556
|
+
if (rawCurrent.legacySettingsImported === true) return {
|
|
8557
|
+
patch: {},
|
|
8558
|
+
diagnostics
|
|
8559
|
+
};
|
|
8560
|
+
if (options.entryId !== "mnemon") throw new Error("Legacy settings belong to the canonical mnemon Entry; another root Entry is ambiguous.");
|
|
8561
|
+
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.");
|
|
8562
|
+
const sections = object$2(options.sections, "Legacy settings document");
|
|
8563
|
+
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.");
|
|
8564
|
+
const relevant = [
|
|
8565
|
+
"mnemon",
|
|
8566
|
+
"mnemon-ui",
|
|
8567
|
+
options.viewNamespace,
|
|
8568
|
+
options.legacyNamespace
|
|
8569
|
+
];
|
|
8570
|
+
if (!relevant.some((key) => Object.hasOwn(sections, key))) return {
|
|
8571
|
+
patch: {},
|
|
8572
|
+
diagnostics
|
|
8573
|
+
};
|
|
8574
|
+
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.`);
|
|
8575
|
+
const current = copiedObject(rawCurrent, "Current config override");
|
|
8576
|
+
if (Object.hasOwn(current, "legacySettingsImported") && typeof current.legacySettingsImported !== "boolean") throw new Error("Current import marker must be boolean");
|
|
8577
|
+
const root = Object.hasOwn(sections, "mnemon") ? copiedObject(sections.mnemon, "mnemon") : {};
|
|
8578
|
+
if (Object.hasOwn(root, "memoryView") || Object.hasOwn(root, "legacySettingsImported")) throw new Error("Legacy mnemon contains reserved migration fields");
|
|
8579
|
+
const oldInteraction = Object.hasOwn(root, "conversationInteraction") ? interaction(root.conversationInteraction, "mnemon.conversationInteraction", [
|
|
8580
|
+
"toolviews",
|
|
8581
|
+
"turnBar",
|
|
8582
|
+
"saveAction"
|
|
8583
|
+
]) : {};
|
|
8584
|
+
const oldUi = Object.hasOwn(sections, "mnemon-ui") ? interaction(sections["mnemon-ui"], "mnemon-ui", ["turnBar", "saveAction"]) : {};
|
|
8585
|
+
const currentInteraction = Object.hasOwn(current, "conversationInteraction") ? interaction(current.conversationInteraction, "Current conversationInteraction", [
|
|
8586
|
+
"toolviews",
|
|
8587
|
+
"turnBar",
|
|
8588
|
+
"saveAction"
|
|
8589
|
+
]) : {};
|
|
8590
|
+
const patch = Object.fromEntries(Object.entries(root).filter(([key]) => key !== "conversationInteraction" && !Object.hasOwn(current, key)));
|
|
8591
|
+
const inheritedInteraction = {
|
|
8592
|
+
...oldInteraction,
|
|
8593
|
+
...oldUi
|
|
8594
|
+
};
|
|
8595
|
+
if (Object.keys(inheritedInteraction).some((key) => !Object.hasOwn(currentInteraction, key))) patch.conversationInteraction = {
|
|
8596
|
+
...inheritedInteraction,
|
|
8597
|
+
...currentInteraction
|
|
8598
|
+
};
|
|
8599
|
+
const currentView = Object.hasOwn(current, "memoryView") ? view(current.memoryView, "Current memoryView") : {};
|
|
8600
|
+
if (Object.hasOwn(sections, options.viewNamespace) || Object.hasOwn(sections, options.legacyNamespace)) {
|
|
8601
|
+
if (!Array.isArray(options.sourceEntryIds)) throw new Error("Source Entry ids must be an array");
|
|
8602
|
+
for (const id of options.sourceEntryIds) entryId(id, "Source Entry ids");
|
|
8603
|
+
const sourceEntryIds = new Set(options.sourceEntryIds);
|
|
8604
|
+
const oldSources = Object.hasOwn(sections, options.legacyNamespace) ? sources(sections[options.legacyNamespace], options.legacyNamespace, sourceEntryIds, diagnostics) : {};
|
|
8605
|
+
const oldView = Object.hasOwn(sections, options.viewNamespace) ? view(sections[options.viewNamespace], options.viewNamespace) : {};
|
|
8606
|
+
const entries = {
|
|
8607
|
+
...oldSources,
|
|
8608
|
+
...oldView.entries
|
|
8609
|
+
};
|
|
8610
|
+
applyEntryOverrides(entries, options.entryOverrides, sourceEntryIds, diagnostics);
|
|
8611
|
+
const migratedView = {
|
|
8612
|
+
...oldView,
|
|
8613
|
+
entries,
|
|
8614
|
+
...currentView
|
|
8615
|
+
};
|
|
8616
|
+
if (!Object.hasOwn(currentView, "entries") || !Object.hasOwn(currentView, "strategyTypeId") && oldView.strategyTypeId !== void 0) patch.memoryView = migratedView;
|
|
8617
|
+
}
|
|
8618
|
+
patch.legacySettingsImported = true;
|
|
8619
|
+
return {
|
|
8620
|
+
patch,
|
|
8621
|
+
diagnostics
|
|
8622
|
+
};
|
|
8623
|
+
} catch (error) {
|
|
8624
|
+
diagnostics.push(error instanceof Error ? error.message : "Legacy settings import could not be planned");
|
|
8625
|
+
return {
|
|
8626
|
+
patch: {},
|
|
8627
|
+
diagnostics
|
|
8628
|
+
};
|
|
8629
|
+
}
|
|
8630
|
+
}
|
|
8631
|
+
//#endregion
|
|
8632
|
+
//#region src/host/settings-service.ts
|
|
8633
|
+
const pendingNativeImports = /* @__PURE__ */ new WeakSet();
|
|
8634
|
+
const clone$1 = (value) => structuredClone(value);
|
|
8635
|
+
const object$1 = (value) => value !== null && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
8636
|
+
function profileYaml(source) {
|
|
8637
|
+
const document = parseDocument(source, { customTags: [{
|
|
8638
|
+
tag: "tag:yaml.org,2002:js",
|
|
8639
|
+
resolve: (value) => ({ __jsExpr: value })
|
|
8640
|
+
}] });
|
|
8641
|
+
if (document.errors.length > 0 || document.warnings.length > 0) throw new Error("Invalid or unsupported legacy/profile YAML; retained backup was not changed");
|
|
8642
|
+
return document.toJS({ maxAliasCount: 100 });
|
|
8643
|
+
}
|
|
8644
|
+
/** A local facade preserves Mnemon's wire namespaces; DSH owns all persistence. */
|
|
8645
|
+
var ProfileMnemonSettings = class {
|
|
8646
|
+
ctx;
|
|
8647
|
+
input;
|
|
8648
|
+
registrations = /* @__PURE__ */ new Map();
|
|
8649
|
+
listeners = /* @__PURE__ */ new Set();
|
|
8650
|
+
revisions = /* @__PURE__ */ new Map();
|
|
8651
|
+
owner;
|
|
8652
|
+
forms;
|
|
8653
|
+
editor;
|
|
8654
|
+
closed = false;
|
|
8655
|
+
importing;
|
|
8656
|
+
nativeImportPending;
|
|
8657
|
+
constructor(ctx, input) {
|
|
8658
|
+
this.ctx = ctx;
|
|
8659
|
+
this.input = input;
|
|
8660
|
+
this.forms = ctx.settings;
|
|
8661
|
+
this.owner = ctx.fiber;
|
|
8662
|
+
this.editor = ctx.get("configEditor");
|
|
8663
|
+
const profile = ctx.get("profileContext");
|
|
8664
|
+
const root = ctx.root ?? ctx;
|
|
8665
|
+
if (profile?.home !== void 0 && existsSync(join(profile.home, "settings.yaml"))) pendingNativeImports.add(root);
|
|
8666
|
+
this.nativeImportPending = pendingNativeImports.has(root);
|
|
8667
|
+
const owner = this.owner;
|
|
8668
|
+
const validate = (candidate) => {
|
|
8669
|
+
const config = plainHostConfig(candidate);
|
|
8670
|
+
for (const registration of this.registrations.values()) {
|
|
8671
|
+
if (registration.legacy) continue;
|
|
8672
|
+
const value = this.resolve(registration, config);
|
|
8673
|
+
registration.validate?.(value);
|
|
8674
|
+
}
|
|
8675
|
+
};
|
|
8676
|
+
ctx.on("internal/config", function(_raw, next) {
|
|
8677
|
+
const candidate = next();
|
|
8678
|
+
if (this === owner) validate(candidate);
|
|
8679
|
+
return candidate;
|
|
8680
|
+
}, { prepend: true });
|
|
8681
|
+
ctx.on("loader/volatile-update", ((paths) => {
|
|
8682
|
+
if (this.closed) return;
|
|
8683
|
+
for (const registration of this.registrations.values()) {
|
|
8684
|
+
if (registration.legacy) continue;
|
|
8685
|
+
if (!paths.some((path) => registration.field === void 0 ? path.length === 0 || !["memoryView", "legacySettingsImported"].includes(path[0]) : path.length === 0 || path[0] === registration.field)) continue;
|
|
8686
|
+
const value = this.resolve(registration);
|
|
8687
|
+
for (const listener of this.listeners) try {
|
|
8688
|
+
listener(registration.namespace, value);
|
|
8689
|
+
} catch (error) {
|
|
8690
|
+
console.warn("dsh-mnemon: committed settings listener failed", error);
|
|
8691
|
+
}
|
|
8692
|
+
}
|
|
8693
|
+
}));
|
|
8694
|
+
ctx.effect(() => {
|
|
8695
|
+
const disposePresentation = owner === void 0 ? void 0 : this.forms.configure({ auto: false }, owner);
|
|
8696
|
+
return () => {
|
|
8697
|
+
this.closed = true;
|
|
8698
|
+
this.listeners.clear();
|
|
8699
|
+
this.revisions.clear();
|
|
8700
|
+
disposePresentation?.();
|
|
8701
|
+
};
|
|
8702
|
+
}, "dsh-mnemon: profile settings");
|
|
8703
|
+
}
|
|
8704
|
+
get writable() {
|
|
8705
|
+
const entry = this.owner?.entry;
|
|
8706
|
+
return !this.closed && this.forms.writable && entry !== void 0 && this.editor?.entries().includes(entry) === true;
|
|
8707
|
+
}
|
|
8708
|
+
onUpdated(listener) {
|
|
8709
|
+
this.listeners.add(listener);
|
|
8710
|
+
return () => {
|
|
8711
|
+
this.listeners.delete(listener);
|
|
8712
|
+
};
|
|
8713
|
+
}
|
|
8714
|
+
resolve(registration, config = plainHostConfig(this.owner?.config ?? this.input)) {
|
|
8715
|
+
const value = registration.legacy ? registration.base : registration.field === void 0 ? config : config[registration.field];
|
|
8716
|
+
return registration.schema(object$1(value));
|
|
8717
|
+
}
|
|
8718
|
+
register(namespace, schema, options) {
|
|
8719
|
+
if (this.registrations.has(namespace)) throw new Error(`Mnemon settings already registered: ${namespace}`);
|
|
8720
|
+
if (typeof schema !== "function") throw new Error("Mnemon settings require a schema");
|
|
8721
|
+
const field = namespace === "mnemon-ui" ? "conversationInteraction" : /^mnemon-view(?:-[a-f0-9]{16})?$/u.test(namespace) ? "memoryView" : void 0;
|
|
8722
|
+
const legacy = /^mnemon-plugins(?:-[a-f0-9]{16})?$/u.test(namespace);
|
|
8723
|
+
if (namespace !== "mnemon" && field === void 0 && !legacy) throw new Error("Unsupported Mnemon settings namespace");
|
|
8724
|
+
const registration = {
|
|
8725
|
+
namespace,
|
|
8726
|
+
...field === void 0 ? {} : { field },
|
|
8727
|
+
legacy,
|
|
8728
|
+
schema,
|
|
8729
|
+
base: clone$1(options.base ?? {}),
|
|
8730
|
+
...options.validate === void 0 ? {} : { validate: options.validate }
|
|
8731
|
+
};
|
|
8732
|
+
const value = this.resolve(registration);
|
|
8733
|
+
options.validate?.(value);
|
|
8734
|
+
this.registrations.set(namespace, registration);
|
|
8735
|
+
return { get: () => this.resolve(registration) };
|
|
8736
|
+
}
|
|
8737
|
+
nativeDescriptor() {
|
|
8738
|
+
if (this.closed || this.owner?.entry === void 0 || !this.editor?.entries().includes(this.owner.entry)) return void 0;
|
|
8739
|
+
const descriptor = this.forms.describe().find((item) => item.ns === this.owner?.entry?.options.id);
|
|
8740
|
+
if (descriptor !== void 0) {
|
|
8741
|
+
this.revisions.set(descriptor.revision, clone$1({
|
|
8742
|
+
ns: descriptor.ns,
|
|
8743
|
+
revision: descriptor.revision,
|
|
8744
|
+
applies: descriptor.applies,
|
|
8745
|
+
value: descriptor.value,
|
|
8746
|
+
base: descriptor.base,
|
|
8747
|
+
user: descriptor.user
|
|
8748
|
+
}));
|
|
8749
|
+
if (this.revisions.size > 64) this.revisions.delete(this.revisions.keys().next().value);
|
|
8750
|
+
}
|
|
8751
|
+
return descriptor;
|
|
8752
|
+
}
|
|
8753
|
+
unchanged(previous, current, registration, operations) {
|
|
8754
|
+
const project = (value) => {
|
|
8755
|
+
if (registration.field !== void 0) return object$1(value)[registration.field];
|
|
8756
|
+
const { memoryView: _view, legacySettingsImported: _imported, conversationInteraction, ...core } = object$1(value);
|
|
8757
|
+
return operations.some((operation) => operation.path[0] === "conversationInteraction") ? {
|
|
8758
|
+
...core,
|
|
8759
|
+
conversationInteraction
|
|
8760
|
+
} : core;
|
|
8761
|
+
};
|
|
8762
|
+
const signature = (descriptor) => canonicalMemoryJson(JSON.parse(JSON.stringify([
|
|
8763
|
+
project(descriptor.value) ?? null,
|
|
8764
|
+
project(descriptor.base) ?? null,
|
|
8765
|
+
project(descriptor.user) ?? null
|
|
8766
|
+
])));
|
|
8767
|
+
return signature(previous) === signature(current);
|
|
8768
|
+
}
|
|
8769
|
+
describe(options) {
|
|
8770
|
+
const raw = this.nativeDescriptor();
|
|
8771
|
+
if (raw === void 0) return [];
|
|
8772
|
+
const descriptor = options?.redactSecrets ? this.forms.describe(options).find((item) => item.ns === this.owner?.entry?.options.id) : raw;
|
|
8773
|
+
if (descriptor === void 0) return [];
|
|
8774
|
+
return [...this.registrations.values()].map((registration) => {
|
|
8775
|
+
const project = (value) => registration.legacy ? {} : registration.field === void 0 ? value : object$1(value)[registration.field];
|
|
8776
|
+
return {
|
|
8777
|
+
ns: registration.namespace,
|
|
8778
|
+
value: project(descriptor.value) ?? {},
|
|
8779
|
+
base: project(descriptor.base) ?? {},
|
|
8780
|
+
user: project(descriptor.user) ?? {},
|
|
8781
|
+
revision: descriptor.revision,
|
|
8782
|
+
applies: "live"
|
|
8783
|
+
};
|
|
8784
|
+
});
|
|
8785
|
+
}
|
|
8786
|
+
async mutate(namespace, operations, expectedRevision) {
|
|
8787
|
+
const registration = this.registrations.get(namespace);
|
|
8788
|
+
if (registration === void 0 || registration.legacy) throw new Error("Unsupported Mnemon settings namespace");
|
|
8789
|
+
if (!this.writable) throw new Error("DSH settings are read-only");
|
|
8790
|
+
const translated = operations.map((operation) => ({
|
|
8791
|
+
...operation,
|
|
8792
|
+
path: [...registration.field === void 0 ? [] : [registration.field], ...operation.path]
|
|
8793
|
+
}));
|
|
8794
|
+
let revision = expectedRevision;
|
|
8795
|
+
const previous = revision === void 0 ? void 0 : this.revisions.get(revision);
|
|
8796
|
+
for (let attempt = 0;; attempt += 1) {
|
|
8797
|
+
if (!this.writable) throw new Error("DSH settings are read-only");
|
|
8798
|
+
try {
|
|
8799
|
+
await this.forms.mutate(this.owner.entry.options.id, translated, revision);
|
|
8800
|
+
return;
|
|
8801
|
+
} catch (error) {
|
|
8802
|
+
if (attempt >= 2 || previous === void 0 || typeof error !== "object" || error === null || !("code" in error) || error.code !== "SETTINGS_CONFLICT") throw error;
|
|
8803
|
+
if (!this.writable) throw new Error("DSH settings are read-only");
|
|
8804
|
+
const current = this.nativeDescriptor();
|
|
8805
|
+
if (current === void 0 || !this.unchanged(previous, current, registration, operations)) throw error;
|
|
8806
|
+
revision = current.revision;
|
|
8807
|
+
}
|
|
8808
|
+
}
|
|
8809
|
+
}
|
|
8810
|
+
/** Read only the retained backup; ConfigEditor preserves all other patch rows. */
|
|
8811
|
+
async importLegacy(sourceEntryIds) {
|
|
8812
|
+
if (this.importing !== void 0) return this.importing;
|
|
8813
|
+
this.importing = this.performImport(sourceEntryIds).finally(() => {
|
|
8814
|
+
this.importing = void 0;
|
|
8815
|
+
});
|
|
8816
|
+
return this.importing;
|
|
8817
|
+
}
|
|
8818
|
+
async performImport(sourceEntryIds) {
|
|
8819
|
+
const profile = this.ctx.get("profileContext");
|
|
8820
|
+
const entry = this.owner?.entry;
|
|
8821
|
+
if (!this.writable || profile?.home === void 0 || entry === void 0) return;
|
|
8822
|
+
if (this.nativeImportPending) {
|
|
8823
|
+
console.warn("dsh-mnemon: DSH is importing settings.yaml; restart once to recover retained Mnemon UI and plugin preferences");
|
|
8824
|
+
return;
|
|
8825
|
+
}
|
|
8826
|
+
if (plainHostConfig(this.owner?.config ?? this.input).legacySettingsImported) return;
|
|
8827
|
+
const backup = join(profile.home, "settings.yaml.imported");
|
|
8828
|
+
let text;
|
|
8829
|
+
try {
|
|
8830
|
+
if ((await stat(backup)).size > 1048576) throw new Error("Legacy settings backup exceeds the import limit");
|
|
8831
|
+
text = await readFile(backup, "utf8");
|
|
8832
|
+
} catch (error) {
|
|
8833
|
+
if (typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT") return;
|
|
8834
|
+
throw error;
|
|
8835
|
+
}
|
|
8836
|
+
const sections = profileYaml(text);
|
|
8837
|
+
const viewNamespace = [...this.registrations.keys()].find((namespace) => namespace.startsWith("mnemon-view"));
|
|
8838
|
+
const legacyNamespace = [...this.registrations.keys()].find((namespace) => namespace.startsWith("mnemon-plugins"));
|
|
8839
|
+
const plan = () => {
|
|
8840
|
+
const configuration = this.editor.configuration().find((item) => item.entry === entry);
|
|
8841
|
+
if (configuration === void 0) throw new Error("Mnemon profile entry is no longer editable");
|
|
8842
|
+
const document = profileYaml(readFileSync(this.editor.documentPath, "utf8"));
|
|
8843
|
+
const entryOverrides = Array.isArray(document) ? document.flatMap((value) => {
|
|
8844
|
+
const row = object$1(value);
|
|
8845
|
+
if (typeof row.id !== "string") return [];
|
|
8846
|
+
const entries = this.editor.entries().filter((candidate) => candidate.options.id === row.id);
|
|
8847
|
+
if (entries.length > 1) throw new Error("Legacy settings import requires unambiguous profile Entry ids");
|
|
8848
|
+
return [{
|
|
8849
|
+
id: entries[0]?.id ?? row.id,
|
|
8850
|
+
..."disabled" in row ? { disabled: row.disabled } : {},
|
|
8851
|
+
..."config" in row ? { config: row.config } : {}
|
|
8852
|
+
}];
|
|
8853
|
+
}) : [];
|
|
8854
|
+
return planLegacySettingsImport({
|
|
8855
|
+
entryId: entry.options.id,
|
|
8856
|
+
viewNamespace,
|
|
8857
|
+
legacyNamespace,
|
|
8858
|
+
sections,
|
|
8859
|
+
currentOverride: configuration.override,
|
|
8860
|
+
entryOverrides,
|
|
8861
|
+
sourceEntryIds
|
|
8862
|
+
});
|
|
8863
|
+
};
|
|
8864
|
+
const preview = plan();
|
|
8865
|
+
if (Object.keys(preview.patch).length === 0) {
|
|
8866
|
+
if (preview.diagnostics.length > 0) console.warn("dsh-mnemon: legacy settings were not imported; retained backup requires review");
|
|
8867
|
+
return;
|
|
8868
|
+
}
|
|
8869
|
+
if (this.closed) return;
|
|
8870
|
+
await this.editor.edit(entry, (current) => {
|
|
8871
|
+
if (this.closed) throw new Error("Mnemon settings are disposed");
|
|
8872
|
+
const next = plan();
|
|
8873
|
+
return {
|
|
8874
|
+
...current,
|
|
8875
|
+
...next.patch
|
|
8876
|
+
};
|
|
8877
|
+
});
|
|
8878
|
+
}
|
|
8879
|
+
};
|
|
8880
|
+
function createHostSettings(ctx, config) {
|
|
8881
|
+
return typeof ctx.settings.register === "function" ? ctx.settings : new ProfileMnemonSettings(ctx, config);
|
|
8882
|
+
}
|
|
8883
|
+
function subscribeSettings(ctx, settings, listener) {
|
|
8884
|
+
return settings instanceof ProfileMnemonSettings ? settings.onUpdated(listener) : ctx.on("settings/updated", listener);
|
|
8885
|
+
}
|
|
8886
|
+
//#endregion
|
|
8887
|
+
//#region src/host/plugin-management.ts
|
|
8888
|
+
const PACKAGE$1 = /^(?:@[a-z0-9._-]+\/)?dsh-mnemon-(source|strategy)-[a-z0-9._-]+$/u;
|
|
8889
|
+
const hash = (value) => createHash("sha256").update(canonicalMemoryJson(value)).digest("hex");
|
|
8890
|
+
const clone = (value) => JSON.parse(JSON.stringify(value));
|
|
8350
8891
|
function contributionRoles(snapshot, entryId) {
|
|
8351
8892
|
const roles = /* @__PURE__ */ new Set();
|
|
8352
8893
|
if (snapshot.sources.some((value) => value.provenance.entryId === entryId)) roles.add("source");
|
|
@@ -8436,6 +8977,7 @@ function orderPlugins(values) {
|
|
|
8436
8977
|
var MemoryPluginManagement = class {
|
|
8437
8978
|
ctx;
|
|
8438
8979
|
engine;
|
|
8980
|
+
settingsService;
|
|
8439
8981
|
settingsNamespace;
|
|
8440
8982
|
settings;
|
|
8441
8983
|
legacySettings;
|
|
@@ -8445,21 +8987,23 @@ var MemoryPluginManagement = class {
|
|
|
8445
8987
|
restoreError;
|
|
8446
8988
|
discoveryWarnings = [];
|
|
8447
8989
|
changingEntries = false;
|
|
8448
|
-
|
|
8990
|
+
restorePending = false;
|
|
8991
|
+
constructor(ctx, engine, settingsService = ctx.settings) {
|
|
8449
8992
|
this.ctx = ctx;
|
|
8450
8993
|
this.engine = engine;
|
|
8994
|
+
this.settingsService = settingsService;
|
|
8451
8995
|
const loader = this.loader();
|
|
8452
|
-
const anchor = loader?.config?.baseUrl ?? loader?.context?.baseUrl;
|
|
8996
|
+
const anchor = loader?.config?.baseUrl ?? loader?.ctx?.baseUrl ?? loader?.context?.baseUrl;
|
|
8453
8997
|
const suffix = anchor ? `-${hash(anchor).slice(0, 16)}` : "";
|
|
8454
8998
|
this.settingsNamespace = `${MNEMON_VIEW_SETTINGS_NAMESPACE}${suffix}`;
|
|
8455
|
-
this.settings =
|
|
8999
|
+
this.settings = settingsService.register(this.settingsNamespace, schema, {
|
|
8456
9000
|
base: { entries: {} },
|
|
8457
9001
|
applies: "live",
|
|
8458
9002
|
validate: (value) => {
|
|
8459
9003
|
preferences(value);
|
|
8460
9004
|
}
|
|
8461
9005
|
});
|
|
8462
|
-
this.legacySettings =
|
|
9006
|
+
this.legacySettings = settingsService.register(`mnemon-plugins${suffix}`, legacySchema, {
|
|
8463
9007
|
base: { sources: {} },
|
|
8464
9008
|
applies: "live",
|
|
8465
9009
|
validate: (value) => {
|
|
@@ -8467,8 +9011,8 @@ var MemoryPluginManagement = class {
|
|
|
8467
9011
|
}
|
|
8468
9012
|
});
|
|
8469
9013
|
}
|
|
8470
|
-
resolveConfig(config) {
|
|
8471
|
-
const selected =
|
|
9014
|
+
resolveConfig(config, view = this.settings.get()) {
|
|
9015
|
+
const selected = view.strategyTypeId;
|
|
8472
9016
|
return selected === void 0 ? config : {
|
|
8473
9017
|
...config,
|
|
8474
9018
|
memoryTopology: {
|
|
@@ -8478,36 +9022,61 @@ var MemoryPluginManagement = class {
|
|
|
8478
9022
|
};
|
|
8479
9023
|
}
|
|
8480
9024
|
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
|
-
};
|
|
9025
|
+
const schedule = () => this.scheduleRestore();
|
|
8491
9026
|
const stops = [
|
|
8492
9027
|
this.ctx.on("loader/entry-init", schedule),
|
|
8493
9028
|
this.ctx.on("loader/partial-dispose", schedule),
|
|
8494
|
-
this.ctx.on("
|
|
9029
|
+
this.ctx.on("app-boot/config-reload", () => this.scheduleRestore(true)),
|
|
9030
|
+
subscribeSettings(this.ctx, this.settingsService, (namespace) => {
|
|
8495
9031
|
if (namespace === this.settingsNamespace || namespace === `mnemon-plugins${this.settingsNamespace.slice(11)}`) schedule();
|
|
8496
|
-
})
|
|
9032
|
+
})
|
|
8497
9033
|
];
|
|
8498
9034
|
schedule();
|
|
8499
9035
|
return () => {
|
|
8500
9036
|
this.closed = true;
|
|
9037
|
+
this.restorePending = false;
|
|
8501
9038
|
clearTimeout(this.timer);
|
|
8502
9039
|
for (const stop of stops.reverse()) stop();
|
|
8503
9040
|
};
|
|
8504
9041
|
}
|
|
9042
|
+
scheduleRestore(profileReload = false) {
|
|
9043
|
+
const hasSavedState = Object.keys(this.settings.get().entries ?? {}).length > 0 || Object.keys(this.legacySettings.get().sources ?? {}).length > 0;
|
|
9044
|
+
if (this.closed || !profileReload && this.changingEntries || !hasSavedState) return;
|
|
9045
|
+
this.restorePending = true;
|
|
9046
|
+
if (this.changingEntries || this.timer) return;
|
|
9047
|
+
this.timer = setTimeout(() => {
|
|
9048
|
+
this.timer = void 0;
|
|
9049
|
+
this.enqueueRestore();
|
|
9050
|
+
}, 0);
|
|
9051
|
+
}
|
|
9052
|
+
enqueueRestore() {
|
|
9053
|
+
if (this.closed || this.changingEntries || !this.restorePending) return;
|
|
9054
|
+
clearTimeout(this.timer);
|
|
9055
|
+
this.timer = void 0;
|
|
9056
|
+
this.restorePending = false;
|
|
9057
|
+
this.exclusive(async () => {
|
|
9058
|
+
try {
|
|
9059
|
+
await this.restore();
|
|
9060
|
+
} catch (error) {
|
|
9061
|
+
this.restoreError = error instanceof Error ? error.message : String(error);
|
|
9062
|
+
}
|
|
9063
|
+
}).catch(() => {});
|
|
9064
|
+
}
|
|
9065
|
+
/** A response must not race the deferred restore after profile reconciliation. */
|
|
9066
|
+
async settled() {
|
|
9067
|
+
do {
|
|
9068
|
+
this.enqueueRestore();
|
|
9069
|
+
const pending = this.queue;
|
|
9070
|
+
await pending;
|
|
9071
|
+
if (pending === this.queue && !this.restorePending) return;
|
|
9072
|
+
} while (!this.closed);
|
|
9073
|
+
}
|
|
8505
9074
|
loader() {
|
|
8506
9075
|
const candidate = this.ctx.get("loader");
|
|
8507
9076
|
return candidate && typeof candidate.entries === "function" ? candidate : void 0;
|
|
8508
9077
|
}
|
|
8509
9078
|
settingsRevision() {
|
|
8510
|
-
return this.
|
|
9079
|
+
return this.settingsService.describe({ redactSecrets: true }).find((value) => value.ns === this.settingsNamespace)?.revision ?? 0;
|
|
8511
9080
|
}
|
|
8512
9081
|
async managed() {
|
|
8513
9082
|
const loader = this.loader();
|
|
@@ -8552,7 +9121,7 @@ var MemoryPluginManagement = class {
|
|
|
8552
9121
|
config: editor === void 0 ? {} : memoryStrategyConfigurationValues(editor, entry.options.config),
|
|
8553
9122
|
enabled: !entry.disabled,
|
|
8554
9123
|
active,
|
|
8555
|
-
writable: this.
|
|
9124
|
+
writable: this.settingsService.writable && !ancestorDisabled && (entry.options.disabled === void 0 || typeof entry.options.disabled === "boolean"),
|
|
8556
9125
|
...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
9126
|
};
|
|
8558
9127
|
const item = {
|
|
@@ -8583,7 +9152,7 @@ var MemoryPluginManagement = class {
|
|
|
8583
9152
|
`mnemon-plugins${this.settingsNamespace.slice(11)}`
|
|
8584
9153
|
]);
|
|
8585
9154
|
return hash({
|
|
8586
|
-
settings: this.
|
|
9155
|
+
settings: this.settingsService.describe({ redactSecrets: true }).filter((value) => namespaces.has(value.ns)).map((value) => [value.ns, value.revision]),
|
|
8587
9156
|
contribution: this.engine.contributionSnapshot().revision,
|
|
8588
9157
|
entries: items.map(({ entry, value, descriptor }) => ({
|
|
8589
9158
|
id: entry.id,
|
|
@@ -8595,8 +9164,10 @@ var MemoryPluginManagement = class {
|
|
|
8595
9164
|
});
|
|
8596
9165
|
}
|
|
8597
9166
|
async catalog() {
|
|
8598
|
-
await this.
|
|
9167
|
+
await this.settled();
|
|
9168
|
+
const pending = this.queue;
|
|
8599
9169
|
const items = await this.managed();
|
|
9170
|
+
if (pending !== this.queue || this.restorePending) return this.catalog();
|
|
8600
9171
|
const values = items.map((item) => clone(item.value));
|
|
8601
9172
|
const snapshot = this.engine.contributionSnapshot();
|
|
8602
9173
|
const managedIds = new Set(items.map((item) => item.entry.id));
|
|
@@ -8655,7 +9226,7 @@ var MemoryPluginManagement = class {
|
|
|
8655
9226
|
}
|
|
8656
9227
|
return {
|
|
8657
9228
|
revision: this.revision(items),
|
|
8658
|
-
writable: this.
|
|
9229
|
+
writable: this.settingsService.writable && this.loader() !== void 0,
|
|
8659
9230
|
entries: orderPlugins(values),
|
|
8660
9231
|
diagnostics: [...this.discoveryWarnings, ...this.restoreError === void 0 ? [] : [this.restoreError]]
|
|
8661
9232
|
};
|
|
@@ -8737,7 +9308,7 @@ var MemoryPluginManagement = class {
|
|
|
8737
9308
|
return captureMemoryContributionSnapshot(candidate);
|
|
8738
9309
|
}
|
|
8739
9310
|
async preview(config, scope, request, signal) {
|
|
8740
|
-
await this.
|
|
9311
|
+
await this.settled();
|
|
8741
9312
|
const items = await this.managed();
|
|
8742
9313
|
const value = await this.evaluateSnapshot(this.proposal(items, request), config, scope, request.strategyTypeId, signal);
|
|
8743
9314
|
if (request.expectedRevision !== this.revision(items)) throw new Error("Memory plugin configuration changed during preview; refresh and retry.");
|
|
@@ -8762,8 +9333,9 @@ var MemoryPluginManagement = class {
|
|
|
8762
9333
|
}
|
|
8763
9334
|
}
|
|
8764
9335
|
async apply(config, scope, request, signal) {
|
|
9336
|
+
await this.settled();
|
|
8765
9337
|
return this.exclusive(async () => {
|
|
8766
|
-
if (!this.
|
|
9338
|
+
if (!this.settingsService.writable || !this.loader()) throw new Error("Memory plugin configuration is read-only");
|
|
8767
9339
|
const items = await this.managed();
|
|
8768
9340
|
const choices = this.validateRequest(items, request);
|
|
8769
9341
|
const expectedSettingsRevision = this.settingsRevision();
|
|
@@ -8775,19 +9347,38 @@ var MemoryPluginManagement = class {
|
|
|
8775
9347
|
...request.entries
|
|
8776
9348
|
}
|
|
8777
9349
|
});
|
|
8778
|
-
|
|
8779
|
-
|
|
8780
|
-
|
|
8781
|
-
|
|
8782
|
-
|
|
8783
|
-
|
|
8784
|
-
|
|
8785
|
-
|
|
8786
|
-
|
|
8787
|
-
|
|
8788
|
-
|
|
8789
|
-
|
|
9350
|
+
let committedRevision;
|
|
9351
|
+
await this.updateEntries(items, choices, {
|
|
9352
|
+
validate: () => this.evaluateSnapshot(this.engine.contributionSnapshot(), config, scope, request.strategyTypeId, signal),
|
|
9353
|
+
persist: async () => {
|
|
9354
|
+
await this.settingsService.mutate(this.settingsNamespace, [{
|
|
9355
|
+
op: "set",
|
|
9356
|
+
path: ["strategyTypeId"],
|
|
9357
|
+
value: next.strategyTypeId
|
|
9358
|
+
}, {
|
|
9359
|
+
op: "set",
|
|
9360
|
+
path: ["entries"],
|
|
9361
|
+
value: next.entries
|
|
9362
|
+
}], expectedSettingsRevision);
|
|
9363
|
+
committedRevision = this.settingsRevision();
|
|
9364
|
+
},
|
|
9365
|
+
compensate: async () => {
|
|
9366
|
+
if (hash(preferences(this.settings.get())) !== hash(next)) throw new Error("Memory plugin settings changed before rollback; refresh and inspect the saved configuration.");
|
|
9367
|
+
await this.settingsService.mutate(this.settingsNamespace, [previous.strategyTypeId === void 0 ? {
|
|
9368
|
+
op: "unset",
|
|
9369
|
+
path: ["strategyTypeId"]
|
|
9370
|
+
} : {
|
|
9371
|
+
op: "set",
|
|
9372
|
+
path: ["strategyTypeId"],
|
|
9373
|
+
value: previous.strategyTypeId
|
|
9374
|
+
}, {
|
|
9375
|
+
op: "set",
|
|
9376
|
+
path: ["entries"],
|
|
9377
|
+
value: previous.entries
|
|
9378
|
+
}], committedRevision);
|
|
9379
|
+
}
|
|
8790
9380
|
}, signal);
|
|
9381
|
+
this.restoreError = void 0;
|
|
8791
9382
|
});
|
|
8792
9383
|
}
|
|
8793
9384
|
async restore() {
|
|
@@ -8814,55 +9405,99 @@ var MemoryPluginManagement = class {
|
|
|
8814
9405
|
this.restoreError = void 0;
|
|
8815
9406
|
}
|
|
8816
9407
|
async updateEntries(items, choices, commit, signal) {
|
|
8817
|
-
const
|
|
8818
|
-
|
|
8819
|
-
|
|
8820
|
-
|
|
8821
|
-
|
|
8822
|
-
|
|
8823
|
-
})
|
|
8824
|
-
const
|
|
9408
|
+
const previous = items.map((item) => ({
|
|
9409
|
+
item,
|
|
9410
|
+
disabled: item.entry.options.disabled ?? null,
|
|
9411
|
+
config: clone(item.entry.options.config ?? {}),
|
|
9412
|
+
enabled: item.value.enabled,
|
|
9413
|
+
active: item.value.active
|
|
9414
|
+
}));
|
|
9415
|
+
const touched = /* @__PURE__ */ new Set();
|
|
9416
|
+
const replay = async (current) => {
|
|
9417
|
+
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);
|
|
9418
|
+
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));
|
|
9419
|
+
for (const item of ordered) {
|
|
9420
|
+
signal?.throwIfAborted();
|
|
9421
|
+
if (this.closed) throw new Error("Memory plugin management service is disposed");
|
|
9422
|
+
const desired = choices.get(item.entry.id);
|
|
9423
|
+
const actual = {
|
|
9424
|
+
enabled: !item.entry.disabled,
|
|
9425
|
+
config: item.editor === void 0 ? {} : memoryStrategyConfigurationValues(item.editor, item.entry.options.config)
|
|
9426
|
+
};
|
|
9427
|
+
const active = contributionRoles(this.engine.contributionSnapshot(), item.entry.id).length > 0;
|
|
9428
|
+
if (hash(desired) === hash(actual) && active === desired.enabled) continue;
|
|
9429
|
+
touched.add(item.entry.id);
|
|
9430
|
+
await item.entry.update(item.editor === void 0 ? { disabled: !desired.enabled } : {
|
|
9431
|
+
disabled: !desired.enabled,
|
|
9432
|
+
config: clone(desired.config)
|
|
9433
|
+
});
|
|
9434
|
+
await item.entry.fiber?.await?.();
|
|
9435
|
+
const registered = contributionRoles(this.engine.contributionSnapshot(), item.entry.id).length > 0;
|
|
9436
|
+
if (item.entry.disabled === desired.enabled || registered !== desired.enabled) throw new Error("Cordis did not register the requested memory plugin state: " + item.entry.id);
|
|
9437
|
+
}
|
|
9438
|
+
};
|
|
9439
|
+
let persisted = false;
|
|
8825
9440
|
this.changingEntries = true;
|
|
8826
9441
|
try {
|
|
8827
9442
|
await this.engine.batch(async () => {
|
|
8828
9443
|
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
|
-
}
|
|
9444
|
+
await replay(items);
|
|
8846
9445
|
signal?.throwIfAborted();
|
|
8847
9446
|
if (this.closed) throw new Error("Memory plugin management service is disposed");
|
|
8848
|
-
|
|
9447
|
+
if (commit !== void 0) {
|
|
9448
|
+
await commit.validate();
|
|
9449
|
+
await commit.persist();
|
|
9450
|
+
persisted = true;
|
|
9451
|
+
const entries = new Map(Array.from(this.loader()?.entries() ?? []).map((entry) => [entry.id, entry]));
|
|
9452
|
+
await replay(items.flatMap((item) => {
|
|
9453
|
+
const entry = entries.get(item.entry.id);
|
|
9454
|
+
return entry === void 0 ? [] : [{
|
|
9455
|
+
...item,
|
|
9456
|
+
entry
|
|
9457
|
+
}];
|
|
9458
|
+
}));
|
|
9459
|
+
await commit.validate();
|
|
9460
|
+
}
|
|
8849
9461
|
} catch (error) {
|
|
8850
9462
|
const failures = [];
|
|
8851
|
-
|
|
8852
|
-
await
|
|
8853
|
-
disabled: previous.disabled,
|
|
8854
|
-
config: previous.config
|
|
8855
|
-
});
|
|
8856
|
-
await previous.item.entry.fiber?.await?.();
|
|
9463
|
+
if (persisted) try {
|
|
9464
|
+
await commit.compensate();
|
|
8857
9465
|
} catch (rollback) {
|
|
8858
9466
|
failures.push(rollback);
|
|
8859
9467
|
}
|
|
8860
|
-
|
|
9468
|
+
const current = new Map(Array.from(this.loader()?.entries() ?? []).map((entry) => [entry.id, entry]));
|
|
9469
|
+
for (const before of previous.reverse()) {
|
|
9470
|
+
const entry = current.get(before.item.entry.id);
|
|
9471
|
+
if (!(entry === void 0 || hash({
|
|
9472
|
+
disabled: entry.options.disabled ?? null,
|
|
9473
|
+
config: entry.options.config ?? {}
|
|
9474
|
+
}) !== hash({
|
|
9475
|
+
disabled: before.disabled,
|
|
9476
|
+
config: before.config
|
|
9477
|
+
}) || !entry.disabled !== before.enabled || contributionRoles(this.engine.contributionSnapshot(), before.item.entry.id).length > 0 !== before.active) && !touched.has(before.item.entry.id)) continue;
|
|
9478
|
+
try {
|
|
9479
|
+
if (entry === void 0) throw new Error("Memory plugin Entry is unavailable for rollback: " + before.item.entry.id);
|
|
9480
|
+
await entry.update(before.item.editor === void 0 ? { disabled: before.disabled } : {
|
|
9481
|
+
disabled: before.disabled,
|
|
9482
|
+
config: before.config
|
|
9483
|
+
});
|
|
9484
|
+
await entry.fiber?.await?.();
|
|
9485
|
+
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);
|
|
9486
|
+
} catch (rollback) {
|
|
9487
|
+
failures.push(rollback);
|
|
9488
|
+
}
|
|
9489
|
+
}
|
|
9490
|
+
if (failures.length) {
|
|
9491
|
+
this.restorePending = false;
|
|
9492
|
+
this.restoreError = "Plugin change failed and rollback was incomplete; inspect DSH plugin state.";
|
|
9493
|
+
throw new AggregateError([error, ...failures], this.restoreError);
|
|
9494
|
+
}
|
|
8861
9495
|
throw error;
|
|
8862
9496
|
}
|
|
8863
9497
|
});
|
|
8864
9498
|
} finally {
|
|
8865
9499
|
this.changingEntries = false;
|
|
9500
|
+
if (this.restorePending) this.scheduleRestore(true);
|
|
8866
9501
|
}
|
|
8867
9502
|
}
|
|
8868
9503
|
exclusive(operation) {
|
|
@@ -9437,19 +10072,21 @@ function optionalWorkspaceRegistry(ctx) {
|
|
|
9437
10072
|
};
|
|
9438
10073
|
}
|
|
9439
10074
|
/** DSH owns assembly; this Host only wires scope, phases and user preferences. */
|
|
9440
|
-
function apply(rawContext,
|
|
10075
|
+
function apply(rawContext, rawConfig = {}) {
|
|
9441
10076
|
const ctx = rawContext;
|
|
10077
|
+
const config = plainHostConfig(rawConfig);
|
|
10078
|
+
const hostSettings = createHostSettings(ctx, rawConfig);
|
|
9442
10079
|
registerMnemonSubagentTokenUsageProjection(ctx);
|
|
9443
10080
|
const extensions = provideMemoryRuntime(ctx);
|
|
9444
|
-
const memoryPlugins = new MemoryPluginManagement(ctx, extensions);
|
|
10081
|
+
const memoryPlugins = new MemoryPluginManagement(ctx, extensions, hostSettings);
|
|
9445
10082
|
const pluginInstallation = new MemoryPluginInstallation(ctx);
|
|
9446
|
-
const effectiveConfig = (value) => memoryPlugins.resolveConfig(resolveConfig(value));
|
|
10083
|
+
const effectiveConfig = (value) => memoryPlugins.resolveConfig(resolveConfig(value), hostSettings instanceof ProfileMnemonSettings ? value.memoryView ?? { entries: {} } : void 0);
|
|
9447
10084
|
const prepared = /* @__PURE__ */ new Map();
|
|
9448
10085
|
const disposePrepared = () => {
|
|
9449
10086
|
for (const candidate of prepared.values()) candidate.graph.dispose();
|
|
9450
10087
|
prepared.clear();
|
|
9451
10088
|
};
|
|
9452
|
-
const settings =
|
|
10089
|
+
const settings = hostSettings.register("mnemon", Config, {
|
|
9453
10090
|
base: config,
|
|
9454
10091
|
applies: "live",
|
|
9455
10092
|
validate: (value) => {
|
|
@@ -9458,6 +10095,10 @@ function apply(rawContext, config = {}) {
|
|
|
9458
10095
|
graph: createRuntimeGraph(effectiveConfig(value), void 0, extensions),
|
|
9459
10096
|
token: Symbol("prepared-runtime")
|
|
9460
10097
|
};
|
|
10098
|
+
if (hostSettings instanceof ProfileMnemonSettings) {
|
|
10099
|
+
candidate.graph.dispose();
|
|
10100
|
+
return;
|
|
10101
|
+
}
|
|
9461
10102
|
prepared.set(value, candidate);
|
|
9462
10103
|
queueMicrotask(() => {
|
|
9463
10104
|
if (prepared.get(value)?.token !== candidate.token) return;
|
|
@@ -9471,7 +10112,8 @@ function apply(rawContext, config = {}) {
|
|
|
9471
10112
|
if (initialCandidate !== void 0) prepared.delete(initialSettings);
|
|
9472
10113
|
const runtime = new LiveMnemonRuntime(initialCandidate?.graph ?? createRuntimeGraph(effectiveConfig(initialSettings), void 0, extensions), optionalWorkspaceRegistry(ctx), ctx.agents, extensions);
|
|
9473
10114
|
const resolved = runtime.config;
|
|
9474
|
-
ctx.
|
|
10115
|
+
ctx.effect(() => subscribeSettings(ctx, hostSettings, (namespace, value) => {
|
|
10116
|
+
const next = value;
|
|
9475
10117
|
if (namespace === memoryPlugins.settingsNamespace) {
|
|
9476
10118
|
runtime.swap(createRuntimeGraph(effectiveConfig(settings.get()), void 0, extensions));
|
|
9477
10119
|
return;
|
|
@@ -9481,9 +10123,9 @@ function apply(rawContext, config = {}) {
|
|
|
9481
10123
|
if (candidate !== void 0) prepared.delete(next);
|
|
9482
10124
|
disposePrepared();
|
|
9483
10125
|
runtime.swap(candidate?.graph ?? createRuntimeGraph(effectiveConfig(next), void 0, extensions));
|
|
9484
|
-
}));
|
|
10126
|
+
}), "dsh-mnemon: live runtime settings");
|
|
9485
10127
|
ctx.effect(() => memoryPlugins.start(), "dsh-mnemon: plugin graph settings");
|
|
9486
|
-
|
|
10128
|
+
hostSettings.register("mnemon-ui", InteractionConfig, {
|
|
9487
10129
|
base: resolveInteractionConfig(resolved.conversationInteraction),
|
|
9488
10130
|
applies: "live"
|
|
9489
10131
|
});
|
|
@@ -9491,7 +10133,7 @@ function apply(rawContext, config = {}) {
|
|
|
9491
10133
|
let disposed = false;
|
|
9492
10134
|
const migrate = () => {
|
|
9493
10135
|
if (disposed) return;
|
|
9494
|
-
migrateLegacyDisplayMode(
|
|
10136
|
+
migrateLegacyDisplayMode(hostSettings).catch((error) => {
|
|
9495
10137
|
console.warn("dsh-mnemon: could not persist the builtin displayMode migration", error);
|
|
9496
10138
|
});
|
|
9497
10139
|
};
|
|
@@ -9504,6 +10146,21 @@ function apply(rawContext, config = {}) {
|
|
|
9504
10146
|
unsubscribe();
|
|
9505
10147
|
};
|
|
9506
10148
|
}, "dsh-mnemon: canonical displayMode migration");
|
|
10149
|
+
if (hostSettings instanceof ProfileMnemonSettings) ctx.effect(() => {
|
|
10150
|
+
let disposed = false;
|
|
10151
|
+
const loader = ctx.get("loader");
|
|
10152
|
+
Promise.resolve(loader?.await?.()).then(async () => {
|
|
10153
|
+
if (disposed) return;
|
|
10154
|
+
const catalog = await memoryPlugins.catalog();
|
|
10155
|
+
if (disposed) return;
|
|
10156
|
+
await hostSettings.importLegacy(catalog.entries.filter((entry) => entry.roles.includes("source")).map((entry) => entry.entryId));
|
|
10157
|
+
}).catch((error) => {
|
|
10158
|
+
console.warn("dsh-mnemon: could not recover retained legacy settings", error);
|
|
10159
|
+
});
|
|
10160
|
+
return () => {
|
|
10161
|
+
disposed = true;
|
|
10162
|
+
};
|
|
10163
|
+
}, "dsh-mnemon: retained settings migration");
|
|
9507
10164
|
const coordinator = new MnemonSubagentCoordinator(ctx.subagents, runtime, ctx, () => {
|
|
9508
10165
|
const taskAgentModel = runtime.config.taskAgentModel;
|
|
9509
10166
|
if (taskAgentModel.mode !== "fixed") return void 0;
|
|
@@ -9532,7 +10189,7 @@ function apply(rawContext, config = {}) {
|
|
|
9532
10189
|
if (webContext.connection === void 0) return;
|
|
9533
10190
|
const managementAuthority = resolved.remoteAccess === "trusted-host" ? "trusted-host" : "loopback";
|
|
9534
10191
|
const rpc = registerRpc(webContext.connection, runtime, lifecycle, void 0, managementAuthority);
|
|
9535
|
-
const settings = registerSettingsRpc(webContext.connection,
|
|
10192
|
+
const settings = registerSettingsRpc(webContext.connection, hostSettings, managementAuthority);
|
|
9536
10193
|
const view = registerViewRpc(webContext.connection, runtime, extensions, memoryPlugins, lifecycle, managementAuthority, pluginInstallation);
|
|
9537
10194
|
if (Context.is(webContext)) new MnemonRemoteService(webContext, {
|
|
9538
10195
|
...rpc,
|
|
@@ -9544,4 +10201,4 @@ function apply(rawContext, config = {}) {
|
|
|
9544
10201
|
});
|
|
9545
10202
|
}
|
|
9546
10203
|
//#endregion
|
|
9547
|
-
export { Config, apply, inject, name, provide };
|
|
10204
|
+
export { LiveConfig as Config, apply, inject, name, provide };
|