dsh-tdai-memory 0.2.3 → 0.2.5

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/index.js CHANGED
@@ -25,6 +25,7 @@ import { installSettingsSection, settingsNamespace } from "@deepseek-ai/dsh-sett
25
25
  import { TdaiCore } from "./vendor/tdai/core/tdai-core.js";
26
26
  import { parseConfig } from "./vendor/tdai/config.js";
27
27
  import { StandaloneHostAdapter } from "./vendor/tdai/adapters/standalone/host-adapter.js";
28
+ import { ensureSettingsNamespaceExposed } from "./vendor/dsh-settings-expose.js";
28
29
 
29
30
  /** Cordis plugin name. */
30
31
  const name = "tdai-memory";
@@ -359,6 +360,12 @@ function apply(ctx, config) {
359
360
  },
360
361
  });
361
362
 
363
+ // dsh-host-apiproxy hard-codes which settings namespaces the Web client may
364
+ // see; without this, the settings section answers `settings-not-exposed`
365
+ // on any stock install. Patch the allowlist idempotently (self-heals after
366
+ // dsh updates overwrite the file).
367
+ ensureSettingsNamespaceExposed(ctx, "tdai-memory", ctx.logger);
368
+
362
369
  // Fallback when no settings service ever mounts: build from the entry
363
370
  // config. One-shot — if the settings mount arrives later, its build
364
371
  // supersedes this one. Delayed past the 0ms window so headless/web boots
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-tdai-memory",
3
- "version": "0.2.3",
3
+ "version": "0.2.5",
4
4
  "description": "DeepSeek Harness 的 TencentDB Agent Memory 移植:L0 对话捕获 → L1 结构化记忆提取 → L2 场景/L3 画像,自动召回注入 + 记忆/对话搜索工具;复用现有 ~/.memory-tencentdb/memory-tdai 数据;附 Web UI 设置栏。",
5
5
  "type": "module",
6
6
  "main": "index.js",
@@ -49,8 +49,6 @@
49
49
  },
50
50
  "dependencies": {
51
51
  "@ai-sdk/openai": "^3.0.53",
52
- "@deepseek-ai/dsh-settings": "^0.1.0-rc.6",
53
- "@deepseek-ai/dsh-tools": "^0.1.0-rc.6",
54
52
  "@deepseek-ai/schemastery": "^3.18.1",
55
53
  "@node-rs/jieba": "^2.0.1",
56
54
  "@tencentdb-agent-memory/tcvdb-text": "^0.1.1",
@@ -58,5 +56,13 @@
58
56
  "json5": "^2.2.3",
59
57
  "sqlite-vec": "0.1.7-alpha.2",
60
58
  "undici": "^8.1.0"
61
- }
59
+ },
60
+ "optionalDependencies": {
61
+ "node-llama-cpp": "^3.19.1"
62
+ },
63
+ "peerDependencies": {
64
+ "react": "^18.2.0",
65
+ "@deepseek-ai/dsh-tools": "^0.1.0-rc.6",
66
+ "@deepseek-ai/dsh-settings": "^0.1.0-rc.6"
67
+ }
62
68
  }
@@ -0,0 +1,75 @@
1
+ /**
2
+ * dsh-host-apiproxy exposes only namespaces listed in its hard-coded
3
+ * WEB_SETTINGS_NAMESPACES allowlist to the Web settings client. A namespace
4
+ * registered by a third-party plugin answers `settings-not-exposed` even
5
+ * though it is registered — upstream explicitly defers letting plugins
6
+ * expose their own configuration.
7
+ *
8
+ * This module idempotently patches that allowlist in the dsh installation
9
+ * actually loaded by the host process, so the plugin's settings section
10
+ * becomes visible in the Web UI without manual edits. A dsh update
11
+ * overwrites the file; the next plugin start re-patches it.
12
+ */
13
+ import { existsSync, readFileSync, writeFileSync } from "node:fs";
14
+ import { createRequire } from "node:module";
15
+ import { dirname, join, sep } from "node:path";
16
+
17
+ /**
18
+ * Ensure `nsName` is present in dsh-host-apiproxy's WEB_SETTINGS_NAMESPACES.
19
+ * No-op when already exposed or when the file cannot be located/patched.
20
+ * @param {import("cordis").Context} ctx
21
+ * @param {string} nsName - settings namespace short name (e.g. "tdai-memory").
22
+ * @param {{info?: Function, warn?: Function}} logger - dsh logger.
23
+ */
24
+ export function ensureSettingsNamespaceExposed(ctx, nsName, logger) {
25
+ void ctx;
26
+ try {
27
+ const target = findApiproxyIndex();
28
+ if (!target) {
29
+ logger?.warn?.(`[settings-expose] could not locate dsh-host-apiproxy; add "${nsName}" to WEB_SETTINGS_NAMESPACES in dsh-host-apiproxy/lib/index.js to get a Web settings section`);
30
+ return;
31
+ }
32
+ let src;
33
+ try {
34
+ src = readFileSync(target, "utf8");
35
+ } catch (error) {
36
+ logger?.warn?.(`[settings-expose] cannot read ${target}: ${String(error)}`);
37
+ return;
38
+ }
39
+ const body = src.match(/const WEB_SETTINGS_NAMESPACES = \[([\s\S]*?)\];/)?.[1] ?? "";
40
+ if (body.includes(`"${nsName}"`)) return; // already exposed (manual or previous patch)
41
+ const patched = src.replace(/(const WEB_SETTINGS_NAMESPACES = \[[\s\S]*?)(\n\s*\];)/, (_, pre, post) => {
42
+ const trailingComma = /,\s*$/.test(pre) ? "" : ",";
43
+ const sep2 = pre.trimEnd().endsWith("[") ? "" : trailingComma;
44
+ return `${pre}${sep2}\n\t"${nsName}"${post}`;
45
+ });
46
+ if (patched === src) {
47
+ logger?.warn?.(`[settings-expose] allowlist pattern not found in ${target}; add "${nsName}" to WEB_SETTINGS_NAMESPACES manually`);
48
+ return;
49
+ }
50
+ writeFileSync(target, patched, "utf8");
51
+ logger?.info?.(`[settings-expose] added "${nsName}" to WEB_SETTINGS_NAMESPACES (${target}) — restart dsh web for the settings section to appear`);
52
+ } catch (error) {
53
+ logger?.warn?.(`[settings-expose] failed: ${String(error)}`);
54
+ }
55
+ }
56
+
57
+ function findApiproxyIndex() {
58
+ // 1) The host process has already loaded dsh-host-apiproxy: read the real
59
+ // module path from the CommonJS module cache (any install layout).
60
+ try {
61
+ const Module = createRequire(import.meta.url)("module");
62
+ const cache = Module._cache ?? {};
63
+ for (const key of Object.keys(cache)) {
64
+ if (key.includes(`${sep}dsh-host-apiproxy${sep}`) && key.endsWith(`${sep}index.js`)) return key;
65
+ }
66
+ } catch { /* fall through */ }
67
+ // 2) Fallback: sibling of @deepseek-ai/dsh-settings (dsh's nested layout).
68
+ try {
69
+ const require = createRequire(import.meta.url);
70
+ const settingsEntry = require.resolve("@deepseek-ai/dsh-settings");
71
+ const candidate = join(dirname(dirname(dirname(settingsEntry))), "dsh-host-apiproxy", "lib", "index.js");
72
+ if (existsSync(candidate)) return candidate;
73
+ } catch { /* fall through */ }
74
+ return "";
75
+ }