dsh-mnemon 0.5.43 → 0.5.44

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/index.js CHANGED
@@ -6,7 +6,7 @@ import { Context } from "@deepseek-ai/cordis";
6
6
  import z from "@deepseek-ai/schemastery";
7
7
  import { basename, delimiter, dirname, isAbsolute, join, normalize, relative, resolve, sep } from "node:path";
8
8
  import { resolveEmbedding, resolvePersistenceStrategy, resolveRecallQuality } from "dsh-mnemon-source-memory-spaces";
9
- import { CATEGORIES, DEFAULT_EMBEDDING_ENDPOINT, DEFAULT_EMBEDDING_MODEL, DEFAULT_EMBEDDING_PROTOCOL, EDGE_TYPES, MEMORY_PLACEMENT_CAPABILITIES, MEMORY_PROVIDER_REGISTRY_FILE, MEMORY_SPACES_DIRECTORY, MEMORY_SPACE_DATABASE_FILE, MEMORY_SPACE_ID_PATTERN, MEMORY_SPACE_NAME_MAX_LENGTH, MEMORY_SPACE_REGISTRY_FILE, MNEMON_ACTIVE_STORE_FILE, MNEMON_EMBEDDING_PROTOCOLS, SOURCES, parseMemorySpaceRegistry, summarizeMemoryProviderRegistry, summarizeMemorySpaceRegistry } from "dsh-mnemon-source-memory-spaces/contracts";
9
+ import { CATEGORIES, DEFAULT_EMBEDDING_ENDPOINT, DEFAULT_EMBEDDING_MODEL, DEFAULT_EMBEDDING_PROTOCOL, EDGE_TYPES, EMBEDDING_CREDENTIAL_PREFIX, MEMORY_PLACEMENT_CAPABILITIES, MEMORY_PROVIDER_REGISTRY_FILE, MEMORY_SPACES_DIRECTORY, MEMORY_SPACE_DATABASE_FILE, MEMORY_SPACE_ID_PATTERN, MEMORY_SPACE_NAME_MAX_LENGTH, MEMORY_SPACE_REGISTRY_FILE, MNEMON_ACTIVE_STORE_FILE, MNEMON_EMBEDDING_PROTOCOLS, SOURCES, parseMemorySpaceRegistry, summarizeMemoryProviderRegistry, summarizeMemorySpaceRegistry } from "dsh-mnemon-source-memory-spaces/contracts";
10
10
  import { RUNTIME_ARCHIVE_DIRECTORY, RUNTIME_DIRECTORY, RUNTIME_ENTRY_DELIMITER, RUNTIME_ENTRY_MAX_BYTES, RUNTIME_LOCK_FILE, RUNTIME_LOCK_STALE_MS, RUNTIME_MEMORIES_FILE, RUNTIME_MEMORY_LIMITS, RUNTIME_MEMORY_LIMIT_MAX_BYTES, RUNTIME_MEMORY_VERSION, RUNTIME_PROJECTION_FILES, assertRuntimePinnedBudget, parseRuntimeBranches, runtimeBytes, runtimeProjection, summarizeRuntimeMemories } from "dsh-mnemon-source-runtime/contracts";
11
11
  import { createHash, randomUUID } from "node:crypto";
12
12
  import fs, { accessSync, chmodSync, closeSync, constants, copyFileSync, existsSync, fstatSync, lstatSync, mkdirSync, openSync, readFileSync, readdirSync, realpathSync, renameSync, rmSync, statSync, writeFileSync } from "node:fs";
