dsh-mnemon 0.5.16 → 0.5.18
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 +10 -5
- 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 +1146 -1099
- package/lib/{runtime-BEX0sc1z.js → runtime-Bk6lFgxd.js} +44 -19
- package/lib/starter.js +67 -0
- 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/lib/types/src/starter.d.ts +5 -0
- package/locale/zh.json +2 -2
- package/package.json +75 -62
- 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";
|
|
@@ -15,14 +15,14 @@ import { RUNTIME_ENTRY_DELIMITER, RUNTIME_MEMORY_LIMITS, RUNTIME_MEMORY_VERSION
|
|
|
15
15
|
import { threeTierActionWorkflow } from "dsh-mnemon-strategy-default-three-tier/extension-sdk";
|
|
16
16
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
17
17
|
import { fileURLToPath } from "node:url";
|
|
18
|
-
import { findMnemonCommand, mnemonNpmLauncher, nodeLauncherEnvironment } from "dsh-mnemon-source-memory-spaces/native-cli";
|
|
18
|
+
import { findMnemonCommand, mnemonNpmLauncher, nodeLauncherEnvironment, resolveMnemonInvocation } from "dsh-mnemon-source-memory-spaces/native-cli";
|
|
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);
|
|
@@ -6486,7 +6475,8 @@ var VersionUpdateManager = class {
|
|
|
6486
6475
|
const launcher = mnemonNpmLauncher(command);
|
|
6487
6476
|
let current;
|
|
6488
6477
|
try {
|
|
6489
|
-
|
|
6478
|
+
const invocation = resolveMnemonInvocation(command, ["--version"]);
|
|
6479
|
+
current = versionFrom((await resultOrThrow(this.processRunner, invocation.command, invocation.args, CHECK_TIMEOUT_MS, { env: invocation.env })).stdout);
|
|
6490
6480
|
} catch {
|
|
6491
6481
|
return { install: {
|
|
6492
6482
|
mode: launcher === void 0 ? "manual" : "npm",
|
|
@@ -6662,17 +6652,6 @@ var VersionUpdateManager = class {
|
|
|
6662
6652
|
return {
|
|
6663
6653
|
checkedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
6664
6654
|
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
6655
|
id: "dsh-mnemon",
|
|
6677
6656
|
name: "dsh-mnemon",
|
|
6678
6657
|
...dshInstall.profileName === void 0 ? {} : { installProfile: dshInstall.profileName },
|
|
@@ -6686,6 +6665,17 @@ var VersionUpdateManager = class {
|
|
|
6686
6665
|
restartRequired: this.pendingRestart.size > 0,
|
|
6687
6666
|
updateHint: dshInstall.mode === "npm" ? dshSupported ? "pnpm" : "pnpm-missing" : dshInstall.mode === "link" ? "link" : "manual",
|
|
6688
6667
|
...dshLatest === void 0 ? { checkError: "latest-unavailable" } : {}
|
|
6668
|
+
}, {
|
|
6669
|
+
id: "mnemon",
|
|
6670
|
+
name: "Mnemon CLI",
|
|
6671
|
+
...mnemonLocal.install.command === void 0 ? {} : { executablePath: mnemonLocal.install.command },
|
|
6672
|
+
...mnemonLocal.current === void 0 ? {} : { current: mnemonLocal.current },
|
|
6673
|
+
...mnemonLatest === void 0 ? {} : { latest: mnemonLatest },
|
|
6674
|
+
outdated: mnemonOutdated,
|
|
6675
|
+
installMode: mnemonLocal.install.mode,
|
|
6676
|
+
updateSupported: mnemonSupported,
|
|
6677
|
+
updateHint: mnemonLocal.install.hint ?? (mnemonLocal.install.mode === "homebrew" ? mnemonSupported ? "brew" : "brew-missing" : mnemonLocal.install.mode === "go" ? "go" : mnemonLocal.install.mode === "missing" ? "install" : "manual"),
|
|
6678
|
+
...mnemonLatest === void 0 ? { checkError: "latest-unavailable" } : {}
|
|
6689
6679
|
}]
|
|
6690
6680
|
};
|
|
6691
6681
|
}
|
|
@@ -6799,6 +6789,13 @@ function requireWritable(runtime) {
|
|
|
6799
6789
|
function requireCapability(runtime, typeId, capability) {
|
|
6800
6790
|
assertParticipation(runtime.graph.config, typeId, capability, "manual");
|
|
6801
6791
|
}
|
|
6792
|
+
/** A memory layer that is off takes no part in reads or writes, management and assistance included. */
|
|
6793
|
+
function requireLayerOn(runtime, sourceTypeId) {
|
|
6794
|
+
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`);
|
|
6795
|
+
}
|
|
6796
|
+
function sourceTypeOf(generation, sourceInstanceKey) {
|
|
6797
|
+
return generation?.sourceInstances().find((source) => source.sourceInstanceKey === sourceInstanceKey)?.sourceTypeId;
|
|
6798
|
+
}
|
|
6802
6799
|
function success$1(value) {
|
|
6803
6800
|
return {
|
|
6804
6801
|
ok: true,
|
|
@@ -6883,8 +6880,12 @@ async function catalog(runtime, lifecycle) {
|
|
|
6883
6880
|
}
|
|
6884
6881
|
}
|
|
6885
6882
|
async function compositionStatus(runtime) {
|
|
6883
|
+
const composition = runtime.graph.memoryComposition.inspect();
|
|
6884
|
+
const strategyTypeId = runtime.graph.memoryComposition.current()?.strategy.definition.manifest.typeId;
|
|
6886
6885
|
return {
|
|
6887
|
-
|
|
6886
|
+
serving: composition.servingGenerationId !== void 0,
|
|
6887
|
+
...strategyTypeId === void 0 ? {} : { strategyTypeId },
|
|
6888
|
+
evaluation: composition.evaluation,
|
|
6888
6889
|
sources: (await catalog(runtime)).sources,
|
|
6889
6890
|
configuration: runtime.graph.config.memoryTopology
|
|
6890
6891
|
};
|
|
@@ -7010,6 +7011,7 @@ function createReadHandler(input, lifecycle, versions) {
|
|
|
7010
7011
|
case "source-management-read": {
|
|
7011
7012
|
const lease = runtime.graph.memoryComposition.acquire();
|
|
7012
7013
|
try {
|
|
7014
|
+
requireLayerOn(runtime, sourceTypeOf(lease.generation, String(payload.sourceInstanceKey ?? "")));
|
|
7013
7015
|
return success$1(await lease.generation.executeManagement({
|
|
7014
7016
|
scope: runtime.scope,
|
|
7015
7017
|
sourceInstanceKey: String(payload.sourceInstanceKey ?? ""),
|
|
@@ -7104,6 +7106,7 @@ function createActivationHandler(input) {
|
|
|
7104
7106
|
try {
|
|
7105
7107
|
const source = (await lease.generation.managementCatalog(runtime.scope)).sources.find((item) => item.sourceInstanceKey === payload.sourceInstanceKey && item.sourceTypeId === "memory-spaces");
|
|
7106
7108
|
if (source === void 0) throw new Error("Memory Spaces Source instance is unavailable");
|
|
7109
|
+
requireLayerOn(runtime, source.sourceTypeId);
|
|
7107
7110
|
return success$1(await lease.generation.executeManagement({
|
|
7108
7111
|
scope: runtime.scope,
|
|
7109
7112
|
sourceInstanceKey: source.sourceInstanceKey,
|
|
@@ -7158,6 +7161,7 @@ function createWriteHandler(input, lifecycle, versions) {
|
|
|
7158
7161
|
...typeof payload.expectedRevision === "string" ? { expectedRevision: payload.expectedRevision } : {},
|
|
7159
7162
|
...signal === void 0 ? {} : { signal }
|
|
7160
7163
|
};
|
|
7164
|
+
requireLayerOn(runtime, sourceTypeOf(runtime.graph.memoryComposition.current(), request.sourceInstanceKey));
|
|
7161
7165
|
if (lifecycle !== void 0) return success$1(await lifecycle.manageSource(runtime.graph, request));
|
|
7162
7166
|
const lease = runtime.graph.memoryComposition.acquire();
|
|
7163
7167
|
try {
|
|
@@ -7171,6 +7175,7 @@ function createWriteHandler(input, lifecycle, versions) {
|
|
|
7171
7175
|
const source = (await catalog(runtime, lifecycle)).sources.find((item) => item.sourceInstanceKey === payload.sourceInstanceKey);
|
|
7172
7176
|
const operation = String(payload.operation ?? "");
|
|
7173
7177
|
if (source === void 0 || !source.assistance.includes(operation)) throw new Error("Host assistance is not available for this Source instance");
|
|
7178
|
+
requireLayerOn(runtime, source.sourceTypeId);
|
|
7174
7179
|
if (operation !== "agent-search" && (payload.confirmed !== true || payload.expectedRevision !== source.revision)) throw new Error("Host assistance requires confirmation of the current Source revision");
|
|
7175
7180
|
const value = await assisted(runtime, lifecycle, source.sourceTypeId, operation, object$4(payload.input), signal, {
|
|
7176
7181
|
sourceInstanceKey: source.sourceInstanceKey,
|
|
@@ -7239,16 +7244,16 @@ function createPackHandler(input) {
|
|
|
7239
7244
|
}
|
|
7240
7245
|
};
|
|
7241
7246
|
}
|
|
7242
|
-
function registerRpc(connection, input, lifecycle, versions
|
|
7247
|
+
function registerRpc(connection, input, lifecycle, versions) {
|
|
7243
7248
|
const versionManager = versions ?? new VersionUpdateManager({ mnemonCliPath: () => input.config.cliPath });
|
|
7244
7249
|
const readHandler = createReadHandler(input, lifecycle, versionManager);
|
|
7245
7250
|
const activationHandler = createActivationHandler(input);
|
|
7246
7251
|
const writeHandler = createWriteHandler(input, lifecycle, versionManager);
|
|
7247
7252
|
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
|
|
7253
|
+
connection.rpc.handle(MNEMON_READ_CHANNEL, readHandler);
|
|
7254
|
+
connection.rpc.handle(MNEMON_ACTIVATION_CHANNEL, activationHandler);
|
|
7255
|
+
connection.rpc.handle(MNEMON_WRITE_CHANNEL, writeHandler);
|
|
7256
|
+
connection.rpc.handle(MNEMON_PACK_CHANNEL, packHandler);
|
|
7252
7257
|
return {
|
|
7253
7258
|
read: readHandler,
|
|
7254
7259
|
activation: activationHandler,
|
|
@@ -7403,9 +7408,9 @@ function createSettingsHandler(settings) {
|
|
|
7403
7408
|
}
|
|
7404
7409
|
};
|
|
7405
7410
|
}
|
|
7406
|
-
function registerSettingsRpc(connection, settings
|
|
7411
|
+
function registerSettingsRpc(connection, settings) {
|
|
7407
7412
|
const handler = createSettingsHandler(settings);
|
|
7408
|
-
connection.rpc.handle(MNEMON_SETTINGS_CHANNEL, handler
|
|
7413
|
+
connection.rpc.handle(MNEMON_SETTINGS_CHANNEL, handler);
|
|
7409
7414
|
return handler;
|
|
7410
7415
|
}
|
|
7411
7416
|
//#endregion
|
|
@@ -8328,7 +8333,6 @@ const mnemonSubagentTokenUsageProjectionDefinition = {
|
|
|
8328
8333
|
key: "mnemonSubagentTokenUsage",
|
|
8329
8334
|
stateVersion: 1,
|
|
8330
8335
|
stateSchema: tokenUsageStateSchema,
|
|
8331
|
-
schema: tokenUsageWire.viewSchema,
|
|
8332
8336
|
init: () => ({
|
|
8333
8337
|
descriptorSeen: false,
|
|
8334
8338
|
totals: emptyTokenUsage(),
|
|
@@ -8351,7 +8355,6 @@ const mnemonSubagentTokenUsageProjectionDefinition = {
|
|
|
8351
8355
|
last: sample
|
|
8352
8356
|
};
|
|
8353
8357
|
},
|
|
8354
|
-
view: tokenUsageWire.view,
|
|
8355
8358
|
wire: tokenUsageWire
|
|
8356
8359
|
};
|
|
8357
8360
|
/** Register lazily when the optional DSH projection service is present. */
|
|
@@ -8361,722 +8364,224 @@ function registerMnemonSubagentTokenUsageProjection(ctx) {
|
|
|
8361
8364
|
});
|
|
8362
8365
|
}
|
|
8363
8366
|
//#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)]));
|
|
8367
|
+
//#region src/host/plugin-management.ts
|
|
8368
|
+
/** Saved choices keep only configuration once the profile patch owns enablement. */
|
|
8369
|
+
function configurationOnly(entries) {
|
|
8370
|
+
return Object.fromEntries(Object.entries(entries).map(([entryId, value]) => [entryId, { config: value.config }]));
|
|
8378
8371
|
}
|
|
8379
|
-
|
|
8380
|
-
|
|
8381
|
-
|
|
8372
|
+
const PACKAGE$1 = /^(?:@[a-z0-9._-]+\/)?dsh-mnemon-(source|strategy)-[a-z0-9._-]+$/u;
|
|
8373
|
+
const hash = (value) => createHash("sha256").update(canonicalMemoryJson(value)).digest("hex");
|
|
8374
|
+
const clone$1 = (value) => JSON.parse(JSON.stringify(value));
|
|
8375
|
+
function contributionRoles(snapshot, entryId) {
|
|
8376
|
+
const roles = /* @__PURE__ */ new Set();
|
|
8377
|
+
if (snapshot.sources.some((value) => value.provenance.entryId === entryId)) roles.add("source");
|
|
8378
|
+
if (snapshot.strategies.some((value) => value.provenance.entryId === entryId)) roles.add("strategy");
|
|
8379
|
+
if ((snapshot.strategyExtensions ?? []).some((value) => value.provenance.entryId === entryId)) roles.add("strategy-extension");
|
|
8380
|
+
return [...roles];
|
|
8382
8381
|
}
|
|
8383
|
-
function
|
|
8384
|
-
const
|
|
8385
|
-
|
|
8386
|
-
const
|
|
8387
|
-
|
|
8388
|
-
|
|
8389
|
-
|
|
8390
|
-
|
|
8391
|
-
|
|
8392
|
-
|
|
8393
|
-
|
|
8394
|
-
|
|
8395
|
-
|
|
8396
|
-
|
|
8397
|
-
|
|
8398
|
-
|
|
8399
|
-
|
|
8400
|
-
|
|
8401
|
-
|
|
8382
|
+
function fallbackDescriptor(entry, snapshot, editor) {
|
|
8383
|
+
const sources = snapshot.sources.filter((value) => value.provenance.entryId === entry.id);
|
|
8384
|
+
const strategies = snapshot.strategies.filter((value) => value.provenance.entryId === entry.id);
|
|
8385
|
+
const extensions = (snapshot.strategyExtensions ?? []).filter((value) => value.provenance.entryId === entry.id);
|
|
8386
|
+
const roles = contributionRoles(snapshot, entry.id);
|
|
8387
|
+
if (roles.length === 0) roles.push(editor?.kind ?? (PACKAGE$1.exec(entry.options.name)?.[1] === "source" ? "source" : "strategy"));
|
|
8388
|
+
const typeId = editor?.typeId ?? strategies[0]?.definition.manifest.typeId ?? extensions[0]?.definition.manifest.typeId ?? sources[0]?.definition.manifest.typeId;
|
|
8389
|
+
const sourceLabel = sources[0]?.definition.manifest.management?.label;
|
|
8390
|
+
const label = editor?.label ?? {
|
|
8391
|
+
en: sourceLabel ?? typeId ?? entry.options.name,
|
|
8392
|
+
"zh-CN": sourceLabel ?? typeId ?? entry.options.name
|
|
8393
|
+
};
|
|
8394
|
+
const description = editor?.description ?? {
|
|
8395
|
+
en: "",
|
|
8396
|
+
"zh-CN": ""
|
|
8397
|
+
};
|
|
8398
|
+
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)}` }];
|
|
8399
|
+
return defineMemoryPlugin({
|
|
8400
|
+
packageName: entry.options.name,
|
|
8401
|
+
label,
|
|
8402
|
+
description,
|
|
8403
|
+
roles,
|
|
8404
|
+
provides
|
|
8405
|
+
});
|
|
8402
8406
|
}
|
|
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;
|
|
8407
|
+
function prepared(item, config) {
|
|
8408
|
+
if (item.editor === void 0) throw new Error(`Plugin does not expose a pure configuration factory: ${item.entry.id}`);
|
|
8409
|
+
const contribution = item.editor.create(config);
|
|
8410
|
+
if ([...contribution.strategies ?? [], ...contribution.strategyExtensions ?? []][0].manifest.packageName !== item.entry.options.name) throw new Error("Plugin factory does not match its declared Entry");
|
|
8411
|
+
if (contribution.plugin !== void 0 && hash(contribution.plugin) !== hash(item.descriptor)) throw new Error("Plugin factory descriptor does not match its module export");
|
|
8412
|
+
return prepareMemoryContributions({
|
|
8413
|
+
...contribution,
|
|
8414
|
+
plugin: contribution.plugin ?? item.descriptor
|
|
8415
|
+
}, { instanceId: item.entry.id });
|
|
8424
8416
|
}
|
|
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
|
-
}
|
|
8417
|
+
function installedPlugin(descriptor, entryId) {
|
|
8488
8418
|
return {
|
|
8489
|
-
|
|
8490
|
-
|
|
8419
|
+
kind: "plugin",
|
|
8420
|
+
instanceKey: `plugin:${entryId}`,
|
|
8421
|
+
provenance: {
|
|
8422
|
+
packageName: descriptor.packageName,
|
|
8423
|
+
entryId
|
|
8424
|
+
},
|
|
8425
|
+
descriptor
|
|
8491
8426
|
};
|
|
8492
8427
|
}
|
|
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
|
-
});
|
|
8428
|
+
function orderPlugins(values) {
|
|
8429
|
+
const byId = new Map(values.map((value) => [value.entryId, value]));
|
|
8430
|
+
const edges = new Map(values.map((value) => [value.entryId, /* @__PURE__ */ new Set()]));
|
|
8431
|
+
const indegree = new Map(values.map((value) => [value.entryId, 0]));
|
|
8432
|
+
for (const dependent of values) for (const requirement of dependent.requires) for (const provider of values) {
|
|
8433
|
+
if (provider.entryId === dependent.entryId || !provider.provides.some((capability) => capability.id === requirement)) continue;
|
|
8434
|
+
if (edges.get(provider.entryId).has(dependent.entryId)) continue;
|
|
8435
|
+
edges.get(provider.entryId).add(dependent.entryId);
|
|
8436
|
+
indegree.set(dependent.entryId, indegree.get(dependent.entryId) + 1);
|
|
8528
8437
|
}
|
|
8529
|
-
|
|
8530
|
-
|
|
8531
|
-
|
|
8532
|
-
|
|
8533
|
-
|
|
8534
|
-
|
|
8535
|
-
|
|
8536
|
-
const
|
|
8537
|
-
|
|
8538
|
-
|
|
8539
|
-
|
|
8540
|
-
|
|
8438
|
+
const stable = (left, right) => byId.get(left).packageName.localeCompare(byId.get(right).packageName) || left.localeCompare(right);
|
|
8439
|
+
const ready = [...indegree].filter(([, count]) => count === 0).map(([entryId]) => entryId).sort(stable);
|
|
8440
|
+
const ordered = [];
|
|
8441
|
+
while (ready.length > 0) {
|
|
8442
|
+
const entryId = ready.shift();
|
|
8443
|
+
ordered.push(byId.get(entryId));
|
|
8444
|
+
for (const dependent of [...edges.get(entryId)].sort(stable)) {
|
|
8445
|
+
const next = indegree.get(dependent) - 1;
|
|
8446
|
+
indegree.set(dependent, next);
|
|
8447
|
+
if (next === 0) {
|
|
8448
|
+
ready.push(dependent);
|
|
8449
|
+
ready.sort(stable);
|
|
8541
8450
|
}
|
|
8542
|
-
entries[id].config = config;
|
|
8543
8451
|
}
|
|
8544
|
-
if (typeof row.disabled === "boolean") entries[id].enabled = !row.disabled;
|
|
8545
8452
|
}
|
|
8453
|
+
if (ordered.length < values.length) ordered.push(...values.filter((value) => !ordered.includes(value)).sort((left, right) => stable(left.entryId, right.entryId)));
|
|
8454
|
+
return ordered;
|
|
8546
8455
|
}
|
|
8547
8456
|
/**
|
|
8548
|
-
*
|
|
8549
|
-
*
|
|
8550
|
-
*
|
|
8457
|
+
* Profile-local plugin graph overlay. Every dsh-mnemon Source or Strategy Entry
|
|
8458
|
+
* is one peer node; activation, configuration, dependency checks and rollback
|
|
8459
|
+
* use one transaction. Contribution roles do not create separate managers.
|
|
8551
8460
|
*/
|
|
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 {
|
|
8461
|
+
var MemoryPluginManagement = class {
|
|
8646
8462
|
ctx;
|
|
8647
|
-
|
|
8648
|
-
|
|
8649
|
-
|
|
8650
|
-
|
|
8651
|
-
|
|
8652
|
-
|
|
8653
|
-
editor;
|
|
8463
|
+
engine;
|
|
8464
|
+
settingsService;
|
|
8465
|
+
settingsNamespace;
|
|
8466
|
+
settings;
|
|
8467
|
+
legacySettings;
|
|
8468
|
+
queue = Promise.resolve();
|
|
8654
8469
|
closed = false;
|
|
8655
|
-
|
|
8656
|
-
|
|
8657
|
-
|
|
8470
|
+
timer;
|
|
8471
|
+
restoreError;
|
|
8472
|
+
discoveryWarnings = [];
|
|
8473
|
+
changingEntries = false;
|
|
8474
|
+
restorePending = false;
|
|
8475
|
+
/** A failed move keeps saved choices in effect instead of retrying on every profile reload. */
|
|
8476
|
+
enablementMoveError;
|
|
8477
|
+
constructor(ctx, engine, settingsService) {
|
|
8658
8478
|
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);
|
|
8479
|
+
this.engine = engine;
|
|
8480
|
+
this.settingsService = settingsService;
|
|
8481
|
+
const loader = this.loader();
|
|
8482
|
+
const anchor = loader?.config?.baseUrl ?? loader?.ctx?.baseUrl ?? loader?.context?.baseUrl;
|
|
8483
|
+
const suffix = anchor ? `-${hash(anchor).slice(0, 16)}` : "";
|
|
8484
|
+
this.settingsNamespace = `${MNEMON_VIEW_SETTINGS_NAMESPACE}${suffix}`;
|
|
8485
|
+
this.settings = settingsService.register(this.settingsNamespace, schema, {
|
|
8486
|
+
base: { entries: {} },
|
|
8487
|
+
applies: "live",
|
|
8488
|
+
validate: (value) => {
|
|
8489
|
+
preferences(value);
|
|
8674
8490
|
}
|
|
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
|
-
}
|
|
8491
|
+
});
|
|
8492
|
+
this.legacySettings = settingsService.register(`mnemon-plugins${suffix}`, legacySchema, {
|
|
8493
|
+
base: { sources: {} },
|
|
8494
|
+
applies: "live",
|
|
8495
|
+
validate: (value) => {
|
|
8496
|
+
legacyPreferences(value);
|
|
8692
8497
|
}
|
|
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");
|
|
8498
|
+
});
|
|
8703
8499
|
}
|
|
8704
|
-
get
|
|
8705
|
-
const
|
|
8706
|
-
return
|
|
8500
|
+
resolveConfig(config, view = this.settings.get()) {
|
|
8501
|
+
const selected = view.strategyTypeId;
|
|
8502
|
+
return selected === void 0 ? config : {
|
|
8503
|
+
...config,
|
|
8504
|
+
memoryTopology: {
|
|
8505
|
+
...config.memoryTopology,
|
|
8506
|
+
strategyId: selected
|
|
8507
|
+
}
|
|
8508
|
+
};
|
|
8707
8509
|
}
|
|
8708
|
-
|
|
8709
|
-
this.
|
|
8510
|
+
start() {
|
|
8511
|
+
const schedule = () => this.scheduleRestore();
|
|
8512
|
+
const stops = [
|
|
8513
|
+
this.ctx.on("loader/entry-init", schedule),
|
|
8514
|
+
this.ctx.on("loader/partial-dispose", schedule),
|
|
8515
|
+
this.ctx.on("app-boot/config-reload", () => this.scheduleRestore(true)),
|
|
8516
|
+
this.settingsService.onUpdated((namespace) => {
|
|
8517
|
+
if (namespace === this.settingsNamespace || namespace === `mnemon-plugins${this.settingsNamespace.slice(11)}`) schedule();
|
|
8518
|
+
})
|
|
8519
|
+
];
|
|
8520
|
+
this.ctx.inject(["pluginManager"], () => {
|
|
8521
|
+
schedule();
|
|
8522
|
+
});
|
|
8523
|
+
schedule();
|
|
8710
8524
|
return () => {
|
|
8711
|
-
this.
|
|
8525
|
+
this.closed = true;
|
|
8526
|
+
this.restorePending = false;
|
|
8527
|
+
clearTimeout(this.timer);
|
|
8528
|
+
for (const stop of stops.reverse()) stop();
|
|
8712
8529
|
};
|
|
8713
8530
|
}
|
|
8714
|
-
|
|
8715
|
-
const
|
|
8716
|
-
|
|
8531
|
+
scheduleRestore(profileReload = false) {
|
|
8532
|
+
const hasSavedState = Object.keys(this.settings.get().entries ?? {}).length > 0 || Object.keys(this.legacySettings.get().sources ?? {}).length > 0;
|
|
8533
|
+
if (this.closed || !profileReload && this.changingEntries || !hasSavedState) return;
|
|
8534
|
+
this.restorePending = true;
|
|
8535
|
+
if (this.changingEntries || this.timer) return;
|
|
8536
|
+
this.timer = setTimeout(() => {
|
|
8537
|
+
this.timer = void 0;
|
|
8538
|
+
this.enqueueRestore();
|
|
8539
|
+
}, 0);
|
|
8717
8540
|
}
|
|
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) };
|
|
8541
|
+
enqueueRestore() {
|
|
8542
|
+
if (this.closed || this.changingEntries || !this.restorePending) return;
|
|
8543
|
+
clearTimeout(this.timer);
|
|
8544
|
+
this.timer = void 0;
|
|
8545
|
+
this.restorePending = false;
|
|
8546
|
+
this.exclusive(async () => {
|
|
8547
|
+
try {
|
|
8548
|
+
await this.restore();
|
|
8549
|
+
} catch (error) {
|
|
8550
|
+
this.restoreError = error instanceof Error ? error.message : String(error);
|
|
8551
|
+
}
|
|
8552
|
+
}).catch(() => {});
|
|
8736
8553
|
}
|
|
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;
|
|
8554
|
+
/** A response must not race the deferred restore after profile reconciliation. */
|
|
8555
|
+
async settled() {
|
|
8556
|
+
do {
|
|
8557
|
+
this.enqueueRestore();
|
|
8558
|
+
const pending = this.queue;
|
|
8559
|
+
await pending;
|
|
8560
|
+
if (pending === this.queue && !this.restorePending) return;
|
|
8561
|
+
} while (!this.closed);
|
|
8752
8562
|
}
|
|
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);
|
|
8563
|
+
loader() {
|
|
8564
|
+
const candidate = this.ctx.get("loader");
|
|
8565
|
+
return candidate && typeof candidate.entries === "function" ? candidate : void 0;
|
|
8768
8566
|
}
|
|
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
|
-
});
|
|
8567
|
+
/**
|
|
8568
|
+
* With the DSH plugin manager, the profile patch owns enablement, so its
|
|
8569
|
+
* Plugins page and Mnemon agree. Profiles without it keep Mnemon's overlay.
|
|
8570
|
+
*/
|
|
8571
|
+
pluginManager() {
|
|
8572
|
+
const candidate = this.ctx.get("pluginManager");
|
|
8573
|
+
return typeof candidate?.setPluginEnabled === "function" ? candidate : void 0;
|
|
8785
8574
|
}
|
|
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
|
-
}
|
|
8575
|
+
async setEnabled(manager, entryId, enabled) {
|
|
8576
|
+
const result = await manager.setPluginEnabled(entryId, enabled);
|
|
8577
|
+
if (result.application !== "applied") throw new Error(`DSH could not ${enabled ? "enable" : "disable"} ${entryId}: ${result.error?.message ?? result.application}`);
|
|
8809
8578
|
}
|
|
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;
|
|
8579
|
+
settingsRevision(namespace = this.settingsNamespace) {
|
|
8580
|
+
return this.settingsService.describe({ redactSecrets: true }).find((value) => value.ns === namespace)?.revision ?? 0;
|
|
8817
8581
|
}
|
|
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;
|
|
8582
|
+
/** The plugin manager owns enablement unless moving the saved choices failed. */
|
|
8583
|
+
enablementOwner() {
|
|
8584
|
+
return this.enablementMoveError === void 0 ? this.pluginManager() : void 0;
|
|
9080
8585
|
}
|
|
9081
8586
|
async managed() {
|
|
9082
8587
|
const loader = this.loader();
|
|
@@ -9168,7 +8673,7 @@ var MemoryPluginManagement = class {
|
|
|
9168
8673
|
const pending = this.queue;
|
|
9169
8674
|
const items = await this.managed();
|
|
9170
8675
|
if (pending !== this.queue || this.restorePending) return this.catalog();
|
|
9171
|
-
const values = items.map((item) => clone(item.value));
|
|
8676
|
+
const values = items.map((item) => clone$1(item.value));
|
|
9172
8677
|
const snapshot = this.engine.contributionSnapshot();
|
|
9173
8678
|
const managedIds = new Set(items.map((item) => item.entry.id));
|
|
9174
8679
|
const entryIds = new Set([
|
|
@@ -9228,7 +8733,7 @@ var MemoryPluginManagement = class {
|
|
|
9228
8733
|
revision: this.revision(items),
|
|
9229
8734
|
writable: this.settingsService.writable && this.loader() !== void 0,
|
|
9230
8735
|
entries: orderPlugins(values),
|
|
9231
|
-
diagnostics: [...this.discoveryWarnings, ...this.restoreError
|
|
8736
|
+
diagnostics: [...this.discoveryWarnings, ...[this.restoreError, this.enablementMoveError].filter((value) => value !== void 0)]
|
|
9232
8737
|
};
|
|
9233
8738
|
}
|
|
9234
8739
|
choices(items, entries) {
|
|
@@ -9259,7 +8764,10 @@ var MemoryPluginManagement = class {
|
|
|
9259
8764
|
entries: request.entries
|
|
9260
8765
|
});
|
|
9261
8766
|
const managedIds = new Set(items.map((item) => item.entry.id));
|
|
9262
|
-
for (const entryId of Object.
|
|
8767
|
+
for (const [entryId, value] of Object.entries(incoming.entries)) {
|
|
8768
|
+
if (!managedIds.has(entryId)) throw new Error("Memory plugin Entry is not managed by this Host: " + entryId);
|
|
8769
|
+
if (typeof value.enabled !== "boolean") throw new Error("Plugin enabled must be boolean");
|
|
8770
|
+
}
|
|
9263
8771
|
const choices = this.choices(items, incoming.entries);
|
|
9264
8772
|
for (const item of items) {
|
|
9265
8773
|
const chosen = choices.get(item.entry.id);
|
|
@@ -9316,8 +8824,9 @@ var MemoryPluginManagement = class {
|
|
|
9316
8824
|
}
|
|
9317
8825
|
async evaluateSnapshot(snapshot, config, scope, strategyTypeId, signal) {
|
|
9318
8826
|
signal?.throwIfAborted();
|
|
8827
|
+
const { strategyFallback: _fallback, ...options } = memoryGenerationOptions(config, scope.workspaceId);
|
|
9319
8828
|
const generation = new MemoryCompositionGeneration(snapshot, {
|
|
9320
|
-
...
|
|
8829
|
+
...options,
|
|
9321
8830
|
strategyTypeId
|
|
9322
8831
|
});
|
|
9323
8832
|
try {
|
|
@@ -9339,14 +8848,24 @@ var MemoryPluginManagement = class {
|
|
|
9339
8848
|
const items = await this.managed();
|
|
9340
8849
|
const choices = this.validateRequest(items, request);
|
|
9341
8850
|
const expectedSettingsRevision = this.settingsRevision();
|
|
8851
|
+
const manager = this.enablementOwner();
|
|
9342
8852
|
const previous = preferences(this.settings.get());
|
|
8853
|
+
const merged = {
|
|
8854
|
+
...previous.entries,
|
|
8855
|
+
...request.entries
|
|
8856
|
+
};
|
|
9343
8857
|
const next = preferences({
|
|
9344
8858
|
strategyTypeId: request.strategyTypeId,
|
|
9345
|
-
entries:
|
|
9346
|
-
...previous.entries,
|
|
9347
|
-
...request.entries
|
|
9348
|
-
}
|
|
8859
|
+
entries: manager === void 0 ? merged : configurationOnly(merged)
|
|
9349
8860
|
});
|
|
8861
|
+
const toggles = manager === void 0 ? [] : items.flatMap((item) => {
|
|
8862
|
+
const enabled = choices.get(item.entry.id).enabled;
|
|
8863
|
+
return enabled === !item.entry.disabled ? [] : [{
|
|
8864
|
+
entryId: item.entry.id,
|
|
8865
|
+
enabled
|
|
8866
|
+
}];
|
|
8867
|
+
}).sort((left, right) => Number(right.enabled) - Number(left.enabled));
|
|
8868
|
+
const written = [];
|
|
9350
8869
|
let committedRevision;
|
|
9351
8870
|
await this.updateEntries(items, choices, {
|
|
9352
8871
|
validate: () => this.evaluateSnapshot(this.engine.contributionSnapshot(), config, scope, request.strategyTypeId, signal),
|
|
@@ -9361,8 +8880,13 @@ var MemoryPluginManagement = class {
|
|
|
9361
8880
|
value: next.entries
|
|
9362
8881
|
}], expectedSettingsRevision);
|
|
9363
8882
|
committedRevision = this.settingsRevision();
|
|
8883
|
+
for (const toggle of toggles) {
|
|
8884
|
+
await this.setEnabled(manager, toggle.entryId, toggle.enabled);
|
|
8885
|
+
written.push(toggle);
|
|
8886
|
+
}
|
|
9364
8887
|
},
|
|
9365
8888
|
compensate: async () => {
|
|
8889
|
+
for (const toggle of [...written].reverse()) await this.setEnabled(manager, toggle.entryId, !toggle.enabled);
|
|
9366
8890
|
if (hash(preferences(this.settings.get())) !== hash(next)) throw new Error("Memory plugin settings changed before rollback; refresh and inspect the saved configuration.");
|
|
9367
8891
|
await this.settingsService.mutate(this.settingsNamespace, [previous.strategyTypeId === void 0 ? {
|
|
9368
8892
|
op: "unset",
|
|
@@ -9381,15 +8905,56 @@ var MemoryPluginManagement = class {
|
|
|
9381
8905
|
this.restoreError = void 0;
|
|
9382
8906
|
});
|
|
9383
8907
|
}
|
|
8908
|
+
/** Move saved enablement into the profile patch once, keeping only configuration overlays. */
|
|
8909
|
+
async moveEnablement(manager, items) {
|
|
8910
|
+
const saved = this.settings.get().entries ?? {};
|
|
8911
|
+
const legacy = this.legacySettings.get().sources ?? {};
|
|
8912
|
+
const moves = items.flatMap((item) => {
|
|
8913
|
+
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;
|
|
8914
|
+
return enabled === void 0 ? [] : [{
|
|
8915
|
+
entryId: item.entry.id,
|
|
8916
|
+
enabled
|
|
8917
|
+
}];
|
|
8918
|
+
}).sort((left, right) => Number(right.enabled) - Number(left.enabled));
|
|
8919
|
+
if (moves.length === 0 && Object.keys(legacy).length === 0) return false;
|
|
8920
|
+
const legacyNamespace = `mnemon-plugins${this.settingsNamespace.slice(11)}`;
|
|
8921
|
+
const revisions = {
|
|
8922
|
+
view: this.settingsRevision(),
|
|
8923
|
+
legacy: this.settingsRevision(legacyNamespace)
|
|
8924
|
+
};
|
|
8925
|
+
for (const move of moves) await this.setEnabled(manager, move.entryId, move.enabled);
|
|
8926
|
+
await this.settingsService.mutate(this.settingsNamespace, [{
|
|
8927
|
+
op: "set",
|
|
8928
|
+
path: ["entries"],
|
|
8929
|
+
value: configurationOnly(saved)
|
|
8930
|
+
}], revisions.view);
|
|
8931
|
+
if (Object.keys(legacy).length > 0) await this.settingsService.mutate(legacyNamespace, [{
|
|
8932
|
+
op: "set",
|
|
8933
|
+
path: ["sources"],
|
|
8934
|
+
value: {}
|
|
8935
|
+
}], revisions.legacy);
|
|
8936
|
+
return true;
|
|
8937
|
+
}
|
|
9384
8938
|
async restore() {
|
|
9385
8939
|
if (this.closed) return;
|
|
9386
|
-
|
|
8940
|
+
let items = await this.managed();
|
|
8941
|
+
const available = this.enablementOwner();
|
|
8942
|
+
if (available !== void 0 && this.settingsService.writable) try {
|
|
8943
|
+
if (await this.moveEnablement(available, items)) items = await this.managed();
|
|
8944
|
+
} catch (error) {
|
|
8945
|
+
this.enablementMoveError = `Saved plugin choices could not move into the DSH profile and stay managed by Mnemon: ${error instanceof Error ? error.message : String(error)}`;
|
|
8946
|
+
}
|
|
8947
|
+
const manager = this.enablementOwner();
|
|
9387
8948
|
const saved = this.settings.get().entries ?? {};
|
|
9388
8949
|
const legacy = this.legacySettings.get().sources ?? {};
|
|
9389
8950
|
const desired = Object.fromEntries(items.flatMap((item) => {
|
|
9390
8951
|
const unified = saved[item.entry.id];
|
|
9391
|
-
|
|
9392
|
-
|
|
8952
|
+
const current = !item.entry.disabled;
|
|
8953
|
+
if (unified !== void 0) return [[item.entry.id, {
|
|
8954
|
+
enabled: manager === void 0 ? unified.enabled ?? current : current,
|
|
8955
|
+
config: unified.config
|
|
8956
|
+
}]];
|
|
8957
|
+
const oldSource = manager === void 0 && item.descriptor.roles.includes("source") ? legacy[item.entry.id] : void 0;
|
|
9393
8958
|
return oldSource === void 0 ? [] : [[item.entry.id, {
|
|
9394
8959
|
enabled: oldSource.enabled,
|
|
9395
8960
|
config: item.value.config
|
|
@@ -9408,7 +8973,7 @@ var MemoryPluginManagement = class {
|
|
|
9408
8973
|
const previous = items.map((item) => ({
|
|
9409
8974
|
item,
|
|
9410
8975
|
disabled: item.entry.options.disabled ?? null,
|
|
9411
|
-
config: clone(item.entry.options.config ?? {}),
|
|
8976
|
+
config: clone$1(item.entry.options.config ?? {}),
|
|
9412
8977
|
enabled: item.value.enabled,
|
|
9413
8978
|
active: item.value.active
|
|
9414
8979
|
}));
|
|
@@ -9429,7 +8994,7 @@ var MemoryPluginManagement = class {
|
|
|
9429
8994
|
touched.add(item.entry.id);
|
|
9430
8995
|
await item.entry.update(item.editor === void 0 ? { disabled: !desired.enabled } : {
|
|
9431
8996
|
disabled: !desired.enabled,
|
|
9432
|
-
config: clone(desired.config)
|
|
8997
|
+
config: clone$1(desired.config)
|
|
9433
8998
|
});
|
|
9434
8999
|
await item.entry.fiber?.await?.();
|
|
9435
9000
|
const registered = contributionRoles(this.engine.contributionSnapshot(), item.entry.id).length > 0;
|
|
@@ -9511,7 +9076,7 @@ var MemoryPluginManagement = class {
|
|
|
9511
9076
|
};
|
|
9512
9077
|
//#endregion
|
|
9513
9078
|
//#region src/host/view-rpc.ts
|
|
9514
|
-
function object(value) {
|
|
9079
|
+
function object$2(value) {
|
|
9515
9080
|
if (typeof value !== "object" || value === null || Array.isArray(value)) throw new Error("View request must be an object");
|
|
9516
9081
|
return value;
|
|
9517
9082
|
}
|
|
@@ -9528,7 +9093,7 @@ function createViewHandler(runtime, engine, management, access, lifecycle, insta
|
|
|
9528
9093
|
"preview",
|
|
9529
9094
|
"inspect-plugin"
|
|
9530
9095
|
].includes(endpoint) : !["apply", "install-plugin"].includes(endpoint)) throw new Error("View operation is not available on this channel");
|
|
9531
|
-
const payload = object(input);
|
|
9096
|
+
const payload = object$2(input);
|
|
9532
9097
|
if (endpoint === "inspect-plugin") {
|
|
9533
9098
|
if (installation === void 0 || typeof payload.packageName !== "string") throw new Error("Plugin discovery is unavailable");
|
|
9534
9099
|
return {
|
|
@@ -9590,9 +9155,9 @@ function createViewHandler(runtime, engine, management, access, lifecycle, insta
|
|
|
9590
9155
|
};
|
|
9591
9156
|
}
|
|
9592
9157
|
if (endpoint !== "preview" && endpoint !== "apply") throw new Error("Unknown View operation");
|
|
9593
|
-
const raw = object(payload.configuration);
|
|
9158
|
+
const raw = object$2(payload.configuration);
|
|
9594
9159
|
if (typeof raw.expectedRevision !== "string" || typeof raw.strategyTypeId !== "string") throw new Error("View configuration requires a revision and Strategy id");
|
|
9595
|
-
object(raw.entries);
|
|
9160
|
+
object$2(raw.entries);
|
|
9596
9161
|
const request = raw;
|
|
9597
9162
|
if (endpoint === "preview") return {
|
|
9598
9163
|
ok: true,
|
|
@@ -9616,11 +9181,11 @@ function createViewHandler(runtime, engine, management, access, lifecycle, insta
|
|
|
9616
9181
|
}
|
|
9617
9182
|
};
|
|
9618
9183
|
}
|
|
9619
|
-
function registerViewRpc(connection, runtime, engine, management, lifecycle,
|
|
9184
|
+
function registerViewRpc(connection, runtime, engine, management, lifecycle, installation) {
|
|
9620
9185
|
const readHandler = createViewHandler(runtime, engine, management, "read", lifecycle, installation);
|
|
9621
9186
|
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
|
|
9187
|
+
connection.rpc.handle(MNEMON_VIEW_CHANNEL, readHandler);
|
|
9188
|
+
connection.rpc.handle(MNEMON_VIEW_WRITE_CHANNEL, writeHandler);
|
|
9624
9189
|
return {
|
|
9625
9190
|
read: readHandler,
|
|
9626
9191
|
write: writeHandler
|
|
@@ -9879,179 +9444,690 @@ var __esDecorate = function(ctor, descriptorIn, decorators, contextIn, initializ
|
|
|
9879
9444
|
else descriptor[key] = _;
|
|
9880
9445
|
}
|
|
9881
9446
|
}
|
|
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: [] }
|
|
9447
|
+
if (target) Object.defineProperty(target, contextIn.name, descriptor);
|
|
9448
|
+
done = true;
|
|
9449
|
+
};
|
|
9450
|
+
function denied() {
|
|
9451
|
+
return {
|
|
9452
|
+
ok: false,
|
|
9453
|
+
error: {
|
|
9454
|
+
code: "bad-request",
|
|
9455
|
+
message: "remote Mnemon management requires remoteAccess: trusted-host",
|
|
9456
|
+
details: { issues: [] }
|
|
9457
|
+
}
|
|
9458
|
+
};
|
|
9459
|
+
}
|
|
9460
|
+
function unknownSettingsEndpoint(endpoint) {
|
|
9461
|
+
return {
|
|
9462
|
+
ok: false,
|
|
9463
|
+
error: {
|
|
9464
|
+
code: "bad-request",
|
|
9465
|
+
message: `unknown remote Mnemon settings endpoint: ${endpoint}`,
|
|
9466
|
+
details: { issues: [] }
|
|
9467
|
+
}
|
|
9468
|
+
};
|
|
9469
|
+
}
|
|
9470
|
+
/**
|
|
9471
|
+
* Project Mnemon's existing handlers through DSH API Gateway. The Gateway owns
|
|
9472
|
+
* `/api`, Host/Origin validation, browser pairing, and response envelopes;
|
|
9473
|
+
* this Service retains Mnemon's narrower management grant.
|
|
9474
|
+
*/
|
|
9475
|
+
let MnemonRemoteService = (() => {
|
|
9476
|
+
let _classSuper = TypertRemoteService;
|
|
9477
|
+
let _instanceExtraInitializers = [];
|
|
9478
|
+
let _read_decorators;
|
|
9479
|
+
let _activation_decorators;
|
|
9480
|
+
let _write_decorators;
|
|
9481
|
+
let _pack_decorators;
|
|
9482
|
+
let _settings_decorators;
|
|
9483
|
+
let _view_decorators;
|
|
9484
|
+
let _viewWrite_decorators;
|
|
9485
|
+
return class MnemonRemoteService extends _classSuper {
|
|
9486
|
+
static {
|
|
9487
|
+
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
|
|
9488
|
+
_read_decorators = [Remote("read")];
|
|
9489
|
+
_activation_decorators = [Remote("activation")];
|
|
9490
|
+
_write_decorators = [Remote("write")];
|
|
9491
|
+
_pack_decorators = [Remote("pack")];
|
|
9492
|
+
_settings_decorators = [Remote("settings")];
|
|
9493
|
+
_view_decorators = [Remote("view")];
|
|
9494
|
+
_viewWrite_decorators = [Remote("viewWrite")];
|
|
9495
|
+
__esDecorate(this, null, _read_decorators, {
|
|
9496
|
+
kind: "method",
|
|
9497
|
+
name: "read",
|
|
9498
|
+
static: false,
|
|
9499
|
+
private: false,
|
|
9500
|
+
access: {
|
|
9501
|
+
has: (obj) => "read" in obj,
|
|
9502
|
+
get: (obj) => obj.read
|
|
9503
|
+
},
|
|
9504
|
+
metadata: _metadata
|
|
9505
|
+
}, null, _instanceExtraInitializers);
|
|
9506
|
+
__esDecorate(this, null, _activation_decorators, {
|
|
9507
|
+
kind: "method",
|
|
9508
|
+
name: "activation",
|
|
9509
|
+
static: false,
|
|
9510
|
+
private: false,
|
|
9511
|
+
access: {
|
|
9512
|
+
has: (obj) => "activation" in obj,
|
|
9513
|
+
get: (obj) => obj.activation
|
|
9514
|
+
},
|
|
9515
|
+
metadata: _metadata
|
|
9516
|
+
}, null, _instanceExtraInitializers);
|
|
9517
|
+
__esDecorate(this, null, _write_decorators, {
|
|
9518
|
+
kind: "method",
|
|
9519
|
+
name: "write",
|
|
9520
|
+
static: false,
|
|
9521
|
+
private: false,
|
|
9522
|
+
access: {
|
|
9523
|
+
has: (obj) => "write" in obj,
|
|
9524
|
+
get: (obj) => obj.write
|
|
9525
|
+
},
|
|
9526
|
+
metadata: _metadata
|
|
9527
|
+
}, null, _instanceExtraInitializers);
|
|
9528
|
+
__esDecorate(this, null, _pack_decorators, {
|
|
9529
|
+
kind: "method",
|
|
9530
|
+
name: "pack",
|
|
9531
|
+
static: false,
|
|
9532
|
+
private: false,
|
|
9533
|
+
access: {
|
|
9534
|
+
has: (obj) => "pack" in obj,
|
|
9535
|
+
get: (obj) => obj.pack
|
|
9536
|
+
},
|
|
9537
|
+
metadata: _metadata
|
|
9538
|
+
}, null, _instanceExtraInitializers);
|
|
9539
|
+
__esDecorate(this, null, _settings_decorators, {
|
|
9540
|
+
kind: "method",
|
|
9541
|
+
name: "settings",
|
|
9542
|
+
static: false,
|
|
9543
|
+
private: false,
|
|
9544
|
+
access: {
|
|
9545
|
+
has: (obj) => "settings" in obj,
|
|
9546
|
+
get: (obj) => obj.settings
|
|
9547
|
+
},
|
|
9548
|
+
metadata: _metadata
|
|
9549
|
+
}, null, _instanceExtraInitializers);
|
|
9550
|
+
__esDecorate(this, null, _view_decorators, {
|
|
9551
|
+
kind: "method",
|
|
9552
|
+
name: "view",
|
|
9553
|
+
static: false,
|
|
9554
|
+
private: false,
|
|
9555
|
+
access: {
|
|
9556
|
+
has: (obj) => "view" in obj,
|
|
9557
|
+
get: (obj) => obj.view
|
|
9558
|
+
},
|
|
9559
|
+
metadata: _metadata
|
|
9560
|
+
}, null, _instanceExtraInitializers);
|
|
9561
|
+
__esDecorate(this, null, _viewWrite_decorators, {
|
|
9562
|
+
kind: "method",
|
|
9563
|
+
name: "viewWrite",
|
|
9564
|
+
static: false,
|
|
9565
|
+
private: false,
|
|
9566
|
+
access: {
|
|
9567
|
+
has: (obj) => "viewWrite" in obj,
|
|
9568
|
+
get: (obj) => obj.viewWrite
|
|
9569
|
+
},
|
|
9570
|
+
metadata: _metadata
|
|
9571
|
+
}, null, _instanceExtraInitializers);
|
|
9572
|
+
if (_metadata) Object.defineProperty(this, Symbol.metadata, {
|
|
9573
|
+
enumerable: true,
|
|
9574
|
+
configurable: true,
|
|
9575
|
+
writable: true,
|
|
9576
|
+
value: _metadata
|
|
9577
|
+
});
|
|
9578
|
+
}
|
|
9579
|
+
handlers = __runInitializers(this, _instanceExtraInitializers);
|
|
9580
|
+
constructor(ctx, handlers) {
|
|
9581
|
+
super(ctx, "mnemonRemote", { namespace: MNEMON_REMOTE_NAMESPACE });
|
|
9582
|
+
this.handlers = handlers;
|
|
9583
|
+
}
|
|
9584
|
+
read(endpoint, payload, signal) {
|
|
9585
|
+
return this.handlers.read(endpoint, payload, signal);
|
|
9586
|
+
}
|
|
9587
|
+
activation(endpoint, payload, signal) {
|
|
9588
|
+
return this.handlers.activation(endpoint, payload, signal);
|
|
9589
|
+
}
|
|
9590
|
+
write(endpoint, payload, signal) {
|
|
9591
|
+
if (!this.handlers.management) return Promise.resolve(denied());
|
|
9592
|
+
return this.handlers.write(endpoint, payload, signal);
|
|
9593
|
+
}
|
|
9594
|
+
pack(endpoint, payload, signal) {
|
|
9595
|
+
if (!this.handlers.management) return Promise.resolve(denied());
|
|
9596
|
+
return this.handlers.pack(endpoint, payload, signal);
|
|
9597
|
+
}
|
|
9598
|
+
async settings(endpoint, payload, signal) {
|
|
9599
|
+
if (endpoint === "mutate" && !this.handlers.management) return denied();
|
|
9600
|
+
if (endpoint !== "get" && endpoint !== "mutate") return unknownSettingsEndpoint(endpoint);
|
|
9601
|
+
const response = await this.handlers.settings(endpoint, payload, signal);
|
|
9602
|
+
if (endpoint !== "get" || this.handlers.management || !response.ok || typeof response.value !== "object" || response.value === null || Array.isArray(response.value)) return response;
|
|
9603
|
+
return {
|
|
9604
|
+
...response,
|
|
9605
|
+
value: {
|
|
9606
|
+
...response.value,
|
|
9607
|
+
writable: false
|
|
9608
|
+
}
|
|
9609
|
+
};
|
|
9610
|
+
}
|
|
9611
|
+
view(endpoint, payload, signal) {
|
|
9612
|
+
return this.handlers.view(endpoint, payload, signal);
|
|
9613
|
+
}
|
|
9614
|
+
viewWrite(endpoint, payload, signal) {
|
|
9615
|
+
if (!this.handlers.management) return Promise.resolve(denied());
|
|
9616
|
+
return this.handlers.viewWrite(endpoint, payload, signal);
|
|
9617
|
+
}
|
|
9618
|
+
};
|
|
9619
|
+
})();
|
|
9620
|
+
//#endregion
|
|
9621
|
+
//#region src/host/live-config.ts
|
|
9622
|
+
function plain(value) {
|
|
9623
|
+
if (isVolatile(value)) return plain(value.get());
|
|
9624
|
+
if (Array.isArray(value)) return value.map(plain);
|
|
9625
|
+
if (value === null || typeof value !== "object") return value;
|
|
9626
|
+
const prototype = Object.getPrototypeOf(value);
|
|
9627
|
+
if (prototype !== Object.prototype && prototype !== null) return value;
|
|
9628
|
+
return Object.fromEntries(Object.entries(value).map(([key, child]) => [key, plain(child)]));
|
|
9629
|
+
}
|
|
9630
|
+
/** Read a detached snapshot of the live profile configuration. */
|
|
9631
|
+
function plainHostConfig(value = {}) {
|
|
9632
|
+
return plain(value);
|
|
9633
|
+
}
|
|
9634
|
+
function liveConfig() {
|
|
9635
|
+
const schema = new z(Config.toJSON());
|
|
9636
|
+
schema.dict = Object.fromEntries(Object.entries(schema.dict ?? {}).map(([key, field]) => [key, key === "remoteAccess" ? field : field.volatile()]));
|
|
9637
|
+
const standard = schema["~standard"];
|
|
9638
|
+
Object.defineProperty(schema, "~standard", { value: {
|
|
9639
|
+
...standard,
|
|
9640
|
+
validate(value) {
|
|
9641
|
+
const parsed = standard.validate(value);
|
|
9642
|
+
if ("then" in parsed) throw new TypeError("Mnemon configuration validation must be synchronous");
|
|
9643
|
+
if (parsed.issues) return parsed;
|
|
9644
|
+
try {
|
|
9645
|
+
resolveConfig(plainHostConfig(parsed.value));
|
|
9646
|
+
return parsed;
|
|
9647
|
+
} catch (error) {
|
|
9648
|
+
return { issues: [{ message: error instanceof Error ? error.message : String(error) }] };
|
|
9649
|
+
}
|
|
9650
|
+
}
|
|
9651
|
+
} });
|
|
9652
|
+
return schema;
|
|
9653
|
+
}
|
|
9654
|
+
/** Profile Config for live forms; transport authority retains normal remounts. */
|
|
9655
|
+
const LiveConfig = liveConfig();
|
|
9656
|
+
//#endregion
|
|
9657
|
+
//#region src/host/legacy-settings-import.ts
|
|
9658
|
+
const UNSAFE_KEYS = /* @__PURE__ */ new Set([
|
|
9659
|
+
"__proto__",
|
|
9660
|
+
"prototype",
|
|
9661
|
+
"constructor"
|
|
9662
|
+
]);
|
|
9663
|
+
const ENTRY_ID = /^[a-zA-Z0-9][a-zA-Z0-9._:/-]{0,299}$/u;
|
|
9664
|
+
const STRATEGY_ID = /^[a-z][a-z0-9-]{0,127}$/u;
|
|
9665
|
+
const VIEW_NAMESPACE = /^mnemon-view(?:-[a-f0-9]{16})?$/u;
|
|
9666
|
+
const LEGACY_NAMESPACE = /^mnemon-plugins(?:-[a-f0-9]{16})?$/u;
|
|
9667
|
+
function object$1(value, label) {
|
|
9668
|
+
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`);
|
|
9669
|
+
for (const key of Reflect.ownKeys(value)) {
|
|
9670
|
+
if (typeof key !== "string" || UNSAFE_KEYS.has(key)) throw new Error(`${label} contains an unsafe key`);
|
|
9671
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
9672
|
+
if (!descriptor.enumerable || !Object.hasOwn(descriptor, "value")) throw new Error(`${label} must contain only data properties`);
|
|
9673
|
+
}
|
|
9674
|
+
return value;
|
|
9675
|
+
}
|
|
9676
|
+
/** Copy JSON data without invoking getters, serializers or prototype methods. */
|
|
9677
|
+
function copy(value, label, ancestors = /* @__PURE__ */ new Set(), depth = 0) {
|
|
9678
|
+
if (value === null || typeof value === "string" || typeof value === "boolean") return value;
|
|
9679
|
+
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
9680
|
+
if (typeof value !== "object" || value === null) throw new Error(`${label} must contain only JSON data`);
|
|
9681
|
+
if (depth > 64 || ancestors.has(value)) throw new Error(`${label} contains cyclic or excessively nested data`);
|
|
9682
|
+
ancestors.add(value);
|
|
9683
|
+
try {
|
|
9684
|
+
if (Array.isArray(value)) {
|
|
9685
|
+
if (Object.getPrototypeOf(value) !== Array.prototype) throw new Error(`${label} must contain plain arrays`);
|
|
9686
|
+
if (Reflect.ownKeys(value).length !== value.length + 1) throw new Error(`${label} contains a sparse or extended array`);
|
|
9687
|
+
return Array.from({ length: value.length }, (_, index) => {
|
|
9688
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, String(index));
|
|
9689
|
+
if (!descriptor || !descriptor.enumerable || !Object.hasOwn(descriptor, "value")) throw new Error(`${label} must contain only data properties`);
|
|
9690
|
+
return copy(descriptor.value, label, ancestors, depth + 1);
|
|
9691
|
+
});
|
|
9692
|
+
}
|
|
9693
|
+
return Object.fromEntries(Object.entries(object$1(value, label)).map(([key, item]) => [key, copy(item, label, ancestors, depth + 1)]));
|
|
9694
|
+
} finally {
|
|
9695
|
+
ancestors.delete(value);
|
|
9696
|
+
}
|
|
9697
|
+
}
|
|
9698
|
+
function copiedObject(value, label) {
|
|
9699
|
+
object$1(value, label);
|
|
9700
|
+
return copy(value, label);
|
|
9701
|
+
}
|
|
9702
|
+
/** Inspect validated copies only; never evaluate expressions or invoke getters. */
|
|
9703
|
+
function containsExpression(value) {
|
|
9704
|
+
return value !== null && typeof value === "object" && (Object.hasOwn(value, "__jsExpr") || Object.values(value).some(containsExpression));
|
|
9705
|
+
}
|
|
9706
|
+
function fields(value, allowed, label) {
|
|
9707
|
+
if (Object.keys(value).some((key) => !allowed.includes(key))) throw new Error(`${label} contains unsupported fields`);
|
|
9708
|
+
}
|
|
9709
|
+
function interaction(value, label, allowed) {
|
|
9710
|
+
const result = copiedObject(value, label);
|
|
9711
|
+
fields(result, allowed, label);
|
|
9712
|
+
if (Object.values(result).some((item) => typeof item !== "boolean")) throw new Error(`${label} preferences must be boolean`);
|
|
9713
|
+
return result;
|
|
9714
|
+
}
|
|
9715
|
+
function entryId(value, label) {
|
|
9716
|
+
if (typeof value !== "string" || !ENTRY_ID.test(value) || UNSAFE_KEYS.has(value)) throw new Error(`${label} contains an invalid Entry id`);
|
|
9717
|
+
}
|
|
9718
|
+
function view(value, label) {
|
|
9719
|
+
const result = copiedObject(value, label);
|
|
9720
|
+
fields(result, ["strategyTypeId", "entries"], label);
|
|
9721
|
+
if (Object.hasOwn(result, "strategyTypeId") && (typeof result.strategyTypeId !== "string" || !STRATEGY_ID.test(result.strategyTypeId))) throw new Error(`${label} contains an invalid Strategy type id`);
|
|
9722
|
+
const entries = {};
|
|
9723
|
+
if (Object.hasOwn(result, "entries")) {
|
|
9724
|
+
const values = object$1(result.entries, `${label}.entries`);
|
|
9725
|
+
if (Object.keys(values).length > 64) throw new Error(`${label} contains too many Entries`);
|
|
9726
|
+
for (const [id, raw] of Object.entries(values)) {
|
|
9727
|
+
entryId(id, label);
|
|
9728
|
+
const item = copiedObject(raw, `${label}.entries`);
|
|
9729
|
+
fields(item, ["enabled", "config"], `${label}.entries`);
|
|
9730
|
+
if (Object.hasOwn(item, "enabled") && typeof item.enabled !== "boolean") throw new Error(`${label} Entry enabled must be boolean`);
|
|
9731
|
+
const config = Object.hasOwn(item, "config") ? copiedObject(item.config, `${label} Entry config`) : {};
|
|
9732
|
+
if (JSON.stringify(config).length > 65536) throw new Error(`${label} Entry config exceeds 64 KiB`);
|
|
9733
|
+
entries[id] = {
|
|
9734
|
+
...typeof item.enabled === "boolean" ? { enabled: item.enabled } : {},
|
|
9735
|
+
config
|
|
9736
|
+
};
|
|
9737
|
+
}
|
|
9738
|
+
}
|
|
9739
|
+
return {
|
|
9740
|
+
...typeof result.strategyTypeId === "string" ? { strategyTypeId: result.strategyTypeId } : {},
|
|
9741
|
+
...Object.hasOwn(result, "entries") ? { entries } : {}
|
|
9742
|
+
};
|
|
9743
|
+
}
|
|
9744
|
+
function sources(value, label, sourceEntryIds, diagnostics) {
|
|
9745
|
+
const result = copiedObject(value, label);
|
|
9746
|
+
fields(result, ["sources"], label);
|
|
9747
|
+
const values = Object.hasOwn(result, "sources") ? object$1(result.sources, `${label}.sources`) : {};
|
|
9748
|
+
if (Object.keys(values).length > 64) throw new Error(`${label} contains too many Source Entries`);
|
|
9749
|
+
const entries = {};
|
|
9750
|
+
for (const [id, raw] of Object.entries(values)) {
|
|
9751
|
+
entryId(id, label);
|
|
9752
|
+
const item = copiedObject(raw, `${label}.sources`);
|
|
9753
|
+
fields(item, ["enabled"], `${label}.sources`);
|
|
9754
|
+
if (typeof item.enabled !== "boolean") throw new Error(`${label} Source enabled must be boolean`);
|
|
9755
|
+
if (!sourceEntryIds.has(id)) {
|
|
9756
|
+
diagnostics.push(`Skipped legacy Source preference for ${id}: the current profile does not declare it as a Source.`);
|
|
9757
|
+
continue;
|
|
9758
|
+
}
|
|
9759
|
+
entries[id] = {
|
|
9760
|
+
enabled: item.enabled,
|
|
9761
|
+
config: {}
|
|
9762
|
+
};
|
|
9763
|
+
}
|
|
9764
|
+
return entries;
|
|
9765
|
+
}
|
|
9766
|
+
function applyEntryOverrides(entries, overrides, sourceEntryIds, diagnostics) {
|
|
9767
|
+
if (!Array.isArray(overrides)) throw new Error("Explicit Entry overrides must be an array");
|
|
9768
|
+
const matching = /* @__PURE__ */ new Map();
|
|
9769
|
+
for (const raw of overrides) {
|
|
9770
|
+
const row = object$1(raw, "Explicit Entry override");
|
|
9771
|
+
entryId(row.id, "Explicit Entry override");
|
|
9772
|
+
if (!Object.hasOwn(entries, row.id)) continue;
|
|
9773
|
+
const previous = matching.get(row.id) ?? {};
|
|
9774
|
+
matching.set(row.id, {
|
|
9775
|
+
...previous,
|
|
9776
|
+
...row.disabled === void 0 ? {} : { disabled: row.disabled },
|
|
9777
|
+
...row.config === void 0 ? {} : { config: row.config }
|
|
9778
|
+
});
|
|
9779
|
+
}
|
|
9780
|
+
for (const [id, row] of matching) {
|
|
9781
|
+
if (row.disabled !== void 0 && typeof row.disabled !== "boolean") {
|
|
9782
|
+
delete entries[id];
|
|
9783
|
+
diagnostics.push(`Skipped legacy View preference for ${id}: its explicit disabled value is not boolean.`);
|
|
9784
|
+
continue;
|
|
9785
|
+
}
|
|
9786
|
+
if (row.config !== void 0 && !sourceEntryIds.has(id)) {
|
|
9787
|
+
const config = copiedObject(row.config, "Explicit Entry config");
|
|
9788
|
+
if (containsExpression(config)) {
|
|
9789
|
+
delete entries[id];
|
|
9790
|
+
diagnostics.push(`Skipped legacy View preference for ${id}: its explicit config contains an expression.`);
|
|
9791
|
+
continue;
|
|
9792
|
+
}
|
|
9793
|
+
entries[id].config = config;
|
|
9794
|
+
}
|
|
9795
|
+
if (typeof row.disabled === "boolean") entries[id].enabled = !row.disabled;
|
|
9796
|
+
}
|
|
9797
|
+
}
|
|
9798
|
+
/**
|
|
9799
|
+
* Recover only the canonical root and the exact owning profile's old namespaces.
|
|
9800
|
+
* This does not read files, edit profile rows, validate plugin domains or commit.
|
|
9801
|
+
* Malformed relevant input rejects the complete plan without an import marker.
|
|
9802
|
+
*/
|
|
9803
|
+
function planLegacySettingsImport(options) {
|
|
9804
|
+
const diagnostics = [];
|
|
9805
|
+
try {
|
|
9806
|
+
const rawCurrent = object$1(options.currentOverride, "Current config override");
|
|
9807
|
+
if (rawCurrent.legacySettingsImported === true) return {
|
|
9808
|
+
patch: {},
|
|
9809
|
+
diagnostics
|
|
9810
|
+
};
|
|
9811
|
+
if (options.entryId !== "mnemon") throw new Error("Legacy settings belong to the canonical mnemon Entry; another root Entry is ambiguous.");
|
|
9812
|
+
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.");
|
|
9813
|
+
const sections = object$1(options.sections, "Legacy settings document");
|
|
9814
|
+
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.");
|
|
9815
|
+
const relevant = [
|
|
9816
|
+
"mnemon",
|
|
9817
|
+
"mnemon-ui",
|
|
9818
|
+
options.viewNamespace,
|
|
9819
|
+
options.legacyNamespace
|
|
9820
|
+
];
|
|
9821
|
+
if (!relevant.some((key) => Object.hasOwn(sections, key))) return {
|
|
9822
|
+
patch: {},
|
|
9823
|
+
diagnostics
|
|
9824
|
+
};
|
|
9825
|
+
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.`);
|
|
9826
|
+
const current = copiedObject(rawCurrent, "Current config override");
|
|
9827
|
+
if (Object.hasOwn(current, "legacySettingsImported") && typeof current.legacySettingsImported !== "boolean") throw new Error("Current import marker must be boolean");
|
|
9828
|
+
const root = Object.hasOwn(sections, "mnemon") ? copiedObject(sections.mnemon, "mnemon") : {};
|
|
9829
|
+
if (Object.hasOwn(root, "memoryView") || Object.hasOwn(root, "legacySettingsImported")) throw new Error("Legacy mnemon contains reserved migration fields");
|
|
9830
|
+
const oldInteraction = Object.hasOwn(root, "conversationInteraction") ? interaction(root.conversationInteraction, "mnemon.conversationInteraction", [
|
|
9831
|
+
"toolviews",
|
|
9832
|
+
"turnBar",
|
|
9833
|
+
"saveAction"
|
|
9834
|
+
]) : {};
|
|
9835
|
+
const oldUi = Object.hasOwn(sections, "mnemon-ui") ? interaction(sections["mnemon-ui"], "mnemon-ui", ["turnBar", "saveAction"]) : {};
|
|
9836
|
+
const currentInteraction = Object.hasOwn(current, "conversationInteraction") ? interaction(current.conversationInteraction, "Current conversationInteraction", [
|
|
9837
|
+
"toolviews",
|
|
9838
|
+
"turnBar",
|
|
9839
|
+
"saveAction"
|
|
9840
|
+
]) : {};
|
|
9841
|
+
const patch = Object.fromEntries(Object.entries(root).filter(([key]) => key !== "conversationInteraction" && !Object.hasOwn(current, key)));
|
|
9842
|
+
const inheritedInteraction = {
|
|
9843
|
+
...oldInteraction,
|
|
9844
|
+
...oldUi
|
|
9845
|
+
};
|
|
9846
|
+
if (Object.keys(inheritedInteraction).some((key) => !Object.hasOwn(currentInteraction, key))) patch.conversationInteraction = {
|
|
9847
|
+
...inheritedInteraction,
|
|
9848
|
+
...currentInteraction
|
|
9849
|
+
};
|
|
9850
|
+
const currentView = Object.hasOwn(current, "memoryView") ? view(current.memoryView, "Current memoryView") : {};
|
|
9851
|
+
if (Object.hasOwn(sections, options.viewNamespace) || Object.hasOwn(sections, options.legacyNamespace)) {
|
|
9852
|
+
if (!Array.isArray(options.sourceEntryIds)) throw new Error("Source Entry ids must be an array");
|
|
9853
|
+
for (const id of options.sourceEntryIds) entryId(id, "Source Entry ids");
|
|
9854
|
+
const sourceEntryIds = new Set(options.sourceEntryIds);
|
|
9855
|
+
const oldSources = Object.hasOwn(sections, options.legacyNamespace) ? sources(sections[options.legacyNamespace], options.legacyNamespace, sourceEntryIds, diagnostics) : {};
|
|
9856
|
+
const oldView = Object.hasOwn(sections, options.viewNamespace) ? view(sections[options.viewNamespace], options.viewNamespace) : {};
|
|
9857
|
+
const entries = {
|
|
9858
|
+
...oldSources,
|
|
9859
|
+
...oldView.entries
|
|
9860
|
+
};
|
|
9861
|
+
applyEntryOverrides(entries, options.entryOverrides, sourceEntryIds, diagnostics);
|
|
9862
|
+
const migratedView = {
|
|
9863
|
+
...oldView,
|
|
9864
|
+
entries,
|
|
9865
|
+
...currentView
|
|
9866
|
+
};
|
|
9867
|
+
if (!Object.hasOwn(currentView, "entries") || !Object.hasOwn(currentView, "strategyTypeId") && oldView.strategyTypeId !== void 0) patch.memoryView = migratedView;
|
|
9868
|
+
}
|
|
9869
|
+
patch.legacySettingsImported = true;
|
|
9870
|
+
return {
|
|
9871
|
+
patch,
|
|
9872
|
+
diagnostics
|
|
9873
|
+
};
|
|
9874
|
+
} catch (error) {
|
|
9875
|
+
diagnostics.push(error instanceof Error ? error.message : "Legacy settings import could not be planned");
|
|
9876
|
+
return {
|
|
9877
|
+
patch: {},
|
|
9878
|
+
diagnostics
|
|
9879
|
+
};
|
|
9880
|
+
}
|
|
9881
|
+
}
|
|
9882
|
+
//#endregion
|
|
9883
|
+
//#region src/host/settings-service.ts
|
|
9884
|
+
const pendingNativeImports = /* @__PURE__ */ new WeakSet();
|
|
9885
|
+
const clone = (value) => structuredClone(value);
|
|
9886
|
+
const object = (value) => value !== null && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
9887
|
+
function profileYaml(source) {
|
|
9888
|
+
const document = parseDocument(source, { customTags: [{
|
|
9889
|
+
tag: "tag:yaml.org,2002:js",
|
|
9890
|
+
resolve: (value) => ({ __jsExpr: value })
|
|
9891
|
+
}] });
|
|
9892
|
+
if (document.errors.length > 0 || document.warnings.length > 0) throw new Error("Invalid or unsupported legacy/profile YAML; retained backup was not changed");
|
|
9893
|
+
return document.toJS({ maxAliasCount: 100 });
|
|
9894
|
+
}
|
|
9895
|
+
/** A local facade preserves Mnemon's wire namespaces; DSH owns all persistence. */
|
|
9896
|
+
var ProfileMnemonSettings = class {
|
|
9897
|
+
ctx;
|
|
9898
|
+
input;
|
|
9899
|
+
registrations = /* @__PURE__ */ new Map();
|
|
9900
|
+
listeners = /* @__PURE__ */ new Set();
|
|
9901
|
+
revisions = /* @__PURE__ */ new Map();
|
|
9902
|
+
owner;
|
|
9903
|
+
forms;
|
|
9904
|
+
editor;
|
|
9905
|
+
closed = false;
|
|
9906
|
+
importing;
|
|
9907
|
+
nativeImportPending;
|
|
9908
|
+
constructor(ctx, input) {
|
|
9909
|
+
this.ctx = ctx;
|
|
9910
|
+
this.input = input;
|
|
9911
|
+
this.forms = ctx.settings;
|
|
9912
|
+
this.owner = ctx.fiber;
|
|
9913
|
+
this.editor = ctx.get("configEditor");
|
|
9914
|
+
const profile = ctx.get("profileContext");
|
|
9915
|
+
const root = ctx.root ?? ctx;
|
|
9916
|
+
if (profile?.home !== void 0 && existsSync(join(profile.home, "settings.yaml"))) pendingNativeImports.add(root);
|
|
9917
|
+
this.nativeImportPending = pendingNativeImports.has(root);
|
|
9918
|
+
const owner = this.owner;
|
|
9919
|
+
const validate = (candidate) => {
|
|
9920
|
+
const config = plainHostConfig(candidate);
|
|
9921
|
+
for (const registration of this.registrations.values()) {
|
|
9922
|
+
if (registration.legacy) continue;
|
|
9923
|
+
const value = this.resolve(registration, config);
|
|
9924
|
+
registration.validate?.(value);
|
|
9925
|
+
}
|
|
9926
|
+
};
|
|
9927
|
+
ctx.on("internal/config", function(_raw, next) {
|
|
9928
|
+
const candidate = next();
|
|
9929
|
+
if (this === owner) validate(candidate);
|
|
9930
|
+
return candidate;
|
|
9931
|
+
}, { prepend: true });
|
|
9932
|
+
ctx.on("loader/volatile-update", ((paths) => {
|
|
9933
|
+
if (this.closed) return;
|
|
9934
|
+
for (const registration of this.registrations.values()) {
|
|
9935
|
+
if (registration.legacy) continue;
|
|
9936
|
+
if (!paths.some((path) => registration.field === void 0 ? path.length === 0 || !["memoryView", "legacySettingsImported"].includes(path[0]) : path.length === 0 || path[0] === registration.field)) continue;
|
|
9937
|
+
const value = this.resolve(registration);
|
|
9938
|
+
for (const listener of this.listeners) try {
|
|
9939
|
+
listener(registration.namespace, value);
|
|
9940
|
+
} catch (error) {
|
|
9941
|
+
console.warn("dsh-mnemon: committed settings listener failed", error);
|
|
9942
|
+
}
|
|
9943
|
+
}
|
|
9944
|
+
}));
|
|
9945
|
+
ctx.effect(() => {
|
|
9946
|
+
const disposePresentation = owner === void 0 ? void 0 : this.forms.configure({ auto: false }, owner);
|
|
9947
|
+
return () => {
|
|
9948
|
+
this.closed = true;
|
|
9949
|
+
this.listeners.clear();
|
|
9950
|
+
this.revisions.clear();
|
|
9951
|
+
disposePresentation?.();
|
|
9952
|
+
};
|
|
9953
|
+
}, "dsh-mnemon: profile settings");
|
|
9954
|
+
}
|
|
9955
|
+
get writable() {
|
|
9956
|
+
const entry = this.owner?.entry;
|
|
9957
|
+
return !this.closed && this.forms.writable && entry !== void 0 && this.editor?.entries().includes(entry) === true;
|
|
9958
|
+
}
|
|
9959
|
+
onUpdated(listener) {
|
|
9960
|
+
this.listeners.add(listener);
|
|
9961
|
+
return () => {
|
|
9962
|
+
this.listeners.delete(listener);
|
|
9963
|
+
};
|
|
9964
|
+
}
|
|
9965
|
+
resolve(registration, config = plainHostConfig(this.owner?.config ?? this.input)) {
|
|
9966
|
+
const value = registration.legacy ? registration.base : registration.field === void 0 ? config : config[registration.field];
|
|
9967
|
+
return registration.schema(object(value));
|
|
9968
|
+
}
|
|
9969
|
+
register(namespace, schema, options) {
|
|
9970
|
+
if (this.registrations.has(namespace)) throw new Error(`Mnemon settings already registered: ${namespace}`);
|
|
9971
|
+
if (typeof schema !== "function") throw new Error("Mnemon settings require a schema");
|
|
9972
|
+
const field = namespace === "mnemon-ui" ? "conversationInteraction" : /^mnemon-view(?:-[a-f0-9]{16})?$/u.test(namespace) ? "memoryView" : void 0;
|
|
9973
|
+
const legacy = /^mnemon-plugins(?:-[a-f0-9]{16})?$/u.test(namespace);
|
|
9974
|
+
if (namespace !== "mnemon" && field === void 0 && !legacy) throw new Error("Unsupported Mnemon settings namespace");
|
|
9975
|
+
const registration = {
|
|
9976
|
+
namespace,
|
|
9977
|
+
...field === void 0 ? {} : { field },
|
|
9978
|
+
legacy,
|
|
9979
|
+
schema,
|
|
9980
|
+
base: clone(options.base ?? {}),
|
|
9981
|
+
...options.validate === void 0 ? {} : { validate: options.validate }
|
|
9982
|
+
};
|
|
9983
|
+
const value = this.resolve(registration);
|
|
9984
|
+
options.validate?.(value);
|
|
9985
|
+
this.registrations.set(namespace, registration);
|
|
9986
|
+
return { get: () => this.resolve(registration) };
|
|
9987
|
+
}
|
|
9988
|
+
nativeDescriptor() {
|
|
9989
|
+
if (this.closed || this.owner?.entry === void 0 || !this.editor?.entries().includes(this.owner.entry)) return void 0;
|
|
9990
|
+
const descriptor = this.forms.describe().find((item) => item.ns === this.owner?.entry?.options.id);
|
|
9991
|
+
if (descriptor !== void 0) {
|
|
9992
|
+
this.revisions.set(descriptor.revision, clone({
|
|
9993
|
+
ns: descriptor.ns,
|
|
9994
|
+
revision: descriptor.revision,
|
|
9995
|
+
applies: descriptor.applies,
|
|
9996
|
+
value: descriptor.value,
|
|
9997
|
+
base: descriptor.base,
|
|
9998
|
+
user: descriptor.user
|
|
9999
|
+
}));
|
|
10000
|
+
if (this.revisions.size > 64) this.revisions.delete(this.revisions.keys().next().value);
|
|
10001
|
+
}
|
|
10002
|
+
return descriptor;
|
|
10003
|
+
}
|
|
10004
|
+
unchanged(previous, current, registration, operations) {
|
|
10005
|
+
const project = (value) => {
|
|
10006
|
+
if (registration.field !== void 0) return object(value)[registration.field];
|
|
10007
|
+
const { memoryView: _view, legacySettingsImported: _imported, conversationInteraction, ...core } = object(value);
|
|
10008
|
+
return operations.some((operation) => operation.path[0] === "conversationInteraction") ? {
|
|
10009
|
+
...core,
|
|
10010
|
+
conversationInteraction
|
|
10011
|
+
} : core;
|
|
10012
|
+
};
|
|
10013
|
+
const signature = (descriptor) => canonicalMemoryJson(JSON.parse(JSON.stringify([
|
|
10014
|
+
project(descriptor.value) ?? null,
|
|
10015
|
+
project(descriptor.base) ?? null,
|
|
10016
|
+
project(descriptor.user) ?? null
|
|
10017
|
+
])));
|
|
10018
|
+
return signature(previous) === signature(current);
|
|
10019
|
+
}
|
|
10020
|
+
describe(options) {
|
|
10021
|
+
const raw = this.nativeDescriptor();
|
|
10022
|
+
if (raw === void 0) return [];
|
|
10023
|
+
const descriptor = options?.redactSecrets ? this.forms.describe(options).find((item) => item.ns === this.owner?.entry?.options.id) : raw;
|
|
10024
|
+
if (descriptor === void 0) return [];
|
|
10025
|
+
return [...this.registrations.values()].map((registration) => {
|
|
10026
|
+
const project = (value) => registration.legacy ? {} : registration.field === void 0 ? value : object(value)[registration.field];
|
|
10027
|
+
return {
|
|
10028
|
+
ns: registration.namespace,
|
|
10029
|
+
value: project(descriptor.value) ?? {},
|
|
10030
|
+
base: project(descriptor.base) ?? {},
|
|
10031
|
+
user: project(descriptor.user) ?? {},
|
|
10032
|
+
revision: descriptor.revision,
|
|
10033
|
+
applies: "live"
|
|
10034
|
+
};
|
|
10035
|
+
});
|
|
10036
|
+
}
|
|
10037
|
+
async mutate(namespace, operations, expectedRevision) {
|
|
10038
|
+
const registration = this.registrations.get(namespace);
|
|
10039
|
+
if (registration === void 0 || registration.legacy) throw new Error("Unsupported Mnemon settings namespace");
|
|
10040
|
+
if (!this.writable) throw new Error("DSH settings are read-only");
|
|
10041
|
+
const translated = operations.map((operation) => ({
|
|
10042
|
+
...operation,
|
|
10043
|
+
path: [...registration.field === void 0 ? [] : [registration.field], ...operation.path]
|
|
10044
|
+
}));
|
|
10045
|
+
let revision = expectedRevision;
|
|
10046
|
+
const previous = revision === void 0 ? void 0 : this.revisions.get(revision);
|
|
10047
|
+
for (let attempt = 0;; attempt += 1) {
|
|
10048
|
+
if (!this.writable) throw new Error("DSH settings are read-only");
|
|
10049
|
+
try {
|
|
10050
|
+
await this.forms.mutate(this.owner.entry.options.id, translated, revision);
|
|
10051
|
+
return;
|
|
10052
|
+
} catch (error) {
|
|
10053
|
+
if (attempt >= 2 || previous === void 0 || typeof error !== "object" || error === null || !("code" in error) || error.code !== "SETTINGS_CONFLICT") throw error;
|
|
10054
|
+
if (!this.writable) throw new Error("DSH settings are read-only");
|
|
10055
|
+
const current = this.nativeDescriptor();
|
|
10056
|
+
if (current === void 0 || !this.unchanged(previous, current, registration, operations)) throw error;
|
|
10057
|
+
revision = current.revision;
|
|
10058
|
+
}
|
|
10059
|
+
}
|
|
10060
|
+
}
|
|
10061
|
+
/** Read only the retained backup; ConfigEditor preserves all other patch rows. */
|
|
10062
|
+
async importLegacy(sourceEntryIds) {
|
|
10063
|
+
if (this.importing !== void 0) return this.importing;
|
|
10064
|
+
this.importing = this.performImport(sourceEntryIds).finally(() => {
|
|
10065
|
+
this.importing = void 0;
|
|
10066
|
+
});
|
|
10067
|
+
return this.importing;
|
|
10068
|
+
}
|
|
10069
|
+
async performImport(sourceEntryIds) {
|
|
10070
|
+
const profile = this.ctx.get("profileContext");
|
|
10071
|
+
const entry = this.owner?.entry;
|
|
10072
|
+
if (!this.writable || profile?.home === void 0 || entry === void 0) return;
|
|
10073
|
+
if (this.nativeImportPending) {
|
|
10074
|
+
console.warn("dsh-mnemon: DSH is importing settings.yaml; restart once to recover retained Mnemon UI and plugin preferences");
|
|
10075
|
+
return;
|
|
9892
10076
|
}
|
|
9893
|
-
|
|
9894
|
-
|
|
9895
|
-
|
|
9896
|
-
|
|
9897
|
-
|
|
9898
|
-
|
|
9899
|
-
|
|
9900
|
-
|
|
9901
|
-
|
|
10077
|
+
if (plainHostConfig(this.owner?.config ?? this.input).legacySettingsImported) return;
|
|
10078
|
+
const backup = join(profile.home, "settings.yaml.imported");
|
|
10079
|
+
let text;
|
|
10080
|
+
try {
|
|
10081
|
+
if ((await stat(backup)).size > 1048576) throw new Error("Legacy settings backup exceeds the import limit");
|
|
10082
|
+
text = await readFile(backup, "utf8");
|
|
10083
|
+
} catch (error) {
|
|
10084
|
+
if (typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT") return;
|
|
10085
|
+
throw error;
|
|
9902
10086
|
}
|
|
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
|
|
10087
|
+
const sections = profileYaml(text);
|
|
10088
|
+
const viewNamespace = [...this.registrations.keys()].find((namespace) => namespace.startsWith("mnemon-view"));
|
|
10089
|
+
const legacyNamespace = [...this.registrations.keys()].find((namespace) => namespace.startsWith("mnemon-plugins"));
|
|
10090
|
+
const plan = () => {
|
|
10091
|
+
const configuration = this.editor.configuration().find((item) => item.entry === entry);
|
|
10092
|
+
if (configuration === void 0) throw new Error("Mnemon profile entry is no longer editable");
|
|
10093
|
+
const document = profileYaml(readFileSync(this.editor.documentPath, "utf8"));
|
|
10094
|
+
const entryOverrides = Array.isArray(document) ? document.flatMap((value) => {
|
|
10095
|
+
const row = object(value);
|
|
10096
|
+
if (typeof row.id !== "string") return [];
|
|
10097
|
+
const entries = this.editor.entries().filter((candidate) => candidate.options.id === row.id);
|
|
10098
|
+
if (entries.length > 1) throw new Error("Legacy settings import requires unambiguous profile Entry ids");
|
|
10099
|
+
return [{
|
|
10100
|
+
id: entries[0]?.id ?? row.id,
|
|
10101
|
+
..."disabled" in row ? { disabled: row.disabled } : {},
|
|
10102
|
+
..."config" in row ? { config: row.config } : {}
|
|
10103
|
+
}];
|
|
10104
|
+
}) : [];
|
|
10105
|
+
return planLegacySettingsImport({
|
|
10106
|
+
entryId: entry.options.id,
|
|
10107
|
+
viewNamespace,
|
|
10108
|
+
legacyNamespace,
|
|
10109
|
+
sections,
|
|
10110
|
+
currentOverride: configuration.override,
|
|
10111
|
+
entryOverrides,
|
|
10112
|
+
sourceEntryIds
|
|
10012
10113
|
});
|
|
10114
|
+
};
|
|
10115
|
+
const preview = plan();
|
|
10116
|
+
if (Object.keys(preview.patch).length === 0) {
|
|
10117
|
+
if (preview.diagnostics.length > 0) console.warn("dsh-mnemon: legacy settings were not imported; retained backup requires review");
|
|
10118
|
+
return;
|
|
10013
10119
|
}
|
|
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;
|
|
10120
|
+
if (this.closed) return;
|
|
10121
|
+
await this.editor.edit(entry, (current) => {
|
|
10122
|
+
if (this.closed) throw new Error("Mnemon settings are disposed");
|
|
10123
|
+
const next = plan();
|
|
10038
10124
|
return {
|
|
10039
|
-
...
|
|
10040
|
-
|
|
10041
|
-
...response.value,
|
|
10042
|
-
writable: false
|
|
10043
|
-
}
|
|
10125
|
+
...current,
|
|
10126
|
+
...next.patch
|
|
10044
10127
|
};
|
|
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
|
-
})();
|
|
10128
|
+
});
|
|
10129
|
+
}
|
|
10130
|
+
};
|
|
10055
10131
|
//#endregion
|
|
10056
10132
|
//#region src/host/plugin.ts
|
|
10057
10133
|
const name = "dsh-mnemon";
|
|
@@ -10075,54 +10151,26 @@ function optionalWorkspaceRegistry(ctx) {
|
|
|
10075
10151
|
function apply(rawContext, rawConfig = {}) {
|
|
10076
10152
|
const ctx = rawContext;
|
|
10077
10153
|
const config = plainHostConfig(rawConfig);
|
|
10078
|
-
const hostSettings =
|
|
10154
|
+
const hostSettings = new ProfileMnemonSettings(ctx, rawConfig);
|
|
10079
10155
|
registerMnemonSubagentTokenUsageProjection(ctx);
|
|
10080
10156
|
const extensions = provideMemoryRuntime(ctx);
|
|
10081
10157
|
const memoryPlugins = new MemoryPluginManagement(ctx, extensions, hostSettings);
|
|
10082
10158
|
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
|
-
};
|
|
10159
|
+
const effectiveConfig = (value) => memoryPlugins.resolveConfig(resolveConfig(value), value.memoryView ?? { entries: {} });
|
|
10089
10160
|
const settings = hostSettings.register("mnemon", Config, {
|
|
10090
10161
|
base: config,
|
|
10091
10162
|
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
|
-
}
|
|
10163
|
+
validate: (value) => createRuntimeGraph(effectiveConfig(value), void 0, extensions).dispose()
|
|
10109
10164
|
});
|
|
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);
|
|
10165
|
+
const runtime = new LiveMnemonRuntime(createRuntimeGraph(effectiveConfig(settings.get()), void 0, extensions), optionalWorkspaceRegistry(ctx), ctx.agents, extensions);
|
|
10114
10166
|
const resolved = runtime.config;
|
|
10115
|
-
ctx.effect(() =>
|
|
10116
|
-
const next = value;
|
|
10167
|
+
ctx.effect(() => hostSettings.onUpdated((namespace, value) => {
|
|
10117
10168
|
if (namespace === memoryPlugins.settingsNamespace) {
|
|
10118
10169
|
runtime.swap(createRuntimeGraph(effectiveConfig(settings.get()), void 0, extensions));
|
|
10119
10170
|
return;
|
|
10120
10171
|
}
|
|
10121
10172
|
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));
|
|
10173
|
+
runtime.swap(createRuntimeGraph(effectiveConfig(value), void 0, extensions));
|
|
10126
10174
|
}), "dsh-mnemon: live runtime settings");
|
|
10127
10175
|
ctx.effect(() => memoryPlugins.start(), "dsh-mnemon: plugin graph settings");
|
|
10128
10176
|
hostSettings.register("mnemon-ui", InteractionConfig, {
|
|
@@ -10146,7 +10194,7 @@ function apply(rawContext, rawConfig = {}) {
|
|
|
10146
10194
|
unsubscribe();
|
|
10147
10195
|
};
|
|
10148
10196
|
}, "dsh-mnemon: canonical displayMode migration");
|
|
10149
|
-
|
|
10197
|
+
ctx.effect(() => {
|
|
10150
10198
|
let disposed = false;
|
|
10151
10199
|
const loader = ctx.get("loader");
|
|
10152
10200
|
Promise.resolve(loader?.await?.()).then(async () => {
|
|
@@ -10178,25 +10226,24 @@ function apply(rawContext, rawConfig = {}) {
|
|
|
10178
10226
|
return async () => {
|
|
10179
10227
|
stop();
|
|
10180
10228
|
await coordinator.dispose();
|
|
10181
|
-
disposePrepared();
|
|
10182
10229
|
runtime.dispose();
|
|
10183
10230
|
};
|
|
10184
10231
|
}, "dsh-mnemon.lifecycle-root()");
|
|
10185
10232
|
registerTools(ctx, runtime, coordinator);
|
|
10186
10233
|
registerCommands(ctx.commands, runtime, coordinator);
|
|
10187
10234
|
registerGuidance(ctx, resolved);
|
|
10188
|
-
ctx.inject(["connection"], (webContext) => {
|
|
10189
|
-
|
|
10190
|
-
|
|
10191
|
-
const rpc = registerRpc(
|
|
10192
|
-
const settings = registerSettingsRpc(
|
|
10193
|
-
const view = registerViewRpc(
|
|
10235
|
+
ctx.inject(["connection", "webServer"], (webContext) => {
|
|
10236
|
+
const connection = Context.is(webContext) ? webContext.extend({ webServer: webContext.get("webServer") }).connection : webContext.connection;
|
|
10237
|
+
if (connection === void 0) return;
|
|
10238
|
+
const rpc = registerRpc(connection, runtime, lifecycle);
|
|
10239
|
+
const settings = registerSettingsRpc(connection, hostSettings);
|
|
10240
|
+
const view = registerViewRpc(connection, runtime, extensions, memoryPlugins, lifecycle, pluginInstallation);
|
|
10194
10241
|
if (Context.is(webContext)) new MnemonRemoteService(webContext, {
|
|
10195
10242
|
...rpc,
|
|
10196
10243
|
settings,
|
|
10197
10244
|
view: view.read,
|
|
10198
10245
|
viewWrite: view.write,
|
|
10199
|
-
management:
|
|
10246
|
+
management: resolved.remoteAccess === "trusted-host"
|
|
10200
10247
|
});
|
|
10201
10248
|
});
|
|
10202
10249
|
}
|