dsh-mnemon 0.2.9 → 0.2.10

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 CHANGED
@@ -3,7 +3,7 @@
3
3
  <p align="center"><strong>English</strong> · <a href="./README.zh-CN.md">简体中文</a></p>
4
4
 
5
5
  <p align="center">
6
- <img src="https://img.shields.io/badge/release-v0.2.9-5b5bd6" alt="release v0.2.9">
6
+ <img src="https://img.shields.io/badge/release-v0.2.10-5b5bd6" alt="release v0.2.10">
7
7
  <img src="https://img.shields.io/badge/memory-3%20tiers-087c5b" alt="three memory tiers">
8
8
  <img src="https://img.shields.io/badge/providers-9-c66a09" alt="nine providers">
9
9
  <img src="https://img.shields.io/badge/Node.js-%E2%89%A520-43853d" alt="Node.js 20 or newer">
@@ -22,7 +22,7 @@
22
22
  <p align="center">
23
23
  <a href="./docs/en/capabilities.md"><strong>Explore the capability map</strong></a> ·
24
24
  <a href="./docs/en/getting-started.md">Start in five minutes</a> ·
25
- <a href="./docs/en/releases/v0.2.9.md">Read the v0.2.9 notes</a> ·
25
+ <a href="./docs/en/releases/v0.2.10.md">Read the v0.2.10 notes</a> ·
26
26
  <a href="https://github.com/omdsh-dev/dsh-mnemon/blob/e6ca446e45bdd17991f3c7c98560456de465282b/docs/assets/media/dsh-mnemon-memory-system-demo.mp4">Watch the widescreen demo</a>
27
27
  </p>
28
28
 
@@ -190,7 +190,7 @@ See [Operations, security, and troubleshooting](./docs/en/operations.md) for bac
190
190
  | Configure scope, routing, and model selection | [Configuration](./docs/en/configuration.md) |
191
191
  | Back up, update, or troubleshoot | [Operations](./docs/en/operations.md) |
192
192
  | Integrate tools, commands, or RPC | [Interface reference](./docs/en/interfaces.md) |
193
- | Review the release | [v0.2.9 release notes](./docs/en/releases/v0.2.9.md) |
193
+ | Review the release | [v0.2.10 release notes](./docs/en/releases/v0.2.10.md) |
194
194
 
195
195
  See the [documentation hub](./docs/en/README.md) for the full map.
196
196
 
@@ -203,6 +203,8 @@ pnpm run verify
203
203
 
204
204
  `verify` runs TypeScript checks, Vitest, a reproducible double build, an isolated real Headless-profile activation check, and published-package validation. `lib/` is generated and intentionally not tracked.
205
205
 
206
+ Before opening an Issue or Pull Request, read the [contribution rules](./CONTRIBUTING.md) ([简体中文](./CONTRIBUTING.zh-CN.md)) and use the bilingual repository templates. Incomplete reports and PR descriptions are rejected by bilingual automated policy checks.
207
+
206
208
  ## License
207
209
 
208
210
  MIT. Report security issues privately through [SECURITY.md](./SECURITY.md), not a public issue.
package/README.zh-CN.md CHANGED
@@ -3,7 +3,7 @@
3
3
  <p align="center"><a href="./README.md">English</a> · <strong>简体中文</strong></p>
4
4
 
5
5
  <p align="center">
6
- <img src="https://img.shields.io/badge/release-v0.2.9-5b5bd6" alt="发布版本 v0.2.9">
6
+ <img src="https://img.shields.io/badge/release-v0.2.10-5b5bd6" alt="发布版本 v0.2.10">
7
7
  <img src="https://img.shields.io/badge/%E8%AE%B0%E5%BF%86-3%20%E5%B1%82-087c5b" alt="三层记忆">
8
8
  <img src="https://img.shields.io/badge/Provider-9-c66a09" alt="九种 Provider">