@@ -392,6 +392,8 @@ const DEFAULT_SKILLS_CONFIG = Object.freeze({
392
392
  targetScope: "user",
393
393
  autoBacktest: true,
394
394
  autoAdopt: false,
395
+ autoAdoptDailyLimit: 2,
396
+ autoAdoptTimeZone: "local",
395
397
  draftMaxTokens: 32768,
396
398
  draftRetryMaxTokens: 65536,
397
399
  hints: true,
@@ -487,6 +489,17 @@ const SkillsConfig = z.object({
487
489
  ]).default(DEFAULT_SKILLS_CONFIG.targetScope),
488
490
  autoBacktest: z.boolean().default(DEFAULT_SKILLS_CONFIG.autoBacktest),
489
491
  autoAdopt: z.boolean().default(DEFAULT_SKILLS_CONFIG.autoAdopt),
492
+ autoAdoptDailyLimit: z.number().step(1).min(0).max(100).default(DEFAULT_SKILLS_CONFIG.autoAdoptDailyLimit),
493
+ autoAdoptTimeZone: z.transform(z.string(), (value) => {
494
+ if (value === "local") return value;
495
+ if (!value || value.length > 100) throw new Error("skills.autoAdoptTimeZone must be an IANA time zone or local");
496
+ try {
497
+ new Intl.DateTimeFormat("en", { timeZone: value }).format(0);
498
+ } catch {
499
+ throw new Error("skills.autoAdoptTimeZone must be an IANA time zone or local");
500
+ }
501
+ return value;
502
+ }).default(DEFAULT_SKILLS_CONFIG.autoAdoptTimeZone),
490
503
  draftMaxTokens: z.number().step(1).min(128).max(131072).default(DEFAULT_SKILLS_CONFIG.draftMaxTokens),
491
504
  draftRetryMaxTokens: z.number().step(1).min(128).max(131072).default(DEFAULT_SKILLS_CONFIG.draftRetryMaxTokens),
492
505
  hints: z.boolean().default(DEFAULT_SKILLS_CONFIG.hints),
@@ -530,7 +543,9 @@ const MnemonEmbeddingSchema = z.object({
530
543
  enabled: z.boolean().default(false),
531
544
  endpoint: z.string().default(DEFAULT_EMBEDDING_ENDPOINT),
532
545
  model: z.string().default(DEFAULT_EMBEDDING_MODEL),
533
- apiKey: z.string().default(""),
546
+ apiKey: z.string().role("secret").default(""),
547
+ apiKeyEnv: z.string(),
548
+ apiKeyRef: z.string(),
534
549
  protocol: z.union(MNEMON_EMBEDDING_PROTOCOLS).default(DEFAULT_EMBEDDING_PROTOCOL)
535
550
  });
536
551
  const RecallQualitySchema = z.object({
@@ -3580,6 +3595,44 @@ var MnemonReviewLedger = class {
3580
3595
  }
3581
3596
  };
3582
3597
  //#endregion
3598
+ //#region src/host/disposable-directory.ts
3599
+ function makeWritable(path) {
3600
+ let entry;
3601
+ try {
3602
+ entry = lstatSync(path);
3603
+ } catch (error) {
3604
+ if (error.code === "ENOENT") return;
3605
+ throw error;
3606
+ }
3607
+ if (entry.isSymbolicLink()) return;
3608
+ if ((entry.mode & 128) === 0) chmodSync(path, entry.mode | 128);
3609
+ if (entry.isDirectory()) for (const name of readdirSync(path)) makeWritable(join(path, name));
3610
+ }
3611
+ /** Remove only a caller-owned disposable tree, including read-only Git packs on Windows. */
3612
+ function removeDisposableDirectory(path) {
3613
+ try {
3614
+ rmSync(path, {
3615
+ recursive: true,
3616
+ force: true
3617
+ });
3618
+ } catch (error) {
3619
+ const code = error.code;
3620
+ if (process.platform !== "win32" || ![
3621
+ "EPERM",
3622
+ "EACCES",
3623
+ "ENOTEMPTY",
3624
+ "EBUSY"
3625
+ ].includes(code ?? "")) throw error;
3626
+ makeWritable(path);
3627
+ rmSync(path, {
3628
+ recursive: true,
3629
+ force: true,
3630
+ maxRetries: 3,
3631
+ retryDelay: 100
3632
+ });
3633
+ }
3634
+ }
3635
+ //#endregion
3583
3636
  //#region src/host/github-transport.ts
3584
3637
  /**
3585
3638
  * How GitHub sign-in reaches GitHub.
@@ -4618,10 +4671,7 @@ var MnemonSyncSettingsStore = class {
4618
4671
  };
4619
4672
  }
4620
4673
  clearMirror() {
4621
- rmSync(this.mirror(), {
4622
- recursive: true,
4623
- force: true
4624
- });
4674
+ removeDisposableDirectory(this.mirror());
4625
4675
  }
4626
4676
  };
4627
4677
  //#endregion
@@ -6003,16 +6053,10 @@ var MnemonGitSync = class {
6003
6053
  cwd: mirror,
6004
6054
  signal
6005
6055
  });
6006
- if (origin.exitCode !== 0 || origin.stdout.trim() !== settings.repoUrl) rmSync(mirror, {
6007
- recursive: true,
6008
- force: true
6009
- });
6056
+ if (origin.exitCode !== 0 || origin.stdout.trim() !== settings.repoUrl) removeDisposableDirectory(mirror);
6010
6057
  }
6011
6058
  if (!existsSync(join(mirror, ".git"))) {
6012
- rmSync(mirror, {
6013
- recursive: true,
6014
- force: true
6015
- });
6059
+ removeDisposableDirectory(mirror);
6016
6060
  const initialized = await this.git([
6017
6061
  "init",
6018
6062
  "--quiet",
@@ -6139,10 +6183,7 @@ var MnemonGitSync = class {
6139
6183
  const root = this.payloadRoot(subdir);
6140
6184
  const mirror = resolve(this.store.mirror());
6141
6185
  if (root === mirror || !root.startsWith(mirror + (process.platform === "win32" ? "\\" : "/"))) throw new Error("sync directory escapes the mirror");
6142
- rmSync(root, {
6143
- recursive: true,
6144
- force: true
6145
- });
6186
+ removeDisposableDirectory(root);
6146
6187
  for (const [path, bytes] of Object.entries(entries)) {
6147
6188
  const file = resolve(root, path);
6148
6189
  mkdirSync(join(file, ".."), {
@@ -9476,7 +9517,7 @@ const WRITE_TOOL_FALLBACK_ACTION = {
9476
9517
  };
9477
9518
  function reviewReceipt(receipt) {
9478
9519
  if (!mutationResultCommitted(receipt.value)) return void 0;
9479
- const value = object$6(receipt.value);
9520
+ const value = object$7(receipt.value);
9480
9521
  const args = optionalObject(receipt.arguments);
9481
9522
  const document = optionalObject(value.document);
9482
9523
  return {
@@ -9487,7 +9528,7 @@ function reviewReceipt(receipt) {
9487
9528
  ...typeof value.revision === "string" ? { revision: value.revision } : {}
9488
9529
  };
9489
9530
  }
9490
- function object$6(value) {
9531
+ function object$7(value) {
9491
9532
  if (typeof value !== "object" || value === null || Array.isArray(value)) throw new Error("memory subagent returned an invalid structured result");
9492
9533
  return value;
9493
9534
  }
@@ -9727,7 +9768,7 @@ async function runtimeArchiveSource(runtimeSource, graph, scope, view, generatio
9727
9768
  return {
9728
9769
  source,
9729
9770
  cleanup,
9730
- memoryBodyIds: new Set(strings(object$6(grant.value).memoryBodyIds)),
9771
+ memoryBodyIds: new Set(strings(object$7(grant.value).memoryBodyIds)),
9731
9772
  writeScope: {
9732
9773
  viewId: view.id,
9733
9774
  grant
@@ -9852,13 +9893,13 @@ ${chunk.context}
9852
9893
  provider = delegated.provider;
9853
9894
  runId = delegated.runId;
9854
9895
  }
9855
- const value = object$6(delegated.result.structured);
9896
+ const value = object$7(delegated.result.structured);
9856
9897
  if (value.action !== "planned") throw new Error(typeof value.summary === "string" && value.summary !== "" ? value.summary : "runtime memory archival routing failed");
9857
9898
  if (!Array.isArray(value.routes) || value.routes.length === 0) throw new Error("runtime memory migration returned no routes");
9858
9899
  const allowedIndexes = new Set(chunk.indexes);
9859
9900
  const proposed = /* @__PURE__ */ new Map();
9860
9901
  for (const candidate of value.routes) {
9861
- const route = object$6(candidate);
9902
+ const route = object$7(candidate);
9862
9903
  const memoryBodyId = typeof route.memoryBodyId === "string" ? route.memoryBodyId.trim() : "";
9863
9904
  if (memoryBodyId === "" || !eligibleById.has(memoryBodyId)) throw new Error(`runtime memory migration selected an invalid Memory Space: ${memoryBodyId || "(empty)"}`);
9864
9905
  if (!Array.isArray(route.sourceIndexes) || route.sourceIndexes.length === 0) throw new Error("runtime memory migration route must contain source indexes");
@@ -10013,10 +10054,10 @@ ${pendingMutationContext(plan)}
10013
10054
 
10014
10055
  ${runtimeSnapshotContext("user", mutable)}`;
10015
10056
  const { provider, runId, result } = await context.model("compaction", "Consolidate local user profile", prompt, USER_COMPACTION_SCHEMA, USER_COMPACTION_PERSONA);
10016
- const value = object$6(result.structured);
10057
+ const value = object$7(result.structured);
10017
10058
  if (value.action !== "compacted") throw new Error(typeof value.summary === "string" && value.summary !== "" ? value.summary : "USER.md compaction failed");
10018
10059
  const compactedEntries = Array.isArray(value.compactedEntries) ? value.compactedEntries.map((entry) => {
10019
- const item = object$6(entry);
10060
+ const item = object$7(entry);
10020
10061
  if (typeof item.content !== "string" || ![
10021
10062
  "critical",
10022
10063
  "normal",
@@ -10194,7 +10235,7 @@ async function archiveDocumentLocked(host, parent, id, signal) {
10194
10235
  const cleanup = graph.source("memory-spaces", agentScope(parent, graph.config)).forInstance(identity.sourceInstanceKey).forGeneration(lease.generation);
10195
10236
  const grant = authority?.context.view.readGrants.find((grant) => grant.sourceInstanceKey === identity.sourceInstanceKey && grant.schema === "dsh-mnemon.memory-spaces/v1");
10196
10237
  if (authority !== void 0 && grant === void 0) throw new Error("document archive requires a Memory Space namespace grant");
10197
- const allowed = grant === void 0 ? void 0 : new Set(strings(object$6(grant.value).memoryBodyIds));
10238
+ const allowed = grant === void 0 ? void 0 : new Set(strings(object$7(grant.value).memoryBodyIds));
10198
10239
  const directory = await memoryService.read("body-directory", null, signal);
10199
10240
  const indexable = (body) => archivableSpace(directory, body);
10200
10241
  const eligible = (body) => indexable(body) && (allowed === void 0 || allowed.has(body.id));
@@ -10204,7 +10245,7 @@ async function archiveDocumentLocked(host, parent, id, signal) {
10204
10245
  throw new Error("document archive requires an existing active Memory Space with exact writes and safe forget");
10205
10246
  }
10206
10247
  const { provider, runId, result } = await host.delegate(parent, "document-archive", "Plan managed document archive", documentArchivePrompt(document, source, bodies), [], DOCUMENT_ARCHIVE_SCHEMA, signal, "spawn", DOCUMENT_ARCHIVE_PERSONA);
10207
- const value = object$6(result.structured);
10248
+ const value = object$7(result.structured);
10208
10249
  const summary = typeof value.summary === "string" ? value.summary.trim() : "";
10209
10250
  if (value.action !== "planned") throw new Error(summary || "document archive planning failed");
10210
10251
  if (summary === "" || summary.length > 1e3) throw new Error("document archive summary must contain 1–1000 characters");
@@ -10507,6 +10548,23 @@ function openAgentTurn(agent) {
10507
10548
  }
10508
10549
  return open;
10509
10550
  }
10551
+ /** PTC dispatch records belong to a real open step, not just an open turn. */
10552
+ function openAgentStep(agent) {
10553
+ let turn;
10554
+ let open;
10555
+ for (const event of agent.session.snapshotEvents()) if (event.type === "turn/start") {
10556
+ turn = typeof event.data.turn === "number" ? event.data.turn : void 0;
10557
+ open = void 0;
10558
+ } else if (event.type === "turn/end" && event.data.turn === turn) {
10559
+ turn = void 0;
10560
+ open = void 0;
10561
+ } else if (event.type === "step/start" && turn !== void 0 && event.data.turn === turn && typeof event.data.step === "number") open = {
10562
+ turn,
10563
+ step: event.data.step
10564
+ };
10565
+ else if (event.type === "step/end" && open?.turn === event.data.turn && open?.step === event.data.step) open = void 0;
10566
+ return open;
10567
+ }
10510
10568
  /**
10511
10569
  * One Agent owns each turn pin. A child additionally retains its delegation
10512
10570
  * across parent completion, collection, and runtime swaps until it is disposed.
@@ -10677,7 +10735,7 @@ async function executeHostTool(tools, input) {
10677
10735
  //#region src/host/review-admission.ts
10678
10736
  const RESULT_TOOL = "mnemon_subagent_result";
10679
10737
  const CHECK_TIMEOUT_MS = 5e3;
10680
- /** An in-turn no-op challenge through the mandatory review completion channel.
10738
+ /** An in-step no-op challenge through the mandatory review completion channel.
10681
10739
  * Inventory alone cannot see execution-time guards. No errors are classified as
10682
10740
  * permission failures, and an unavailable checkpoint is never a permanent ban.
10683
10741
  */
@@ -10703,7 +10761,7 @@ var AutomaticReviewAdmission = class {
10703
10761
  async check(agent, signal) {
10704
10762
  signal.throwIfAborted();
10705
10763
  const tools = agent.ctx.tools;
10706
- if (this.disposed || tools?.execute === void 0 || this.draining.has(agent) || openAgentTurn(agent) === void 0) return false;
10764
+ if (this.disposed || tools?.execute === void 0 || this.draining.has(agent) || openAgentStep(agent) === void 0) return false;
10707
10765
  const controller = new AbortController();
10708
10766
  this.controllers.add(controller);
10709
10767
  const combined = AbortSignal.any([signal, controller.signal]);
@@ -11116,7 +11174,7 @@ var MnemonSubagentCoordinator = class {
11116
11174
  if (!isSubagent(execution.agent)) throw new Error("Mnemon subagent result tools are restricted to delegated children");
11117
11175
  execution.signal.throwIfAborted();
11118
11176
  assertDshOutputValue(RESULT_TOOL_INPUT_SCHEMA, args);
11119
- const request = object$6(args);
11177
+ const request = object$7(args);
11120
11178
  const submit = this.resultRequests.get(String(request.requestId));
11121
11179
  if (this.disposed || submit === void 0) throw new Error("Mnemon subagent result request is unknown or no longer active");
11122
11180
  return submit(request.result, execution);
@@ -11353,7 +11411,7 @@ var MnemonSubagentCoordinator = class {
11353
11411
  ].join("\n\n");
11354
11412
  const schema = providerPlacementSchema(prepared.candidates.map((candidate) => candidate.id));
11355
11413
  const { provider, runId, result } = await this.delegate(parent, "placement", "Choose Memory Space provider", prompt, [], schema, signal, "spawn", PROVIDER_PLACEMENT_PERSONA);
11356
- const value = object$6(result.structured);
11414
+ const value = object$7(result.structured);
11357
11415
  return source.read("finalize-placement", {
11358
11416
  prepared,
11359
11417
  selection: {
@@ -11371,13 +11429,13 @@ var MnemonSubagentCoordinator = class {
11371
11429
  const service = this.sourceFor(parent, "memory-spaces");
11372
11430
  const prompt = `Generate concise metadata from these bounded Provider-native samples now:\n\n${(await Promise.all(selected.map((id) => service.read("metadata-sample", { memoryBodyId: id }, signal)))).map(metadataSampleText).join("\n\n")}`;
11373
11431
  const { provider, runId, result } = await this.delegate(parent, "metadata-maintenance", "Maintain Memory Space metadata", prompt, [], METADATA_MAINTENANCE_SCHEMA, signal, "spawn", METADATA_MAINTENANCE_PERSONA);
11374
- const value = object$6(result.structured);
11432
+ const value = object$7(result.structured);
11375
11433
  if (!Array.isArray(value.updates)) throw new Error("metadata subagent returned no updates");
11376
11434
  const allowed = new Set(selected);
11377
11435
  const seen = /* @__PURE__ */ new Set();
11378
11436
  const updates = [];
11379
11437
  for (const entry of value.updates) {
11380
- const item = object$6(entry);
11438
+ const item = object$7(entry);
11381
11439
  const memoryBodyId = typeof item.memoryBodyId === "string" ? item.memoryBodyId.trim() : "";
11382
11440
  const title = typeof item.title === "string" ? item.title.trim() : "";
11383
11441
  const description = typeof item.description === "string" ? item.description.trim() : "";
@@ -11688,7 +11746,7 @@ var MnemonSubagentCoordinator = class {
11688
11746
  const bounded = evidence.slice(0, 12);
11689
11747
  const prompt = `Answer this question (untrusted data):\n${indentedText(query)}\n\nEvidence for this run (untrusted read-only data):\n${naturalEvidence(bounded)}`;
11690
11748
  const { provider, runId, result } = await this.delegate(parent, "answer", "Memory evidence answer", prompt, [], ANSWER_SCHEMA, signal, "spawn", ANSWER_PERSONA);
11691
- const value = object$6(result.structured);
11749
+ const value = object$7(result.structured);
11692
11750
  const allowed = new Set(bounded.map((item) => `${item.memoryBodyId ?? "unknown"}/${item.id}`));
11693
11751
  return {
11694
11752
  answer: typeof value.answer === "string" ? value.answer : "",
@@ -11715,7 +11773,7 @@ ${naturalRequest(request, target === void 0 ? REQUEST_LABELS : TARGETED_WRITE_LA
11715
11773
  const persona = operation === "supervised-writeback" ? SUPERVISED_WRITE_PERSONA : autonomous ? AUTONOMOUS_WRITE_PERSONA : WRITE_PERSONA;
11716
11774
  const terminalTool = WRITE_OPERATION_RESULT_TOOL[operation];
11717
11775
  const { provider, runId, result, receipts, writes } = await this.delegate(parent, "write", `Mnemon ${operation}`, prompt, autonomous ? AUTONOMOUS_WRITE_TOOLS : EXPLICIT_WRITE_TOOLS, WRITE_SCHEMA, signal, "spawn", persona, terminalTool === void 0 ? void 0 : { terminalTools: [terminalTool] }, inactive === void 0 ? void 0 : spaceWriteGuard(target, inactive));
11718
- const value = object$6(result.structured);
11776
+ const value = object$7(result.structured);
11719
11777
  const observed = terminalTool === void 0 ? void 0 : recoverStructuredResult({ terminalTools: [terminalTool] }, receipts);
11720
11778
  const claimed = typeof observed?.action === "string" ? observed.action : typeof value.action === "string" ? value.action : "failed";
11721
11779
  if (!autonomous) return {
@@ -11824,7 +11882,7 @@ ${naturalRequest(request, target === void 0 ? REQUEST_LABELS : TARGETED_WRITE_LA
11824
11882
  const base = reviewPersona(tools.includes("mnemon_runtime_memory"));
11825
11883
  const persona = preferred === "fork" ? base : base.replaceAll("inherited", "supplied bounded");
11826
11884
  const { provider, runId, result } = await this.delegate(parent, "review", "Mnemon idle checkpoint review", prompt, tools, WRITE_SCHEMA, execution.signal, preferred, persona, { terminalTools: writers }, void 0, void 0, admission);
11827
- const value = object$6(result.structured);
11885
+ const value = object$7(result.structured);
11828
11886
  return {
11829
11887
  delegated: true,
11830
11888
  runId,
@@ -11995,7 +12053,7 @@ This is the only completion channel for this run. Do not finish with a plain-tex
11995
12053
  "failed",
11996
12054
  "partial",
11997
12055
  "unknown"
11998
- ].includes(String(object$6(structured).action))) throw new Error(`memory review reported ${object$6(structured).action}`);
12056
+ ].includes(String(object$7(structured).action))) throw new Error(`memory review reported ${object$7(structured).action}`);
11999
12057
  completed = {
12000
12058
  provider,
12001
12059
  runId: activeRun.id,
@@ -12158,7 +12216,7 @@ const MNEMON_ACTIVITY_SCHEMA = "dsh-mnemon.activity/v1";
12158
12216
  const MAX_ITEMS = 8;
12159
12217
  const MAX_TITLE = 160;
12160
12218
  const MAX_EXCERPT = 500;
12161
- function object$5(value) {
12219
+ function object$6(value) {
12162
12220
  return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
12163
12221
  }
12164
12222
  function bounded(value, maximum) {
@@ -12168,7 +12226,7 @@ function bounded(value, maximum) {
12168
12226
  return truncate(normalized, maximum);
12169
12227
  }
12170
12228
  function item(value, index) {
12171
- const entry = object$5(value);
12229
+ const entry = object$6(value);
12172
12230
  if (entry === void 0) return void 0;
12173
12231
  const content = bounded(entry.content ?? entry.text ?? entry.excerpt, MAX_EXCERPT);
12174
12232
  const explicitTitle = bounded(entry.title ?? entry.label ?? entry.name ?? entry.memoryBodyName, MAX_TITLE);
@@ -12182,7 +12240,7 @@ function item(value, index) {
12182
12240
  };
12183
12241
  }
12184
12242
  function resultItems(value) {
12185
- const root = object$5(value);
12243
+ const root = object$6(value);
12186
12244
  if (root === void 0) return [];
12187
12245
  const candidates = [
12188
12246
  root.results,
@@ -12201,8 +12259,8 @@ function resultItems(value) {
12201
12259
  return items;
12202
12260
  }
12203
12261
  function writeItem(argsValue, operationId) {
12204
- const outer = object$5(argsValue) ?? {};
12205
- const input = object$5(outer.input) ?? outer;
12262
+ const outer = object$6(argsValue) ?? {};
12263
+ const input = object$6(outer.input) ?? outer;
12206
12264
  const content = bounded(input.content ?? input.description ?? input.reason ?? input.summary ?? input.old_text ?? input.oldText, MAX_EXCERPT);
12207
12265
  const explicitTitle = bounded(input.title ?? input.name, MAX_TITLE);
12208
12266
  const identity = bounded(input.id ?? input.memoryBodyId ?? input.targetMemoryBodyId ?? input.sourceId, 300);
@@ -12214,7 +12272,7 @@ function writeItem(argsValue, operationId) {
12214
12272
  };
12215
12273
  }
12216
12274
  function reference(argsValue, key) {
12217
- return bounded(object$5(argsValue)?.[key], 600);
12275
+ return bounded(object$6(argsValue)?.[key], 600);
12218
12276
  }
12219
12277
  function memoryReadPresentation(sourceTypeId, operationId, referenceKey) {
12220
12278
  return (args, value) => ({
@@ -12233,7 +12291,7 @@ function memoryWritePresentation(sourceTypeId, operationId, referenceKey) {
12233
12291
  operationId,
12234
12292
  ...sourceTypeId === void 0 ? {} : { sourceTypeId },
12235
12293
  ...referenceKey === void 0 || reference(args, referenceKey) === void 0 ? {} : { reference: reference(args, referenceKey) },
12236
- committed: mutationResultCommitted(value) || operationId === "mutate" && object$5(value)?.success === true,
12294
+ committed: mutationResultCommitted(value) || operationId === "mutate" && object$6(value)?.success === true,
12237
12295
  item: writeItem(args, operationId)
12238
12296
  });
12239
12297
  }
@@ -12243,7 +12301,7 @@ function namedToolPresentation(name) {
12243
12301
  return tool.kind === "write" ? memoryWritePresentation(tool.sourceTypeId, tool.operation) : memoryReadPresentation(tool.sourceTypeId, tool.operation);
12244
12302
  }
12245
12303
  function validItem(value) {
12246
- const entry = object$5(value);
12304
+ const entry = object$6(value);
12247
12305
  return entry !== void 0 && bounded(entry.id, 300) === entry.id && bounded(entry.title, MAX_TITLE) === entry.title && (entry.excerpt === void 0 || bounded(entry.excerpt, MAX_EXCERPT) === entry.excerpt);
12248
12306
  }
12249
12307
  function cleanItem(value) {
@@ -12256,7 +12314,7 @@ function cleanItem(value) {
12256
12314
  }
12257
12315
  /** Fail closed on arbitrary third-party/session metadata. */
12258
12316
  function parseMnemonActivityMeta(value, callId, toolName) {
12259
- const meta = object$5(value);
12317
+ const meta = object$6(value);
12260
12318
  if (meta?.schema !== "dsh-mnemon.activity/v1" || meta.kind !== "read" && meta.kind !== "write") return {};
12261
12319
  const operationId = bounded(meta.operationId, 300);
12262
12320
  const sourceTypeId = bounded(meta.sourceTypeId, 128);
@@ -12825,6 +12883,7 @@ var MnemonAgentLifecycle = class {
12825
12883
  reviewController;
12826
12884
  reviewRunning = false;
12827
12885
  reviewAccessBlocked = false;
12886
+ reviewAdmission;
12828
12887
  lastReviewAt;
12829
12888
  lastReviewAction;
12830
12889
  lastReviewScore;
@@ -12862,6 +12921,10 @@ var MnemonAgentLifecycle = class {
12862
12921
  this.agent.ctx.on("session/event", ((session, event) => this.sessionEvent(session, event))),
12863
12922
  this.agent.ctx.on("system-prompt/assemble", ((assembly, context, next) => this.assemblePrompt(assembly, context, next))),
12864
12923
  this.agent.ctx.on("agent/pre-step", ((payload, next) => this.preStep(payload, next)), { prepend: true }),
12924
+ this.agent.ctx.on("agent/request", (async (payload, next) => {
12925
+ await this.prepareReviewAccess(payload);
12926
+ return next();
12927
+ }), { prepend: true }),
12865
12928
  this.agent.ctx.on("agent/turn-stopping", ((payload) => this.finishTurn(payload)))
12866
12929
  ];
12867
12930
  return () => {
@@ -13006,18 +13069,28 @@ var MnemonAgentLifecycle = class {
13006
13069
  activity.toolCallCount = tools.count;
13007
13070
  activity.toolNames = tools.names;
13008
13071
  if (!this.reviewActivity().eligible || !this.reviewAdmitted(payload.turn)) return;
13072
+ const admission = this.reviewAdmission;
13073
+ if (admission?.turn === payload.turn && admission.policy === this.reviewPolicy() && admission.available) this.scheduleIdleReview(payload.turn);
13074
+ }
13075
+ async prepareReviewAccess(payload) {
13076
+ this.recordComposedTurn(payload.turn);
13077
+ if (payload.signal.aborted || !this.restoreWatermark() || !this.idleReviewAllowed() || this.turnActivity.get(payload.turn)?.noMaintenance) return;
13078
+ const policy = this.reviewPolicy();
13079
+ if (this.reviewAdmission?.turn === payload.turn && this.reviewAdmission.policy === policy) return;
13009
13080
  const controller = new AbortController();
13010
13081
  const signal = AbortSignal.any([payload.signal, controller.signal]);
13011
13082
  const epoch = this.reviewEpoch;
13012
- const policy = this.reviewPolicy();
13013
13083
  this.reviewController = controller;
13014
13084
  this.reviewRunning = true;
13015
- let admitted = false;
13016
13085
  try {
13017
13086
  const available = await this.coordinator.checkReviewAccess(this.agent, signal);
13018
13087
  if (signal.aborted || epoch !== this.reviewEpoch || policy !== this.reviewPolicy() || !this.idleReviewAllowed()) return;
13019
13088
  this.reviewAccessBlocked = !available;
13020
- admitted = available;
13089
+ this.reviewAdmission = {
13090
+ turn: payload.turn,
13091
+ policy,
13092
+ available
13093
+ };
13021
13094
  } catch (error) {
13022
13095
  if (!signal.aborted) this.fail(error);
13023
13096
  } finally {
@@ -13026,7 +13099,6 @@ var MnemonAgentLifecycle = class {
13026
13099
  this.reviewController = void 0;
13027
13100
  }
13028
13101
  }
13029
- if (admitted) this.scheduleIdleReview(payload.turn);
13030
13102
  }
13031
13103
  sessionEvent(session, event) {
13032
13104
  if (session !== this.agent.session) return;
@@ -13119,6 +13191,7 @@ var MnemonAgentLifecycle = class {
13119
13191
  if (policy !== this.observedReviewPolicy) {
13120
13192
  this.cancelIdleReview(true);
13121
13193
  this.reviewAccessBlocked = false;
13194
+ this.reviewAdmission = void 0;
13122
13195
  }
13123
13196
  this.observedReviewPolicy = policy;
13124
13197
  this.restoreWatermark();
@@ -14139,9 +14212,17 @@ var SkillAutoAdoption = class {
14139
14212
  if (suggestion?.status !== "pending" || suggestion.draftId !== void 0) throw new AutomaticSkillStop("changed");
14140
14213
  job.action = suggestion.action;
14141
14214
  this.checkpoint(job);
14215
+ const settings = this.host.settings();
14216
+ const reserved = await job.source.mutate("auto-adoption-reserve", {
14217
+ id: job.id,
14218
+ limit: settings.autoAdoptDailyLimit,
14219
+ timeZone: settings.autoAdoptTimeZone
14220
+ }, job.controller.signal);
14221
+ if (!reserved.allowed) throw new AutomaticSkillStop(reserved.reason, `${reserved.used}/${reserved.limit} · ${reserved.date} · ${reserved.timeZone}`);
14142
14222
  await this.record(job, {
14143
14223
  stage: "queued",
14144
- attempt
14224
+ attempt,
14225
+ detail: `${reserved.used}/${reserved.limit} · ${reserved.date} · ${reserved.timeZone}`
14145
14226
  });
14146
14227
  const cases = (await job.source.read("cases", { skill: suggestion.skillName })).filter((entry) => entry.enabled);
14147
14228
  if (cases.length === 0) throw new AutomaticSkillStop("no-cases");
@@ -14213,6 +14294,7 @@ var SkillAutoAdoption = class {
14213
14294
  await job.source.mutate("draft-adopt", {
14214
14295
  id: draft.id,
14215
14296
  automatic: {
14297
+ reservationId: reserved.reservationId,
14216
14298
  draftHash: hashSkillDraft(draft),
14217
14299
  baselineRunId: baseline.runId,
14218
14300
  draftRunId: candidate.runId,
@@ -14244,7 +14326,7 @@ var SkillAutoAdoption = class {
14244
14326
  attempt: Math.min(attempt, 3),
14245
14327
  reason,
14246
14328
  ...scores,
14247
- ...failure instanceof AutomaticSkillStop ? {} : { detail: failure instanceof Error ? failure.message : String(failure) }
14329
+ ...failure instanceof AutomaticSkillStop && failure.message === failure.reason ? {} : { detail: failure instanceof Error ? failure.message : String(failure) }
14248
14330
  }).catch((recordError) => this.host.warn("Could not record automatic adoption outcome", recordError));
14249
14331
  } finally {
14250
14332
  for (const id of runIds) await job.source.mutate("run-cancel", { id }).catch((error) => this.host.warn("Could not stop automatic skill backtest", error));
@@ -15120,7 +15202,9 @@ function newSkillRoot(settings, source, catalog, explicit) {
15120
15202
  if (settings.targetScope === "storage" && source.scope === void 0) throw new Error("The skill destination needs a known storage scope; select User or Project in Skills settings.");
15121
15203
  root = settings.targetScope === "project" || settings.targetScope === "storage" && (source.scope?.storage === "workspace" || source.scope?.storage === "workspaces") ? "project-dsh" : "user-dsh";
15122
15204
  }
15123
- const directory = catalog.roots.find((candidate) => candidate.kind === root)?.path;
15205
+ const destination = catalog.roots.find((candidate) => candidate.kind === root);
15206
+ if (destination?.readOnly) throw new Error(`Cannot create a skill in ${root}: linked skill roots are read-only.`);
15207
+ const directory = destination?.path;
15124
15208
  if (directory === void 0 || root.startsWith("project-") && catalog.projectRoot === void 0) throw new Error("Project skill roots need a selected workspace; select a workspace or choose User in Skills settings.");
15125
15209
  if (root.startsWith("project-")) try {
15126
15210
  if (!statSync(catalog.projectRoot).isDirectory()) throw new Error("not a directory");
@@ -15456,6 +15540,7 @@ var SkillEvolution = class {
15456
15540
  ...input.draftId === void 0 ? {} : { draftId: input.draftId },
15457
15541
  ...input.skill === void 0 ? {} : { skill: input.skill }
15458
15542
  });
15543
+ if (pack.skill?.readOnly) throw new Error("Linked skills are read-only; use a local copy before generating an improvement draft.");
15459
15544
  const previousId = input.draftId ?? pack.suggestion?.draftId;
15460
15545
  const previous = previousId === void 0 ? (await source.read("drafts", {
15461
15546
  skill: pack.skillName,
@@ -15510,6 +15595,7 @@ var SkillEvolution = class {
15510
15595
  return await abortable(signal, async () => {
15511
15596
  const pack = await source.read("evidence-pack", { suggestionId: input.suggestionId }, signal);
15512
15597
  signal.throwIfAborted();
15598
+ if (pack.skill?.readOnly) throw new AutomaticSkillStop("changed");
15513
15599
  if (pack.action !== input.action || pack.action === "update" && pack.suggestion?.skillFileHash !== pack.skill?.hash) throw new AutomaticSkillStop("changed");
15514
15600
  const targetRoot = pack.action === "update" ? pack.skill.root : newSkillRoot(this.host.settings(), source, await source.read("catalog", null, signal), input.previous?.targetRoot ?? pack.suggestion?.targetRoot);
15515
15601
  const guidance = [...input.previous?.guidance ?? [], ...input.guidance === "" ? [] : [input.guidance]].slice(-8);
@@ -15923,7 +16009,7 @@ function skillsSourceFor(runtime, agent) {
15923
16009
  }
15924
16010
  //#endregion
15925
16011
  //#region src/host/rpc.ts
15926
- function object$4(value) {
16012
+ function object$5(value) {
15927
16013
  if (typeof value !== "object" || value === null || Array.isArray(value)) throw new Error("payload must be an object");
15928
16014
  return value;
15929
16015
  }
@@ -16119,7 +16205,7 @@ async function assisted(runtime, lifecycle, typeId, operation, input, signal, ta
16119
16205
  ...signal === void 0 ? {} : { signal }
16120
16206
  });
16121
16207
  return {
16122
- ...object$4(result.value),
16208
+ ...object$5(result.value),
16123
16209
  revision: result.revision
16124
16210
  };
16125
16211
  } finally {
@@ -16246,7 +16332,7 @@ async function skillAssistance(runtime, lifecycle, operation, input, signal) {
16246
16332
  case "skill-backtest": {
16247
16333
  const skillName = optionalString(input.skillName, "skillName");
16248
16334
  if (skillName === void 0) throw new Error("skillName is required");
16249
- const target = object$4(input.target);
16335
+ const target = object$5(input.target);
16250
16336
  if (![
16251
16337
  "current",
16252
16338
  "draft",
@@ -16286,7 +16372,7 @@ async function skillAssistance(runtime, lifecycle, operation, input, signal) {
16286
16372
  function createReadHandler(input, lifecycle, versions) {
16287
16373
  return async (endpoint, rawPayload, signal) => {
16288
16374
  try {
16289
- const payload = object$4(rawPayload);
16375
+ const payload = object$5(rawPayload);
16290
16376
  if (endpoint === "versions") {
16291
16377
  if (versions === void 0) throw new Error("version checks are unavailable");
16292
16378
  return success$1(await versions.check());
@@ -16307,7 +16393,7 @@ function createReadHandler(input, lifecycle, versions) {
16307
16393
  if (lifecycle === void 0 || payload.operation !== "agent-search") throw new Error("Read-only Host assistance is unavailable");
16308
16394
  const source = (await catalog(runtime, lifecycle)).sources.find((item) => item.sourceInstanceKey === payload.sourceInstanceKey);
16309
16395
  if (source === void 0 || !source.assistance.includes("agent-search")) throw new Error("Host assistance is not available for this Source instance");
16310
- const value = await assisted(runtime, lifecycle, source.sourceTypeId, "agent-search", object$4(payload.input), signal);
16396
+ const value = await assisted(runtime, lifecycle, source.sourceTypeId, "agent-search", object$5(payload.input), signal);
16311
16397
  return success$1({
16312
16398
  revision: (await catalog(runtime)).sources.find((item) => item.sourceInstanceKey === source.sourceInstanceKey)?.revision ?? source.revision,
16313
16399
  value
@@ -16419,9 +16505,9 @@ function createActivationHandler(input) {
16419
16505
  return async (endpoint, rawPayload, signal) => {
16420
16506
  try {
16421
16507
  if (endpoint === "source-assistance") {
16422
- const payload = object$4(rawPayload);
16508
+ const payload = object$5(rawPayload);
16423
16509
  if (payload.operation !== "activation" || payload.confirmed !== true) throw new Error("Unsupported activation operation");
16424
- const fields = object$4(payload.input);
16510
+ const fields = object$5(payload.input);
16425
16511
  if (Object.keys(fields).some((key) => key !== "memoryBodyId" && key !== "active") || typeof fields.active !== "boolean" || typeof fields.memoryBodyId !== "string") throw new Error("Activation accepts only a Memory Space id and boolean state");
16426
16512
  const runtime = scoped(input, payload);
16427
16513
  requireWritable(runtime);
@@ -16445,7 +16531,7 @@ function createActivationHandler(input) {
16445
16531
  }
16446
16532
  }
16447
16533
  if (endpoint !== "body") return badRequest$1("unknown activation endpoint: " + endpoint);
16448
- const payload = object$4(rawPayload);
16534
+ const payload = object$5(rawPayload);
16449
16535
  const unexpected = Object.keys(payload).filter((field) => !ACTIVATION_FIELDS.has(field));
16450
16536
  if (unexpected.length > 0) return badRequest$1("unsupported activation fields: " + unexpected.join(", "));
16451
16537
  if (typeof payload.memoryBodyId !== "string" || payload.memoryBodyId.trim() === "") return badRequest$1("memoryBodyId must be a non-empty string");
@@ -16464,7 +16550,7 @@ function createActivationHandler(input) {
16464
16550
  function createWriteHandler(input, lifecycle, versions) {
16465
16551
  return async (endpoint, rawPayload, signal) => {
16466
16552
  try {
16467
- const payload = object$4(rawPayload);
16553
+ const payload = object$5(rawPayload);
16468
16554
  if (endpoint === "version-update") {
16469
16555
  if (versions === void 0) throw new Error("version updates are unavailable");
16470
16556
  if (!input.config.writeEnabled) throw new Error("dsh-mnemon is configured read-only (writeEnabled: false)");
@@ -16500,12 +16586,12 @@ function createWriteHandler(input, lifecycle, versions) {
16500
16586
  if (source === void 0 || !source.assistance.includes(operation)) throw new Error("Host assistance is not available for this Source instance");
16501
16587
  requireLayerOn(runtime, source.sourceTypeId);
16502
16588
  if (operation !== "agent-search" && (payload.confirmed !== true || payload.expectedRevision !== source.revision)) throw new Error("Host assistance requires confirmation of the current Source revision");
16503
- const value = await assisted(runtime, lifecycle, source.sourceTypeId, operation, object$4(payload.input), signal, {
16589
+ const value = await assisted(runtime, lifecycle, source.sourceTypeId, operation, object$5(payload.input), signal, {
16504
16590
  sourceInstanceKey: source.sourceInstanceKey,
16505
16591
  expectedRevision: source.revision
16506
16592
  });
16507
16593
  if (source.sourceTypeId === "runtime") return success$1({
16508
- revision: object$4(value).revision,
16594
+ revision: object$5(value).revision,
16509
16595
  value
16510
16596
  });
16511
16597
  return success$1({
@@ -16549,7 +16635,7 @@ function createWriteHandler(input, lifecycle, versions) {
16549
16635
  function createPackHandler(input, nativeDirectoryPicker = () => false) {
16550
16636
  return async (endpoint, rawPayload) => {
16551
16637
  try {
16552
- const payload = object$4(rawPayload);
16638
+ const payload = object$5(rawPayload);
16553
16639
  const runtime = scoped(input, payload);
16554
16640
  const manager = runtime.graph.packs;
16555
16641
  if (endpoint === "target") return success$1({
@@ -16586,7 +16672,7 @@ function githubAuth(input) {
16586
16672
  function createSyncHandler(input, onConfigured) {
16587
16673
  return async (endpoint, rawPayload, signal) => {
16588
16674
  try {
16589
- const payload = object$4(rawPayload);
16675
+ const payload = object$5(rawPayload);
16590
16676
  const runtime = scoped(input, payload);
16591
16677
  const sync = runtime.graph.sync;
16592
16678
  if (endpoint === "status") return success$1(await sync.status(signal));
@@ -16659,7 +16745,7 @@ function createSyncHandler(input, onConfigured) {
16659
16745
  function createReviewHandler(input, lifecycle) {
16660
16746
  return async (endpoint, rawPayload, signal) => {
16661
16747
  try {
16662
- const payload = object$4(rawPayload);
16748
+ const payload = object$5(rawPayload);
16663
16749
  const ledger = input.reviews;
16664
16750
  if (endpoint === "view") return success$1(ledger.view());
16665
16751
  if (endpoint === "opinion") {
@@ -16746,6 +16832,106 @@ function hasNativeDirectoryPicker(ctx) {
16746
16832
  }
16747
16833
  }
16748
16834
  //#endregion
16835
+ //#region src/host/embedding-settings.ts
16836
+ const object$4 = (value) => typeof value === "object" && value !== null && !Array.isArray(value) ? value : {};
16837
+ /** Preserve other Host redaction while never returning a legacy inline key. */
16838
+ function publicEmbeddingSettings(value, original, metadata = false) {
16839
+ const config = object$4(value);
16840
+ if (!metadata && config.embedding === void 0) return value;
16841
+ const embedding = object$4(config.embedding);
16842
+ const raw = object$4(object$4(original).embedding);
16843
+ const apiKeyStorage = raw.apiKeyEnv ? "environment" : raw.apiKeyRef ? "credentials" : raw.apiKey ? "legacy" : "none";
16844
+ return {
16845
+ ...config,
16846
+ embedding: {
16847
+ ...embedding,
16848
+ ..."apiKey" in embedding ? { apiKey: "" } : {},
16849
+ ...metadata ? {
16850
+ apiKeyStorage,
16851
+ apiKeyConfigured: apiKeyStorage !== "none"
16852
+ } : {}
16853
+ }
16854
+ };
16855
+ }
16856
+ /** Write/verify a new record before referencing it; failures keep the old configuration and key intact. */
16857
+ async function prepareEmbeddingSettings(settings, namespace, operations, revision, store) {
16858
+ const last = operations.findLastIndex((operation) => operation.path.length === 1 && operation.path[0] === "embedding");
16859
+ if (namespace !== "mnemon" || last === -1) return {
16860
+ operations,
16861
+ revision
16862
+ };
16863
+ const operation = operations[last];
16864
+ const edits = operations.filter((entry, index) => index === last || entry.path[0] !== "embedding");
16865
+ if (operation.op === "unset") return {
16866
+ operations: edits,
16867
+ revision
16868
+ };
16869
+ const view = settings.describe({ redactSecrets: false }).find((candidate) => candidate.ns === namespace);
16870
+ if (view === void 0) throw new Error("Mnemon settings are unavailable");
16871
+ if (revision !== void 0 && revision !== view.revision) throw new Error("Settings changed; reload before saving the embedding connection");
16872
+ const previous = resolveEmbedding(object$4(object$4(view.value).embedding));
16873
+ const input = object$4(operation.value);
16874
+ if (typeof operation.value !== "object" || operation.value === null || Array.isArray(operation.value)) throw new Error("Embedding settings must be an object");
16875
+ if (input.apiKey !== void 0 && typeof input.apiKey !== "string") throw new Error("Embedding API key must be text");
16876
+ if (input.clearApiKey !== void 0 && typeof input.clearApiKey !== "boolean") throw new Error("clearApiKey must be boolean");
16877
+ const { apiKeyStorage: _storage, apiKeyConfigured: _configured, clearApiKey: _clear, ...next } = input;
16878
+ let resolved = resolveEmbedding(next);
16879
+ let rollback;
16880
+ if (input.clearApiKey === true) {
16881
+ next.apiKey = "";
16882
+ next.apiKeyRef = "";
16883
+ next.apiKeyEnv = "";
16884
+ } else if (resolved.apiKeyEnv) {
16885
+ if (resolved.apiKey) throw new Error("Choose an embedding API key or an environment variable, not both");
16886
+ next.apiKey = "";
16887
+ next.apiKeyRef = "";
16888
+ } else {
16889
+ if (resolved.apiKeyRef && resolved.apiKeyRef !== previous.apiKeyRef) throw new Error("Save a key to create an embedding credential reference");
16890
+ const sameEndpoint = resolved.endpoint === previous.endpoint;
16891
+ if (!resolved.apiKey && !sameEndpoint && (previous.apiKeyRef || previous.apiKey)) throw new Error("Changing the embedding endpoint requires a new key, an environment variable, or explicitly removing the saved key");
16892
+ const key = resolved.apiKey || (sameEndpoint ? previous.apiKey : "");
16893
+ if (key) {
16894
+ const credentials = store?.();
16895
+ if (credentials === void 0) throw new Error("DSH credentials storage is unavailable; configure apiKeyEnv instead. The existing connection was not changed");
16896
+ const reference = EMBEDDING_CREDENTIAL_PREFIX + randomUUID();
16897
+ const payload = {
16898
+ version: 1,
16899
+ endpoint: resolved.endpoint,
16900
+ apiKey: key
16901
+ };
16902
+ rollback = async () => {
16903
+ await credentials.deleteRecord(reference);
16904
+ };
16905
+ try {
16906
+ await credentials.modifyRecord(reference, async () => ({
16907
+ kind: "grant",
16908
+ payload
16909
+ }));
16910
+ const record = await credentials.readRecord(reference);
16911
+ if (record?.kind !== "grant" || record.payload?.version !== 1 || record.payload.endpoint !== payload.endpoint || record.payload.apiKey !== key) throw new Error("Credential readback failed");
16912
+ } catch {
16913
+ await rollback().catch(() => {});
16914
+ throw new Error("Could not save and verify the embedding credential; the existing connection was not changed");
16915
+ }
16916
+ next.apiKey = "";
16917
+ next.apiKeyRef = reference;
16918
+ } else if (sameEndpoint && previous.apiKeyRef) {
16919
+ next.apiKey = "";
16920
+ next.apiKeyRef = previous.apiKeyRef;
16921
+ }
16922
+ }
16923
+ resolved = resolveEmbedding(next);
16924
+ if (resolved.apiKey) throw new Error("Embedding settings must not persist a plaintext key");
16925
+ return {
16926
+ operations: edits.map((entry) => entry === operation ? {
16927
+ ...entry,
16928
+ value: next
16929
+ } : entry),
16930
+ revision: revision ?? view.revision,
16931
+ ...rollback === void 0 ? {} : { rollback }
16932
+ };
16933
+ }
16934
+ //#endregion
16749
16935
  //#region src/host/settings.ts
16750
16936
  function success(value) {
16751
16937
  return {
@@ -16776,14 +16962,16 @@ function badRequest(message) {
16776
16962
  function descriptor(settings, namespace) {
16777
16963
  const view = settings.describe({ redactSecrets: true }).find((candidate) => candidate.ns === namespace);
16778
16964
  if (view === void 0) throw new Error(`${namespace} settings namespace is unavailable`);
16965
+ const raw = namespace === "mnemon" ? settings.describe({ redactSecrets: false }).find((candidate) => candidate.ns === namespace) : void 0;
16966
+ const visible = namespace === "mnemon" ? publicEmbeddingSettings(view.value, raw?.value, true) : view.value;
16779
16967
  return {
16780
16968
  status: "ready",
16781
16969
  value: namespace === "mnemon" && displayModeOf(view.value) === "buildin" ? {
16782
- ...object$3(view.value),
16970
+ ...object$3(visible),
16783
16971
  displayMode: "builtin"
16784
- } : view.value,
16785
- base: view.base,
16786
- user: view.user,
16972
+ } : visible,
16973
+ base: namespace === "mnemon" ? publicEmbeddingSettings(view.base, raw?.base) : view.base,
16974
+ user: namespace === "mnemon" ? publicEmbeddingSettings(view.user, raw?.user) : view.user,
16787
16975
  revision: view.revision,
16788
16976
  writable: settings.writable,
16789
16977
  mode: "host",
@@ -16860,7 +17048,7 @@ function mutablePath(namespace, path) {
16860
17048
  if (path.length === 4 && path[0] === "memoryTopology" && path[1] === "layers" && path[3] === "enabled") return MEMORY_LAYER_ID.test(path[2]);
16861
17049
  return INTERACTION_PATHS.some((allowed) => allowed.length === path.length && allowed.every((segment, index) => segment === path[index]));
16862
17050
  }
16863
- function createSettingsHandler(settings) {
17051
+ function createSettingsHandler(settings, credentials) {
16864
17052
  return async (endpoint, rawPayload) => {
16865
17053
  let namespace = MNEMON_SETTINGS_NAMESPACE;
16866
17054
  try {
@@ -16887,7 +17075,13 @@ function createSettingsHandler(settings) {
16887
17075
  };
16888
17076
  });
16889
17077
  const revision = payload.expectedRevision === void 0 ? void 0 : Number(payload.expectedRevision);
16890
- await settings.mutate(namespace, ops, revision);
17078
+ const prepared = await prepareEmbeddingSettings(settings, namespace, ops, revision, credentials);
17079
+ try {
17080
+ await settings.mutate(namespace, prepared.operations, prepared.revision);
17081
+ } catch (error) {
17082
+ await prepared.rollback?.().catch(() => {});
17083
+ throw error;
17084
+ }
16891
17085
  if (namespace === "mnemon") await migrateLegacyDisplayMode(settings);
16892
17086
  return success(descriptor(settings, namespace));
16893
17087
  } catch (error) {
@@ -16895,8 +17089,8 @@ function createSettingsHandler(settings) {
16895
17089
  }
16896
17090
  };
16897
17091
  }
16898
- function registerSettingsRpc(connection, settings) {
16899
- const handler = createSettingsHandler(settings);
17092
+ function registerSettingsRpc(connection, settings, credentials) {
17093
+ const handler = createSettingsHandler(settings, credentials);
16900
17094
  connection.rpc.handle(MNEMON_SETTINGS_CHANNEL, handler);
16901
17095
  return handler;
16902
17096
  }
@@ -19981,7 +20175,7 @@ function apply(rawContext, rawConfig = {}) {
19981
20175
  pluginCommand: () => dshPluginCommand(ctx.get("profileContext"))
19982
20176
  });
19983
20177
  const rpc = registerRpc(connection, runtime, lifecycle, versions, () => autoBackup.refresh(), () => hasNativeDirectoryPicker(ctx));
19984
- const settings = registerSettingsRpc(connection, hostSettings);
20178
+ const settings = registerSettingsRpc(connection, hostSettings, () => ctx.get("credentials") ?? ctx.credentials);
19985
20179
  const view = registerViewRpc(connection, runtime, extensions, memoryPlugins, lifecycle, pluginInstallation);
19986
20180
  if (Context.is(webContext)) new MnemonRemoteService(webContext, {
19987
20181
  ...rpc,