dsh-mnemon 0.5.16 → 0.5.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -8
- package/README.zh-CN.md +11 -9
- package/cordis.patch.yml +6 -1
- package/lib/client.js +7299 -4437
- package/lib/contracts.js +45 -2
- package/lib/core.js +1 -1
- package/lib/{definitions-CSPV0ER1.js → definitions-j9QPbrXb.js} +16 -3
- package/lib/extension-sdk.js +75 -5
- package/lib/index.js +1140 -1095
- package/lib/{runtime-BEX0sc1z.js → runtime-Bk6lFgxd.js} +44 -19
- package/lib/{strategy-configuration-D8IEKZdS.js → strategy-configuration-sVkKToSW.js} +1 -1
- package/lib/testing.js +3 -3
- package/lib/types/src/client/component-ui.d.ts +118 -0
- package/lib/types/src/client/extension-sdk.d.ts +1 -0
- package/lib/types/src/client/locales.d.ts +174 -154
- package/lib/types/src/client/source-pages.d.ts +2 -2
- package/lib/types/src/client/ui-icons.d.ts +3 -4
- package/lib/types/src/core/contracts/view.d.ts +28 -2
- package/lib/types/src/host/config.d.ts +1 -1
- package/lib/types/src/host/live-config.d.ts +4 -4
- package/lib/types/src/host/protocol.d.ts +16 -8
- package/lib/types/src/host/view-protocol.d.ts +6 -1
- package/lib/types/src/sdk/index.d.ts +2 -1
- package/lib/types/src/sdk/testing.d.ts +1 -0
- package/lib/types/src/sdk/view-extensions.d.ts +12 -0
- package/locale/zh.json +2 -2
- package/package.json +63 -61
- package/lib/contracts-D4ghDRK4.js +0 -35
package/lib/index.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { f as withMemoryStorageLock, n as memoryStrategyConfigurationValues, r as readMemoryStrategyConfiguration, s as receipt } from "./strategy-configuration-
|
|
2
|
-
import { a as
|
|
3
|
-
import {
|
|
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-sVkKToSW.js";
|
|
2
|
+
import { a as validateMemoryPluginGraph, i as captureMemoryContributionSnapshot, n as isMemoryCompositionUnavailable, o as prepareMemoryContributions, r as MemoryCompositionGeneration, t as provideMemoryRuntime } from "./runtime-Bk6lFgxd.js";
|
|
3
|
+
import { DEFAULT_MEMORY_VIEW_BUDGET, MEMORY_CAPABILITIES } from "./contracts.js";
|
|
4
|
+
import { r as defineMemoryPlugin, t as canonicalMemoryJson } from "./definitions-j9QPbrXb.js";
|
|
5
5
|
import { Context } from "@deepseek-ai/cordis";
|
|
6
|
-
import z from "schemastery";
|
|
6
|
+
import z from "@deepseek-ai/schemastery";
|
|
7
7
|
import { basename, delimiter, dirname, isAbsolute, join, normalize, resolve } from "node:path";
|
|
8
8
|
import { resolveEmbedding, resolvePersistenceStrategy, resolveRecallQuality } from "dsh-mnemon-source-memory-spaces";
|
|
9
9
|
import { createHash, randomUUID } from "node:crypto";
|
|
@@ -19,10 +19,10 @@ import { findMnemonCommand, mnemonNpmLauncher, nodeLauncherEnvironment } from "d
|
|
|
19
19
|
import { spawn } from "node:child_process";
|
|
20
20
|
import { StringDecoder } from "node:string_decoder";
|
|
21
21
|
import { z as z$1 } from "zod";
|
|
22
|
+
import { Remote, TypertRemoteService } from "@deepseek-ai/dsh-typert-protocol";
|
|
23
|
+
import { isVolatile } from "@deepseek-ai/cosmokit";
|
|
22
24
|
import { readFile, stat } from "node:fs/promises";
|
|
23
25
|
import { parseDocument } from "yaml";
|
|
24
|
-
import * as cosmokit from "@deepseek-ai/cosmokit";
|
|
25
|
-
import { Remote, TypertRemoteService } from "@deepseek-ai/dsh-typert-protocol";
|
|
26
26
|
//#region src/host/view-protocol.ts
|
|
27
27
|
const MNEMON_VIEW_CHANNEL = "/dsh-mnemon-view";
|
|
28
28
|
const MNEMON_VIEW_WRITE_CHANNEL = "/dsh-mnemon-view-settings";
|
|
@@ -61,6 +61,12 @@ const DEFAULT_IDLE_REVIEW = {
|
|
|
61
61
|
maxContextChars: 24e3,
|
|
62
62
|
maxTokens: 4096
|
|
63
63
|
};
|
|
64
|
+
/** The Sources that keep their data in Mnemon's data directory, in the order a backup lists them. */
|
|
65
|
+
const MNEMON_PACK_COMPONENTS = [
|
|
66
|
+
"runtime",
|
|
67
|
+
"documents",
|
|
68
|
+
"memory-spaces"
|
|
69
|
+
];
|
|
64
70
|
const CATEGORIES = [
|
|
65
71
|
"preference",
|
|
66
72
|
"decision",
|
|
@@ -119,7 +125,7 @@ function preferences(value) {
|
|
|
119
125
|
for (const [entryId, item] of Object.entries(entries)) {
|
|
120
126
|
if (!ENTRY_ID$1.test(entryId)) throw new Error("Invalid memory plugin Entry id");
|
|
121
127
|
const candidate = record$3(item);
|
|
122
|
-
if (typeof candidate.enabled !== "boolean") throw new Error("Plugin enabled must be boolean");
|
|
128
|
+
if (candidate.enabled !== void 0 && typeof candidate.enabled !== "boolean") throw new Error("Plugin enabled must be boolean");
|
|
123
129
|
record$3(candidate.config);
|
|
124
130
|
}
|
|
125
131
|
return clone$2(value);
|
|
@@ -474,6 +480,59 @@ function resolveConfig(config = {}) {
|
|
|
474
480
|
};
|
|
475
481
|
}
|
|
476
482
|
//#endregion
|
|
483
|
+
//#region src/host/workspace-storage.ts
|
|
484
|
+
/** Host workspace identity, including aliases with not-yet-created descendants. */
|
|
485
|
+
function canonicalWorkspacePath(workspacePath) {
|
|
486
|
+
if (!isAbsolute(workspacePath) || workspacePath.includes("\0")) throw new Error("Workspace path must be absolute");
|
|
487
|
+
let parent = resolve(workspacePath);
|
|
488
|
+
const suffix = [];
|
|
489
|
+
for (;;) {
|
|
490
|
+
let real;
|
|
491
|
+
try {
|
|
492
|
+
real = realpathSync.native(parent);
|
|
493
|
+
} catch (error) {
|
|
494
|
+
if (error.code !== "ENOENT") throw error;
|
|
495
|
+
const next = dirname(parent);
|
|
496
|
+
if (next === parent) throw error;
|
|
497
|
+
suffix.unshift(parent.slice(next.length).replace(/^[/\\]+/u, ""));
|
|
498
|
+
parent = next;
|
|
499
|
+
continue;
|
|
500
|
+
}
|
|
501
|
+
if (suffix.length > 0 && !statSync(real).isDirectory()) throw Object.assign(/* @__PURE__ */ new Error(`ENOTDIR: not a directory, realpath '${parent}'`), {
|
|
502
|
+
code: "ENOTDIR",
|
|
503
|
+
path: parent,
|
|
504
|
+
syscall: "realpath"
|
|
505
|
+
});
|
|
506
|
+
return join(real, ...suffix);
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
/** A rename or move selects a new directory; resolving identity never writes. */
|
|
510
|
+
function workspaceStorageId(workspacePath) {
|
|
511
|
+
return createHash("sha256").update(canonicalWorkspacePath(workspacePath)).digest("hex");
|
|
512
|
+
}
|
|
513
|
+
//#endregion
|
|
514
|
+
//#region src/host/storage-root.ts
|
|
515
|
+
function expandDirectory(value) {
|
|
516
|
+
return resolve(value === "~" ? homedir() : value.startsWith("~/") ? join(homedir(), value.slice(2)) : value);
|
|
517
|
+
}
|
|
518
|
+
/** Host owns every built-in layout; Sources own the data within the chosen root. */
|
|
519
|
+
function storageDirectory(config, workspaceRoot) {
|
|
520
|
+
const globalRoot = process.env.MNEMON_DATA_DIR?.trim() || "~/.mnemon";
|
|
521
|
+
switch (config.storageScope) {
|
|
522
|
+
case "global": return expandDirectory(globalRoot);
|
|
523
|
+
case "custom": return expandDirectory(config.dataDir);
|
|
524
|
+
case "workspace": return resolve(workspaceRoot ?? process.cwd(), ".mnemon");
|
|
525
|
+
case "workspaces": return join(expandDirectory(config.dataDir ?? globalRoot), "workspaces", workspaceStorageId(resolve(workspaceRoot ?? process.cwd())));
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
function createStorageRoot(config, workspaceRoot) {
|
|
529
|
+
const directory = storageDirectory(config, workspaceRoot);
|
|
530
|
+
return {
|
|
531
|
+
effectiveDataDir: () => directory,
|
|
532
|
+
withExclusive: (operation) => withMemoryStorageLock(directory, operation)
|
|
533
|
+
};
|
|
534
|
+
}
|
|
535
|
+
//#endregion
|
|
477
536
|
//#region src/host/pack.ts
|
|
478
537
|
const MNEMON_PACK_FORMAT = "mnemonpack";
|
|
479
538
|
const MNEMON_PACK_MIME = "application/zip";
|
|
@@ -487,11 +546,7 @@ const COMPONENT_DIRECTORIES = {
|
|
|
487
546
|
documents: "documents",
|
|
488
547
|
"memory-spaces": "data"
|
|
489
548
|
};
|
|
490
|
-
const COMPONENT_ORDER =
|
|
491
|
-
"runtime",
|
|
492
|
-
"documents",
|
|
493
|
-
"memory-spaces"
|
|
494
|
-
];
|
|
549
|
+
const COMPONENT_ORDER = MNEMON_PACK_COMPONENTS;
|
|
495
550
|
const BODY_ID = /^[a-zA-Z0-9][a-zA-Z0-9_-]*$/;
|
|
496
551
|
const SQLITE_HEADER = Buffer.from("SQLite format 3\0", "binary");
|
|
497
552
|
function record$2(value) {
|
|
@@ -1175,7 +1230,8 @@ var MnemonPackManager = class {
|
|
|
1175
1230
|
target() {
|
|
1176
1231
|
return {
|
|
1177
1232
|
root: this.root,
|
|
1178
|
-
scope: this.config.storageScope
|
|
1233
|
+
scope: this.config.storageScope,
|
|
1234
|
+
defaultRoot: resolve(createStorageRoot({ storageScope: "global" }).effectiveDataDir())
|
|
1179
1235
|
};
|
|
1180
1236
|
}
|
|
1181
1237
|
async exportPack(scope) {
|
|
@@ -1264,59 +1320,6 @@ var MnemonPackManager = class {
|
|
|
1264
1320
|
}
|
|
1265
1321
|
};
|
|
1266
1322
|
//#endregion
|
|
1267
|
-
//#region src/host/workspace-storage.ts
|
|
1268
|
-
/** Host workspace identity, including aliases with not-yet-created descendants. */
|
|
1269
|
-
function canonicalWorkspacePath(workspacePath) {
|
|
1270
|
-
if (!isAbsolute(workspacePath) || workspacePath.includes("\0")) throw new Error("Workspace path must be absolute");
|
|
1271
|
-
let parent = resolve(workspacePath);
|
|
1272
|
-
const suffix = [];
|
|
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);
|
|
1291
|
-
}
|
|
1292
|
-
}
|
|
1293
|
-
/** A rename or move selects a new directory; resolving identity never writes. */
|
|
1294
|
-
function workspaceStorageId(workspacePath) {
|
|
1295
|
-
return createHash("sha256").update(canonicalWorkspacePath(workspacePath)).digest("hex");
|
|
1296
|
-
}
|
|
1297
|
-
//#endregion
|
|
1298
|
-
//#region src/host/storage-root.ts
|
|
1299
|
-
function expandDirectory(value) {
|
|
1300
|
-
return resolve(value === "~" ? homedir() : value.startsWith("~/") ? join(homedir(), value.slice(2)) : value);
|
|
1301
|
-
}
|
|
1302
|
-
/** Host owns every built-in layout; Sources own the data within the chosen root. */
|
|
1303
|
-
function storageDirectory(config, workspaceRoot) {
|
|
1304
|
-
const globalRoot = process.env.MNEMON_DATA_DIR?.trim() || "~/.mnemon";
|
|
1305
|
-
switch (config.storageScope) {
|
|
1306
|
-
case "global": return expandDirectory(globalRoot);
|
|
1307
|
-
case "custom": return expandDirectory(config.dataDir);
|
|
1308
|
-
case "workspace": return resolve(workspaceRoot ?? process.cwd(), ".mnemon");
|
|
1309
|
-
case "workspaces": return join(expandDirectory(config.dataDir ?? globalRoot), "workspaces", workspaceStorageId(resolve(workspaceRoot ?? process.cwd())));
|
|
1310
|
-
}
|
|
1311
|
-
}
|
|
1312
|
-
function createStorageRoot(config, workspaceRoot) {
|
|
1313
|
-
const directory = storageDirectory(config, workspaceRoot);
|
|
1314
|
-
return {
|
|
1315
|
-
effectiveDataDir: () => directory,
|
|
1316
|
-
withExclusive: (operation) => withMemoryStorageLock(directory, operation)
|
|
1317
|
-
};
|
|
1318
|
-
}
|
|
1319
|
-
//#endregion
|
|
1320
1323
|
//#region src/host/storage-scope.ts
|
|
1321
1324
|
function expandHome(path) {
|
|
1322
1325
|
if (path === "~") return homedir();
|
|
@@ -2184,6 +2187,7 @@ function memoryGenerationOptions(config, workspaceRoot) {
|
|
|
2184
2187
|
const userDirectory = config.runtimeUserScope === "global" ? createStorageRoot({ storageScope: "global" }).effectiveDataDir() : directory;
|
|
2185
2188
|
return {
|
|
2186
2189
|
strategyTypeId: config.memoryTopology.strategyId,
|
|
2190
|
+
strategyFallback: "sole-strategy",
|
|
2187
2191
|
sourceTimeoutMs: config.timeoutMs,
|
|
2188
2192
|
sourceCapabilities: (installed) => MEMORY_CAPABILITIES.filter((capability) => (config.writeEnabled || ![
|
|
2189
2193
|
"write",
|
|
@@ -2474,12 +2478,13 @@ async function execute(serviceOrSource, coordinator, invocation) {
|
|
|
2474
2478
|
text: `Mnemon 不可用:${status.error ?? "未知错误"}`
|
|
2475
2479
|
};
|
|
2476
2480
|
const stats = status.stats;
|
|
2481
|
+
const nativeInstalled = status.commandFound !== false;
|
|
2477
2482
|
return {
|
|
2478
2483
|
kind: "success",
|
|
2479
2484
|
text: [
|
|
2480
|
-
`Mnemon ${status.version ?? ""} · default=${status.mnemonDefaultStore}`.trim(),
|
|
2485
|
+
nativeInstalled ? `Mnemon ${status.version ?? ""} · default=${status.mnemonDefaultStore}`.trim() : "Mnemon Native: 未安装 CLI(可选,其他 Provider 不受影响)",
|
|
2481
2486
|
`DSH 已激活: ${status.dshActiveStores.join(", ") || "none"}`,
|
|
2482
|
-
`CLI: ${status.cliPath}
|
|
2487
|
+
...nativeInstalled ? [`CLI: ${status.cliPath}`] : [],
|
|
2483
2488
|
`数据目录: ${status.dataDir}`,
|
|
2484
2489
|
`有效记忆: ${stats?.totalInsights ?? 0} · 连接: ${stats?.edgeCount ?? 0} · 已删除: ${stats?.deletedInsights ?? 0}`,
|
|
2485
2490
|
`模式: ${status.writeEnabled ? "读写" : "只读"} · 默认召回: ${status.defaultRecallLimit}`
|
|
@@ -2595,11 +2600,14 @@ function applyMemoryViewGuidance(assembly, view, routingEnabled = true) {
|
|
|
2595
2600
|
sections
|
|
2596
2601
|
});
|
|
2597
2602
|
}
|
|
2603
|
+
/** Register once the prompt service is active; Cordis re-runs this if the service is replaced. */
|
|
2598
2604
|
function registerGuidance(ctx, config) {
|
|
2599
|
-
ctx.
|
|
2600
|
-
|
|
2601
|
-
|
|
2602
|
-
|
|
2605
|
+
ctx.inject(["systemPrompt"], (prompted) => {
|
|
2606
|
+
prompted.get("systemPrompt").section({
|
|
2607
|
+
name: GUIDANCE_SECTION_NAME,
|
|
2608
|
+
order: 150,
|
|
2609
|
+
text: () => config?.routingGuidance === false ? "" : ROUTING_GUIDANCE
|
|
2610
|
+
});
|
|
2603
2611
|
});
|
|
2604
2612
|
}
|
|
2605
2613
|
//#endregion
|
|
@@ -2669,36 +2677,13 @@ function mutationResultCommitted(result) {
|
|
|
2669
2677
|
return COMMITTED_MUTATION_COUNTS.some((key) => typeof value[key] === "number" && Number.isFinite(value[key]) && value[key] > 0);
|
|
2670
2678
|
}
|
|
2671
2679
|
//#endregion
|
|
2672
|
-
//#region src/host/session-events.ts
|
|
2673
|
-
function eventArray(value) {
|
|
2674
|
-
return Array.isArray(value) ? value : void 0;
|
|
2675
|
-
}
|
|
2676
|
-
/**
|
|
2677
|
-
* Materialize one immutable event-log snapshot across supported DSH releases.
|
|
2678
|
-
* Capability detection keeps alpha and stable rc behavior on one code path.
|
|
2679
|
-
*/
|
|
2680
|
-
function hostSessionEvents(session) {
|
|
2681
|
-
if (typeof session.snapshotEvents === "function") {
|
|
2682
|
-
const events = eventArray(session.snapshotEvents());
|
|
2683
|
-
if (events !== void 0) return events;
|
|
2684
|
-
}
|
|
2685
|
-
const events = eventArray(session.events);
|
|
2686
|
-
if (events !== void 0) return events;
|
|
2687
|
-
throw new TypeError("Unsupported DSH Session event API: expected snapshotEvents() or events[]");
|
|
2688
|
-
}
|
|
2689
|
-
/** Read one exact event without materializing the alpha log when possible. */
|
|
2690
|
-
function hostSessionEventAt(session, seq) {
|
|
2691
|
-
if (typeof session.eventAt === "function") return session.eventAt(seq);
|
|
2692
|
-
return hostSessionEvents(session)[seq];
|
|
2693
|
-
}
|
|
2694
|
-
//#endregion
|
|
2695
2680
|
//#region src/host/review-tools.ts
|
|
2696
2681
|
const startingReview = new AsyncLocalStorage();
|
|
2697
2682
|
/**
|
|
2698
|
-
*
|
|
2699
|
-
*
|
|
2700
|
-
*
|
|
2701
|
-
*
|
|
2683
|
+
* Pausing stays the conservative default while Team tools are installed; the
|
|
2684
|
+
* operator can select scoped review instead (verified with DSH/Teams
|
|
2685
|
+
* 0.1.7-rc.2). That opt-in still requires startGuardedReview; it never removes
|
|
2686
|
+
* another plugin's policy.
|
|
2702
2687
|
*/
|
|
2703
2688
|
function idleReviewBlockReason(parent, agentTeams = "pause") {
|
|
2704
2689
|
return agentTeams !== "scoped" && parent.ctx?.get?.("agentTeams") !== void 0 && parent.ctx.tools?.get?.("spawn_teammate", parent) !== void 0 ? "agent-team" : void 0;
|
|
@@ -2797,9 +2782,8 @@ function textContent(content, toolResult = false) {
|
|
|
2797
2782
|
}
|
|
2798
2783
|
/** Use only the current public surface, so rewound or compacted evidence cannot reappear. */
|
|
2799
2784
|
function reviewCheckpoint(session, maxChars) {
|
|
2800
|
-
const nodes = session.surface
|
|
2801
|
-
|
|
2802
|
-
const events = hostSessionEvents(session);
|
|
2785
|
+
const nodes = session.surface.nodes;
|
|
2786
|
+
const events = session.snapshotEvents();
|
|
2803
2787
|
const completed = [...events].reverse().find((event) => event.type === "turn/end");
|
|
2804
2788
|
if (completed === void 0) return "No completed checkpoint is available. Skip this review without a mutation.";
|
|
2805
2789
|
const end = completed.seq ?? events.indexOf(completed);
|
|
@@ -2808,7 +2792,7 @@ function reviewCheckpoint(session, maxChars) {
|
|
|
2808
2792
|
let remaining = maxChars - 122;
|
|
2809
2793
|
const candidates = nodes.filter((seq) => seq < end);
|
|
2810
2794
|
for (const seq of candidates.slice(-128).reverse()) {
|
|
2811
|
-
const event =
|
|
2795
|
+
const event = session.eventAt(seq);
|
|
2812
2796
|
if (event === void 0 || ![
|
|
2813
2797
|
"user/message",
|
|
2814
2798
|
"assistant/message",
|
|
@@ -2834,8 +2818,8 @@ function evidenceInsights(evidence) {
|
|
|
2834
2818
|
...optionalObject(item.provenance) ?? {},
|
|
2835
2819
|
id: item.id,
|
|
2836
2820
|
content: item.text,
|
|
2837
|
-
score: item.score,
|
|
2838
|
-
revision: item.revision
|
|
2821
|
+
...item.score === void 0 ? {} : { score: item.score },
|
|
2822
|
+
...item.revision === void 0 ? {} : { revision: item.revision }
|
|
2839
2823
|
};
|
|
2840
2824
|
});
|
|
2841
2825
|
}
|
|
@@ -3207,7 +3191,7 @@ function subagentFailureDetail(run, result) {
|
|
|
3207
3191
|
const diagnostic = safeFailureDetail(result.diagnostic);
|
|
3208
3192
|
if (diagnostic !== "") return diagnostic;
|
|
3209
3193
|
}
|
|
3210
|
-
const events = run.localAgent === void 0 ? [] :
|
|
3194
|
+
const events = run.localAgent === void 0 ? [] : run.localAgent.session.snapshotEvents();
|
|
3211
3195
|
for (let index = events.length - 1; index >= 0; index -= 1) {
|
|
3212
3196
|
const event = events[index];
|
|
3213
3197
|
if (event?.type !== "turn/end") continue;
|
|
@@ -3753,7 +3737,7 @@ var MnemonSubagentCoordinator = class {
|
|
|
3753
3737
|
const context = {
|
|
3754
3738
|
runtime,
|
|
3755
3739
|
inspectRuntime: runtime,
|
|
3756
|
-
maintain: threeTierActionWorkflow(
|
|
3740
|
+
maintain: threeTierActionWorkflow(lease.generation.strategy.definition.manifest.typeId, "runtime", "mutate") !== void 0,
|
|
3757
3741
|
commit: () => runtime.mutate("mutate", request, signal),
|
|
3758
3742
|
memorySpaces: async () => {
|
|
3759
3743
|
if (!graph.config.writeEnabled || !this.runtimeSource.config.writeEnabled) throw new Error("dsh-mnemon is configured read-only");
|
|
@@ -5071,7 +5055,7 @@ function inspectMemoryView(generation, view, state, turn, memoryText) {
|
|
|
5071
5055
|
/** The durable log, not a parent session id, identifies the executing turn. */
|
|
5072
5056
|
function openAgentTurn(agent) {
|
|
5073
5057
|
let open;
|
|
5074
|
-
for (const event of
|
|
5058
|
+
for (const event of agent.session.snapshotEvents()) {
|
|
5075
5059
|
const turn = typeof event.data.turn === "number" ? event.data.turn : void 0;
|
|
5076
5060
|
if (event.type === "turn/start" && turn !== void 0) open = turn;
|
|
5077
5061
|
else if (event.type === "turn/end" && turn === open) open = void 0;
|
|
@@ -5087,6 +5071,9 @@ var AgentMemoryTurn = class {
|
|
|
5087
5071
|
runtime;
|
|
5088
5072
|
delegation;
|
|
5089
5073
|
pinned;
|
|
5074
|
+
/** A turn that runs without memory because no composition was serving when it began. */
|
|
5075
|
+
unavailable;
|
|
5076
|
+
warned;
|
|
5090
5077
|
pending;
|
|
5091
5078
|
generation = 0;
|
|
5092
5079
|
closed = false;
|
|
@@ -5103,6 +5090,10 @@ var AgentMemoryTurn = class {
|
|
|
5103
5090
|
get current() {
|
|
5104
5091
|
return this.pinned;
|
|
5105
5092
|
}
|
|
5093
|
+
/** Why the current turn has no View, when memory could not be composed for it. */
|
|
5094
|
+
get unavailableReason() {
|
|
5095
|
+
return this.unavailable?.reason;
|
|
5096
|
+
}
|
|
5106
5097
|
inspect(workspaceRoot) {
|
|
5107
5098
|
if (this.lastInspection === void 0) return void 0;
|
|
5108
5099
|
if (workspaceRoot !== void 0 && resolve(workspaceRoot) !== this.lastWorkspace) return void 0;
|
|
@@ -5133,14 +5124,23 @@ var AgentMemoryTurn = class {
|
|
|
5133
5124
|
async begin(turn, signal) {
|
|
5134
5125
|
if (this.closed) throw new Error("memory Agent lifetime has ended");
|
|
5135
5126
|
signal?.throwIfAborted();
|
|
5136
|
-
if (this.pinned?.turn === turn) return;
|
|
5127
|
+
if (this.pinned?.turn === turn || this.unavailable?.turn === turn) return;
|
|
5137
5128
|
if (this.pending?.turn === turn) return this.pending.result;
|
|
5138
5129
|
this.end();
|
|
5139
5130
|
const generation = this.generation;
|
|
5140
5131
|
const controller = new AbortController();
|
|
5141
5132
|
const abort = () => controller.abort(signal.reason);
|
|
5142
5133
|
signal?.addEventListener("abort", abort, { once: true });
|
|
5143
|
-
const result = this.pin(turn, generation, controller.signal)
|
|
5134
|
+
const result = this.pin(turn, generation, controller.signal).catch((error) => {
|
|
5135
|
+
if (!isMemoryCompositionUnavailable(error) || this.closed || this.generation !== generation) throw error;
|
|
5136
|
+
this.unavailable = {
|
|
5137
|
+
turn,
|
|
5138
|
+
reason: error.message
|
|
5139
|
+
};
|
|
5140
|
+
this.clearInspection();
|
|
5141
|
+
if (this.warned !== error.message) console.warn(`[dsh-mnemon] this turn runs without memory: ${error.message}`);
|
|
5142
|
+
this.warned = error.message;
|
|
5143
|
+
});
|
|
5144
5144
|
this.pending = {
|
|
5145
5145
|
turn,
|
|
5146
5146
|
generation,
|
|
@@ -5155,8 +5155,9 @@ var AgentMemoryTurn = class {
|
|
|
5155
5155
|
}
|
|
5156
5156
|
}
|
|
5157
5157
|
end(turn) {
|
|
5158
|
-
if (turn !== void 0 && this.pinned?.turn !== turn && this.pending?.turn !== turn) return;
|
|
5158
|
+
if (turn !== void 0 && this.pinned?.turn !== turn && this.pending?.turn !== turn && this.unavailable?.turn !== turn) return;
|
|
5159
5159
|
this.generation += 1;
|
|
5160
|
+
this.unavailable = void 0;
|
|
5160
5161
|
this.pending?.controller.abort(/* @__PURE__ */ new Error("memory turn ended during View preparation"));
|
|
5161
5162
|
this.pending = void 0;
|
|
5162
5163
|
const pinned = this.pinned;
|
|
@@ -5186,6 +5187,7 @@ var AgentMemoryTurn = class {
|
|
|
5186
5187
|
context,
|
|
5187
5188
|
release: execution.release
|
|
5188
5189
|
};
|
|
5190
|
+
this.warned = void 0;
|
|
5189
5191
|
this.lastInspection = inspection;
|
|
5190
5192
|
this.lastWorkspace = context.scope.workspaceId === void 0 ? void 0 : resolve(context.scope.workspaceId);
|
|
5191
5193
|
} catch (error) {
|
|
@@ -5309,12 +5311,6 @@ var MnemonAgentLifecycle = class {
|
|
|
5309
5311
|
memoryActivity = new TurnActivityProjection();
|
|
5310
5312
|
turnActivity = /* @__PURE__ */ new Map();
|
|
5311
5313
|
/**
|
|
5312
|
-
* Fallback presence marker for hosts that publish no surface projection.
|
|
5313
|
-
* A host with a surface answers the question from what the model can
|
|
5314
|
-
* actually see, which is what makes a rewind self-correcting.
|
|
5315
|
-
*/
|
|
5316
|
-
cueInjected = false;
|
|
5317
|
-
/**
|
|
5318
5314
|
* Text of the runtime memory snapshot most recently injected as this
|
|
5319
5315
|
* plugin's own message. `.context()` used to get supersede-on-change for free
|
|
5320
5316
|
* from the host's runtime-context projection; carrying the snapshot as an own
|
|
@@ -5335,6 +5331,7 @@ var MnemonAgentLifecycle = class {
|
|
|
5335
5331
|
lastPhase = "idle";
|
|
5336
5332
|
lastAt;
|
|
5337
5333
|
lastError;
|
|
5334
|
+
composedTurn;
|
|
5338
5335
|
constructor(agent, coordinator, config, counters, source, memoryTurn) {
|
|
5339
5336
|
this.agent = agent;
|
|
5340
5337
|
this.coordinator = coordinator;
|
|
@@ -5345,20 +5342,6 @@ var MnemonAgentLifecycle = class {
|
|
|
5345
5342
|
}
|
|
5346
5343
|
start() {
|
|
5347
5344
|
const disposers = [
|
|
5348
|
-
this.agent.ctx.on("agent/session-start", ((payload) => {
|
|
5349
|
-
this.releaseView();
|
|
5350
|
-
this.memoryTurn?.clearInspection();
|
|
5351
|
-
this.cancelIdleReview(true);
|
|
5352
|
-
this.guidedTurns.clear();
|
|
5353
|
-
this.turnActivity.clear();
|
|
5354
|
-
this.memoryActivity.reset();
|
|
5355
|
-
this.startSource = payload.source;
|
|
5356
|
-
this.primePending = true;
|
|
5357
|
-
this.cueInjected = false;
|
|
5358
|
-
this.injectedMemoryText = void 0;
|
|
5359
|
-
this.lastError = void 0;
|
|
5360
|
-
this.mark("prime");
|
|
5361
|
-
})),
|
|
5362
5345
|
this.agent.ctx.on("session/event", ((session, event) => this.sessionEvent(session, event))),
|
|
5363
5346
|
this.agent.ctx.on("system-prompt/assemble", ((assembly, context, next) => this.assemblePrompt(assembly, context, next))),
|
|
5364
5347
|
this.agent.ctx.on("agent/pre-step", ((payload, next) => this.preStep(payload, next)), { prepend: true }),
|
|
@@ -5377,7 +5360,7 @@ var MnemonAgentLifecycle = class {
|
|
|
5377
5360
|
startSource: this.startSource,
|
|
5378
5361
|
primePending: this.primePending,
|
|
5379
5362
|
guidedTurns: this.guidedTurns.size,
|
|
5380
|
-
memoryToolCalls: memoryToolCalls(
|
|
5363
|
+
memoryToolCalls: memoryToolCalls(this.agent.session.snapshotEvents()),
|
|
5381
5364
|
idleReviewPending: this.idleReviewTimer !== void 0,
|
|
5382
5365
|
reviewRunning: this.reviewRunning,
|
|
5383
5366
|
reviewActivity: this.reviewActivity(),
|
|
@@ -5400,11 +5383,11 @@ var MnemonAgentLifecycle = class {
|
|
|
5400
5383
|
}
|
|
5401
5384
|
/** Incremental snapshot of settled Mnemon activity in this durable log. */
|
|
5402
5385
|
turnMemoryActivities() {
|
|
5403
|
-
return this.memoryActivity.snapshot(
|
|
5386
|
+
return this.memoryActivity.snapshot(this.agent.session.snapshotEvents());
|
|
5404
5387
|
}
|
|
5405
5388
|
/** Plain text of one finalized assistant message, from this agent's session log. */
|
|
5406
5389
|
assistantMessageText(messageId) {
|
|
5407
|
-
return assistantMessageText(
|
|
5390
|
+
return assistantMessageText(this.agent.session.snapshotEvents(), messageId);
|
|
5408
5391
|
}
|
|
5409
5392
|
memoryWake() {
|
|
5410
5393
|
const pinned = this.memoryTurn?.current;
|
|
@@ -5414,19 +5397,17 @@ var MnemonAgentLifecycle = class {
|
|
|
5414
5397
|
/**
|
|
5415
5398
|
* Whether the reminder is still visible to the model.
|
|
5416
5399
|
*
|
|
5417
|
-
* Read from the surface rather than
|
|
5418
|
-
* surface replacement inside the same live
|
|
5419
|
-
*
|
|
5420
|
-
*
|
|
5421
|
-
*
|
|
5400
|
+
* Read from the surface rather than an Agent-scoped flag, because a rewind
|
|
5401
|
+
* is a surface replacement inside the same live Agent: DSH does not recreate
|
|
5402
|
+
* the Agent, so a flag would stay set and the reminder would never return.
|
|
5403
|
+
* The durable event log cannot answer this either, since it is append-only
|
|
5404
|
+
* and still contains the discarded message.
|
|
5422
5405
|
*
|
|
5423
5406
|
* Scanning forward is cheap: the reminder sits near the head of the surface,
|
|
5424
5407
|
* so the loop exits after a few nodes even on a long session.
|
|
5425
5408
|
*/
|
|
5426
5409
|
cueAlreadyVisible() {
|
|
5427
|
-
const
|
|
5428
|
-
if (nodes === void 0) return this.cueInjected;
|
|
5429
|
-
for (const seq of nodes) if (isOwnUserMessageEvent(hostSessionEventAt(this.agent.session, seq))) return true;
|
|
5410
|
+
for (const seq of this.agent.session.surface.nodes) if (isOwnUserMessageEvent(this.agent.session.eventAt(seq))) return true;
|
|
5430
5411
|
return false;
|
|
5431
5412
|
}
|
|
5432
5413
|
/**
|
|
@@ -5474,7 +5455,6 @@ var MnemonAgentLifecycle = class {
|
|
|
5474
5455
|
kind: "enter",
|
|
5475
5456
|
messages: withSnapshot(decision.messages)
|
|
5476
5457
|
};
|
|
5477
|
-
this.cueInjected = true;
|
|
5478
5458
|
this.guidedTurns.add(payload.turn);
|
|
5479
5459
|
if (this.config.recallMode === "guided") this.counters.recallCues += 1;
|
|
5480
5460
|
if (this.config.writebackMode === "guided" && this.config.writeEnabled) this.counters.writebackCues += 1;
|
|
@@ -5508,10 +5488,9 @@ var MnemonAgentLifecycle = class {
|
|
|
5508
5488
|
}
|
|
5509
5489
|
scheduleIdleReview(turn) {
|
|
5510
5490
|
this.cancelIdleReview(true);
|
|
5511
|
-
if (!this.idleReviewAllowed()) return;
|
|
5512
|
-
if (this.config.memoryTopology.strategyId !== "default-three-tier") return;
|
|
5491
|
+
if (!this.idleReviewAllowed() || !this.composedByDefault(turn)) return;
|
|
5513
5492
|
const activity = this.ensureTurnActivity(turn);
|
|
5514
|
-
const tools = completedToolActivity(
|
|
5493
|
+
const tools = completedToolActivity(this.agent.session.snapshotEvents(), turn);
|
|
5515
5494
|
activity.toolCallCount = tools.count;
|
|
5516
5495
|
activity.toolNames = tools.names;
|
|
5517
5496
|
if (!this.reviewActivity().eligible || !this.reviewAdmitted(turn)) return;
|
|
@@ -5523,10 +5502,26 @@ var MnemonAgentLifecycle = class {
|
|
|
5523
5502
|
return;
|
|
5524
5503
|
}
|
|
5525
5504
|
if (this.agent.status !== "idle") return;
|
|
5526
|
-
if (!
|
|
5505
|
+
if (!this.agent.session.snapshotEvents().some((event) => event.type === "turn/end" && eventTurn(event) === turn) || !this.reviewActivity().eligible || !this.reviewAdmitted(turn)) return;
|
|
5527
5506
|
this.runIdleReview();
|
|
5528
5507
|
}, Math.max(this.config.idleReviewMs, (this.lastReviewAttemptAt ?? -Infinity) + this.config.idleReview.minIntervalMs - Date.now()));
|
|
5529
5508
|
}
|
|
5509
|
+
/**
|
|
5510
|
+
* Automatic three-tier maintenance belongs to the default product, not to
|
|
5511
|
+
* every third-party View Strategy, and only to turns that Strategy actually
|
|
5512
|
+
* composed: a turn served by a fallback Strategy, or run without memory, has
|
|
5513
|
+
* nothing for it to maintain. Explicit management remains available.
|
|
5514
|
+
*/
|
|
5515
|
+
composedByDefault(turn) {
|
|
5516
|
+
if (this.memoryTurn === void 0) return true;
|
|
5517
|
+
const pinned = this.memoryTurn.current;
|
|
5518
|
+
if (pinned?.turn === turn) this.composedTurn = {
|
|
5519
|
+
turn,
|
|
5520
|
+
strategyTypeId: pinned.context.view.strategyTypeId
|
|
5521
|
+
};
|
|
5522
|
+
else if (this.composedTurn?.turn !== turn) this.composedTurn = void 0;
|
|
5523
|
+
return this.composedTurn?.strategyTypeId === "default-three-tier";
|
|
5524
|
+
}
|
|
5530
5525
|
idleReviewAllowed() {
|
|
5531
5526
|
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";
|
|
5532
5527
|
}
|
|
@@ -5603,7 +5598,7 @@ var MnemonAgentLifecycle = class {
|
|
|
5603
5598
|
explicitCandidate ||= activity.explicitCandidate;
|
|
5604
5599
|
completedNonMemoryTool ||= activity.toolCallCount > 0 && [...activity.toolNames].some((name) => !name.startsWith("mnemon_"));
|
|
5605
5600
|
}
|
|
5606
|
-
const assistantTextLength =
|
|
5601
|
+
const assistantTextLength = this.agent.session.snapshotEvents().filter((event) => {
|
|
5607
5602
|
const turn = eventTurn(event);
|
|
5608
5603
|
return turn !== void 0 && turns.has(turn);
|
|
5609
5604
|
}).map(assistantEventTextLength).reduce((total, length) => total + length, 0);
|
|
@@ -5664,8 +5659,8 @@ var MnemonLifecycle = class {
|
|
|
5664
5659
|
this.runtimeSource = runtimeSource;
|
|
5665
5660
|
}
|
|
5666
5661
|
start() {
|
|
5667
|
-
const stopCreated = this.ctx.on("agent/created", (({ agent }) => {
|
|
5668
|
-
this.install(agent,
|
|
5662
|
+
const stopCreated = this.ctx.on("agent/created", (({ agent, source }) => {
|
|
5663
|
+
this.install(agent, source);
|
|
5669
5664
|
}));
|
|
5670
5665
|
for (const agent of this.ctx.agents.roots()) this.install(agent, "adopted");
|
|
5671
5666
|
return () => {
|
|
@@ -5689,7 +5684,7 @@ var MnemonLifecycle = class {
|
|
|
5689
5684
|
idleReviewMs: this.config.idleReviewMs,
|
|
5690
5685
|
activeAgents: this.owners.size,
|
|
5691
5686
|
sessionAvailable: agent !== void 0,
|
|
5692
|
-
taskAgentAvailable: this.
|
|
5687
|
+
taskAgentAvailable: this.taskAgentModelOptions(requestedId ?? "", workspaceRoot) !== void 0,
|
|
5693
5688
|
counters: { ...this.counters },
|
|
5694
5689
|
subagents: this.coordinator.snapshot(),
|
|
5695
5690
|
...owner === void 0 ? {} : { current: owner.snapshot() }
|
|
@@ -5937,20 +5932,15 @@ var MnemonLifecycle = class {
|
|
|
5937
5932
|
* workspace graph without borrowing conversation history or ownership.
|
|
5938
5933
|
*/
|
|
5939
5934
|
async runTaskAgent(fallbackSessionId, workspaceRoot, signal, operation) {
|
|
5940
|
-
const create = this.ctx.agents.create?.bind(this.ctx.agents);
|
|
5941
|
-
if (create === void 0) {
|
|
5942
|
-
const fallback = workspaceRoot === void 0 ? this.ctx.agents.get(fallbackSessionId.trim()) ?? this.availableAgent() : this.availableAgent(workspaceRoot);
|
|
5943
|
-
if (fallback === void 0) throw new Error("current DSH host cannot create a task Agent and no matching live Agent is available");
|
|
5944
|
-
return operation(fallback);
|
|
5945
|
-
}
|
|
5946
5935
|
const sessionId = randomUUID();
|
|
5947
5936
|
this.taskAgentIds.add(sessionId);
|
|
5948
5937
|
let handle;
|
|
5949
5938
|
let failure;
|
|
5950
5939
|
try {
|
|
5951
|
-
|
|
5940
|
+
const creation = await this.taskAgentCreation(fallbackSessionId, workspaceRoot);
|
|
5941
|
+
handle = await this.ctx.agents.create({
|
|
5952
5942
|
sessionId,
|
|
5953
|
-
...
|
|
5943
|
+
...creation,
|
|
5954
5944
|
signal
|
|
5955
5945
|
});
|
|
5956
5946
|
return await operation(handle.agent);
|
|
@@ -6089,7 +6079,6 @@ var MnemonLifecycle = class {
|
|
|
6089
6079
|
}
|
|
6090
6080
|
};
|
|
6091
6081
|
try {
|
|
6092
|
-
stops.push(agent.ctx.on("agent/session-start", (() => memory.end())));
|
|
6093
6082
|
stops.push(agent.ctx.on("system-prompt/assemble", (async (_assembly, context, next) => {
|
|
6094
6083
|
if (context.agent !== void 0 && context.agent !== agent) return next();
|
|
6095
6084
|
const turn = openAgentTurn(agent);
|
|
@@ -6662,17 +6651,6 @@ var VersionUpdateManager = class {
|
|
|
6662
6651
|
return {
|
|
6663
6652
|
checkedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
6664
6653
|
components: [{
|
|
6665
|
-
id: "mnemon",
|
|
6666
|
-
name: "Mnemon CLI",
|
|
6667
|
-
...mnemonLocal.install.command === void 0 ? {} : { executablePath: mnemonLocal.install.command },
|
|
6668
|
-
...mnemonLocal.current === void 0 ? {} : { current: mnemonLocal.current },
|
|
6669
|
-
...mnemonLatest === void 0 ? {} : { latest: mnemonLatest },
|
|
6670
|
-
outdated: mnemonOutdated,
|
|
6671
|
-
installMode: mnemonLocal.install.mode,
|
|
6672
|
-
updateSupported: mnemonSupported,
|
|
6673
|
-
updateHint: mnemonLocal.install.hint ?? (mnemonLocal.install.mode === "homebrew" ? mnemonSupported ? "brew" : "brew-missing" : mnemonLocal.install.mode === "go" ? "go" : mnemonLocal.install.mode === "missing" ? "install" : "manual"),
|
|
6674
|
-
...mnemonLatest === void 0 ? { checkError: "latest-unavailable" } : {}
|
|
6675
|
-
}, {
|
|
6676
6654
|
id: "dsh-mnemon",
|
|
6677
6655
|
name: "dsh-mnemon",
|
|
6678
6656
|
...dshInstall.profileName === void 0 ? {} : { installProfile: dshInstall.profileName },
|
|
@@ -6686,6 +6664,17 @@ var VersionUpdateManager = class {
|
|
|
6686
6664
|
restartRequired: this.pendingRestart.size > 0,
|
|
6687
6665
|
updateHint: dshInstall.mode === "npm" ? dshSupported ? "pnpm" : "pnpm-missing" : dshInstall.mode === "link" ? "link" : "manual",
|
|
6688
6666
|
...dshLatest === void 0 ? { checkError: "latest-unavailable" } : {}
|
|
6667
|
+
}, {
|
|
6668
|
+
id: "mnemon",
|
|
6669
|
+
name: "Mnemon CLI",
|
|
6670
|
+
...mnemonLocal.install.command === void 0 ? {} : { executablePath: mnemonLocal.install.command },
|
|
6671
|
+
...mnemonLocal.current === void 0 ? {} : { current: mnemonLocal.current },
|
|
6672
|
+
...mnemonLatest === void 0 ? {} : { latest: mnemonLatest },
|
|
6673
|
+
outdated: mnemonOutdated,
|
|
6674
|
+
installMode: mnemonLocal.install.mode,
|
|
6675
|
+
updateSupported: mnemonSupported,
|
|
6676
|
+
updateHint: mnemonLocal.install.hint ?? (mnemonLocal.install.mode === "homebrew" ? mnemonSupported ? "brew" : "brew-missing" : mnemonLocal.install.mode === "go" ? "go" : mnemonLocal.install.mode === "missing" ? "install" : "manual"),
|
|
6677
|
+
...mnemonLatest === void 0 ? { checkError: "latest-unavailable" } : {}
|
|
6689
6678
|
}]
|
|
6690
6679
|
};
|
|
6691
6680
|
}
|
|
@@ -6799,6 +6788,13 @@ function requireWritable(runtime) {
|
|
|
6799
6788
|
function requireCapability(runtime, typeId, capability) {
|
|
6800
6789
|
assertParticipation(runtime.graph.config, typeId, capability, "manual");
|
|
6801
6790
|
}
|
|
6791
|
+
/** A memory layer that is off takes no part in reads or writes, management and assistance included. */
|
|
6792
|
+
function requireLayerOn(runtime, sourceTypeId) {
|
|
6793
|
+
if (sourceTypeId !== void 0 && runtime.graph.config.memoryTopology.layers[sourceTypeId]?.enabled === false) throw new Error(`Memory layer ${sourceTypeId} is off; turn it on to read or change it`);
|
|
6794
|
+
}
|
|
6795
|
+
function sourceTypeOf(generation, sourceInstanceKey) {
|
|
6796
|
+
return generation?.sourceInstances().find((source) => source.sourceInstanceKey === sourceInstanceKey)?.sourceTypeId;
|
|
6797
|
+
}
|
|
6802
6798
|
function success$1(value) {
|
|
6803
6799
|
return {
|
|
6804
6800
|
ok: true,
|
|
@@ -6883,8 +6879,12 @@ async function catalog(runtime, lifecycle) {
|
|
|
6883
6879
|
}
|
|
6884
6880
|
}
|
|
6885
6881
|
async function compositionStatus(runtime) {
|
|
6882
|
+
const composition = runtime.graph.memoryComposition.inspect();
|
|
6883
|
+
const strategyTypeId = runtime.graph.memoryComposition.current()?.strategy.definition.manifest.typeId;
|
|
6886
6884
|
return {
|
|
6887
|
-
|
|
6885
|
+
serving: composition.servingGenerationId !== void 0,
|
|
6886
|
+
...strategyTypeId === void 0 ? {} : { strategyTypeId },
|
|
6887
|
+
evaluation: composition.evaluation,
|
|
6888
6888
|
sources: (await catalog(runtime)).sources,
|
|
6889
6889
|
configuration: runtime.graph.config.memoryTopology
|
|
6890
6890
|
};
|
|
@@ -7010,6 +7010,7 @@ function createReadHandler(input, lifecycle, versions) {
|
|
|
7010
7010
|
case "source-management-read": {
|
|
7011
7011
|
const lease = runtime.graph.memoryComposition.acquire();
|
|
7012
7012
|
try {
|
|
7013
|
+
requireLayerOn(runtime, sourceTypeOf(lease.generation, String(payload.sourceInstanceKey ?? "")));
|
|
7013
7014
|
return success$1(await lease.generation.executeManagement({
|
|
7014
7015
|
scope: runtime.scope,
|
|
7015
7016
|
sourceInstanceKey: String(payload.sourceInstanceKey ?? ""),
|
|
@@ -7104,6 +7105,7 @@ function createActivationHandler(input) {
|
|
|
7104
7105
|
try {
|
|
7105
7106
|
const source = (await lease.generation.managementCatalog(runtime.scope)).sources.find((item) => item.sourceInstanceKey === payload.sourceInstanceKey && item.sourceTypeId === "memory-spaces");
|
|
7106
7107
|
if (source === void 0) throw new Error("Memory Spaces Source instance is unavailable");
|
|
7108
|
+
requireLayerOn(runtime, source.sourceTypeId);
|
|
7107
7109
|
return success$1(await lease.generation.executeManagement({
|
|
7108
7110
|
scope: runtime.scope,
|
|
7109
7111
|
sourceInstanceKey: source.sourceInstanceKey,
|
|
@@ -7158,6 +7160,7 @@ function createWriteHandler(input, lifecycle, versions) {
|
|
|
7158
7160
|
...typeof payload.expectedRevision === "string" ? { expectedRevision: payload.expectedRevision } : {},
|
|
7159
7161
|
...signal === void 0 ? {} : { signal }
|
|
7160
7162
|
};
|
|
7163
|
+
requireLayerOn(runtime, sourceTypeOf(runtime.graph.memoryComposition.current(), request.sourceInstanceKey));
|
|
7161
7164
|
if (lifecycle !== void 0) return success$1(await lifecycle.manageSource(runtime.graph, request));
|
|
7162
7165
|
const lease = runtime.graph.memoryComposition.acquire();
|
|
7163
7166
|
try {
|
|
@@ -7171,6 +7174,7 @@ function createWriteHandler(input, lifecycle, versions) {
|
|
|
7171
7174
|
const source = (await catalog(runtime, lifecycle)).sources.find((item) => item.sourceInstanceKey === payload.sourceInstanceKey);
|
|
7172
7175
|
const operation = String(payload.operation ?? "");
|
|
7173
7176
|
if (source === void 0 || !source.assistance.includes(operation)) throw new Error("Host assistance is not available for this Source instance");
|
|
7177
|
+
requireLayerOn(runtime, source.sourceTypeId);
|
|
7174
7178
|
if (operation !== "agent-search" && (payload.confirmed !== true || payload.expectedRevision !== source.revision)) throw new Error("Host assistance requires confirmation of the current Source revision");
|
|
7175
7179
|
const value = await assisted(runtime, lifecycle, source.sourceTypeId, operation, object$4(payload.input), signal, {
|
|
7176
7180
|
sourceInstanceKey: source.sourceInstanceKey,
|
|
@@ -7239,16 +7243,16 @@ function createPackHandler(input) {
|
|
|
7239
7243
|
}
|
|
7240
7244
|
};
|
|
7241
7245
|
}
|
|
7242
|
-
function registerRpc(connection, input, lifecycle, versions
|
|
7246
|
+
function registerRpc(connection, input, lifecycle, versions) {
|
|
7243
7247
|
const versionManager = versions ?? new VersionUpdateManager({ mnemonCliPath: () => input.config.cliPath });
|
|
7244
7248
|
const readHandler = createReadHandler(input, lifecycle, versionManager);
|
|
7245
7249
|
const activationHandler = createActivationHandler(input);
|
|
7246
7250
|
const writeHandler = createWriteHandler(input, lifecycle, versionManager);
|
|
7247
7251
|
const packHandler = createPackHandler(input);
|
|
7248
|
-
connection.rpc.handle(MNEMON_READ_CHANNEL, readHandler
|
|
7249
|
-
connection.rpc.handle(MNEMON_ACTIVATION_CHANNEL, activationHandler
|
|
7250
|
-
connection.rpc.handle(MNEMON_WRITE_CHANNEL, writeHandler
|
|
7251
|
-
connection.rpc.handle(MNEMON_PACK_CHANNEL, packHandler
|
|
7252
|
+
connection.rpc.handle(MNEMON_READ_CHANNEL, readHandler);
|
|
7253
|
+
connection.rpc.handle(MNEMON_ACTIVATION_CHANNEL, activationHandler);
|
|
7254
|
+
connection.rpc.handle(MNEMON_WRITE_CHANNEL, writeHandler);
|
|
7255
|
+
connection.rpc.handle(MNEMON_PACK_CHANNEL, packHandler);
|
|
7252
7256
|
return {
|
|
7253
7257
|
read: readHandler,
|
|
7254
7258
|
activation: activationHandler,
|
|
@@ -7403,9 +7407,9 @@ function createSettingsHandler(settings) {
|
|
|
7403
7407
|
}
|
|
7404
7408
|
};
|
|
7405
7409
|
}
|
|
7406
|
-
function registerSettingsRpc(connection, settings
|
|
7410
|
+
function registerSettingsRpc(connection, settings) {
|
|
7407
7411
|
const handler = createSettingsHandler(settings);
|
|
7408
|
-
connection.rpc.handle(MNEMON_SETTINGS_CHANNEL, handler
|
|
7412
|
+
connection.rpc.handle(MNEMON_SETTINGS_CHANNEL, handler);
|
|
7409
7413
|
return handler;
|
|
7410
7414
|
}
|
|
7411
7415
|
//#endregion
|
|
@@ -8328,7 +8332,6 @@ const mnemonSubagentTokenUsageProjectionDefinition = {
|
|
|
8328
8332
|
key: "mnemonSubagentTokenUsage",
|
|
8329
8333
|
stateVersion: 1,
|
|
8330
8334
|
stateSchema: tokenUsageStateSchema,
|
|
8331
|
-
schema: tokenUsageWire.viewSchema,
|
|
8332
8335
|
init: () => ({
|
|
8333
8336
|
descriptorSeen: false,
|
|
8334
8337
|
totals: emptyTokenUsage(),
|
|
@@ -8351,7 +8354,6 @@ const mnemonSubagentTokenUsageProjectionDefinition = {
|
|
|
8351
8354
|
last: sample
|
|
8352
8355
|
};
|
|
8353
8356
|
},
|
|
8354
|
-
view: tokenUsageWire.view,
|
|
8355
8357
|
wire: tokenUsageWire
|
|
8356
8358
|
};
|
|
8357
8359
|
/** Register lazily when the optional DSH projection service is present. */
|
|
@@ -8361,722 +8363,224 @@ function registerMnemonSubagentTokenUsageProjection(ctx) {
|
|
|
8361
8363
|
});
|
|
8362
8364
|
}
|
|
8363
8365
|
//#endregion
|
|
8364
|
-
//#region src/host/
|
|
8365
|
-
|
|
8366
|
-
|
|
8367
|
-
|
|
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)]));
|
|
8366
|
+
//#region src/host/plugin-management.ts
|
|
8367
|
+
/** Saved choices keep only configuration once the profile patch owns enablement. */
|
|
8368
|
+
function configurationOnly(entries) {
|
|
8369
|
+
return Object.fromEntries(Object.entries(entries).map(([entryId, value]) => [entryId, { config: value.config }]));
|
|
8378
8370
|
}
|
|
8379
|
-
|
|
8380
|
-
|
|
8381
|
-
|
|
8371
|
+
const PACKAGE$1 = /^(?:@[a-z0-9._-]+\/)?dsh-mnemon-(source|strategy)-[a-z0-9._-]+$/u;
|
|
8372
|
+
const hash = (value) => createHash("sha256").update(canonicalMemoryJson(value)).digest("hex");
|
|
8373
|
+
const clone$1 = (value) => JSON.parse(JSON.stringify(value));
|
|
8374
|
+
function contributionRoles(snapshot, entryId) {
|
|
8375
|
+
const roles = /* @__PURE__ */ new Set();
|
|
8376
|
+
if (snapshot.sources.some((value) => value.provenance.entryId === entryId)) roles.add("source");
|
|
8377
|
+
if (snapshot.strategies.some((value) => value.provenance.entryId === entryId)) roles.add("strategy");
|
|
8378
|
+
if ((snapshot.strategyExtensions ?? []).some((value) => value.provenance.entryId === entryId)) roles.add("strategy-extension");
|
|
8379
|
+
return [...roles];
|
|
8382
8380
|
}
|
|
8383
|
-
function
|
|
8384
|
-
const
|
|
8385
|
-
|
|
8386
|
-
const
|
|
8387
|
-
|
|
8388
|
-
|
|
8389
|
-
|
|
8390
|
-
|
|
8391
|
-
|
|
8392
|
-
|
|
8393
|
-
|
|
8394
|
-
|
|
8395
|
-
|
|
8396
|
-
|
|
8397
|
-
|
|
8398
|
-
|
|
8399
|
-
|
|
8400
|
-
|
|
8401
|
-
|
|
8381
|
+
function fallbackDescriptor(entry, snapshot, editor) {
|
|
8382
|
+
const sources = snapshot.sources.filter((value) => value.provenance.entryId === entry.id);
|
|
8383
|
+
const strategies = snapshot.strategies.filter((value) => value.provenance.entryId === entry.id);
|
|
8384
|
+
const extensions = (snapshot.strategyExtensions ?? []).filter((value) => value.provenance.entryId === entry.id);
|
|
8385
|
+
const roles = contributionRoles(snapshot, entry.id);
|
|
8386
|
+
if (roles.length === 0) roles.push(editor?.kind ?? (PACKAGE$1.exec(entry.options.name)?.[1] === "source" ? "source" : "strategy"));
|
|
8387
|
+
const typeId = editor?.typeId ?? strategies[0]?.definition.manifest.typeId ?? extensions[0]?.definition.manifest.typeId ?? sources[0]?.definition.manifest.typeId;
|
|
8388
|
+
const sourceLabel = sources[0]?.definition.manifest.management?.label;
|
|
8389
|
+
const label = editor?.label ?? {
|
|
8390
|
+
en: sourceLabel ?? typeId ?? entry.options.name,
|
|
8391
|
+
"zh-CN": sourceLabel ?? typeId ?? entry.options.name
|
|
8392
|
+
};
|
|
8393
|
+
const description = editor?.description ?? {
|
|
8394
|
+
en: "",
|
|
8395
|
+
"zh-CN": ""
|
|
8396
|
+
};
|
|
8397
|
+
const provides = roles.includes("source") ? [{ id: "source" }, ...sources.map((source) => ({ id: `source.${source.definition.manifest.role}` }))] : [{ id: roles.includes("strategy") ? "strategy" : `strategy.${typeId ?? hash(entry.options.name).slice(0, 12)}` }];
|
|
8398
|
+
return defineMemoryPlugin({
|
|
8399
|
+
packageName: entry.options.name,
|
|
8400
|
+
label,
|
|
8401
|
+
description,
|
|
8402
|
+
roles,
|
|
8403
|
+
provides
|
|
8404
|
+
});
|
|
8402
8405
|
}
|
|
8403
|
-
|
|
8404
|
-
|
|
8405
|
-
|
|
8406
|
-
|
|
8407
|
-
|
|
8408
|
-
|
|
8409
|
-
|
|
8410
|
-
|
|
8411
|
-
|
|
8412
|
-
const ENTRY_ID = /^[a-zA-Z0-9][a-zA-Z0-9._:/-]{0,299}$/u;
|
|
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;
|
|
8406
|
+
function prepared(item, config) {
|
|
8407
|
+
if (item.editor === void 0) throw new Error(`Plugin does not expose a pure configuration factory: ${item.entry.id}`);
|
|
8408
|
+
const contribution = item.editor.create(config);
|
|
8409
|
+
if ([...contribution.strategies ?? [], ...contribution.strategyExtensions ?? []][0].manifest.packageName !== item.entry.options.name) throw new Error("Plugin factory does not match its declared Entry");
|
|
8410
|
+
if (contribution.plugin !== void 0 && hash(contribution.plugin) !== hash(item.descriptor)) throw new Error("Plugin factory descriptor does not match its module export");
|
|
8411
|
+
return prepareMemoryContributions({
|
|
8412
|
+
...contribution,
|
|
8413
|
+
plugin: contribution.plugin ?? item.descriptor
|
|
8414
|
+
}, { instanceId: item.entry.id });
|
|
8424
8415
|
}
|
|
8425
|
-
|
|
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);
|
|
8445
|
-
}
|
|
8446
|
-
}
|
|
8447
|
-
function copiedObject(value, label) {
|
|
8448
|
-
object$2(value, label);
|
|
8449
|
-
return copy(value, label);
|
|
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
|
-
}
|
|
8416
|
+
function installedPlugin(descriptor, entryId) {
|
|
8488
8417
|
return {
|
|
8489
|
-
|
|
8490
|
-
|
|
8418
|
+
kind: "plugin",
|
|
8419
|
+
instanceKey: `plugin:${entryId}`,
|
|
8420
|
+
provenance: {
|
|
8421
|
+
packageName: descriptor.packageName,
|
|
8422
|
+
entryId
|
|
8423
|
+
},
|
|
8424
|
+
descriptor
|
|
8491
8425
|
};
|
|
8492
8426
|
}
|
|
8493
|
-
function
|
|
8494
|
-
const
|
|
8495
|
-
|
|
8496
|
-
const
|
|
8497
|
-
|
|
8498
|
-
|
|
8499
|
-
|
|
8500
|
-
entryId(
|
|
8501
|
-
|
|
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
|
-
});
|
|
8427
|
+
function orderPlugins(values) {
|
|
8428
|
+
const byId = new Map(values.map((value) => [value.entryId, value]));
|
|
8429
|
+
const edges = new Map(values.map((value) => [value.entryId, /* @__PURE__ */ new Set()]));
|
|
8430
|
+
const indegree = new Map(values.map((value) => [value.entryId, 0]));
|
|
8431
|
+
for (const dependent of values) for (const requirement of dependent.requires) for (const provider of values) {
|
|
8432
|
+
if (provider.entryId === dependent.entryId || !provider.provides.some((capability) => capability.id === requirement)) continue;
|
|
8433
|
+
if (edges.get(provider.entryId).has(dependent.entryId)) continue;
|
|
8434
|
+
edges.get(provider.entryId).add(dependent.entryId);
|
|
8435
|
+
indegree.set(dependent.entryId, indegree.get(dependent.entryId) + 1);
|
|
8528
8436
|
}
|
|
8529
|
-
|
|
8530
|
-
|
|
8531
|
-
|
|
8532
|
-
|
|
8533
|
-
|
|
8534
|
-
|
|
8535
|
-
|
|
8536
|
-
const
|
|
8537
|
-
|
|
8538
|
-
|
|
8539
|
-
|
|
8540
|
-
|
|
8437
|
+
const stable = (left, right) => byId.get(left).packageName.localeCompare(byId.get(right).packageName) || left.localeCompare(right);
|
|
8438
|
+
const ready = [...indegree].filter(([, count]) => count === 0).map(([entryId]) => entryId).sort(stable);
|
|
8439
|
+
const ordered = [];
|
|
8440
|
+
while (ready.length > 0) {
|
|
8441
|
+
const entryId = ready.shift();
|
|
8442
|
+
ordered.push(byId.get(entryId));
|
|
8443
|
+
for (const dependent of [...edges.get(entryId)].sort(stable)) {
|
|
8444
|
+
const next = indegree.get(dependent) - 1;
|
|
8445
|
+
indegree.set(dependent, next);
|
|
8446
|
+
if (next === 0) {
|
|
8447
|
+
ready.push(dependent);
|
|
8448
|
+
ready.sort(stable);
|
|
8541
8449
|
}
|
|
8542
|
-
entries[id].config = config;
|
|
8543
8450
|
}
|
|
8544
|
-
if (typeof row.disabled === "boolean") entries[id].enabled = !row.disabled;
|
|
8545
8451
|
}
|
|
8452
|
+
if (ordered.length < values.length) ordered.push(...values.filter((value) => !ordered.includes(value)).sort((left, right) => stable(left.entryId, right.entryId)));
|
|
8453
|
+
return ordered;
|
|
8546
8454
|
}
|
|
8547
8455
|
/**
|
|
8548
|
-
*
|
|
8549
|
-
*
|
|
8550
|
-
*
|
|
8456
|
+
* Profile-local plugin graph overlay. Every dsh-mnemon Source or Strategy Entry
|
|
8457
|
+
* is one peer node; activation, configuration, dependency checks and rollback
|
|
8458
|
+
* use one transaction. Contribution roles do not create separate managers.
|
|
8551
8459
|
*/
|
|
8552
|
-
|
|
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 {
|
|
8460
|
+
var MemoryPluginManagement = class {
|
|
8646
8461
|
ctx;
|
|
8647
|
-
|
|
8648
|
-
|
|
8649
|
-
|
|
8650
|
-
|
|
8651
|
-
|
|
8652
|
-
|
|
8653
|
-
editor;
|
|
8462
|
+
engine;
|
|
8463
|
+
settingsService;
|
|
8464
|
+
settingsNamespace;
|
|
8465
|
+
settings;
|
|
8466
|
+
legacySettings;
|
|
8467
|
+
queue = Promise.resolve();
|
|
8654
8468
|
closed = false;
|
|
8655
|
-
|
|
8656
|
-
|
|
8657
|
-
|
|
8469
|
+
timer;
|
|
8470
|
+
restoreError;
|
|
8471
|
+
discoveryWarnings = [];
|
|
8472
|
+
changingEntries = false;
|
|
8473
|
+
restorePending = false;
|
|
8474
|
+
/** A failed move keeps saved choices in effect instead of retrying on every profile reload. */
|
|
8475
|
+
enablementMoveError;
|
|
8476
|
+
constructor(ctx, engine, settingsService) {
|
|
8658
8477
|
this.ctx = ctx;
|
|
8659
|
-
this.
|
|
8660
|
-
this.
|
|
8661
|
-
|
|
8662
|
-
|
|
8663
|
-
const
|
|
8664
|
-
|
|
8665
|
-
|
|
8666
|
-
|
|
8667
|
-
|
|
8668
|
-
|
|
8669
|
-
|
|
8670
|
-
for (const registration of this.registrations.values()) {
|
|
8671
|
-
if (registration.legacy) continue;
|
|
8672
|
-
const value = this.resolve(registration, config);
|
|
8673
|
-
registration.validate?.(value);
|
|
8478
|
+
this.engine = engine;
|
|
8479
|
+
this.settingsService = settingsService;
|
|
8480
|
+
const loader = this.loader();
|
|
8481
|
+
const anchor = loader?.config?.baseUrl ?? loader?.ctx?.baseUrl ?? loader?.context?.baseUrl;
|
|
8482
|
+
const suffix = anchor ? `-${hash(anchor).slice(0, 16)}` : "";
|
|
8483
|
+
this.settingsNamespace = `${MNEMON_VIEW_SETTINGS_NAMESPACE}${suffix}`;
|
|
8484
|
+
this.settings = settingsService.register(this.settingsNamespace, schema, {
|
|
8485
|
+
base: { entries: {} },
|
|
8486
|
+
applies: "live",
|
|
8487
|
+
validate: (value) => {
|
|
8488
|
+
preferences(value);
|
|
8674
8489
|
}
|
|
8675
|
-
};
|
|
8676
|
-
|
|
8677
|
-
|
|
8678
|
-
|
|
8679
|
-
|
|
8680
|
-
|
|
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
|
-
}
|
|
8490
|
+
});
|
|
8491
|
+
this.legacySettings = settingsService.register(`mnemon-plugins${suffix}`, legacySchema, {
|
|
8492
|
+
base: { sources: {} },
|
|
8493
|
+
applies: "live",
|
|
8494
|
+
validate: (value) => {
|
|
8495
|
+
legacyPreferences(value);
|
|
8692
8496
|
}
|
|
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");
|
|
8497
|
+
});
|
|
8703
8498
|
}
|
|
8704
|
-
get
|
|
8705
|
-
const
|
|
8706
|
-
return
|
|
8499
|
+
resolveConfig(config, view = this.settings.get()) {
|
|
8500
|
+
const selected = view.strategyTypeId;
|
|
8501
|
+
return selected === void 0 ? config : {
|
|
8502
|
+
...config,
|
|
8503
|
+
memoryTopology: {
|
|
8504
|
+
...config.memoryTopology,
|
|
8505
|
+
strategyId: selected
|
|
8506
|
+
}
|
|
8507
|
+
};
|
|
8707
8508
|
}
|
|
8708
|
-
|
|
8709
|
-
this.
|
|
8509
|
+
start() {
|
|
8510
|
+
const schedule = () => this.scheduleRestore();
|
|
8511
|
+
const stops = [
|
|
8512
|
+
this.ctx.on("loader/entry-init", schedule),
|
|
8513
|
+
this.ctx.on("loader/partial-dispose", schedule),
|
|
8514
|
+
this.ctx.on("app-boot/config-reload", () => this.scheduleRestore(true)),
|
|
8515
|
+
this.settingsService.onUpdated((namespace) => {
|
|
8516
|
+
if (namespace === this.settingsNamespace || namespace === `mnemon-plugins${this.settingsNamespace.slice(11)}`) schedule();
|
|
8517
|
+
})
|
|
8518
|
+
];
|
|
8519
|
+
this.ctx.inject(["pluginManager"], () => {
|
|
8520
|
+
schedule();
|
|
8521
|
+
});
|
|
8522
|
+
schedule();
|
|
8710
8523
|
return () => {
|
|
8711
|
-
this.
|
|
8524
|
+
this.closed = true;
|
|
8525
|
+
this.restorePending = false;
|
|
8526
|
+
clearTimeout(this.timer);
|
|
8527
|
+
for (const stop of stops.reverse()) stop();
|
|
8712
8528
|
};
|
|
8713
8529
|
}
|
|
8714
|
-
|
|
8715
|
-
const
|
|
8716
|
-
|
|
8530
|
+
scheduleRestore(profileReload = false) {
|
|
8531
|
+
const hasSavedState = Object.keys(this.settings.get().entries ?? {}).length > 0 || Object.keys(this.legacySettings.get().sources ?? {}).length > 0;
|
|
8532
|
+
if (this.closed || !profileReload && this.changingEntries || !hasSavedState) return;
|
|
8533
|
+
this.restorePending = true;
|
|
8534
|
+
if (this.changingEntries || this.timer) return;
|
|
8535
|
+
this.timer = setTimeout(() => {
|
|
8536
|
+
this.timer = void 0;
|
|
8537
|
+
this.enqueueRestore();
|
|
8538
|
+
}, 0);
|
|
8717
8539
|
}
|
|
8718
|
-
|
|
8719
|
-
if (this.
|
|
8720
|
-
|
|
8721
|
-
|
|
8722
|
-
|
|
8723
|
-
|
|
8724
|
-
|
|
8725
|
-
|
|
8726
|
-
|
|
8727
|
-
|
|
8728
|
-
|
|
8729
|
-
|
|
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) };
|
|
8540
|
+
enqueueRestore() {
|
|
8541
|
+
if (this.closed || this.changingEntries || !this.restorePending) return;
|
|
8542
|
+
clearTimeout(this.timer);
|
|
8543
|
+
this.timer = void 0;
|
|
8544
|
+
this.restorePending = false;
|
|
8545
|
+
this.exclusive(async () => {
|
|
8546
|
+
try {
|
|
8547
|
+
await this.restore();
|
|
8548
|
+
} catch (error) {
|
|
8549
|
+
this.restoreError = error instanceof Error ? error.message : String(error);
|
|
8550
|
+
}
|
|
8551
|
+
}).catch(() => {});
|
|
8736
8552
|
}
|
|
8737
|
-
|
|
8738
|
-
|
|
8739
|
-
|
|
8740
|
-
|
|
8741
|
-
this.
|
|
8742
|
-
|
|
8743
|
-
|
|
8744
|
-
|
|
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;
|
|
8553
|
+
/** A response must not race the deferred restore after profile reconciliation. */
|
|
8554
|
+
async settled() {
|
|
8555
|
+
do {
|
|
8556
|
+
this.enqueueRestore();
|
|
8557
|
+
const pending = this.queue;
|
|
8558
|
+
await pending;
|
|
8559
|
+
if (pending === this.queue && !this.restorePending) return;
|
|
8560
|
+
} while (!this.closed);
|
|
8752
8561
|
}
|
|
8753
|
-
|
|
8754
|
-
const
|
|
8755
|
-
|
|
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);
|
|
8562
|
+
loader() {
|
|
8563
|
+
const candidate = this.ctx.get("loader");
|
|
8564
|
+
return candidate && typeof candidate.entries === "function" ? candidate : void 0;
|
|
8768
8565
|
}
|
|
8769
|
-
|
|
8770
|
-
|
|
8771
|
-
|
|
8772
|
-
|
|
8773
|
-
|
|
8774
|
-
|
|
8775
|
-
|
|
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
|
-
});
|
|
8566
|
+
/**
|
|
8567
|
+
* With the DSH plugin manager, the profile patch owns enablement, so its
|
|
8568
|
+
* Plugins page and Mnemon agree. Profiles without it keep Mnemon's overlay.
|
|
8569
|
+
*/
|
|
8570
|
+
pluginManager() {
|
|
8571
|
+
const candidate = this.ctx.get("pluginManager");
|
|
8572
|
+
return typeof candidate?.setPluginEnabled === "function" ? candidate : void 0;
|
|
8785
8573
|
}
|
|
8786
|
-
async
|
|
8787
|
-
const
|
|
8788
|
-
if (
|
|
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
|
-
}
|
|
8574
|
+
async setEnabled(manager, entryId, enabled) {
|
|
8575
|
+
const result = await manager.setPluginEnabled(entryId, enabled);
|
|
8576
|
+
if (result.application !== "applied") throw new Error(`DSH could not ${enabled ? "enable" : "disable"} ${entryId}: ${result.error?.message ?? result.application}`);
|
|
8809
8577
|
}
|
|
8810
|
-
|
|
8811
|
-
|
|
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;
|
|
8578
|
+
settingsRevision(namespace = this.settingsNamespace) {
|
|
8579
|
+
return this.settingsService.describe({ redactSecrets: true }).find((value) => value.ns === namespace)?.revision ?? 0;
|
|
8817
8580
|
}
|
|
8818
|
-
|
|
8819
|
-
|
|
8820
|
-
|
|
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));
|
|
8891
|
-
function contributionRoles(snapshot, entryId) {
|
|
8892
|
-
const roles = /* @__PURE__ */ new Set();
|
|
8893
|
-
if (snapshot.sources.some((value) => value.provenance.entryId === entryId)) roles.add("source");
|
|
8894
|
-
if (snapshot.strategies.some((value) => value.provenance.entryId === entryId)) roles.add("strategy");
|
|
8895
|
-
if ((snapshot.strategyExtensions ?? []).some((value) => value.provenance.entryId === entryId)) roles.add("strategy-extension");
|
|
8896
|
-
return [...roles];
|
|
8897
|
-
}
|
|
8898
|
-
function fallbackDescriptor(entry, snapshot, editor) {
|
|
8899
|
-
const sources = snapshot.sources.filter((value) => value.provenance.entryId === entry.id);
|
|
8900
|
-
const strategies = snapshot.strategies.filter((value) => value.provenance.entryId === entry.id);
|
|
8901
|
-
const extensions = (snapshot.strategyExtensions ?? []).filter((value) => value.provenance.entryId === entry.id);
|
|
8902
|
-
const roles = contributionRoles(snapshot, entry.id);
|
|
8903
|
-
if (roles.length === 0) roles.push(editor?.kind ?? (PACKAGE$1.exec(entry.options.name)?.[1] === "source" ? "source" : "strategy"));
|
|
8904
|
-
const typeId = editor?.typeId ?? strategies[0]?.definition.manifest.typeId ?? extensions[0]?.definition.manifest.typeId ?? sources[0]?.definition.manifest.typeId;
|
|
8905
|
-
const sourceLabel = sources[0]?.definition.manifest.management?.label;
|
|
8906
|
-
const label = editor?.label ?? {
|
|
8907
|
-
en: sourceLabel ?? typeId ?? entry.options.name,
|
|
8908
|
-
"zh-CN": sourceLabel ?? typeId ?? entry.options.name
|
|
8909
|
-
};
|
|
8910
|
-
const description = editor?.description ?? {
|
|
8911
|
-
en: "",
|
|
8912
|
-
"zh-CN": ""
|
|
8913
|
-
};
|
|
8914
|
-
const provides = roles.includes("source") ? [{ id: "source" }, ...sources.map((source) => ({ id: `source.${source.definition.manifest.role}` }))] : [{ id: roles.includes("strategy") ? "strategy" : `strategy.${typeId ?? hash(entry.options.name).slice(0, 12)}` }];
|
|
8915
|
-
return defineMemoryPlugin({
|
|
8916
|
-
packageName: entry.options.name,
|
|
8917
|
-
label,
|
|
8918
|
-
description,
|
|
8919
|
-
roles,
|
|
8920
|
-
provides
|
|
8921
|
-
});
|
|
8922
|
-
}
|
|
8923
|
-
function prepared(item, config) {
|
|
8924
|
-
if (item.editor === void 0) throw new Error(`Plugin does not expose a pure configuration factory: ${item.entry.id}`);
|
|
8925
|
-
const contribution = item.editor.create(config);
|
|
8926
|
-
if ([...contribution.strategies ?? [], ...contribution.strategyExtensions ?? []][0].manifest.packageName !== item.entry.options.name) throw new Error("Plugin factory does not match its declared Entry");
|
|
8927
|
-
if (contribution.plugin !== void 0 && hash(contribution.plugin) !== hash(item.descriptor)) throw new Error("Plugin factory descriptor does not match its module export");
|
|
8928
|
-
return prepareMemoryContributions({
|
|
8929
|
-
...contribution,
|
|
8930
|
-
plugin: contribution.plugin ?? item.descriptor
|
|
8931
|
-
}, { instanceId: item.entry.id });
|
|
8932
|
-
}
|
|
8933
|
-
function installedPlugin(descriptor, entryId) {
|
|
8934
|
-
return {
|
|
8935
|
-
kind: "plugin",
|
|
8936
|
-
instanceKey: `plugin:${entryId}`,
|
|
8937
|
-
provenance: {
|
|
8938
|
-
packageName: descriptor.packageName,
|
|
8939
|
-
entryId
|
|
8940
|
-
},
|
|
8941
|
-
descriptor
|
|
8942
|
-
};
|
|
8943
|
-
}
|
|
8944
|
-
function orderPlugins(values) {
|
|
8945
|
-
const byId = new Map(values.map((value) => [value.entryId, value]));
|
|
8946
|
-
const edges = new Map(values.map((value) => [value.entryId, /* @__PURE__ */ new Set()]));
|
|
8947
|
-
const indegree = new Map(values.map((value) => [value.entryId, 0]));
|
|
8948
|
-
for (const dependent of values) for (const requirement of dependent.requires) for (const provider of values) {
|
|
8949
|
-
if (provider.entryId === dependent.entryId || !provider.provides.some((capability) => capability.id === requirement)) continue;
|
|
8950
|
-
if (edges.get(provider.entryId).has(dependent.entryId)) continue;
|
|
8951
|
-
edges.get(provider.entryId).add(dependent.entryId);
|
|
8952
|
-
indegree.set(dependent.entryId, indegree.get(dependent.entryId) + 1);
|
|
8953
|
-
}
|
|
8954
|
-
const stable = (left, right) => byId.get(left).packageName.localeCompare(byId.get(right).packageName) || left.localeCompare(right);
|
|
8955
|
-
const ready = [...indegree].filter(([, count]) => count === 0).map(([entryId]) => entryId).sort(stable);
|
|
8956
|
-
const ordered = [];
|
|
8957
|
-
while (ready.length > 0) {
|
|
8958
|
-
const entryId = ready.shift();
|
|
8959
|
-
ordered.push(byId.get(entryId));
|
|
8960
|
-
for (const dependent of [...edges.get(entryId)].sort(stable)) {
|
|
8961
|
-
const next = indegree.get(dependent) - 1;
|
|
8962
|
-
indegree.set(dependent, next);
|
|
8963
|
-
if (next === 0) {
|
|
8964
|
-
ready.push(dependent);
|
|
8965
|
-
ready.sort(stable);
|
|
8966
|
-
}
|
|
8967
|
-
}
|
|
8968
|
-
}
|
|
8969
|
-
if (ordered.length < values.length) ordered.push(...values.filter((value) => !ordered.includes(value)).sort((left, right) => stable(left.entryId, right.entryId)));
|
|
8970
|
-
return ordered;
|
|
8971
|
-
}
|
|
8972
|
-
/**
|
|
8973
|
-
* Profile-local plugin graph overlay. Every dsh-mnemon Source or Strategy Entry
|
|
8974
|
-
* is one peer node; activation, configuration, dependency checks and rollback
|
|
8975
|
-
* use one transaction. Contribution roles do not create separate managers.
|
|
8976
|
-
*/
|
|
8977
|
-
var MemoryPluginManagement = class {
|
|
8978
|
-
ctx;
|
|
8979
|
-
engine;
|
|
8980
|
-
settingsService;
|
|
8981
|
-
settingsNamespace;
|
|
8982
|
-
settings;
|
|
8983
|
-
legacySettings;
|
|
8984
|
-
queue = Promise.resolve();
|
|
8985
|
-
closed = false;
|
|
8986
|
-
timer;
|
|
8987
|
-
restoreError;
|
|
8988
|
-
discoveryWarnings = [];
|
|
8989
|
-
changingEntries = false;
|
|
8990
|
-
restorePending = false;
|
|
8991
|
-
constructor(ctx, engine, settingsService = ctx.settings) {
|
|
8992
|
-
this.ctx = ctx;
|
|
8993
|
-
this.engine = engine;
|
|
8994
|
-
this.settingsService = settingsService;
|
|
8995
|
-
const loader = this.loader();
|
|
8996
|
-
const anchor = loader?.config?.baseUrl ?? loader?.ctx?.baseUrl ?? loader?.context?.baseUrl;
|
|
8997
|
-
const suffix = anchor ? `-${hash(anchor).slice(0, 16)}` : "";
|
|
8998
|
-
this.settingsNamespace = `${MNEMON_VIEW_SETTINGS_NAMESPACE}${suffix}`;
|
|
8999
|
-
this.settings = settingsService.register(this.settingsNamespace, schema, {
|
|
9000
|
-
base: { entries: {} },
|
|
9001
|
-
applies: "live",
|
|
9002
|
-
validate: (value) => {
|
|
9003
|
-
preferences(value);
|
|
9004
|
-
}
|
|
9005
|
-
});
|
|
9006
|
-
this.legacySettings = settingsService.register(`mnemon-plugins${suffix}`, legacySchema, {
|
|
9007
|
-
base: { sources: {} },
|
|
9008
|
-
applies: "live",
|
|
9009
|
-
validate: (value) => {
|
|
9010
|
-
legacyPreferences(value);
|
|
9011
|
-
}
|
|
9012
|
-
});
|
|
9013
|
-
}
|
|
9014
|
-
resolveConfig(config, view = this.settings.get()) {
|
|
9015
|
-
const selected = view.strategyTypeId;
|
|
9016
|
-
return selected === void 0 ? config : {
|
|
9017
|
-
...config,
|
|
9018
|
-
memoryTopology: {
|
|
9019
|
-
...config.memoryTopology,
|
|
9020
|
-
strategyId: selected
|
|
9021
|
-
}
|
|
9022
|
-
};
|
|
9023
|
-
}
|
|
9024
|
-
start() {
|
|
9025
|
-
const schedule = () => this.scheduleRestore();
|
|
9026
|
-
const stops = [
|
|
9027
|
-
this.ctx.on("loader/entry-init", schedule),
|
|
9028
|
-
this.ctx.on("loader/partial-dispose", schedule),
|
|
9029
|
-
this.ctx.on("app-boot/config-reload", () => this.scheduleRestore(true)),
|
|
9030
|
-
subscribeSettings(this.ctx, this.settingsService, (namespace) => {
|
|
9031
|
-
if (namespace === this.settingsNamespace || namespace === `mnemon-plugins${this.settingsNamespace.slice(11)}`) schedule();
|
|
9032
|
-
})
|
|
9033
|
-
];
|
|
9034
|
-
schedule();
|
|
9035
|
-
return () => {
|
|
9036
|
-
this.closed = true;
|
|
9037
|
-
this.restorePending = false;
|
|
9038
|
-
clearTimeout(this.timer);
|
|
9039
|
-
for (const stop of stops.reverse()) stop();
|
|
9040
|
-
};
|
|
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
|
-
}
|
|
9074
|
-
loader() {
|
|
9075
|
-
const candidate = this.ctx.get("loader");
|
|
9076
|
-
return candidate && typeof candidate.entries === "function" ? candidate : void 0;
|
|
9077
|
-
}
|
|
9078
|
-
settingsRevision() {
|
|
9079
|
-
return this.settingsService.describe({ redactSecrets: true }).find((value) => value.ns === this.settingsNamespace)?.revision ?? 0;
|
|
8581
|
+
/** The plugin manager owns enablement unless moving the saved choices failed. */
|
|
8582
|
+
enablementOwner() {
|
|
8583
|
+
return this.enablementMoveError === void 0 ? this.pluginManager() : void 0;
|
|
9080
8584
|
}
|
|
9081
8585
|
async managed() {
|
|
9082
8586
|
const loader = this.loader();
|
|
@@ -9168,7 +8672,7 @@ var MemoryPluginManagement = class {
|
|
|
9168
8672
|
const pending = this.queue;
|
|
9169
8673
|
const items = await this.managed();
|
|
9170
8674
|
if (pending !== this.queue || this.restorePending) return this.catalog();
|
|
9171
|
-
const values = items.map((item) => clone(item.value));
|
|
8675
|
+
const values = items.map((item) => clone$1(item.value));
|
|
9172
8676
|
const snapshot = this.engine.contributionSnapshot();
|
|
9173
8677
|
const managedIds = new Set(items.map((item) => item.entry.id));
|
|
9174
8678
|
const entryIds = new Set([
|
|
@@ -9228,7 +8732,7 @@ var MemoryPluginManagement = class {
|
|
|
9228
8732
|
revision: this.revision(items),
|
|
9229
8733
|
writable: this.settingsService.writable && this.loader() !== void 0,
|
|
9230
8734
|
entries: orderPlugins(values),
|
|
9231
|
-
diagnostics: [...this.discoveryWarnings, ...this.restoreError
|
|
8735
|
+
diagnostics: [...this.discoveryWarnings, ...[this.restoreError, this.enablementMoveError].filter((value) => value !== void 0)]
|
|
9232
8736
|
};
|
|
9233
8737
|
}
|
|
9234
8738
|
choices(items, entries) {
|
|
@@ -9259,7 +8763,10 @@ var MemoryPluginManagement = class {
|
|
|
9259
8763
|
entries: request.entries
|
|
9260
8764
|
});
|
|
9261
8765
|
const managedIds = new Set(items.map((item) => item.entry.id));
|
|
9262
|
-
for (const entryId of Object.
|
|
8766
|
+
for (const [entryId, value] of Object.entries(incoming.entries)) {
|
|
8767
|
+
if (!managedIds.has(entryId)) throw new Error("Memory plugin Entry is not managed by this Host: " + entryId);
|
|
8768
|
+
if (typeof value.enabled !== "boolean") throw new Error("Plugin enabled must be boolean");
|
|
8769
|
+
}
|
|
9263
8770
|
const choices = this.choices(items, incoming.entries);
|
|
9264
8771
|
for (const item of items) {
|
|
9265
8772
|
const chosen = choices.get(item.entry.id);
|
|
@@ -9316,8 +8823,9 @@ var MemoryPluginManagement = class {
|
|
|
9316
8823
|
}
|
|
9317
8824
|
async evaluateSnapshot(snapshot, config, scope, strategyTypeId, signal) {
|
|
9318
8825
|
signal?.throwIfAborted();
|
|
8826
|
+
const { strategyFallback: _fallback, ...options } = memoryGenerationOptions(config, scope.workspaceId);
|
|
9319
8827
|
const generation = new MemoryCompositionGeneration(snapshot, {
|
|
9320
|
-
...
|
|
8828
|
+
...options,
|
|
9321
8829
|
strategyTypeId
|
|
9322
8830
|
});
|
|
9323
8831
|
try {
|
|
@@ -9339,14 +8847,24 @@ var MemoryPluginManagement = class {
|
|
|
9339
8847
|
const items = await this.managed();
|
|
9340
8848
|
const choices = this.validateRequest(items, request);
|
|
9341
8849
|
const expectedSettingsRevision = this.settingsRevision();
|
|
8850
|
+
const manager = this.enablementOwner();
|
|
9342
8851
|
const previous = preferences(this.settings.get());
|
|
8852
|
+
const merged = {
|
|
8853
|
+
...previous.entries,
|
|
8854
|
+
...request.entries
|
|
8855
|
+
};
|
|
9343
8856
|
const next = preferences({
|
|
9344
8857
|
strategyTypeId: request.strategyTypeId,
|
|
9345
|
-
entries:
|
|
9346
|
-
...previous.entries,
|
|
9347
|
-
...request.entries
|
|
9348
|
-
}
|
|
8858
|
+
entries: manager === void 0 ? merged : configurationOnly(merged)
|
|
9349
8859
|
});
|
|
8860
|
+
const toggles = manager === void 0 ? [] : items.flatMap((item) => {
|
|
8861
|
+
const enabled = choices.get(item.entry.id).enabled;
|
|
8862
|
+
return enabled === !item.entry.disabled ? [] : [{
|
|
8863
|
+
entryId: item.entry.id,
|
|
8864
|
+
enabled
|
|
8865
|
+
}];
|
|
8866
|
+
}).sort((left, right) => Number(right.enabled) - Number(left.enabled));
|
|
8867
|
+
const written = [];
|
|
9350
8868
|
let committedRevision;
|
|
9351
8869
|
await this.updateEntries(items, choices, {
|
|
9352
8870
|
validate: () => this.evaluateSnapshot(this.engine.contributionSnapshot(), config, scope, request.strategyTypeId, signal),
|
|
@@ -9361,8 +8879,13 @@ var MemoryPluginManagement = class {
|
|
|
9361
8879
|
value: next.entries
|
|
9362
8880
|
}], expectedSettingsRevision);
|
|
9363
8881
|
committedRevision = this.settingsRevision();
|
|
8882
|
+
for (const toggle of toggles) {
|
|
8883
|
+
await this.setEnabled(manager, toggle.entryId, toggle.enabled);
|
|
8884
|
+
written.push(toggle);
|
|
8885
|
+
}
|
|
9364
8886
|
},
|
|
9365
8887
|
compensate: async () => {
|
|
8888
|
+
for (const toggle of [...written].reverse()) await this.setEnabled(manager, toggle.entryId, !toggle.enabled);
|
|
9366
8889
|
if (hash(preferences(this.settings.get())) !== hash(next)) throw new Error("Memory plugin settings changed before rollback; refresh and inspect the saved configuration.");
|
|
9367
8890
|
await this.settingsService.mutate(this.settingsNamespace, [previous.strategyTypeId === void 0 ? {
|
|
9368
8891
|
op: "unset",
|
|
@@ -9381,15 +8904,56 @@ var MemoryPluginManagement = class {
|
|
|
9381
8904
|
this.restoreError = void 0;
|
|
9382
8905
|
});
|
|
9383
8906
|
}
|
|
8907
|
+
/** Move saved enablement into the profile patch once, keeping only configuration overlays. */
|
|
8908
|
+
async moveEnablement(manager, items) {
|
|
8909
|
+
const saved = this.settings.get().entries ?? {};
|
|
8910
|
+
const legacy = this.legacySettings.get().sources ?? {};
|
|
8911
|
+
const moves = items.flatMap((item) => {
|
|
8912
|
+
const enabled = saved[item.entry.id] !== void 0 ? saved[item.entry.id].enabled : item.descriptor.roles.includes("source") ? legacy[item.entry.id]?.enabled : void 0;
|
|
8913
|
+
return enabled === void 0 ? [] : [{
|
|
8914
|
+
entryId: item.entry.id,
|
|
8915
|
+
enabled
|
|
8916
|
+
}];
|
|
8917
|
+
}).sort((left, right) => Number(right.enabled) - Number(left.enabled));
|
|
8918
|
+
if (moves.length === 0 && Object.keys(legacy).length === 0) return false;
|
|
8919
|
+
const legacyNamespace = `mnemon-plugins${this.settingsNamespace.slice(11)}`;
|
|
8920
|
+
const revisions = {
|
|
8921
|
+
view: this.settingsRevision(),
|
|
8922
|
+
legacy: this.settingsRevision(legacyNamespace)
|
|
8923
|
+
};
|
|
8924
|
+
for (const move of moves) await this.setEnabled(manager, move.entryId, move.enabled);
|
|
8925
|
+
await this.settingsService.mutate(this.settingsNamespace, [{
|
|
8926
|
+
op: "set",
|
|
8927
|
+
path: ["entries"],
|
|
8928
|
+
value: configurationOnly(saved)
|
|
8929
|
+
}], revisions.view);
|
|
8930
|
+
if (Object.keys(legacy).length > 0) await this.settingsService.mutate(legacyNamespace, [{
|
|
8931
|
+
op: "set",
|
|
8932
|
+
path: ["sources"],
|
|
8933
|
+
value: {}
|
|
8934
|
+
}], revisions.legacy);
|
|
8935
|
+
return true;
|
|
8936
|
+
}
|
|
9384
8937
|
async restore() {
|
|
9385
8938
|
if (this.closed) return;
|
|
9386
|
-
|
|
8939
|
+
let items = await this.managed();
|
|
8940
|
+
const available = this.enablementOwner();
|
|
8941
|
+
if (available !== void 0 && this.settingsService.writable) try {
|
|
8942
|
+
if (await this.moveEnablement(available, items)) items = await this.managed();
|
|
8943
|
+
} catch (error) {
|
|
8944
|
+
this.enablementMoveError = `Saved plugin choices could not move into the DSH profile and stay managed by Mnemon: ${error instanceof Error ? error.message : String(error)}`;
|
|
8945
|
+
}
|
|
8946
|
+
const manager = this.enablementOwner();
|
|
9387
8947
|
const saved = this.settings.get().entries ?? {};
|
|
9388
8948
|
const legacy = this.legacySettings.get().sources ?? {};
|
|
9389
8949
|
const desired = Object.fromEntries(items.flatMap((item) => {
|
|
9390
8950
|
const unified = saved[item.entry.id];
|
|
9391
|
-
|
|
9392
|
-
|
|
8951
|
+
const current = !item.entry.disabled;
|
|
8952
|
+
if (unified !== void 0) return [[item.entry.id, {
|
|
8953
|
+
enabled: manager === void 0 ? unified.enabled ?? current : current,
|
|
8954
|
+
config: unified.config
|
|
8955
|
+
}]];
|
|
8956
|
+
const oldSource = manager === void 0 && item.descriptor.roles.includes("source") ? legacy[item.entry.id] : void 0;
|
|
9393
8957
|
return oldSource === void 0 ? [] : [[item.entry.id, {
|
|
9394
8958
|
enabled: oldSource.enabled,
|
|
9395
8959
|
config: item.value.config
|
|
@@ -9408,7 +8972,7 @@ var MemoryPluginManagement = class {
|
|
|
9408
8972
|
const previous = items.map((item) => ({
|
|
9409
8973
|
item,
|
|
9410
8974
|
disabled: item.entry.options.disabled ?? null,
|
|
9411
|
-
config: clone(item.entry.options.config ?? {}),
|
|
8975
|
+
config: clone$1(item.entry.options.config ?? {}),
|
|
9412
8976
|
enabled: item.value.enabled,
|
|
9413
8977
|
active: item.value.active
|
|
9414
8978
|
}));
|
|
@@ -9429,7 +8993,7 @@ var MemoryPluginManagement = class {
|
|
|
9429
8993
|
touched.add(item.entry.id);
|
|
9430
8994
|
await item.entry.update(item.editor === void 0 ? { disabled: !desired.enabled } : {
|
|
9431
8995
|
disabled: !desired.enabled,
|
|
9432
|
-
config: clone(desired.config)
|
|
8996
|
+
config: clone$1(desired.config)
|
|
9433
8997
|
});
|
|
9434
8998
|
await item.entry.fiber?.await?.();
|
|
9435
8999
|
const registered = contributionRoles(this.engine.contributionSnapshot(), item.entry.id).length > 0;
|
|
@@ -9511,7 +9075,7 @@ var MemoryPluginManagement = class {
|
|
|
9511
9075
|
};
|
|
9512
9076
|
//#endregion
|
|
9513
9077
|
//#region src/host/view-rpc.ts
|
|
9514
|
-
function object(value) {
|
|
9078
|
+
function object$2(value) {
|
|
9515
9079
|
if (typeof value !== "object" || value === null || Array.isArray(value)) throw new Error("View request must be an object");
|
|
9516
9080
|
return value;
|
|
9517
9081
|
}
|
|
@@ -9528,7 +9092,7 @@ function createViewHandler(runtime, engine, management, access, lifecycle, insta
|
|
|
9528
9092
|
"preview",
|
|
9529
9093
|
"inspect-plugin"
|
|
9530
9094
|
].includes(endpoint) : !["apply", "install-plugin"].includes(endpoint)) throw new Error("View operation is not available on this channel");
|
|
9531
|
-
const payload = object(input);
|
|
9095
|
+
const payload = object$2(input);
|
|
9532
9096
|
if (endpoint === "inspect-plugin") {
|
|
9533
9097
|
if (installation === void 0 || typeof payload.packageName !== "string") throw new Error("Plugin discovery is unavailable");
|
|
9534
9098
|
return {
|
|
@@ -9590,9 +9154,9 @@ function createViewHandler(runtime, engine, management, access, lifecycle, insta
|
|
|
9590
9154
|
};
|
|
9591
9155
|
}
|
|
9592
9156
|
if (endpoint !== "preview" && endpoint !== "apply") throw new Error("Unknown View operation");
|
|
9593
|
-
const raw = object(payload.configuration);
|
|
9157
|
+
const raw = object$2(payload.configuration);
|
|
9594
9158
|
if (typeof raw.expectedRevision !== "string" || typeof raw.strategyTypeId !== "string") throw new Error("View configuration requires a revision and Strategy id");
|
|
9595
|
-
object(raw.entries);
|
|
9159
|
+
object$2(raw.entries);
|
|
9596
9160
|
const request = raw;
|
|
9597
9161
|
if (endpoint === "preview") return {
|
|
9598
9162
|
ok: true,
|
|
@@ -9616,11 +9180,11 @@ function createViewHandler(runtime, engine, management, access, lifecycle, insta
|
|
|
9616
9180
|
}
|
|
9617
9181
|
};
|
|
9618
9182
|
}
|
|
9619
|
-
function registerViewRpc(connection, runtime, engine, management, lifecycle,
|
|
9183
|
+
function registerViewRpc(connection, runtime, engine, management, lifecycle, installation) {
|
|
9620
9184
|
const readHandler = createViewHandler(runtime, engine, management, "read", lifecycle, installation);
|
|
9621
9185
|
const writeHandler = createViewHandler(runtime, engine, management, "write", lifecycle, installation);
|
|
9622
|
-
connection.rpc.handle(MNEMON_VIEW_CHANNEL, readHandler
|
|
9623
|
-
connection.rpc.handle(MNEMON_VIEW_WRITE_CHANNEL, writeHandler
|
|
9186
|
+
connection.rpc.handle(MNEMON_VIEW_CHANNEL, readHandler);
|
|
9187
|
+
connection.rpc.handle(MNEMON_VIEW_WRITE_CHANNEL, writeHandler);
|
|
9624
9188
|
return {
|
|
9625
9189
|
read: readHandler,
|
|
9626
9190
|
write: writeHandler
|
|
@@ -9879,179 +9443,690 @@ var __esDecorate = function(ctor, descriptorIn, decorators, contextIn, initializ
|
|
|
9879
9443
|
else descriptor[key] = _;
|
|
9880
9444
|
}
|
|
9881
9445
|
}
|
|
9882
|
-
if (target) Object.defineProperty(target, contextIn.name, descriptor);
|
|
9883
|
-
done = true;
|
|
9884
|
-
};
|
|
9885
|
-
function denied() {
|
|
9886
|
-
return {
|
|
9887
|
-
ok: false,
|
|
9888
|
-
error: {
|
|
9889
|
-
code: "bad-request",
|
|
9890
|
-
message: "remote Mnemon management requires remoteAccess: trusted-host",
|
|
9891
|
-
details: { issues: [] }
|
|
9446
|
+
if (target) Object.defineProperty(target, contextIn.name, descriptor);
|
|
9447
|
+
done = true;
|
|
9448
|
+
};
|
|
9449
|
+
function denied() {
|
|
9450
|
+
return {
|
|
9451
|
+
ok: false,
|
|
9452
|
+
error: {
|
|
9453
|
+
code: "bad-request",
|
|
9454
|
+
message: "remote Mnemon management requires remoteAccess: trusted-host",
|
|
9455
|
+
details: { issues: [] }
|
|
9456
|
+
}
|
|
9457
|
+
};
|
|
9458
|
+
}
|
|
9459
|
+
function unknownSettingsEndpoint(endpoint) {
|
|
9460
|
+
return {
|
|
9461
|
+
ok: false,
|
|
9462
|
+
error: {
|
|
9463
|
+
code: "bad-request",
|
|
9464
|
+
message: `unknown remote Mnemon settings endpoint: ${endpoint}`,
|
|
9465
|
+
details: { issues: [] }
|
|
9466
|
+
}
|
|
9467
|
+
};
|
|
9468
|
+
}
|
|
9469
|
+
/**
|
|
9470
|
+
* Project Mnemon's existing handlers through DSH API Gateway. The Gateway owns
|
|
9471
|
+
* `/api`, Host/Origin validation, browser pairing, and response envelopes;
|
|
9472
|
+
* this Service retains Mnemon's narrower management grant.
|
|
9473
|
+
*/
|
|
9474
|
+
let MnemonRemoteService = (() => {
|
|
9475
|
+
let _classSuper = TypertRemoteService;
|
|
9476
|
+
let _instanceExtraInitializers = [];
|
|
9477
|
+
let _read_decorators;
|
|
9478
|
+
let _activation_decorators;
|
|
9479
|
+
let _write_decorators;
|
|
9480
|
+
let _pack_decorators;
|
|
9481
|
+
let _settings_decorators;
|
|
9482
|
+
let _view_decorators;
|
|
9483
|
+
let _viewWrite_decorators;
|
|
9484
|
+
return class MnemonRemoteService extends _classSuper {
|
|
9485
|
+
static {
|
|
9486
|
+
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
|
|
9487
|
+
_read_decorators = [Remote("read")];
|
|
9488
|
+
_activation_decorators = [Remote("activation")];
|
|
9489
|
+
_write_decorators = [Remote("write")];
|
|
9490
|
+
_pack_decorators = [Remote("pack")];
|
|
9491
|
+
_settings_decorators = [Remote("settings")];
|
|
9492
|
+
_view_decorators = [Remote("view")];
|
|
9493
|
+
_viewWrite_decorators = [Remote("viewWrite")];
|
|
9494
|
+
__esDecorate(this, null, _read_decorators, {
|
|
9495
|
+
kind: "method",
|
|
9496
|
+
name: "read",
|
|
9497
|
+
static: false,
|
|
9498
|
+
private: false,
|
|
9499
|
+
access: {
|
|
9500
|
+
has: (obj) => "read" in obj,
|
|
9501
|
+
get: (obj) => obj.read
|
|
9502
|
+
},
|
|
9503
|
+
metadata: _metadata
|
|
9504
|
+
}, null, _instanceExtraInitializers);
|
|
9505
|
+
__esDecorate(this, null, _activation_decorators, {
|
|
9506
|
+
kind: "method",
|
|
9507
|
+
name: "activation",
|
|
9508
|
+
static: false,
|
|
9509
|
+
private: false,
|
|
9510
|
+
access: {
|
|
9511
|
+
has: (obj) => "activation" in obj,
|
|
9512
|
+
get: (obj) => obj.activation
|
|
9513
|
+
},
|
|
9514
|
+
metadata: _metadata
|
|
9515
|
+
}, null, _instanceExtraInitializers);
|
|
9516
|
+
__esDecorate(this, null, _write_decorators, {
|
|
9517
|
+
kind: "method",
|
|
9518
|
+
name: "write",
|
|
9519
|
+
static: false,
|
|
9520
|
+
private: false,
|
|
9521
|
+
access: {
|
|
9522
|
+
has: (obj) => "write" in obj,
|
|
9523
|
+
get: (obj) => obj.write
|
|
9524
|
+
},
|
|
9525
|
+
metadata: _metadata
|
|
9526
|
+
}, null, _instanceExtraInitializers);
|
|
9527
|
+
__esDecorate(this, null, _pack_decorators, {
|
|
9528
|
+
kind: "method",
|
|
9529
|
+
name: "pack",
|
|
9530
|
+
static: false,
|
|
9531
|
+
private: false,
|
|
9532
|
+
access: {
|
|
9533
|
+
has: (obj) => "pack" in obj,
|
|
9534
|
+
get: (obj) => obj.pack
|
|
9535
|
+
},
|
|
9536
|
+
metadata: _metadata
|
|
9537
|
+
}, null, _instanceExtraInitializers);
|
|
9538
|
+
__esDecorate(this, null, _settings_decorators, {
|
|
9539
|
+
kind: "method",
|
|
9540
|
+
name: "settings",
|
|
9541
|
+
static: false,
|
|
9542
|
+
private: false,
|
|
9543
|
+
access: {
|
|
9544
|
+
has: (obj) => "settings" in obj,
|
|
9545
|
+
get: (obj) => obj.settings
|
|
9546
|
+
},
|
|
9547
|
+
metadata: _metadata
|
|
9548
|
+
}, null, _instanceExtraInitializers);
|
|
9549
|
+
__esDecorate(this, null, _view_decorators, {
|
|
9550
|
+
kind: "method",
|
|
9551
|
+
name: "view",
|
|
9552
|
+
static: false,
|
|
9553
|
+
private: false,
|
|
9554
|
+
access: {
|
|
9555
|
+
has: (obj) => "view" in obj,
|
|
9556
|
+
get: (obj) => obj.view
|
|
9557
|
+
},
|
|
9558
|
+
metadata: _metadata
|
|
9559
|
+
}, null, _instanceExtraInitializers);
|
|
9560
|
+
__esDecorate(this, null, _viewWrite_decorators, {
|
|
9561
|
+
kind: "method",
|
|
9562
|
+
name: "viewWrite",
|
|
9563
|
+
static: false,
|
|
9564
|
+
private: false,
|
|
9565
|
+
access: {
|
|
9566
|
+
has: (obj) => "viewWrite" in obj,
|
|
9567
|
+
get: (obj) => obj.viewWrite
|
|
9568
|
+
},
|
|
9569
|
+
metadata: _metadata
|
|
9570
|
+
}, null, _instanceExtraInitializers);
|
|
9571
|
+
if (_metadata) Object.defineProperty(this, Symbol.metadata, {
|
|
9572
|
+
enumerable: true,
|
|
9573
|
+
configurable: true,
|
|
9574
|
+
writable: true,
|
|
9575
|
+
value: _metadata
|
|
9576
|
+
});
|
|
9577
|
+
}
|
|
9578
|
+
handlers = __runInitializers(this, _instanceExtraInitializers);
|
|
9579
|
+
constructor(ctx, handlers) {
|
|
9580
|
+
super(ctx, "mnemonRemote", { namespace: MNEMON_REMOTE_NAMESPACE });
|
|
9581
|
+
this.handlers = handlers;
|
|
9582
|
+
}
|
|
9583
|
+
read(endpoint, payload, signal) {
|
|
9584
|
+
return this.handlers.read(endpoint, payload, signal);
|
|
9585
|
+
}
|
|
9586
|
+
activation(endpoint, payload, signal) {
|
|
9587
|
+
return this.handlers.activation(endpoint, payload, signal);
|
|
9588
|
+
}
|
|
9589
|
+
write(endpoint, payload, signal) {
|
|
9590
|
+
if (!this.handlers.management) return Promise.resolve(denied());
|
|
9591
|
+
return this.handlers.write(endpoint, payload, signal);
|
|
9592
|
+
}
|
|
9593
|
+
pack(endpoint, payload, signal) {
|
|
9594
|
+
if (!this.handlers.management) return Promise.resolve(denied());
|
|
9595
|
+
return this.handlers.pack(endpoint, payload, signal);
|
|
9596
|
+
}
|
|
9597
|
+
async settings(endpoint, payload, signal) {
|
|
9598
|
+
if (endpoint === "mutate" && !this.handlers.management) return denied();
|
|
9599
|
+
if (endpoint !== "get" && endpoint !== "mutate") return unknownSettingsEndpoint(endpoint);
|
|
9600
|
+
const response = await this.handlers.settings(endpoint, payload, signal);
|
|
9601
|
+
if (endpoint !== "get" || this.handlers.management || !response.ok || typeof response.value !== "object" || response.value === null || Array.isArray(response.value)) return response;
|
|
9602
|
+
return {
|
|
9603
|
+
...response,
|
|
9604
|
+
value: {
|
|
9605
|
+
...response.value,
|
|
9606
|
+
writable: false
|
|
9607
|
+
}
|
|
9608
|
+
};
|
|
9609
|
+
}
|
|
9610
|
+
view(endpoint, payload, signal) {
|
|
9611
|
+
return this.handlers.view(endpoint, payload, signal);
|
|
9612
|
+
}
|
|
9613
|
+
viewWrite(endpoint, payload, signal) {
|
|
9614
|
+
if (!this.handlers.management) return Promise.resolve(denied());
|
|
9615
|
+
return this.handlers.viewWrite(endpoint, payload, signal);
|
|
9616
|
+
}
|
|
9617
|
+
};
|
|
9618
|
+
})();
|
|
9619
|
+
//#endregion
|
|
9620
|
+
//#region src/host/live-config.ts
|
|
9621
|
+
function plain(value) {
|
|
9622
|
+
if (isVolatile(value)) return plain(value.get());
|
|
9623
|
+
if (Array.isArray(value)) return value.map(plain);
|
|
9624
|
+
if (value === null || typeof value !== "object") return value;
|
|
9625
|
+
const prototype = Object.getPrototypeOf(value);
|
|
9626
|
+
if (prototype !== Object.prototype && prototype !== null) return value;
|
|
9627
|
+
return Object.fromEntries(Object.entries(value).map(([key, child]) => [key, plain(child)]));
|
|
9628
|
+
}
|
|
9629
|
+
/** Read a detached snapshot of the live profile configuration. */
|
|
9630
|
+
function plainHostConfig(value = {}) {
|
|
9631
|
+
return plain(value);
|
|
9632
|
+
}
|
|
9633
|
+
function liveConfig() {
|
|
9634
|
+
const schema = new z(Config.toJSON());
|
|
9635
|
+
schema.dict = Object.fromEntries(Object.entries(schema.dict ?? {}).map(([key, field]) => [key, key === "remoteAccess" ? field : field.volatile()]));
|
|
9636
|
+
const standard = schema["~standard"];
|
|
9637
|
+
Object.defineProperty(schema, "~standard", { value: {
|
|
9638
|
+
...standard,
|
|
9639
|
+
validate(value) {
|
|
9640
|
+
const parsed = standard.validate(value);
|
|
9641
|
+
if ("then" in parsed) throw new TypeError("Mnemon configuration validation must be synchronous");
|
|
9642
|
+
if (parsed.issues) return parsed;
|
|
9643
|
+
try {
|
|
9644
|
+
resolveConfig(plainHostConfig(parsed.value));
|
|
9645
|
+
return parsed;
|
|
9646
|
+
} catch (error) {
|
|
9647
|
+
return { issues: [{ message: error instanceof Error ? error.message : String(error) }] };
|
|
9648
|
+
}
|
|
9649
|
+
}
|
|
9650
|
+
} });
|
|
9651
|
+
return schema;
|
|
9652
|
+
}
|
|
9653
|
+
/** Profile Config for live forms; transport authority retains normal remounts. */
|
|
9654
|
+
const LiveConfig = liveConfig();
|
|
9655
|
+
//#endregion
|
|
9656
|
+
//#region src/host/legacy-settings-import.ts
|
|
9657
|
+
const UNSAFE_KEYS = /* @__PURE__ */ new Set([
|
|
9658
|
+
"__proto__",
|
|
9659
|
+
"prototype",
|
|
9660
|
+
"constructor"
|
|
9661
|
+
]);
|
|
9662
|
+
const ENTRY_ID = /^[a-zA-Z0-9][a-zA-Z0-9._:/-]{0,299}$/u;
|
|
9663
|
+
const STRATEGY_ID = /^[a-z][a-z0-9-]{0,127}$/u;
|
|
9664
|
+
const VIEW_NAMESPACE = /^mnemon-view(?:-[a-f0-9]{16})?$/u;
|
|
9665
|
+
const LEGACY_NAMESPACE = /^mnemon-plugins(?:-[a-f0-9]{16})?$/u;
|
|
9666
|
+
function object$1(value, label) {
|
|
9667
|
+
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`);
|
|
9668
|
+
for (const key of Reflect.ownKeys(value)) {
|
|
9669
|
+
if (typeof key !== "string" || UNSAFE_KEYS.has(key)) throw new Error(`${label} contains an unsafe key`);
|
|
9670
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
9671
|
+
if (!descriptor.enumerable || !Object.hasOwn(descriptor, "value")) throw new Error(`${label} must contain only data properties`);
|
|
9672
|
+
}
|
|
9673
|
+
return value;
|
|
9674
|
+
}
|
|
9675
|
+
/** Copy JSON data without invoking getters, serializers or prototype methods. */
|
|
9676
|
+
function copy(value, label, ancestors = /* @__PURE__ */ new Set(), depth = 0) {
|
|
9677
|
+
if (value === null || typeof value === "string" || typeof value === "boolean") return value;
|
|
9678
|
+
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
9679
|
+
if (typeof value !== "object" || value === null) throw new Error(`${label} must contain only JSON data`);
|
|
9680
|
+
if (depth > 64 || ancestors.has(value)) throw new Error(`${label} contains cyclic or excessively nested data`);
|
|
9681
|
+
ancestors.add(value);
|
|
9682
|
+
try {
|
|
9683
|
+
if (Array.isArray(value)) {
|
|
9684
|
+
if (Object.getPrototypeOf(value) !== Array.prototype) throw new Error(`${label} must contain plain arrays`);
|
|
9685
|
+
if (Reflect.ownKeys(value).length !== value.length + 1) throw new Error(`${label} contains a sparse or extended array`);
|
|
9686
|
+
return Array.from({ length: value.length }, (_, index) => {
|
|
9687
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, String(index));
|
|
9688
|
+
if (!descriptor || !descriptor.enumerable || !Object.hasOwn(descriptor, "value")) throw new Error(`${label} must contain only data properties`);
|
|
9689
|
+
return copy(descriptor.value, label, ancestors, depth + 1);
|
|
9690
|
+
});
|
|
9691
|
+
}
|
|
9692
|
+
return Object.fromEntries(Object.entries(object$1(value, label)).map(([key, item]) => [key, copy(item, label, ancestors, depth + 1)]));
|
|
9693
|
+
} finally {
|
|
9694
|
+
ancestors.delete(value);
|
|
9695
|
+
}
|
|
9696
|
+
}
|
|
9697
|
+
function copiedObject(value, label) {
|
|
9698
|
+
object$1(value, label);
|
|
9699
|
+
return copy(value, label);
|
|
9700
|
+
}
|
|
9701
|
+
/** Inspect validated copies only; never evaluate expressions or invoke getters. */
|
|
9702
|
+
function containsExpression(value) {
|
|
9703
|
+
return value !== null && typeof value === "object" && (Object.hasOwn(value, "__jsExpr") || Object.values(value).some(containsExpression));
|
|
9704
|
+
}
|
|
9705
|
+
function fields(value, allowed, label) {
|
|
9706
|
+
if (Object.keys(value).some((key) => !allowed.includes(key))) throw new Error(`${label} contains unsupported fields`);
|
|
9707
|
+
}
|
|
9708
|
+
function interaction(value, label, allowed) {
|
|
9709
|
+
const result = copiedObject(value, label);
|
|
9710
|
+
fields(result, allowed, label);
|
|
9711
|
+
if (Object.values(result).some((item) => typeof item !== "boolean")) throw new Error(`${label} preferences must be boolean`);
|
|
9712
|
+
return result;
|
|
9713
|
+
}
|
|
9714
|
+
function entryId(value, label) {
|
|
9715
|
+
if (typeof value !== "string" || !ENTRY_ID.test(value) || UNSAFE_KEYS.has(value)) throw new Error(`${label} contains an invalid Entry id`);
|
|
9716
|
+
}
|
|
9717
|
+
function view(value, label) {
|
|
9718
|
+
const result = copiedObject(value, label);
|
|
9719
|
+
fields(result, ["strategyTypeId", "entries"], label);
|
|
9720
|
+
if (Object.hasOwn(result, "strategyTypeId") && (typeof result.strategyTypeId !== "string" || !STRATEGY_ID.test(result.strategyTypeId))) throw new Error(`${label} contains an invalid Strategy type id`);
|
|
9721
|
+
const entries = {};
|
|
9722
|
+
if (Object.hasOwn(result, "entries")) {
|
|
9723
|
+
const values = object$1(result.entries, `${label}.entries`);
|
|
9724
|
+
if (Object.keys(values).length > 64) throw new Error(`${label} contains too many Entries`);
|
|
9725
|
+
for (const [id, raw] of Object.entries(values)) {
|
|
9726
|
+
entryId(id, label);
|
|
9727
|
+
const item = copiedObject(raw, `${label}.entries`);
|
|
9728
|
+
fields(item, ["enabled", "config"], `${label}.entries`);
|
|
9729
|
+
if (Object.hasOwn(item, "enabled") && typeof item.enabled !== "boolean") throw new Error(`${label} Entry enabled must be boolean`);
|
|
9730
|
+
const config = Object.hasOwn(item, "config") ? copiedObject(item.config, `${label} Entry config`) : {};
|
|
9731
|
+
if (JSON.stringify(config).length > 65536) throw new Error(`${label} Entry config exceeds 64 KiB`);
|
|
9732
|
+
entries[id] = {
|
|
9733
|
+
...typeof item.enabled === "boolean" ? { enabled: item.enabled } : {},
|
|
9734
|
+
config
|
|
9735
|
+
};
|
|
9736
|
+
}
|
|
9737
|
+
}
|
|
9738
|
+
return {
|
|
9739
|
+
...typeof result.strategyTypeId === "string" ? { strategyTypeId: result.strategyTypeId } : {},
|
|
9740
|
+
...Object.hasOwn(result, "entries") ? { entries } : {}
|
|
9741
|
+
};
|
|
9742
|
+
}
|
|
9743
|
+
function sources(value, label, sourceEntryIds, diagnostics) {
|
|
9744
|
+
const result = copiedObject(value, label);
|
|
9745
|
+
fields(result, ["sources"], label);
|
|
9746
|
+
const values = Object.hasOwn(result, "sources") ? object$1(result.sources, `${label}.sources`) : {};
|
|
9747
|
+
if (Object.keys(values).length > 64) throw new Error(`${label} contains too many Source Entries`);
|
|
9748
|
+
const entries = {};
|
|
9749
|
+
for (const [id, raw] of Object.entries(values)) {
|
|
9750
|
+
entryId(id, label);
|
|
9751
|
+
const item = copiedObject(raw, `${label}.sources`);
|
|
9752
|
+
fields(item, ["enabled"], `${label}.sources`);
|
|
9753
|
+
if (typeof item.enabled !== "boolean") throw new Error(`${label} Source enabled must be boolean`);
|
|
9754
|
+
if (!sourceEntryIds.has(id)) {
|
|
9755
|
+
diagnostics.push(`Skipped legacy Source preference for ${id}: the current profile does not declare it as a Source.`);
|
|
9756
|
+
continue;
|
|
9757
|
+
}
|
|
9758
|
+
entries[id] = {
|
|
9759
|
+
enabled: item.enabled,
|
|
9760
|
+
config: {}
|
|
9761
|
+
};
|
|
9762
|
+
}
|
|
9763
|
+
return entries;
|
|
9764
|
+
}
|
|
9765
|
+
function applyEntryOverrides(entries, overrides, sourceEntryIds, diagnostics) {
|
|
9766
|
+
if (!Array.isArray(overrides)) throw new Error("Explicit Entry overrides must be an array");
|
|
9767
|
+
const matching = /* @__PURE__ */ new Map();
|
|
9768
|
+
for (const raw of overrides) {
|
|
9769
|
+
const row = object$1(raw, "Explicit Entry override");
|
|
9770
|
+
entryId(row.id, "Explicit Entry override");
|
|
9771
|
+
if (!Object.hasOwn(entries, row.id)) continue;
|
|
9772
|
+
const previous = matching.get(row.id) ?? {};
|
|
9773
|
+
matching.set(row.id, {
|
|
9774
|
+
...previous,
|
|
9775
|
+
...row.disabled === void 0 ? {} : { disabled: row.disabled },
|
|
9776
|
+
...row.config === void 0 ? {} : { config: row.config }
|
|
9777
|
+
});
|
|
9778
|
+
}
|
|
9779
|
+
for (const [id, row] of matching) {
|
|
9780
|
+
if (row.disabled !== void 0 && typeof row.disabled !== "boolean") {
|
|
9781
|
+
delete entries[id];
|
|
9782
|
+
diagnostics.push(`Skipped legacy View preference for ${id}: its explicit disabled value is not boolean.`);
|
|
9783
|
+
continue;
|
|
9784
|
+
}
|
|
9785
|
+
if (row.config !== void 0 && !sourceEntryIds.has(id)) {
|
|
9786
|
+
const config = copiedObject(row.config, "Explicit Entry config");
|
|
9787
|
+
if (containsExpression(config)) {
|
|
9788
|
+
delete entries[id];
|
|
9789
|
+
diagnostics.push(`Skipped legacy View preference for ${id}: its explicit config contains an expression.`);
|
|
9790
|
+
continue;
|
|
9791
|
+
}
|
|
9792
|
+
entries[id].config = config;
|
|
9793
|
+
}
|
|
9794
|
+
if (typeof row.disabled === "boolean") entries[id].enabled = !row.disabled;
|
|
9795
|
+
}
|
|
9796
|
+
}
|
|
9797
|
+
/**
|
|
9798
|
+
* Recover only the canonical root and the exact owning profile's old namespaces.
|
|
9799
|
+
* This does not read files, edit profile rows, validate plugin domains or commit.
|
|
9800
|
+
* Malformed relevant input rejects the complete plan without an import marker.
|
|
9801
|
+
*/
|
|
9802
|
+
function planLegacySettingsImport(options) {
|
|
9803
|
+
const diagnostics = [];
|
|
9804
|
+
try {
|
|
9805
|
+
const rawCurrent = object$1(options.currentOverride, "Current config override");
|
|
9806
|
+
if (rawCurrent.legacySettingsImported === true) return {
|
|
9807
|
+
patch: {},
|
|
9808
|
+
diagnostics
|
|
9809
|
+
};
|
|
9810
|
+
if (options.entryId !== "mnemon") throw new Error("Legacy settings belong to the canonical mnemon Entry; another root Entry is ambiguous.");
|
|
9811
|
+
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.");
|
|
9812
|
+
const sections = object$1(options.sections, "Legacy settings document");
|
|
9813
|
+
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.");
|
|
9814
|
+
const relevant = [
|
|
9815
|
+
"mnemon",
|
|
9816
|
+
"mnemon-ui",
|
|
9817
|
+
options.viewNamespace,
|
|
9818
|
+
options.legacyNamespace
|
|
9819
|
+
];
|
|
9820
|
+
if (!relevant.some((key) => Object.hasOwn(sections, key))) return {
|
|
9821
|
+
patch: {},
|
|
9822
|
+
diagnostics
|
|
9823
|
+
};
|
|
9824
|
+
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.`);
|
|
9825
|
+
const current = copiedObject(rawCurrent, "Current config override");
|
|
9826
|
+
if (Object.hasOwn(current, "legacySettingsImported") && typeof current.legacySettingsImported !== "boolean") throw new Error("Current import marker must be boolean");
|
|
9827
|
+
const root = Object.hasOwn(sections, "mnemon") ? copiedObject(sections.mnemon, "mnemon") : {};
|
|
9828
|
+
if (Object.hasOwn(root, "memoryView") || Object.hasOwn(root, "legacySettingsImported")) throw new Error("Legacy mnemon contains reserved migration fields");
|
|
9829
|
+
const oldInteraction = Object.hasOwn(root, "conversationInteraction") ? interaction(root.conversationInteraction, "mnemon.conversationInteraction", [
|
|
9830
|
+
"toolviews",
|
|
9831
|
+
"turnBar",
|
|
9832
|
+
"saveAction"
|
|
9833
|
+
]) : {};
|
|
9834
|
+
const oldUi = Object.hasOwn(sections, "mnemon-ui") ? interaction(sections["mnemon-ui"], "mnemon-ui", ["turnBar", "saveAction"]) : {};
|
|
9835
|
+
const currentInteraction = Object.hasOwn(current, "conversationInteraction") ? interaction(current.conversationInteraction, "Current conversationInteraction", [
|
|
9836
|
+
"toolviews",
|
|
9837
|
+
"turnBar",
|
|
9838
|
+
"saveAction"
|
|
9839
|
+
]) : {};
|
|
9840
|
+
const patch = Object.fromEntries(Object.entries(root).filter(([key]) => key !== "conversationInteraction" && !Object.hasOwn(current, key)));
|
|
9841
|
+
const inheritedInteraction = {
|
|
9842
|
+
...oldInteraction,
|
|
9843
|
+
...oldUi
|
|
9844
|
+
};
|
|
9845
|
+
if (Object.keys(inheritedInteraction).some((key) => !Object.hasOwn(currentInteraction, key))) patch.conversationInteraction = {
|
|
9846
|
+
...inheritedInteraction,
|
|
9847
|
+
...currentInteraction
|
|
9848
|
+
};
|
|
9849
|
+
const currentView = Object.hasOwn(current, "memoryView") ? view(current.memoryView, "Current memoryView") : {};
|
|
9850
|
+
if (Object.hasOwn(sections, options.viewNamespace) || Object.hasOwn(sections, options.legacyNamespace)) {
|
|
9851
|
+
if (!Array.isArray(options.sourceEntryIds)) throw new Error("Source Entry ids must be an array");
|
|
9852
|
+
for (const id of options.sourceEntryIds) entryId(id, "Source Entry ids");
|
|
9853
|
+
const sourceEntryIds = new Set(options.sourceEntryIds);
|
|
9854
|
+
const oldSources = Object.hasOwn(sections, options.legacyNamespace) ? sources(sections[options.legacyNamespace], options.legacyNamespace, sourceEntryIds, diagnostics) : {};
|
|
9855
|
+
const oldView = Object.hasOwn(sections, options.viewNamespace) ? view(sections[options.viewNamespace], options.viewNamespace) : {};
|
|
9856
|
+
const entries = {
|
|
9857
|
+
...oldSources,
|
|
9858
|
+
...oldView.entries
|
|
9859
|
+
};
|
|
9860
|
+
applyEntryOverrides(entries, options.entryOverrides, sourceEntryIds, diagnostics);
|
|
9861
|
+
const migratedView = {
|
|
9862
|
+
...oldView,
|
|
9863
|
+
entries,
|
|
9864
|
+
...currentView
|
|
9865
|
+
};
|
|
9866
|
+
if (!Object.hasOwn(currentView, "entries") || !Object.hasOwn(currentView, "strategyTypeId") && oldView.strategyTypeId !== void 0) patch.memoryView = migratedView;
|
|
9867
|
+
}
|
|
9868
|
+
patch.legacySettingsImported = true;
|
|
9869
|
+
return {
|
|
9870
|
+
patch,
|
|
9871
|
+
diagnostics
|
|
9872
|
+
};
|
|
9873
|
+
} catch (error) {
|
|
9874
|
+
diagnostics.push(error instanceof Error ? error.message : "Legacy settings import could not be planned");
|
|
9875
|
+
return {
|
|
9876
|
+
patch: {},
|
|
9877
|
+
diagnostics
|
|
9878
|
+
};
|
|
9879
|
+
}
|
|
9880
|
+
}
|
|
9881
|
+
//#endregion
|
|
9882
|
+
//#region src/host/settings-service.ts
|
|
9883
|
+
const pendingNativeImports = /* @__PURE__ */ new WeakSet();
|
|
9884
|
+
const clone = (value) => structuredClone(value);
|
|
9885
|
+
const object = (value) => value !== null && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
9886
|
+
function profileYaml(source) {
|
|
9887
|
+
const document = parseDocument(source, { customTags: [{
|
|
9888
|
+
tag: "tag:yaml.org,2002:js",
|
|
9889
|
+
resolve: (value) => ({ __jsExpr: value })
|
|
9890
|
+
}] });
|
|
9891
|
+
if (document.errors.length > 0 || document.warnings.length > 0) throw new Error("Invalid or unsupported legacy/profile YAML; retained backup was not changed");
|
|
9892
|
+
return document.toJS({ maxAliasCount: 100 });
|
|
9893
|
+
}
|
|
9894
|
+
/** A local facade preserves Mnemon's wire namespaces; DSH owns all persistence. */
|
|
9895
|
+
var ProfileMnemonSettings = class {
|
|
9896
|
+
ctx;
|
|
9897
|
+
input;
|
|
9898
|
+
registrations = /* @__PURE__ */ new Map();
|
|
9899
|
+
listeners = /* @__PURE__ */ new Set();
|
|
9900
|
+
revisions = /* @__PURE__ */ new Map();
|
|
9901
|
+
owner;
|
|
9902
|
+
forms;
|
|
9903
|
+
editor;
|
|
9904
|
+
closed = false;
|
|
9905
|
+
importing;
|
|
9906
|
+
nativeImportPending;
|
|
9907
|
+
constructor(ctx, input) {
|
|
9908
|
+
this.ctx = ctx;
|
|
9909
|
+
this.input = input;
|
|
9910
|
+
this.forms = ctx.settings;
|
|
9911
|
+
this.owner = ctx.fiber;
|
|
9912
|
+
this.editor = ctx.get("configEditor");
|
|
9913
|
+
const profile = ctx.get("profileContext");
|
|
9914
|
+
const root = ctx.root ?? ctx;
|
|
9915
|
+
if (profile?.home !== void 0 && existsSync(join(profile.home, "settings.yaml"))) pendingNativeImports.add(root);
|
|
9916
|
+
this.nativeImportPending = pendingNativeImports.has(root);
|
|
9917
|
+
const owner = this.owner;
|
|
9918
|
+
const validate = (candidate) => {
|
|
9919
|
+
const config = plainHostConfig(candidate);
|
|
9920
|
+
for (const registration of this.registrations.values()) {
|
|
9921
|
+
if (registration.legacy) continue;
|
|
9922
|
+
const value = this.resolve(registration, config);
|
|
9923
|
+
registration.validate?.(value);
|
|
9924
|
+
}
|
|
9925
|
+
};
|
|
9926
|
+
ctx.on("internal/config", function(_raw, next) {
|
|
9927
|
+
const candidate = next();
|
|
9928
|
+
if (this === owner) validate(candidate);
|
|
9929
|
+
return candidate;
|
|
9930
|
+
}, { prepend: true });
|
|
9931
|
+
ctx.on("loader/volatile-update", ((paths) => {
|
|
9932
|
+
if (this.closed) return;
|
|
9933
|
+
for (const registration of this.registrations.values()) {
|
|
9934
|
+
if (registration.legacy) continue;
|
|
9935
|
+
if (!paths.some((path) => registration.field === void 0 ? path.length === 0 || !["memoryView", "legacySettingsImported"].includes(path[0]) : path.length === 0 || path[0] === registration.field)) continue;
|
|
9936
|
+
const value = this.resolve(registration);
|
|
9937
|
+
for (const listener of this.listeners) try {
|
|
9938
|
+
listener(registration.namespace, value);
|
|
9939
|
+
} catch (error) {
|
|
9940
|
+
console.warn("dsh-mnemon: committed settings listener failed", error);
|
|
9941
|
+
}
|
|
9942
|
+
}
|
|
9943
|
+
}));
|
|
9944
|
+
ctx.effect(() => {
|
|
9945
|
+
const disposePresentation = owner === void 0 ? void 0 : this.forms.configure({ auto: false }, owner);
|
|
9946
|
+
return () => {
|
|
9947
|
+
this.closed = true;
|
|
9948
|
+
this.listeners.clear();
|
|
9949
|
+
this.revisions.clear();
|
|
9950
|
+
disposePresentation?.();
|
|
9951
|
+
};
|
|
9952
|
+
}, "dsh-mnemon: profile settings");
|
|
9953
|
+
}
|
|
9954
|
+
get writable() {
|
|
9955
|
+
const entry = this.owner?.entry;
|
|
9956
|
+
return !this.closed && this.forms.writable && entry !== void 0 && this.editor?.entries().includes(entry) === true;
|
|
9957
|
+
}
|
|
9958
|
+
onUpdated(listener) {
|
|
9959
|
+
this.listeners.add(listener);
|
|
9960
|
+
return () => {
|
|
9961
|
+
this.listeners.delete(listener);
|
|
9962
|
+
};
|
|
9963
|
+
}
|
|
9964
|
+
resolve(registration, config = plainHostConfig(this.owner?.config ?? this.input)) {
|
|
9965
|
+
const value = registration.legacy ? registration.base : registration.field === void 0 ? config : config[registration.field];
|
|
9966
|
+
return registration.schema(object(value));
|
|
9967
|
+
}
|
|
9968
|
+
register(namespace, schema, options) {
|
|
9969
|
+
if (this.registrations.has(namespace)) throw new Error(`Mnemon settings already registered: ${namespace}`);
|
|
9970
|
+
if (typeof schema !== "function") throw new Error("Mnemon settings require a schema");
|
|
9971
|
+
const field = namespace === "mnemon-ui" ? "conversationInteraction" : /^mnemon-view(?:-[a-f0-9]{16})?$/u.test(namespace) ? "memoryView" : void 0;
|
|
9972
|
+
const legacy = /^mnemon-plugins(?:-[a-f0-9]{16})?$/u.test(namespace);
|
|
9973
|
+
if (namespace !== "mnemon" && field === void 0 && !legacy) throw new Error("Unsupported Mnemon settings namespace");
|
|
9974
|
+
const registration = {
|
|
9975
|
+
namespace,
|
|
9976
|
+
...field === void 0 ? {} : { field },
|
|
9977
|
+
legacy,
|
|
9978
|
+
schema,
|
|
9979
|
+
base: clone(options.base ?? {}),
|
|
9980
|
+
...options.validate === void 0 ? {} : { validate: options.validate }
|
|
9981
|
+
};
|
|
9982
|
+
const value = this.resolve(registration);
|
|
9983
|
+
options.validate?.(value);
|
|
9984
|
+
this.registrations.set(namespace, registration);
|
|
9985
|
+
return { get: () => this.resolve(registration) };
|
|
9986
|
+
}
|
|
9987
|
+
nativeDescriptor() {
|
|
9988
|
+
if (this.closed || this.owner?.entry === void 0 || !this.editor?.entries().includes(this.owner.entry)) return void 0;
|
|
9989
|
+
const descriptor = this.forms.describe().find((item) => item.ns === this.owner?.entry?.options.id);
|
|
9990
|
+
if (descriptor !== void 0) {
|
|
9991
|
+
this.revisions.set(descriptor.revision, clone({
|
|
9992
|
+
ns: descriptor.ns,
|
|
9993
|
+
revision: descriptor.revision,
|
|
9994
|
+
applies: descriptor.applies,
|
|
9995
|
+
value: descriptor.value,
|
|
9996
|
+
base: descriptor.base,
|
|
9997
|
+
user: descriptor.user
|
|
9998
|
+
}));
|
|
9999
|
+
if (this.revisions.size > 64) this.revisions.delete(this.revisions.keys().next().value);
|
|
10000
|
+
}
|
|
10001
|
+
return descriptor;
|
|
10002
|
+
}
|
|
10003
|
+
unchanged(previous, current, registration, operations) {
|
|
10004
|
+
const project = (value) => {
|
|
10005
|
+
if (registration.field !== void 0) return object(value)[registration.field];
|
|
10006
|
+
const { memoryView: _view, legacySettingsImported: _imported, conversationInteraction, ...core } = object(value);
|
|
10007
|
+
return operations.some((operation) => operation.path[0] === "conversationInteraction") ? {
|
|
10008
|
+
...core,
|
|
10009
|
+
conversationInteraction
|
|
10010
|
+
} : core;
|
|
10011
|
+
};
|
|
10012
|
+
const signature = (descriptor) => canonicalMemoryJson(JSON.parse(JSON.stringify([
|
|
10013
|
+
project(descriptor.value) ?? null,
|
|
10014
|
+
project(descriptor.base) ?? null,
|
|
10015
|
+
project(descriptor.user) ?? null
|
|
10016
|
+
])));
|
|
10017
|
+
return signature(previous) === signature(current);
|
|
10018
|
+
}
|
|
10019
|
+
describe(options) {
|
|
10020
|
+
const raw = this.nativeDescriptor();
|
|
10021
|
+
if (raw === void 0) return [];
|
|
10022
|
+
const descriptor = options?.redactSecrets ? this.forms.describe(options).find((item) => item.ns === this.owner?.entry?.options.id) : raw;
|
|
10023
|
+
if (descriptor === void 0) return [];
|
|
10024
|
+
return [...this.registrations.values()].map((registration) => {
|
|
10025
|
+
const project = (value) => registration.legacy ? {} : registration.field === void 0 ? value : object(value)[registration.field];
|
|
10026
|
+
return {
|
|
10027
|
+
ns: registration.namespace,
|
|
10028
|
+
value: project(descriptor.value) ?? {},
|
|
10029
|
+
base: project(descriptor.base) ?? {},
|
|
10030
|
+
user: project(descriptor.user) ?? {},
|
|
10031
|
+
revision: descriptor.revision,
|
|
10032
|
+
applies: "live"
|
|
10033
|
+
};
|
|
10034
|
+
});
|
|
10035
|
+
}
|
|
10036
|
+
async mutate(namespace, operations, expectedRevision) {
|
|
10037
|
+
const registration = this.registrations.get(namespace);
|
|
10038
|
+
if (registration === void 0 || registration.legacy) throw new Error("Unsupported Mnemon settings namespace");
|
|
10039
|
+
if (!this.writable) throw new Error("DSH settings are read-only");
|
|
10040
|
+
const translated = operations.map((operation) => ({
|
|
10041
|
+
...operation,
|
|
10042
|
+
path: [...registration.field === void 0 ? [] : [registration.field], ...operation.path]
|
|
10043
|
+
}));
|
|
10044
|
+
let revision = expectedRevision;
|
|
10045
|
+
const previous = revision === void 0 ? void 0 : this.revisions.get(revision);
|
|
10046
|
+
for (let attempt = 0;; attempt += 1) {
|
|
10047
|
+
if (!this.writable) throw new Error("DSH settings are read-only");
|
|
10048
|
+
try {
|
|
10049
|
+
await this.forms.mutate(this.owner.entry.options.id, translated, revision);
|
|
10050
|
+
return;
|
|
10051
|
+
} catch (error) {
|
|
10052
|
+
if (attempt >= 2 || previous === void 0 || typeof error !== "object" || error === null || !("code" in error) || error.code !== "SETTINGS_CONFLICT") throw error;
|
|
10053
|
+
if (!this.writable) throw new Error("DSH settings are read-only");
|
|
10054
|
+
const current = this.nativeDescriptor();
|
|
10055
|
+
if (current === void 0 || !this.unchanged(previous, current, registration, operations)) throw error;
|
|
10056
|
+
revision = current.revision;
|
|
10057
|
+
}
|
|
10058
|
+
}
|
|
10059
|
+
}
|
|
10060
|
+
/** Read only the retained backup; ConfigEditor preserves all other patch rows. */
|
|
10061
|
+
async importLegacy(sourceEntryIds) {
|
|
10062
|
+
if (this.importing !== void 0) return this.importing;
|
|
10063
|
+
this.importing = this.performImport(sourceEntryIds).finally(() => {
|
|
10064
|
+
this.importing = void 0;
|
|
10065
|
+
});
|
|
10066
|
+
return this.importing;
|
|
10067
|
+
}
|
|
10068
|
+
async performImport(sourceEntryIds) {
|
|
10069
|
+
const profile = this.ctx.get("profileContext");
|
|
10070
|
+
const entry = this.owner?.entry;
|
|
10071
|
+
if (!this.writable || profile?.home === void 0 || entry === void 0) return;
|
|
10072
|
+
if (this.nativeImportPending) {
|
|
10073
|
+
console.warn("dsh-mnemon: DSH is importing settings.yaml; restart once to recover retained Mnemon UI and plugin preferences");
|
|
10074
|
+
return;
|
|
9892
10075
|
}
|
|
9893
|
-
|
|
9894
|
-
|
|
9895
|
-
|
|
9896
|
-
|
|
9897
|
-
|
|
9898
|
-
|
|
9899
|
-
|
|
9900
|
-
|
|
9901
|
-
|
|
10076
|
+
if (plainHostConfig(this.owner?.config ?? this.input).legacySettingsImported) return;
|
|
10077
|
+
const backup = join(profile.home, "settings.yaml.imported");
|
|
10078
|
+
let text;
|
|
10079
|
+
try {
|
|
10080
|
+
if ((await stat(backup)).size > 1048576) throw new Error("Legacy settings backup exceeds the import limit");
|
|
10081
|
+
text = await readFile(backup, "utf8");
|
|
10082
|
+
} catch (error) {
|
|
10083
|
+
if (typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT") return;
|
|
10084
|
+
throw error;
|
|
9902
10085
|
}
|
|
9903
|
-
|
|
9904
|
-
|
|
9905
|
-
|
|
9906
|
-
|
|
9907
|
-
|
|
9908
|
-
|
|
9909
|
-
|
|
9910
|
-
|
|
9911
|
-
|
|
9912
|
-
|
|
9913
|
-
|
|
9914
|
-
|
|
9915
|
-
|
|
9916
|
-
|
|
9917
|
-
|
|
9918
|
-
|
|
9919
|
-
|
|
9920
|
-
|
|
9921
|
-
|
|
9922
|
-
|
|
9923
|
-
|
|
9924
|
-
|
|
9925
|
-
|
|
9926
|
-
|
|
9927
|
-
|
|
9928
|
-
|
|
9929
|
-
_viewWrite_decorators = [Remote("viewWrite")];
|
|
9930
|
-
__esDecorate(this, null, _read_decorators, {
|
|
9931
|
-
kind: "method",
|
|
9932
|
-
name: "read",
|
|
9933
|
-
static: false,
|
|
9934
|
-
private: false,
|
|
9935
|
-
access: {
|
|
9936
|
-
has: (obj) => "read" in obj,
|
|
9937
|
-
get: (obj) => obj.read
|
|
9938
|
-
},
|
|
9939
|
-
metadata: _metadata
|
|
9940
|
-
}, null, _instanceExtraInitializers);
|
|
9941
|
-
__esDecorate(this, null, _activation_decorators, {
|
|
9942
|
-
kind: "method",
|
|
9943
|
-
name: "activation",
|
|
9944
|
-
static: false,
|
|
9945
|
-
private: false,
|
|
9946
|
-
access: {
|
|
9947
|
-
has: (obj) => "activation" in obj,
|
|
9948
|
-
get: (obj) => obj.activation
|
|
9949
|
-
},
|
|
9950
|
-
metadata: _metadata
|
|
9951
|
-
}, null, _instanceExtraInitializers);
|
|
9952
|
-
__esDecorate(this, null, _write_decorators, {
|
|
9953
|
-
kind: "method",
|
|
9954
|
-
name: "write",
|
|
9955
|
-
static: false,
|
|
9956
|
-
private: false,
|
|
9957
|
-
access: {
|
|
9958
|
-
has: (obj) => "write" in obj,
|
|
9959
|
-
get: (obj) => obj.write
|
|
9960
|
-
},
|
|
9961
|
-
metadata: _metadata
|
|
9962
|
-
}, null, _instanceExtraInitializers);
|
|
9963
|
-
__esDecorate(this, null, _pack_decorators, {
|
|
9964
|
-
kind: "method",
|
|
9965
|
-
name: "pack",
|
|
9966
|
-
static: false,
|
|
9967
|
-
private: false,
|
|
9968
|
-
access: {
|
|
9969
|
-
has: (obj) => "pack" in obj,
|
|
9970
|
-
get: (obj) => obj.pack
|
|
9971
|
-
},
|
|
9972
|
-
metadata: _metadata
|
|
9973
|
-
}, null, _instanceExtraInitializers);
|
|
9974
|
-
__esDecorate(this, null, _settings_decorators, {
|
|
9975
|
-
kind: "method",
|
|
9976
|
-
name: "settings",
|
|
9977
|
-
static: false,
|
|
9978
|
-
private: false,
|
|
9979
|
-
access: {
|
|
9980
|
-
has: (obj) => "settings" in obj,
|
|
9981
|
-
get: (obj) => obj.settings
|
|
9982
|
-
},
|
|
9983
|
-
metadata: _metadata
|
|
9984
|
-
}, null, _instanceExtraInitializers);
|
|
9985
|
-
__esDecorate(this, null, _view_decorators, {
|
|
9986
|
-
kind: "method",
|
|
9987
|
-
name: "view",
|
|
9988
|
-
static: false,
|
|
9989
|
-
private: false,
|
|
9990
|
-
access: {
|
|
9991
|
-
has: (obj) => "view" in obj,
|
|
9992
|
-
get: (obj) => obj.view
|
|
9993
|
-
},
|
|
9994
|
-
metadata: _metadata
|
|
9995
|
-
}, null, _instanceExtraInitializers);
|
|
9996
|
-
__esDecorate(this, null, _viewWrite_decorators, {
|
|
9997
|
-
kind: "method",
|
|
9998
|
-
name: "viewWrite",
|
|
9999
|
-
static: false,
|
|
10000
|
-
private: false,
|
|
10001
|
-
access: {
|
|
10002
|
-
has: (obj) => "viewWrite" in obj,
|
|
10003
|
-
get: (obj) => obj.viewWrite
|
|
10004
|
-
},
|
|
10005
|
-
metadata: _metadata
|
|
10006
|
-
}, null, _instanceExtraInitializers);
|
|
10007
|
-
if (_metadata) Object.defineProperty(this, Symbol.metadata, {
|
|
10008
|
-
enumerable: true,
|
|
10009
|
-
configurable: true,
|
|
10010
|
-
writable: true,
|
|
10011
|
-
value: _metadata
|
|
10086
|
+
const sections = profileYaml(text);
|
|
10087
|
+
const viewNamespace = [...this.registrations.keys()].find((namespace) => namespace.startsWith("mnemon-view"));
|
|
10088
|
+
const legacyNamespace = [...this.registrations.keys()].find((namespace) => namespace.startsWith("mnemon-plugins"));
|
|
10089
|
+
const plan = () => {
|
|
10090
|
+
const configuration = this.editor.configuration().find((item) => item.entry === entry);
|
|
10091
|
+
if (configuration === void 0) throw new Error("Mnemon profile entry is no longer editable");
|
|
10092
|
+
const document = profileYaml(readFileSync(this.editor.documentPath, "utf8"));
|
|
10093
|
+
const entryOverrides = Array.isArray(document) ? document.flatMap((value) => {
|
|
10094
|
+
const row = object(value);
|
|
10095
|
+
if (typeof row.id !== "string") return [];
|
|
10096
|
+
const entries = this.editor.entries().filter((candidate) => candidate.options.id === row.id);
|
|
10097
|
+
if (entries.length > 1) throw new Error("Legacy settings import requires unambiguous profile Entry ids");
|
|
10098
|
+
return [{
|
|
10099
|
+
id: entries[0]?.id ?? row.id,
|
|
10100
|
+
..."disabled" in row ? { disabled: row.disabled } : {},
|
|
10101
|
+
..."config" in row ? { config: row.config } : {}
|
|
10102
|
+
}];
|
|
10103
|
+
}) : [];
|
|
10104
|
+
return planLegacySettingsImport({
|
|
10105
|
+
entryId: entry.options.id,
|
|
10106
|
+
viewNamespace,
|
|
10107
|
+
legacyNamespace,
|
|
10108
|
+
sections,
|
|
10109
|
+
currentOverride: configuration.override,
|
|
10110
|
+
entryOverrides,
|
|
10111
|
+
sourceEntryIds
|
|
10012
10112
|
});
|
|
10113
|
+
};
|
|
10114
|
+
const preview = plan();
|
|
10115
|
+
if (Object.keys(preview.patch).length === 0) {
|
|
10116
|
+
if (preview.diagnostics.length > 0) console.warn("dsh-mnemon: legacy settings were not imported; retained backup requires review");
|
|
10117
|
+
return;
|
|
10013
10118
|
}
|
|
10014
|
-
|
|
10015
|
-
|
|
10016
|
-
|
|
10017
|
-
|
|
10018
|
-
}
|
|
10019
|
-
read(endpoint, payload, signal) {
|
|
10020
|
-
return this.handlers.read(endpoint, payload, signal);
|
|
10021
|
-
}
|
|
10022
|
-
activation(endpoint, payload, signal) {
|
|
10023
|
-
return this.handlers.activation(endpoint, payload, signal);
|
|
10024
|
-
}
|
|
10025
|
-
write(endpoint, payload, signal) {
|
|
10026
|
-
if (!this.handlers.management) return Promise.resolve(denied());
|
|
10027
|
-
return this.handlers.write(endpoint, payload, signal);
|
|
10028
|
-
}
|
|
10029
|
-
pack(endpoint, payload, signal) {
|
|
10030
|
-
if (!this.handlers.management) return Promise.resolve(denied());
|
|
10031
|
-
return this.handlers.pack(endpoint, payload, signal);
|
|
10032
|
-
}
|
|
10033
|
-
async settings(endpoint, payload, signal) {
|
|
10034
|
-
if (endpoint === "mutate" && !this.handlers.management) return denied();
|
|
10035
|
-
if (endpoint !== "get" && endpoint !== "mutate") return unknownSettingsEndpoint(endpoint);
|
|
10036
|
-
const response = await this.handlers.settings(endpoint, payload, signal);
|
|
10037
|
-
if (endpoint !== "get" || this.handlers.management || !response.ok || typeof response.value !== "object" || response.value === null || Array.isArray(response.value)) return response;
|
|
10119
|
+
if (this.closed) return;
|
|
10120
|
+
await this.editor.edit(entry, (current) => {
|
|
10121
|
+
if (this.closed) throw new Error("Mnemon settings are disposed");
|
|
10122
|
+
const next = plan();
|
|
10038
10123
|
return {
|
|
10039
|
-
...
|
|
10040
|
-
|
|
10041
|
-
...response.value,
|
|
10042
|
-
writable: false
|
|
10043
|
-
}
|
|
10124
|
+
...current,
|
|
10125
|
+
...next.patch
|
|
10044
10126
|
};
|
|
10045
|
-
}
|
|
10046
|
-
|
|
10047
|
-
|
|
10048
|
-
}
|
|
10049
|
-
viewWrite(endpoint, payload, signal) {
|
|
10050
|
-
if (!this.handlers.management) return Promise.resolve(denied());
|
|
10051
|
-
return this.handlers.viewWrite(endpoint, payload, signal);
|
|
10052
|
-
}
|
|
10053
|
-
};
|
|
10054
|
-
})();
|
|
10127
|
+
});
|
|
10128
|
+
}
|
|
10129
|
+
};
|
|
10055
10130
|
//#endregion
|
|
10056
10131
|
//#region src/host/plugin.ts
|
|
10057
10132
|
const name = "dsh-mnemon";
|
|
@@ -10075,54 +10150,26 @@ function optionalWorkspaceRegistry(ctx) {
|
|
|
10075
10150
|
function apply(rawContext, rawConfig = {}) {
|
|
10076
10151
|
const ctx = rawContext;
|
|
10077
10152
|
const config = plainHostConfig(rawConfig);
|
|
10078
|
-
const hostSettings =
|
|
10153
|
+
const hostSettings = new ProfileMnemonSettings(ctx, rawConfig);
|
|
10079
10154
|
registerMnemonSubagentTokenUsageProjection(ctx);
|
|
10080
10155
|
const extensions = provideMemoryRuntime(ctx);
|
|
10081
10156
|
const memoryPlugins = new MemoryPluginManagement(ctx, extensions, hostSettings);
|
|
10082
10157
|
const pluginInstallation = new MemoryPluginInstallation(ctx);
|
|
10083
|
-
const effectiveConfig = (value) => memoryPlugins.resolveConfig(resolveConfig(value),
|
|
10084
|
-
const prepared = /* @__PURE__ */ new Map();
|
|
10085
|
-
const disposePrepared = () => {
|
|
10086
|
-
for (const candidate of prepared.values()) candidate.graph.dispose();
|
|
10087
|
-
prepared.clear();
|
|
10088
|
-
};
|
|
10158
|
+
const effectiveConfig = (value) => memoryPlugins.resolveConfig(resolveConfig(value), value.memoryView ?? { entries: {} });
|
|
10089
10159
|
const settings = hostSettings.register("mnemon", Config, {
|
|
10090
10160
|
base: config,
|
|
10091
10161
|
applies: "live",
|
|
10092
|
-
validate: (value) =>
|
|
10093
|
-
disposePrepared();
|
|
10094
|
-
const candidate = {
|
|
10095
|
-
graph: createRuntimeGraph(effectiveConfig(value), void 0, extensions),
|
|
10096
|
-
token: Symbol("prepared-runtime")
|
|
10097
|
-
};
|
|
10098
|
-
if (hostSettings instanceof ProfileMnemonSettings) {
|
|
10099
|
-
candidate.graph.dispose();
|
|
10100
|
-
return;
|
|
10101
|
-
}
|
|
10102
|
-
prepared.set(value, candidate);
|
|
10103
|
-
queueMicrotask(() => {
|
|
10104
|
-
if (prepared.get(value)?.token !== candidate.token) return;
|
|
10105
|
-
prepared.delete(value);
|
|
10106
|
-
candidate.graph.dispose();
|
|
10107
|
-
});
|
|
10108
|
-
}
|
|
10162
|
+
validate: (value) => createRuntimeGraph(effectiveConfig(value), void 0, extensions).dispose()
|
|
10109
10163
|
});
|
|
10110
|
-
const
|
|
10111
|
-
const initialCandidate = prepared.get(initialSettings);
|
|
10112
|
-
if (initialCandidate !== void 0) prepared.delete(initialSettings);
|
|
10113
|
-
const runtime = new LiveMnemonRuntime(initialCandidate?.graph ?? createRuntimeGraph(effectiveConfig(initialSettings), void 0, extensions), optionalWorkspaceRegistry(ctx), ctx.agents, extensions);
|
|
10164
|
+
const runtime = new LiveMnemonRuntime(createRuntimeGraph(effectiveConfig(settings.get()), void 0, extensions), optionalWorkspaceRegistry(ctx), ctx.agents, extensions);
|
|
10114
10165
|
const resolved = runtime.config;
|
|
10115
|
-
ctx.effect(() =>
|
|
10116
|
-
const next = value;
|
|
10166
|
+
ctx.effect(() => hostSettings.onUpdated((namespace, value) => {
|
|
10117
10167
|
if (namespace === memoryPlugins.settingsNamespace) {
|
|
10118
10168
|
runtime.swap(createRuntimeGraph(effectiveConfig(settings.get()), void 0, extensions));
|
|
10119
10169
|
return;
|
|
10120
10170
|
}
|
|
10121
10171
|
if (namespace !== "mnemon") return;
|
|
10122
|
-
|
|
10123
|
-
if (candidate !== void 0) prepared.delete(next);
|
|
10124
|
-
disposePrepared();
|
|
10125
|
-
runtime.swap(candidate?.graph ?? createRuntimeGraph(effectiveConfig(next), void 0, extensions));
|
|
10172
|
+
runtime.swap(createRuntimeGraph(effectiveConfig(value), void 0, extensions));
|
|
10126
10173
|
}), "dsh-mnemon: live runtime settings");
|
|
10127
10174
|
ctx.effect(() => memoryPlugins.start(), "dsh-mnemon: plugin graph settings");
|
|
10128
10175
|
hostSettings.register("mnemon-ui", InteractionConfig, {
|
|
@@ -10146,7 +10193,7 @@ function apply(rawContext, rawConfig = {}) {
|
|
|
10146
10193
|
unsubscribe();
|
|
10147
10194
|
};
|
|
10148
10195
|
}, "dsh-mnemon: canonical displayMode migration");
|
|
10149
|
-
|
|
10196
|
+
ctx.effect(() => {
|
|
10150
10197
|
let disposed = false;
|
|
10151
10198
|
const loader = ctx.get("loader");
|
|
10152
10199
|
Promise.resolve(loader?.await?.()).then(async () => {
|
|
@@ -10178,7 +10225,6 @@ function apply(rawContext, rawConfig = {}) {
|
|
|
10178
10225
|
return async () => {
|
|
10179
10226
|
stop();
|
|
10180
10227
|
await coordinator.dispose();
|
|
10181
|
-
disposePrepared();
|
|
10182
10228
|
runtime.dispose();
|
|
10183
10229
|
};
|
|
10184
10230
|
}, "dsh-mnemon.lifecycle-root()");
|
|
@@ -10187,16 +10233,15 @@ function apply(rawContext, rawConfig = {}) {
|
|
|
10187
10233
|
registerGuidance(ctx, resolved);
|
|
10188
10234
|
ctx.inject(["connection"], (webContext) => {
|
|
10189
10235
|
if (webContext.connection === void 0) return;
|
|
10190
|
-
const
|
|
10191
|
-
const
|
|
10192
|
-
const
|
|
10193
|
-
const view = registerViewRpc(webContext.connection, runtime, extensions, memoryPlugins, lifecycle, managementAuthority, pluginInstallation);
|
|
10236
|
+
const rpc = registerRpc(webContext.connection, runtime, lifecycle);
|
|
10237
|
+
const settings = registerSettingsRpc(webContext.connection, hostSettings);
|
|
10238
|
+
const view = registerViewRpc(webContext.connection, runtime, extensions, memoryPlugins, lifecycle, pluginInstallation);
|
|
10194
10239
|
if (Context.is(webContext)) new MnemonRemoteService(webContext, {
|
|
10195
10240
|
...rpc,
|
|
10196
10241
|
settings,
|
|
10197
10242
|
view: view.read,
|
|
10198
10243
|
viewWrite: view.write,
|
|
10199
|
-
management:
|
|
10244
|
+
management: resolved.remoteAccess === "trusted-host"
|
|
10200
10245
|
});
|
|
10201
10246
|
});
|
|
10202
10247
|
}
|