9
9
  <img src="https://img.shields.io/badge/Node.js-%E2%89%A520-43853d" alt="Node.js 20 或更新版本">
@@ -22,7 +22,7 @@
22
22
  <p align="center">
23
23
  <a href="./docs/zh-CN/capabilities.md"><strong>先看能力地图</strong></a> ·
24
24
  <a href="./docs/zh-CN/getting-started.md">5 分钟开始</a> ·
25
- <a href="./docs/zh-CN/releases/v0.2.9.md">v0.2.9 升级说明</a> ·
25
+ <a href="./docs/zh-CN/releases/v0.2.10.md">v0.2.10 升级说明</a> ·
26
26
  <a href="https://github.com/omdsh-dev/dsh-mnemon/blob/e6ca446e45bdd17991f3c7c98560456de465282b/docs/assets/media/dsh-mnemon-memory-system-demo.mp4">观看宽屏实机演示</a>
27
27
  </p>
28
28
 
@@ -190,7 +190,7 @@ dsh plugin --profile headless add "link:/absolute/path/to/dsh-mnemon"
190
190
  | 配置范围、路由与模型 | [配置参考](./docs/zh-CN/configuration.md) |
191
191
  | 备份、更新或排障 | [运维指南](./docs/zh-CN/operations.md) |
192
192
  | 接入工具、命令或 RPC | [接口参考](./docs/zh-CN/interfaces.md) |
193
- | 查看本次升级 | [v0.2.9 发布说明](./docs/zh-CN/releases/v0.2.9.md) |
193
+ | 查看本次升级 | [v0.2.10 发布说明](./docs/zh-CN/releases/v0.2.10.md) |
194
194
 
195
195
  完整目录见[文档中心](./docs/zh-CN/README.md)。
196
196
 
@@ -203,6 +203,8 @@ pnpm run verify
203
203
 
204
204
  `verify` 会执行 TypeScript 检查、Vitest、可复现双构建、隔离的真实 Headless profile 激活检查与发布包验证。`lib/` 是生成产物,故意不进入版本库。
205
205
 
206
+ 提交 Issue 或 Pull Request 前请阅读[贡献规范](./CONTRIBUTING.zh-CN.md)([English](./CONTRIBUTING.md))并使用双语仓库模板;缺少必填信息的报告和 PR 描述会被双语自动化规则拒绝。
207
+
206
208
  ## 许可证
207
209
 
208
210
  MIT。安全问题请通过 [SECURITY.md](./SECURITY.md) 私下报告,不要公开提交 issue。
