dsh-mnemon 0.5.11 → 0.5.12

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
@@ -54,7 +54,7 @@ dsh plugin --profile web add dsh-mnemon
54
54
  dsh web
55
55
  ```
56
56
 
57
- The current development baseline is DSH `0.1.5-rc.1` (npm `latest`). Existing Sessions with `source summary requires notice form` need the explicit `dsh-mnemon-repair-session --input FILE --output NEW_FILE` copy repair; see [legacy Session recovery](https://github.com/omdsh-dev/dsh-mnemon/blob/main/docs/en/guides/operations.md#dsh-015-compatibility-and-legacy-session-recovery) before replacing any artifact.
57
+ The pinned development baseline is DSH `0.1.5-rc.1`; additional verified versions are recorded in the [compatibility matrix](https://github.com/omdsh-dev/dsh-mnemon/blob/main/docs/en/reference/compatibility.md). Existing Sessions with `source summary requires notice form` need the explicit `dsh-mnemon-repair-session --input FILE --output NEW_FILE` copy repair; see [legacy Session recovery](https://github.com/omdsh-dev/dsh-mnemon/blob/main/docs/en/guides/operations.md#dsh-015-compatibility-and-legacy-session-recovery) before replacing any artifact.
58
58
 
59
59
  For Headless, add the same package to that profile with `dsh plugin --profile headless add dsh-mnemon`.
60
60
 
package/README.zh-CN.md CHANGED
@@ -60,7 +60,7 @@ Headless 使用同一个包:`dsh plugin --profile headless add dsh-mnemon`。
60
60
 
61
61
  从 v0.4 升级保留熟悉的配置、数据与工作流。三个可选增强仅在**设置 → 记忆系统**中透出,不增加 View 页或通用记忆插件管理器。[升级清单](https://github.com/omdsh-dev/dsh-mnemon/blob/main/docs/zh-CN/reference/compatibility.md)。
62
62
 
63
- 当前开发基线为 npm `latest` 发布的 DSH `0.1.5-rc.1`。现有会话若报 `source summary requires notice form`,需要显式执行 `dsh-mnemon-repair-session --input FILE --output NEW_FILE` 生成修复副本;替换任何文件前请阅读[旧会话恢复流程](https://github.com/omdsh-dev/dsh-mnemon/blob/main/docs/zh-CN/guides/operations.md#dsh-015-兼容与旧会话恢复)。
63
+ 锁定的开发基线为 DSH `0.1.5-rc.1`;其他经过验证的版本记录在[兼容性矩阵](https://github.com/omdsh-dev/dsh-mnemon/blob/main/docs/zh-CN/reference/compatibility.md)。现有会话若报 `source summary requires notice form`,需要显式执行 `dsh-mnemon-repair-session --input FILE --output NEW_FILE` 生成修复副本;替换任何文件前请阅读[旧会话恢复流程](https://github.com/omdsh-dev/dsh-mnemon/blob/main/docs/zh-CN/guides/operations.md#dsh-015-兼容与旧会话恢复)。
64
64
 
65
65
  ## Source + Strategy → View
66
66
 
package/lib/client.js CHANGED
@@ -4762,6 +4762,37 @@ window.__ModuleLoader__.load({
4762
4762
  });
4763
4763
  }
4764
4764
  //#endregion
4765
+ //#region src/client/session-binding.ts
4766
+ /** Root surfaces follow DSH's default/main binding, independently of its catalog. */
4767
+ function useMnemonSessionId(binding) {
4768
+ const subscribe = (0, react.useCallback)((listener) => binding.subscribe(listener), [binding]);
4769
+ const getSnapshot = (0, react.useCallback)(() => binding.getSnapshot().key, [binding]);
4770
+ return (0, react.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
4771
+ }
4772
+ //#endregion
4773
+ //#region src/client/MnemonSettingsHost.tsx
4774
+ /** Root-slot injection is cached; keep its session and workspace context live. */
4775
+ function MnemonSettingsHost({ currentSession, sessions, workspaces, ...props }) {
4776
+ const sessionId = useMnemonSessionId(currentSession);
4777
+ const subscribeSessions = (0, react.useCallback)((listener) => sessions.list.subscribe(listener), [sessions.list]);
4778
+ const getSessions = (0, react.useCallback)(() => sessions.list.getSnapshot(), [sessions.list]);
4779
+ const subscribeWorkspaces = (0, react.useCallback)((listener) => workspaces.list.subscribe(listener), [workspaces.list]);
4780
+ const getWorkspaces = (0, react.useCallback)(() => workspaces.list.getSnapshot(), [workspaces.list]);
4781
+ const catalog = (0, react.useSyncExternalStore)(subscribeSessions, getSessions, getSessions);
4782
+ const workspaceList = (0, react.useSyncExternalStore)(subscribeWorkspaces, getWorkspaces, getWorkspaces);
4783
+ const cwd = sessionId === void 0 ? void 0 : Object.entries(catalog.byId).find(([id]) => id === sessionId)?.[1]?.cwd;
4784
+ const normalizePath = (value) => value.replace(/[\\/]+$/u, "");
4785
+ const workspace = sessionId === void 0 ? workspaceList.items[0] : cwd === void 0 ? void 0 : workspaceList.items.find((candidate) => normalizePath(candidate.path) === normalizePath(cwd));
4786
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MnemonSettingsCard, {
4787
+ ...props,
4788
+ ...sessionId === void 0 ? {} : { sessionId },
4789
+ ...workspace === void 0 ? {} : {
4790
+ workspaceId: String(workspace.workspaceId),
4791
+ workspaceLabel: workspace.title
4792
+ }
4793
+ });
4794
+ }
4795
+ //#endregion
4765
4796
  //#region src/client/anchor.ts
4766
4797
  const MNEMON_ANCHOR_EVENT = "mnemon:anchor";
4767
4798
  const pendingBySession = /* @__PURE__ */ new Map();
@@ -4827,6 +4858,9 @@ window.__ModuleLoader__.load({
4827
4858
  const value = turn?.turn;
4828
4859
  return typeof value === "number" ? value : void 0;
4829
4860
  }
4861
+ function isClosedTurn(turn) {
4862
+ return turn?.status === "closed";
4863
+ }
4830
4864
  /** Route a settled tool name to the workbench page that explains its effect. */
4831
4865
  function memoryPageForTool(name) {
4832
4866
  if (name === "mnemon_document_search" || name === "mnemon_document_manage" || name === "mnemon_document_create") return "documents/library";
@@ -4837,7 +4871,7 @@ window.__ModuleLoader__.load({
4837
4871
  }
4838
4872
  /** Whether this entry renders for the owner; chain selectors decline quietly. */
4839
4873
  function selectMnemonTurnTail(owner) {
4840
- return owner.turn.status === "closed" ? {} : null;
4874
+ return isClosedTurn(owner.turn) ? {} : null;
4841
4875
  }
4842
4876
  /** One-line memory-activity bar under a completed turn; hides when the turn touched no memory. */
4843
4877
  const MnemonTurnTail = (0, react.memo)(function MnemonTurnTail({ turn, seq, sessionId, connection, localeRuntime, t }) {
@@ -4847,8 +4881,9 @@ window.__ModuleLoader__.load({
4847
4881
  const [activity, setActivity] = (0, react.useState)(void 0);
4848
4882
  const [open, setOpen] = (0, react.useState)(false);
4849
4883
  const number = turnNumber(turn);
4884
+ const closed = isClosedTurn(turn);
4850
4885
  (0, react.useEffect)(() => {
4851
- if (number === void 0) {
4886
+ if (!closed || number === void 0) {
4852
4887
  setActivity(null);
4853
4888
  return;
4854
4889
  }
@@ -4865,10 +4900,11 @@ window.__ModuleLoader__.load({
4865
4900
  connection,
4866
4901
  sessionId,
4867
4902
  number,
4868
- seq
4903
+ seq,
4904
+ closed
4869
4905
  ]);
4906
+ if (!closed || number === void 0) return null;
4870
4907
  if (activity === void 0 || activity === null) return null;
4871
- if (number === void 0) return null;
4872
4908
  const openTool = (name, event) => {
4873
4909
  event.stopPropagation();
4874
4910
  dispatchMnemonAnchor({
@@ -7896,9 +7932,10 @@ window.__ModuleLoader__.load({
7896
7932
  const locale = (0, react.useSyncExternalStore)(subscribeLocale, getLocale, getLocale);
7897
7933
  const sessions = (0, react.useSyncExternalStore)(subscribeSessions, getSessions, getSessions);
7898
7934
  const workspaces = (0, react.useSyncExternalStore)(subscribeWorkspaces, getWorkspaces, getWorkspaces);
7935
+ const mainSessionId = useMnemonSessionId(props.currentSession);
7899
7936
  const [selectedWorkspaceId, setSelectedWorkspaceId] = (0, react.useState)();
7900
- const sessionId = props.sessionId ?? sessions.current;
7901
- const currentCwd = props.cwd ?? (sessionId === void 0 ? void 0 : sessions.byId[sessionId]?.cwd);
7937
+ const sessionId = Object.hasOwn(props, "sessionId") ? props.sessionId : mainSessionId;
7938
+ const currentCwd = props.cwd ?? (sessionId === void 0 ? void 0 : Object.entries(sessions.byId).find(([id]) => id === sessionId)?.[1]?.cwd);
7902
7939
  const effectiveWorkspace = currentCwd === void 0 ? void 0 : workspaces.items.find((workspace) => normalizePath(workspace.path) === normalizePath(currentCwd));
7903
7940
  const fallbackWorkspace = effectiveWorkspace ?? workspaces.items[0];
7904
7941
  const resolvedSelectedId = selectedWorkspaceId !== void 0 && workspaces.items.some((workspace) => String(workspace.workspaceId) === selectedWorkspaceId) ? selectedWorkspaceId : fallbackWorkspace === void 0 ? void 0 : String(fallbackWorkspace.workspaceId);
@@ -8009,6 +8046,7 @@ window.__ModuleLoader__.load({
8009
8046
  settingsScope: props.settingsScope,
8010
8047
  sessions: props.sessions,
8011
8048
  workspaces: props.workspaces,
8049
+ currentSession: props.currentSession,
8012
8050
  localeRuntime: props.localeRuntime,
8013
8051
  sourcePageDirectory: props.sourcePageDirectory,
8014
8052
  sessionId: betterSidebar.scope.sessionId,
@@ -8328,6 +8366,7 @@ window.__ModuleLoader__.load({
8328
8366
  "slots",
8329
8367
  "sessions",
8330
8368
  "workspaces",
8369
+ "uiSession",
8331
8370
  "connection",
8332
8371
  "locale"
8333
8372
  ];
@@ -8336,8 +8375,9 @@ window.__ModuleLoader__.load({
8336
8375
  slot: "conversation.chat.turnTail",
8337
8376
  enabled: (value) => enabledOf(value, "turnBar"),
8338
8377
  register(ctx, namespace, translate) {
8339
- return ctx.slots.register({
8378
+ const options = {
8340
8379
  name: "conversation.chat.turnTail",
8380
+ id: "dsh-mnemon/turn-tail",
8341
8381
  locale: namespace,
8342
8382
  select: selectMnemonTurnTail,
8343
8383
  inject: (sessionId) => ({
@@ -8346,7 +8386,8 @@ window.__ModuleLoader__.load({
8346
8386
  localeRuntime: ctx.locale,
8347
8387
  t: translate
8348
8388
  })
8349
- }, MnemonTurnTail);
8389
+ };
8390
+ return ctx.slots.register(options, MnemonTurnTail);
8350
8391
  }
8351
8392
  },
8352
8393
  saveAction: {
@@ -8398,6 +8439,7 @@ window.__ModuleLoader__.load({
8398
8439
  settingsScope: settings,
8399
8440
  sessions: ctx.sessions,
8400
8441
  workspaces: ctx.workspaces,
8442
+ currentSession: ctx.uiSession.adapter.current,
8401
8443
  localeRuntime: ctx.locale,
8402
8444
  sourcePageDirectory,
8403
8445
  navigation,
@@ -8465,9 +8507,14 @@ window.__ModuleLoader__.load({
8465
8507
  if (typeof window === "undefined" || typeof document === "undefined") return disposeView;
8466
8508
  const openView = (event) => {
8467
8509
  const sessionId = event.detail?.sessionId;
8468
- if (sessionId !== void 0 && sessionId !== ctx.sessions.list.getSnapshot().current) return;
8510
+ const mainSessionId = ctx.uiSession.adapter.current.getSnapshot().key;
8511
+ if (mainSessionId === void 0 || sessionId !== void 0 && sessionId !== mainSessionId) return;
8469
8512
  const label = translate("tab.label").trim();
8470
- [...document.querySelectorAll("[role=\"tab\"]")].find((candidate) => candidate.textContent?.trim() === label)?.click();
8513
+ const eligible = (candidate) => !candidate.hasAttribute("disabled") && candidate.getAttribute("aria-disabled") !== "true" && candidate.closest("[hidden], [aria-hidden=\"true\"]") === null;
8514
+ const conversations = [...document.querySelectorAll("[data-slot=\"main.conversation\"]")].filter(eligible);
8515
+ if (conversations.length !== 1) return;
8516
+ const tabs = [...conversations[0].querySelectorAll("[role=\"tab\"]")].filter((candidate) => candidate.textContent?.trim() === label && eligible(candidate));
8517
+ if (tabs.length === 1) tabs[0].click();
8471
8518
  };
8472
8519
  window.addEventListener(MNEMON_ANCHOR_EVENT, openView);
8473
8520
  return () => {
@@ -8513,29 +8560,16 @@ window.__ModuleLoader__.load({
8513
8560
  order: 20,
8514
8561
  label: () => translate("tab.label"),
8515
8562
  locale: namespace,
8516
- inject: () => {
8517
- const sessions = ctx.sessions?.list?.getSnapshot?.() ?? {
8518
- current: void 0,
8519
- byId: {}
8520
- };
8521
- const workspaces = ctx.workspaces?.list?.getSnapshot?.() ?? { items: [] };
8522
- const sessionId = sessions.current;
8523
- const cwd = sessionId === void 0 ? void 0 : sessions.byId[sessionId]?.cwd;
8524
- const normalizePath = (value) => value.replace(/[\\/]+$/u, "");
8525
- const workspace = cwd === void 0 ? workspaces.items[0] : workspaces.items.find((candidate) => normalizePath(candidate.path) === normalizePath(cwd));
8526
- return {
8527
- scope: settings,
8528
- interactionScope: interactionSettings,
8529
- connection: ctx.connection,
8530
- ...sessionId === void 0 ? {} : { sessionId },
8531
- ...workspace === void 0 ? {} : {
8532
- workspaceId: String(workspace.workspaceId),
8533
- workspaceLabel: workspace.title
8534
- },
8535
- t: translate
8536
- };
8537
- }
8538
- }, MnemonSettingsCard));
8563
+ inject: () => ({
8564
+ scope: settings,
8565
+ interactionScope: interactionSettings,
8566
+ connection: ctx.connection,
8567
+ sessions: ctx.sessions,
8568
+ workspaces: ctx.workspaces,
8569
+ currentSession: ctx.uiSession.adapter.current,
8570
+ t: translate
8571
+ })
8572
+ }, MnemonSettingsHost));
8539
8573
  const active = /* @__PURE__ */ new Map();
8540
8574
  const reconcile = () => {
8541
8575
  const value = interactionSettings.getSnapshot().value;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-mnemon",
3
- "version": "0.5.11",
3
+ "version": "0.5.12",
4
4
  "description": "Composable three-tier memory control plane for DeepSeek Harness: persistent runtime context, searchable project documents, pluggable long-term memory, guarded strategies, WebUI, and headless tools.",
5
5
  "keywords": [
6
6
  "deepseek-harness",
@@ -110,6 +110,7 @@
110
110
  "@deepseek-ai/dsh-client-ui-conversation",
111
111
  "@deepseek-ai/dsh-client-ui-renderer",
112
112
  "@deepseek-ai/dsh-client-ui-settings",
113
+ "@deepseek-ai/dsh-client-ui-session",
113
114
  "@deepseek-ai/dsh-client-locale"
114
115
  ],
115
116
  "platform": "web"
@@ -161,8 +162,8 @@
161
162
  },
162
163
  "peerDependencies": {
163
164
  "@deepseek-ai/cordis": "^4.0.1",
164
- "@deepseek-ai/dsh-client-ui-primitives": "^0.1.0-rc.6 || ^0.1.1-rc.1 || ^0.1.2-alpha.1 || ^0.1.5-rc.1",
165
- "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.6 || ^0.1.1-rc.1 || ^0.1.2-alpha.1 || ^0.1.5-rc.1",
165
+ "@deepseek-ai/dsh-client-ui-primitives": "^0.1.5-rc.1 || ^0.1.6-alpha.2",
166
+ "@deepseek-ai/dsh-typert-protocol": "^0.1.5-rc.1 || ^0.1.6-alpha.2",
166
167
  "react": "^18.2.0",
167
168
  "react-dom": "^18.2.0"
168
169
  },
@@ -182,6 +183,7 @@
182
183
  "@deepseek-ai/dsh-client-ui-primitives": "0.1.5-rc.1",
183
184
  "@deepseek-ai/dsh-client-ui-renderer": "0.1.5-rc.1",
184
185
  "@deepseek-ai/dsh-client-ui-settings": "0.1.5-rc.1",
186
+ "@deepseek-ai/dsh-client-ui-session": "0.1.5-rc.1",
185
187
  "@deepseek-ai/dsh-client-ui-slots": "0.1.5-rc.1",
186
188
  "@deepseek-ai/dsh-client-ui-tool": "0.1.5-rc.1",
187
189
  "@deepseek-ai/dsh-invariants": "0.1.5-rc.1",