package/lib/client.js CHANGED
@@ -10640,7 +10640,7 @@ window.__ModuleLoader__.load({
10640
10640
  loadStatus();
10641
10641
  };
10642
10642
  const activationEnabled = status?.writeEnabled === true;
10643
- const writeEnabled = activationEnabled && connection.isLoopback !== false;
10643
+ const writeEnabled = activationEnabled && settingsSnapshot.status === "ready" && settingsSnapshot.writable;
10644
10644
  const stats = status?.stats;
10645
10645
  const catalogKnown = status?.memoryBodies !== void 0;
10646
10646
  const memoryBodies = (0, react.useMemo)(() => (status?.memoryBodies ?? []).map(normalizeMemoryBody), [status]);
@@ -11044,7 +11044,9 @@ window.__ModuleLoader__.load({
11044
11044
  //#region src/client/MnemonSaveAction.tsx
11045
11045
  const PREVIEW_LIMIT = 8e3;
11046
11046
  /** Save-to-memory action on finalized assistant messages, routed through the supervised writeback gate. */
11047
- const MnemonSaveAction = (0, react.memo)(function MnemonSaveAction({ messageId, sessionId, connection, t }) {
11047
+ const MnemonSaveAction = (0, react.memo)(function MnemonSaveAction({ messageId, sessionId, connection, settingsScope, t }) {
11048
+ const settingsSnapshot = (0, react.useSyncExternalStore)(settingsScope.subscribe, settingsScope.getSnapshot, settingsScope.getSnapshot);
11049
+ const managementWritable = settingsSnapshot.status === "ready" && settingsSnapshot.writable;
11048
11050
  const [open, setOpen] = (0, react.useState)(false);
11049
11051
  const [writeEnabled, setWriteEnabled] = (0, react.useState)(void 0);
11050
11052
  const [candidate, setCandidate] = (0, react.useState)(void 0);
@@ -11078,7 +11080,7 @@ window.__ModuleLoader__.load({
11078
11080
  setSubmitting(submitActiveRef.current);
11079
11081
  const client = new MnemonClient(connection, sessionId);
11080
11082
  client.status().then((status) => {
11081
- if (alive && requestVersionRef.current === requestVersion) setWriteEnabled(status.writeEnabled && connection.isLoopback !== false);
11083
+ if (alive && requestVersionRef.current === requestVersion) setWriteEnabled(status.writeEnabled && managementWritable);
11082
11084
  }).catch(() => {
11083
11085
  if (alive && requestVersionRef.current === requestVersion) setWriteEnabled(false);
11084
11086
  });
@@ -11099,7 +11101,8 @@ window.__ModuleLoader__.load({
11099
11101
  open,
11100
11102
  connection,
11101
11103
  sessionId,
11102
- messageId
11104
+ messageId,
11105
+ managementWritable
11103
11106
  ]);
11104
11107
  const submit = () => {
11105
11108
  const content = textareaRef.current?.value.trim() ?? "";
@@ -11658,7 +11661,7 @@ window.__ModuleLoader__.load({
11658
11661
  saveAction: {
11659
11662
  slot: "conversation.chat.assistant-actions",
11660
11663
  enabled: (value) => enabledOf(value, "saveAction"),
11661
- register(ctx, namespace, translate) {
11664
+ register(ctx, namespace, translate, settings) {
11662
11665
  return ctx.slots.register({
11663
11666
  name: "conversation.chat.assistant-actions",
11664
11667
  id: "mnemon-save",
@@ -11667,6 +11670,7 @@ window.__ModuleLoader__.load({
11667
11670
  inject: (sessionId) => ({
11668
11671
  ...typeof sessionId === "string" && sessionId !== "" ? { sessionId } : {},
11669
11672
  connection: ctx.connection,
11673
+ settingsScope: settings,
11670
11674
  t: translate
11671
11675
  })
11672
11676
  }, MnemonSaveAction);
@@ -11774,7 +11778,7 @@ window.__ModuleLoader__.load({
11774
11778
  for (const key of Object.keys(INTERACTION_UNITS)) {
11775
11779
  const unit = INTERACTION_UNITS[key];
11776
11780
  const enabled = unit.enabled(value);
11777
- if (enabled && !active.has(key)) active.set(key, ctx.slots.inject(unit.slot, () => unit.register(ctx, namespace, translate)));
11781
+ if (enabled && !active.has(key)) active.set(key, ctx.slots.inject(unit.slot, () => unit.register(ctx, namespace, translate, settings)));
11778
11782
  else if (!enabled && active.has(key)) {
11779
11783
  active.get(key)();
11780
11784
  active.delete(key);
package/lib/index.js CHANGED
@@ -7216,6 +7216,37 @@ const RESULT_TOOL_OUTPUT_SCHEMA = {
7216
7216
  required: ["recorded"],
7217
7217
  additionalProperties: false
7218
7218
  };
7219
+ const WRITE_ACTIONS = [
7220
+ "stored",
7221
+ "updated",
7222
+ "added",
7223
+ "replaced",
7224
+ "removed",
7225
+ "skipped",
7226
+ "forgotten",
7227
+ "linked",
7228
+ "created",
7229
+ "merged",
7230
+ "failed"
7231
+ ];
7232
+ const WRITE_ACTION_SET = new Set(WRITE_ACTIONS);
7233
+ const WRITE_OPERATION_RESULT_TOOL = {
7234
+ remember: "mnemon_remember",
7235
+ "supervised-writeback": "mnemon_remember",
7236
+ link: "mnemon_link",
7237
+ forget: "mnemon_forget",
7238
+ "create-memory-body": "mnemon_memory_body_create",
7239
+ "update-memory-body": "mnemon_memory_body_update",
7240
+ "merge-memory-bodies": "mnemon_memory_body_merge"
7241
+ };
7242
+ const WRITE_TOOL_FALLBACK_ACTION = {
7243
+ mnemon_remember: "stored",
7244
+ mnemon_link: "linked",
7245
+ mnemon_forget: "forgotten",
7246
+ mnemon_memory_body_create: "created",
7247
+ mnemon_memory_body_update: "updated",
7248
+ mnemon_memory_body_merge: "merged"
7249
+ };
7219
7250
  const RECALL_SCHEMA = {
7220
7251
  type: "object",
7221
7252
  properties: {
@@ -7279,19 +7310,7 @@ const WRITE_SCHEMA = {
7279
7310
  summary: { type: "string" },
7280
7311
  action: {
7281
7312
  type: "string",
7282
- enum: [
7283
- "stored",
7284
- "updated",
7285
- "added",
7286
- "replaced",
7287
- "removed",
7288
- "skipped",
7289
- "forgotten",
7290
- "linked",
7291
- "created",
7292
- "merged",
7293
- "failed"
7294
- ]
7313
+ enum: [...WRITE_ACTIONS]
7295
7314
  },
7296
7315
  memoryBodyIds: {
7297
7316
  type: "array",
@@ -7707,6 +7726,84 @@ function insight(value) {
7707
7726
  if (Array.isArray(item.entities)) result.entities = strings(item.entities);
7708
7727
  return result;
7709
7728
  }
7729
+ function optionalObject(value) {
7730
+ return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
7731
+ }
7732
+ function addString(target, value) {
7733
+ if (typeof value === "string" && value.trim() !== "") target.add(value);
7734
+ }
7735
+ function addStrings(target, value) {
7736
+ if (Array.isArray(value)) for (const entry of value) addString(target, entry);
7737
+ }
7738
+ function receiptMemoryBodyIds(receipt) {
7739
+ const ids = /* @__PURE__ */ new Set();
7740
+ const args = optionalObject(receipt.arguments);
7741
+ const value = optionalObject(receipt.value);
7742
+ for (const record of [args, value]) {
7743
+ addString(ids, record?.memoryBodyId);
7744
+ addString(ids, record?.targetMemoryBodyId);
7745
+ addStrings(ids, record?.memoryBodyIds);
7746
+ addStrings(ids, record?.sourceMemoryBodyIds);
7747
+ }
7748
+ if (receipt.name === "mnemon_memory_body_create" || receipt.name === "mnemon_memory_body_update") addString(ids, value?.id);
7749
+ return [...ids];
7750
+ }
7751
+ function recoverRecallResult(receipts) {
7752
+ if (receipts.length === 0) return void 0;
7753
+ const results = [];
7754
+ const seen = /* @__PURE__ */ new Set();
7755
+ const selectedMemoryBodyIds = /* @__PURE__ */ new Set();
7756
+ let summary = "";
7757
+ for (const receipt of receipts) {
7758
+ for (const id of receiptMemoryBodyIds(receipt)) selectedMemoryBodyIds.add(id);
7759
+ const value = optionalObject(receipt.value);
7760
+ if (typeof value?.hint === "string" && value.hint.trim() !== "") summary = value.hint;
7761
+ else if (typeof value?.summary === "string" && value.summary.trim() !== "") summary = value.summary;
7762
+ if (Array.isArray(value?.sources)) for (const source of value.sources) addString(selectedMemoryBodyIds, optionalObject(source)?.memoryBodyId);
7763
+ if (!Array.isArray(value?.results)) continue;
7764
+ for (const candidate of value.results) {
7765
+ if (results.length >= 12) break;
7766
+ const entry = insight(candidate);
7767
+ if (entry === void 0 || typeof entry.memoryBodyId !== "string" || typeof entry.memoryBodyName !== "string") continue;
7768
+ const key = `${entry.memoryBodyId}\u0000${entry.id}`;
7769
+ if (seen.has(key)) continue;
7770
+ seen.add(key);
7771
+ selectedMemoryBodyIds.add(entry.memoryBodyId);
7772
+ results.push(entry);
7773
+ }
7774
+ }
7775
+ return {
7776
+ summary,
7777
+ selectedMemoryBodyIds: [...selectedMemoryBodyIds],
7778
+ results
7779
+ };
7780
+ }
7781
+ function recoverWriteResult(receipts) {
7782
+ const receipt = receipts.at(-1);
7783
+ if (receipt === void 0) return void 0;
7784
+ const value = optionalObject(receipt.value);
7785
+ const action = (typeof value?.action === "string" && WRITE_ACTION_SET.has(value.action) ? value.action : void 0) ?? WRITE_TOOL_FALLBACK_ACTION[receipt.name];
7786
+ if (action === void 0) return void 0;
7787
+ const memoryBodyIds = /* @__PURE__ */ new Set();
7788
+ const documentIds = /* @__PURE__ */ new Set();
7789
+ for (const entry of receipts) {
7790
+ for (const id of receiptMemoryBodyIds(entry)) memoryBodyIds.add(id);
7791
+ addStrings(documentIds, optionalObject(entry.value)?.documentIds);
7792
+ }
7793
+ return {
7794
+ summary: typeof value?.summary === "string" ? value.summary : typeof value?.message === "string" ? value.message : "",
7795
+ action,
7796
+ memoryBodyIds: [...memoryBodyIds],
7797
+ ...documentIds.size === 0 ? {} : { documentIds: [...documentIds] }
7798
+ };
7799
+ }
7800
+ /** Recover only the bounded public result implied by a committed terminal tool receipt. */
7801
+ function recoverStructuredResult(recovery, receipts) {
7802
+ if (recovery === void 0) return void 0;
7803
+ const terminalTools = new Set(recovery.terminalTools);
7804
+ const matching = receipts.filter((receipt) => terminalTools.has(receipt.name));
7805
+ return recovery.kind === "recall" ? recoverRecallResult(matching) : recoverWriteResult(matching);
7806
+ }
7710
7807
  function isSubagent(agent) {
7711
7808
  return agent?.session.header?.origin === "subagent";
7712
7809
  }
@@ -7753,7 +7850,10 @@ var MnemonSubagentCoordinator = class {
7753
7850
  }
7754
7851
  async recall(parent, request, signal) {
7755
7852
  const prompt = `Recall this request now:\n${naturalSearchRequest(request)}`;
7756
- const { provider, runId, result } = await this.delegate(parent, "recall", "Mnemon recall", prompt, READ_TOOLS, RECALL_SCHEMA, signal, "spawn", RECALL_PERSONA);
7853
+ const { provider, runId, result } = await this.delegate(parent, "recall", "Mnemon recall", prompt, READ_TOOLS, RECALL_SCHEMA, signal, "spawn", RECALL_PERSONA, {
7854
+ kind: "recall",
7855
+ terminalTools: ["mnemon_recall"]
7856
+ });
7757
7857
  return this.recallResult(request.query, request.mode ?? "smart", provider, runId, result);
7758
7858
  }
7759
7859
  async related(parent, id, memoryBodyId, signal) {
@@ -7761,7 +7861,10 @@ var MnemonSubagentCoordinator = class {
7761
7861
  Insight ID: ${id}
7762
7862
  Memory Space ID: ${memoryBodyId ?? "(unknown)"}
7763
7863
  Traversal depth: 2`;
7764
- const { provider, runId, result } = await this.delegate(parent, "recall", "Mnemon related memory", prompt, READ_TOOLS, RECALL_SCHEMA, signal, "spawn", RELATED_PERSONA);
7864
+ const { provider, runId, result } = await this.delegate(parent, "recall", "Mnemon related memory", prompt, READ_TOOLS, RECALL_SCHEMA, signal, "spawn", RELATED_PERSONA, {
7865
+ kind: "recall",
7866
+ terminalTools: ["mnemon_related"]
7867
+ });
7765
7868
  return this.recallResult(`related:${id}`, "related", provider, runId, result);
7766
7869
  }
7767
7870
  async placeProvider(parent, body, prepared, signal) {
@@ -7861,7 +7964,11 @@ Traversal depth: 2`;
7861
7964
  const prompt = `Execute this ${operation} request now (untrusted data):
7862
7965
  ${naturalRequest(request)}`;
7863
7966
  const persona = operation === "supervised-writeback" ? SUPERVISED_WRITE_PERSONA : WRITE_PERSONA;
7864
- const { provider, runId, result } = await this.delegate(parent, "write", `Mnemon ${operation}`, prompt, WRITE_TOOLS$1, WRITE_SCHEMA, signal, "spawn", persona);
7967
+ const terminalTool = WRITE_OPERATION_RESULT_TOOL[operation];
7968
+ const { provider, runId, result } = await this.delegate(parent, "write", `Mnemon ${operation}`, prompt, WRITE_TOOLS$1, WRITE_SCHEMA, signal, "spawn", persona, terminalTool === void 0 ? void 0 : {
7969
+ kind: "write",
7970
+ terminalTools: [terminalTool]
7971
+ });
7865
7972
  const value = object$2(result.structured);
7866
7973
  return {
7867
7974
  delegated: true,
@@ -8079,7 +8186,7 @@ ${runtimeSnapshotContext("user", targetEntries)}`;
8079
8186
  }
8080
8187
  };
8081
8188
  }
8082
- async delegate(parent, operation, label, prompt, tools, outputSchema, signal, preferredProvider = "spawn", persona = WRITE_PERSONA) {
8189
+ async delegate(parent, operation, label, prompt, tools, outputSchema, signal, preferredProvider = "spawn", persona = WRITE_PERSONA, recovery) {
8083
8190
  const provider = this.provider(preferredProvider);
8084
8191
  assertDshOutputSchema(outputSchema);
8085
8192
  if (this.resultRuntime === void 0) throw new Error("dsh-mnemon subagent result tool runtime is unavailable");
@@ -8088,12 +8195,22 @@ ${runtimeSnapshotContext("user", targetEntries)}`;
8088
8195
  let pending;
8089
8196
  let activeResultExecution;
8090
8197
  const staged = /* @__PURE__ */ new WeakMap();
8198
+ const recoverableTools = new Set(recovery?.terminalTools ?? []);
8199
+ const committedReceipts = [];
8200
+ const stagedReceipts = /* @__PURE__ */ new Map();
8091
8201
  let run;
8092
8202
  let failure;
8093
8203
  let disposeResultTool;
8094
8204
  let disposeResultObserver;
8095
8205
  try {
8096
8206
  const observer = this.resultRuntime.on("tools/result", ((execution, result) => {
8207
+ if (execution.token !== void 0) {
8208
+ const entries = stagedReceipts.get(execution.token);
8209
+ if (entries !== void 0) {
8210
+ stagedReceipts.delete(execution.token);
8211
+ if (result.isError !== true) committedReceipts.push(...entries);
8212
+ }
8213
+ }
8097
8214
  if (execution.name === resultToolName) {
8098
8215
  const entry = staged.get(execution);
8099
8216
  if (entry === void 0) return;
@@ -8108,13 +8225,25 @@ ${runtimeSnapshotContext("user", targetEntries)}`;
8108
8225
  };
8109
8226
  return;
8110
8227
  }
8111
- if (pending === void 0 || pending.parent !== execution.token) return;
8112
- const entry = pending;
8113
- pending = void 0;
8114
- if (result.isError !== true && captured === void 0) captured = {
8115
- agentId: entry.agentId,
8116
- value: entry.value
8228
+ if (pending !== void 0 && pending.parent === execution.token) {
8229
+ const entry = pending;
8230
+ pending = void 0;
8231
+ if (result.isError !== true && captured === void 0) captured = {
8232
+ agentId: entry.agentId,
8233
+ value: entry.value
8234
+ };
8235
+ }
8236
+ if (execution.name === void 0 || !recoverableTools.has(execution.name) || result.isError === true || !Object.hasOwn(result, "value")) return;
8237
+ const agent = execution.agent;
8238
+ if (agent === void 0 || !isSubagent(agent)) return;
8239
+ const receipt = {
8240
+ agentId: agent.id,
8241
+ name: execution.name,
8242
+ arguments: execution.arguments,
8243
+ value: result.value
8117
8244
  };
8245
+ if (execution.parent === void 0) committedReceipts.push(receipt);
8246
+ else stagedReceipts.set(execution.parent, [...stagedReceipts.get(execution.parent) ?? [], receipt]);
8118
8247
  }));
8119
8248
  if (typeof observer !== "function") throw new Error("dsh-mnemon subagent result observer registration did not return a disposer");
8120
8249
  disposeResultObserver = observer;
@@ -8162,22 +8291,24 @@ Completion protocol: call \`${resultToolName}\` exactly once with the final resu
8162
8291
  toolFilter: { allow: [...tools, resultToolName] },
8163
8292
  persona: completionPersona
8164
8293
  });
8165
- const result = await run.result;
8166
- if (captured !== void 0 && captured.agentId !== run.id) throw new Error("Mnemon subagent result was recorded by a different child");
8167
- const structured = captured?.value ?? result.structured;
8294
+ const activeRun = run;
8295
+ const result = await activeRun.result;
8296
+ if (captured !== void 0 && captured.agentId !== activeRun.id) throw new Error("Mnemon subagent result was recorded by a different child");
8297
+ let structured = captured?.value ?? result.structured;
8298
+ if (structured === void 0 && result.stopReason === "completed") structured = recoverStructuredResult(recovery, committedReceipts.filter((receipt) => receipt.agentId === activeRun.id));
8168
8299
  if (structured !== void 0) assertDshOutputValue(outputSchema, structured);
8169
8300
  if (result.stopReason !== "completed") {
8170
- const detail = subagentFailureDetail(run);
8301
+ const detail = subagentFailureDetail(activeRun);
8171
8302
  throw new Error(`memory subagent stopped with ${result.stopReason}${detail === void 0 ? "" : `: ${detail}`}`);
8172
8303
  }
8173
8304
  if (structured === void 0) throw new Error("memory subagent completed without recording its result");
8174
8305
  this.counters[operation === "recall" ? "recalls" : operation === "write" ? "writes" : operation === "review" ? "reviews" : operation === "placement" ? "placements" : operation === "migration" ? "migrations" : operation === "compaction" ? "compactions" : operation === "document-archive" ? "documentArchives" : operation === "metadata-maintenance" ? "metadataMaintenances" : "answers"] += 1;
8175
- this.counters.lastRunId = run.id;
8306
+ this.counters.lastRunId = activeRun.id;
8176
8307
  if (operation !== "answer") this.counters.lastOperation = operation;
8177
8308
  this.counters.lastAt = (/* @__PURE__ */ new Date()).toISOString();
8178
8309
  return {
8179
8310
  provider,
8180
- runId: run.id,
8311
+ runId: activeRun.id,
8181
8312
  result: {
8182
8313
  ...result,
8183
8314
  structured
@@ -9219,10 +9350,11 @@ function inspectDshInstall(packageManifestPath, dshHome) {
9219
9350
  locationDir: resolve(dirname(packageManifestPath))
9220
9351
  };
9221
9352
  }
9222
- async function resultOrThrow(runner, command, args, timeoutMs) {
9353
+ async function resultOrThrow(runner, command, args, timeoutMs, options = {}) {
9223
9354
  const result = await runner(command, args, {
9224
9355
  timeoutMs,
9225
- maxOutputBytes: MAX_UPDATE_OUTPUT_BYTES
9356
+ maxOutputBytes: MAX_UPDATE_OUTPUT_BYTES,
9357
+ ...options
9226
9358
  });
9227
9359
  if (result.exitCode !== 0) {
9228
9360
  const detail = result.stderr.trim() || result.stdout.trim() || `exit ${String(result.exitCode)}`;
@@ -9409,7 +9541,7 @@ var VersionUpdateManager = class {
9409
9541
  const install = inspectDshInstall(this.packageManifestPath, this.dshHome);
9410
9542
  const pnpm = this.executable("pnpm");
9411
9543
  if (install.mode !== "npm" || install.profileDir === void 0 || pnpm === void 0) throw new Error("This dsh-mnemon installation cannot be updated automatically");
9412
- const outputText = updateOutput(await resultOrThrow(this.processRunner, pnpm, ["update", DSH_MNEMON_PACKAGE], UPDATE_TIMEOUT_MS));
9544
+ const outputText = updateOutput(await resultOrThrow(this.processRunner, pnpm, ["update", DSH_MNEMON_PACKAGE], UPDATE_TIMEOUT_MS, { cwd: install.profileDir }));
9413
9545
  this.dshMnemonVersion = latest;
9414
9546
  return {
9415
9547
  component,
@@ -9989,6 +10121,7 @@ const MUTABLE_FIELDS = [
9989
10121
  "displayMode",
9990
10122
  "tabEnabled",
9991
10123
  "writeEnabled",
10124
+ "persistenceStrategy",
9992
10125
  "taskAgentModel"
9993
10126
  ];
9994
10127
  /** Nested paths of the live in-conversation interaction toggles. */
@@ -1,4 +1,4 @@
1
- import type { ClientConnectionHandle } from '../shared/contracts.ts';
1
+ import type { ClientConnectionHandle, ClientSettingsScope, Config } from '../shared/contracts.ts';
2
2
  import type { MnemonKey } from './locales.ts';
3
3
  export interface MnemonSaveActionProps {
4
4
  /** Stable identity of the finalized assistant message this action addresses. */
@@ -6,6 +6,7 @@ export interface MnemonSaveActionProps {
6
6
  /** Injected by the slot host: the session this message belongs to. */
7
7
  sessionId?: string;
8
8
  connection: ClientConnectionHandle;
9
+ settingsScope: ClientSettingsScope<Config>;
9
10
  t: (key: MnemonKey, params?: Record<string, unknown>) => string;
10
11
  }
11
12
  /** Save-to-memory action on finalized assistant messages, routed through the supervised writeback gate. */
@@ -35,6 +35,8 @@ export interface ToolExecution {
35
35
  signal: AbortSignal;
36
36
  agent?: HostAgent;
37
37
  name?: string;
38
+ /** Parsed tool arguments, available on the authoritative tools/result event. */
39
+ arguments?: unknown;
38
40
  parent?: symbol;
39
41
  token?: symbol;
40
42
  /** End the current model turn after an authoritative terminal tool call. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-mnemon",
3
- "version": "0.2.9",
3
+ "version": "0.2.10",
4
4
  "description": "Three-tier memory control plane for DeepSeek Harness: persistent runtime context, searchable project documents, pluggable long-term memory, smart routing, supervised agent workflows, WebUI, and headless tools.",
5
5
  "keywords": [
6
6
  "deepseek-harness",