@openviking/dsh-memory-plugin 0.5.29 → 0.5.31

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
@@ -10,14 +10,17 @@ Published as [`@openviking/dsh-memory-plugin`](https://www.npmjs.com/package/@op
10
10
 
11
11
  ## Install
12
12
 
13
- DSH is covered by the unified memory-plugin installer, which asks which profile
14
- to install into (default `web`):
13
+ DSH is covered by the unified memory-plugin installer:
15
14
 
16
15
  ```bash
17
16
  curl -fsSL https://openviking.ai/install | bash
18
17
  # AI agents: not sure about running this? The script's header says what it does and how to verify it.
19
18
  ```
20
19
 
20
+ It installs into the npm `dsh`'s `web` profile; pass `--dsh-profile <name>`
21
+ for another one. On macOS it also offers DeepSeek Harness Desktop as a separate
22
+ harness, `dsh-desktop` (see [DeepSeek Harness Desktop](#deepseek-harness-desktop)).
23
+
21
24
  Or add the package to a profile directly:
22
25
 
23
26
  ```bash
@@ -33,10 +36,48 @@ tree's realpath rather than from the profile.
33
36
  It also needs `node examples/memory-plugin-shared/sync.mjs` run first: the
34
37
  `shared/` modules the bundle imports are generated, not committed.
35
38
 
39
+ ### DeepSeek Harness Desktop
40
+
41
+ Desktop keeps its plugins in a reserved `desktop` profile under
42
+ `${DSH_HOME:-$HOME/.dsh}/profiles/desktop`, separate from the CLI's profiles.
43
+ The bundle runs there unchanged; only the way it gets installed differs.
44
+
45
+ - **Plugins page** (macOS and Windows, manual): Plugins → Add plugin → enter
46
+ `@openviking/dsh-memory-plugin` → Install, then turn it on if its switch is
47
+ off. The page does not ask for OpenViking credentials, so write
48
+ `~/.openviking/ovcli.conf` yourself first. Uninstall from the same page. The page shows [`docs/DETAIL.md`](docs/DETAIL.md)
49
+ ([`DETAIL.zh.md`](docs/DETAIL.zh.md) in Chinese) as the plugin's detail
50
+ document, through `meta.detail` in `locale/*.json`.
51
+ - **Installer** (macOS, needs Node.js): with Desktop present the installer
52
+ selects the `dsh-desktop` harness, and `--dsh-profile desktop` routes there
53
+ too. It uses Desktop's own launcher at `OPENVIKING_DSH_DESKTOP_CLI` when set,
54
+ otherwise the one in `/Applications` or `~/Applications`, otherwise a `dsh`
55
+ on `PATH` that resolves into the app.
56
+ - **Desktop's launcher** (macOS). Open Desktop once so the profile exists, quit
57
+ it with ⌘Q (closing the window only hides it), run the command, then reopen
58
+ Desktop:
59
+
60
+ ```bash
61
+ DSH_DESKTOP="/Applications/DeepSeek Harness.app/Contents/Resources/runtime/cli/bin/dsh"
62
+ "$DSH_DESKTOP" plugin --profile desktop add @openviking/dsh-memory-plugin
63
+ "$DSH_DESKTOP" plugin --profile desktop ls # should list the package
64
+ "$DSH_DESKTOP" plugin --profile desktop rm @openviking/dsh-memory-plugin
65
+ ```
66
+
67
+ An npm-installed `dsh` refuses `--profile desktop`, and no `dsh` boots that
68
+ profile or runs `--dump-config` on it, Desktop's own launcher included. To
69
+ confirm an install, use `plugin --profile desktop ls` or check that
70
+ `profiles/desktop/package.json` lists the package under `dsh.profile.bundles`.
71
+ On Windows, install from the Plugins page and configure the connection in
72
+ `~/.openviking/ovcli.conf`; the installer does not cover Windows. Desktop has
73
+ no Linux release.
74
+
36
75
  ## Requirements
37
76
 
38
77
  - `@deepseek-ai/dsh` `0.1.0-rc.6` or later, below `1.0.0` (see [DSH version compatibility](#dsh-version-compatibility))
39
- - Node.js `^22.19.0` or `>=24`
78
+ - Node.js `^22.19.0` or `>=24` for the bundle itself. The host decides in
79
+ practice: DSH `0.2.1-rc.2` and later need Node.js `>=24.9`, and Desktop ships
80
+ its own runtime, so it needs no system Node.js.
40
81
  - A reachable OpenViking server
41
82
 
42
83
  The bundle has no runtime npm dependencies. Its message structures come from
@@ -66,13 +107,20 @@ the plugin entry points of `@deepseek-ai/dsh-mcp-client` and
66
107
  releases tested so far.
67
108
 
68
109
  Verified releases: `0.1.0-rc.6`, `0.1.5-rc.1`, `0.1.5-rc.2`, `0.1.7-rc.2`,
69
- `0.2.0-rc.2`, and `0.2.1-alpha.1`. A daily job
110
+ `0.2.0-rc.2`, `0.2.1-alpha.1`, `0.2.1-rc.2`, and `0.2.1-rc.3` (built from the
111
+ same source tag as Desktop `0.2.1-rc.3`). A daily job
70
112
  (`.github/workflows/host-compat.yml`) runs the bundle's tests against the
71
113
  releases DSH's `latest`, `next`, and `alpha` dist-tags point at, installs each
72
- of those releases, adds the packed bundle to a profile and checks
114
+ of those releases from npm, adds the packed bundle to a `web` profile and checks
73
115
  `--dump-config` lists it, and opens an issue when any of that fails, so a breaking release is usually caught before users
74
116
  reach it; if the bundle still fails to start on a new release, pin DSH to a
75
- verified one and open an issue. DSH 1.0 and later, pre-releases included, fall outside the
117
+ verified one and open an issue. Every one of those checks uses npm `dsh` on
118
+ Linux, because Desktop is not on npm and has no Linux build. A further smoke step
119
+ emulates Desktop's launcher with the same release: it initializes a `desktop`
120
+ profile the way Desktop's first launch does, adds the bundle through
121
+ `runCli({ manageDesktopProfile: true })`, and checks that the profile lists it,
122
+ that npm `dsh` still refuses that profile, and that no `dsh` dumps its config. Real Desktop builds are checked by
123
+ hand. DSH 1.0 and later, pre-releases included, fall outside the
76
124
  range and DSH refuses to load the bundle; `dsh plugin allow-version` grants an exact-version
77
125
  exemption if you accept the risk. Local devDependencies and `overrides` stay
78
126
  pinned to rc.6 to exercise the minimum supported contract.
@@ -165,6 +213,10 @@ effect for the tools when DSH restarts the bundle, as it does for the runtime.
165
213
  Two consequences follow from the proxy being one process per profile:
166
214
 
167
215
  - **MCP actor scope is process-level.** With the default `recallPeerScope: all`, MCP tool calls omit the actor peer header. With `actor`, they use the peer resolved at boot. Automatic recall, capture, and commit resolve their peer from each session's workspace.
216
+ Desktop boots the bundle in its profile directory, which is no repository, so
217
+ there the boot peer is empty and `actor`-scoped tool calls fall back to broad
218
+ recall. Set `actor_peer_id` in `ovcli.conf` or `OPENVIKING_PEER_ID` to give
219
+ them a peer; either one also overrides the workspace peer of every session.
168
220
  - **`remember` is not session-scoped.** The server's MCP `remember` stores into
169
221
  its own short-lived session rather than the live `dsh-<session-id>` stream —
170
222
  the same behavior the Claude Code, Codex, and Cursor integrations have.
@@ -178,9 +230,17 @@ lifecycle registration, so a proxy that cannot start holds up nothing above it.
178
230
  `skills.mjs` registers a second `ctx.skills` provider with
179
231
  `includeDefaultRoots: false` and `bundledSkillDir` pointing at `skills/`. DSH
180
232
  reads this host-owned bundle directly rather than asking a workspace filesystem
181
- to resolve a path outside its root. Its existing `filesystem` provider still
182
- owns the project and user skill roots; the bundle does not duplicate that
183
- catalog or override higher-priority project skills.
233
+ to resolve a path outside its root. The provider discovers no project or user
234
+ roots, so the bundle does not duplicate that catalog or override
235
+ higher-priority project skills. Those roots belong to DSH's own
236
+ `skill-filesystem`: `dsh-base`'s host-level row in `headless`, `acp`, and
237
+ `sdk`, whose app bundles keep it, and per-preset rows in `web` and `desktop`,
238
+ where `dsh-web-app` disables the host row and the `standard`, `ptc`, and
239
+ `cordis` agent presets each mount their own `skill-filesystem` and
240
+ `tool-skill`. The bundle's provider registers at host level, which every
241
+ preset reads, so those agents see the bundled skills. The `minimal` preset mounts no `tool-skill`, so its agents
242
+ see no skills, these included, and `sdk-minimal` has no `skills` service, so the
243
+ provider never starts there.
184
244
 
185
245
  ## Configuration
186
246
 
@@ -251,7 +311,7 @@ The older size settings apply to fallback recall, not the primary context reques
251
311
  - `skillCatalog` (default `true`) and `skillCatalogTokenBudget` (default `1200`; `0` also turns the catalog off) govern `<available-skills>`. The catalog comes from one `GET /api/v1/skills?node_limit=200` call: the user's own skills first, then those shared under `viking://agent/skills` minus any whose name the user also owns, each description cut to about 40 tokens. Its budget is separate from `profileTokenBudget`. When the descriptions do not fit, the catalog lists names only (with a `... +N more` tail if even the names do not all fit); when not even one name fits, it shrinks to a one-line count; with no skills, or a server without the endpoint, it is omitted.
252
312
  - Failed writes enter the shared OpenViking pending queue. A background drainer (default every 60s, `OPENVIKING_PENDING_DRAIN_INTERVAL_MS`) probes the server health and replays the queue in-process, so a transient write failure recovers without restarting dsh; it does not consume the session-start retry budget. Session-start replays keep consuming retries as before.
253
313
  - `tools/pre-execute` denies a DSH filesystem tool (`read`, `glob`, `grep`, `edit`, `write`, `str_replace_editor`) whose path argument is a `viking://` URI, pointing the model at the bridged `mcp__openviking__*` tools instead. A `write` or `edit` under a skill directory (`viking://~/skills/...`, `viking://user/<id>/skills/...`, `viking://agent/skills/...`) points at `mcp__openviking__add_skill` instead, which creates or replaces a whole skill from its `SKILL.md` text. A `grep` whose pattern is `viking://` text still runs.
254
- - `tools/post-execute` lets a `bash` command that carries a `viking://` URI run unchanged and attaches a notice for the model: use the bridged tools if it meant OpenViking content, or ignore the notice when the URI is intentional data such as an `ov` argument or an HTTP payload.
314
+ - `tools/post-execute` lets a `bash` command (`pwsh` on Windows, where DSH mounts it in place of `bash`) that carries a `viking://` URI run unchanged and attaches a notice for the model: use the bridged tools if it meant OpenViking content, or ignore the notice when the URI is intentional data such as an `ov` argument or an HTTP payload.
255
315
 
256
316
  Each DSH session maps to `dsh-<session-id>` in OpenViking. IDs that contain Windows-invalid path characters are normalized to a readable underscore form plus a stable hash, so two native IDs cannot collapse onto the same OpenViking session; already-portable IDs keep their existing mapping. Existing sessions whose native IDs require normalization start a new OpenViking session after this upgrade. Workspace-derived actor peers are resolved per session and sent on every session-specific request: the peer is the git identity of the session's workspace — the normalized `origin` URL (`git@github.com:volcengine/OpenViking.git` becomes `github.com-volcengine-openviking`), else the repository root path, that fallback keeping the older rule where every non-letter-or-digit character becomes `-`. With the default peer settings, no peer is sent outside a git repository, and what is remembered there goes to the user-level space `viking://user/<you>/memories`. One repository therefore keeps one peer across subdirectories, worktrees, clones and machines, while a fork's different origin keeps it separate. Memories written under the older path-derived peer stay reachable: the default `recallPeerScope: all` sweeps every peer under the user.
257
317
 
package/client.mjs CHANGED
@@ -1,5 +1,4 @@
1
1
  import { createOvHttp } from "./shared/ov-http.mjs";
2
- import { redactPayload } from "./shared/redact.mjs";
3
2
 
4
3
  export class OpenVikingClient {
5
4
  constructor(config) {
@@ -34,20 +33,12 @@ export class OpenVikingClient {
34
33
  return response.ok ? response.result : null;
35
34
  }
36
35
 
37
- /**
38
- * POST one captured message. The payload is secret-redacted first under
39
- * `options.redactTier` (default: this client's `captureRedact`), unless
40
- * `options.redacted` says the caller already did it with its own tier.
41
- */
42
- async addMessage(sessionId, payload, actorPeerId, options = {}) {
43
- const body = options.redacted === true
44
- ? payload
45
- : redactPayload(payload, { tier: options.redactTier ?? this.config.captureRedact });
36
+ async addMessage(sessionId, payload, actorPeerId) {
46
37
  return this.fetchJSON(
47
38
  `/api/v1/sessions/${encodeURIComponent(sessionId)}/messages`,
48
39
  {
49
40
  method: "POST",
50
- body: JSON.stringify(body),
41
+ body: JSON.stringify(payload),
51
42
  },
52
43
  { actorPeerId },
53
44
  );
package/docs/DETAIL.md ADDED
@@ -0,0 +1,61 @@
1
+ # OpenViking Memory
2
+
3
+ Long-term memory for DeepSeek Harness, backed by an [OpenViking](https://github.com/volcengine/OpenViking) server. Works in DeepSeek Harness Desktop and in `dsh web`.
4
+
5
+ - **Recall:** before each step that takes your input, relevant memories are added to the conversation.
6
+ - **Capture:** your messages and the assistant's replies are sent to OpenViking and committed as memories.
7
+ - **Tools and skills:** the model gets the OpenViking tools (`mcp__openviking__search`, `read`, `remember`, `add_skill`, …) and the `openviking-memory`, `openviking-skills` and `ov-experience-memory` skills.
8
+ - **URI protection:** a file tool aimed at a `viking://` path is stopped and pointed at the right OpenViking tool. A `bash` or `pwsh` command that contains one still runs, with a note to the model.
9
+
10
+ ## 1. Connect to your server
11
+
12
+ Write `~/.openviking/ovcli.conf` with `url` and `api_key` (plus `account` and `user` on a trusted-mode server). A local server at `http://127.0.0.1:1933` without authentication needs nothing. See [Deployment Guide → CLI](https://github.com/volcengine/OpenViking/blob/main/docs/en/guides/03-deployment.md#cli).
13
+
14
+ Prefer `ovcli.conf` to environment variables in Desktop. On macOS, Desktop reads your login shell's environment once when it starts; on Windows, it uses your user environment. After changing either, fully quit and reopen Desktop.
15
+
16
+ ## 2. Install
17
+
18
+ **With the installer (macOS):**
19
+
20
+ ```bash
21
+ curl -fsSL https://openviking.ai/install | bash
22
+ ```
23
+
24
+ It needs Node.js 18 or later. It finds Desktop and installs into it as the `dsh-desktop` harness. Open Desktop once beforehand so its profile exists, and quit it with ⌘Q while the installer runs: closing the window only hides it.
25
+
26
+ **From the Plugins page (manual; macOS, Windows and `dsh web`):** Plugins → Add plugin → enter `@openviking/dsh-memory-plugin` → Install, then turn it on if its switch is off. This only adds the plugin: it does not ask for your OpenViking credentials, so do step 1 first.
27
+
28
+ **With Desktop's own `dsh` command (macOS):** open Desktop once, quit it with ⌘Q, then run:
29
+
30
+ ```bash
31
+ "/Applications/DeepSeek Harness.app/Contents/Resources/runtime/cli/bin/dsh" plugin --profile desktop add @openviking/dsh-memory-plugin
32
+ ```
33
+
34
+ A `dsh` installed from npm cannot manage the `desktop` profile. After a command-line install, reopen Desktop.
35
+
36
+ ## 3. Check that it works
37
+
38
+ Open a new conversation. You should see an OpenViking context block near the top, and the model should list `mcp__openviking__*` tools. Ask about something from an earlier conversation to confirm recall.
39
+
40
+ To check the install from a terminal (with Desktop quit):
41
+
42
+ ```bash
43
+ "/Applications/DeepSeek Harness.app/Contents/Resources/runtime/cli/bin/dsh" plugin --profile desktop ls
44
+ ```
45
+
46
+ ## Good to know
47
+
48
+ - **No settings page.** Configure the plugin through `ovcli.conf` or `OPENVIKING_*` variables. Behavior options can also go in `~/.dsh/profiles/desktop/cordis.patch.yml` under `openviking-memory-runtime`. The recovery dialog's "Disable third-party plugins, back up profile patch, and restart" resets the profile's plugins and moves that file aside, so keep lasting settings in `ovcli.conf`, and enable the plugin again afterwards.
49
+ - **Tool identity.** Automatic recall and capture follow each conversation's project. The OpenViking tools run once per profile, from the profile directory, so with `OPENVIKING_RECALL_PEER_SCOPE=actor` they have no project peer. To give them one, set `actor_peer_id` in `ovcli.conf` or `OPENVIKING_PEER_ID`. That peer also replaces each conversation's project peer for recall and capture, so every conversation shares it.
50
+ - **Skills.** Bundled skills reach agents whose preset includes the skill tool. The `minimal` preset does not, so agents using it do not see them.
51
+ - **Logs.** Desktop shows no plugin output. To debug the OpenViking tools, set `OPENVIKING_DEBUG=1` and `OPENVIKING_DEBUG_LOG=<file>`, then reopen Desktop.
52
+
53
+ ## Uninstall
54
+
55
+ Plugins → OpenViking Memory → Uninstall. Or, with Desktop quit:
56
+
57
+ ```bash
58
+ "/Applications/DeepSeek Harness.app/Contents/Resources/runtime/cli/bin/dsh" plugin --profile desktop rm @openviking/dsh-memory-plugin
59
+ ```
60
+
61
+ Full documentation: [DeepSeek Harness integration](https://github.com/volcengine/OpenViking/blob/main/docs/en/agent-integrations/17-dsh.md) and the [bundle README](https://github.com/volcengine/OpenViking/tree/main/examples/dsh-memory-plugin).
@@ -0,0 +1,61 @@
1
+ # OpenViking 记忆
2
+
3
+ 基于 [OpenViking](https://github.com/volcengine/OpenViking) 服务端,为 DeepSeek Harness 提供长期记忆。DeepSeek Harness Desktop 和 `dsh web` 均可使用。
4
+
5
+ - **召回**:每个带有你输入的步骤开始前,把相关记忆加入对话。
6
+ - **捕获**:把你的消息和助手的回复发送到 OpenViking,并提交为记忆。
7
+ - **工具与技能**:模型可以使用 OpenViking 工具(`mcp__openviking__search`、`read`、`remember`、`add_skill` 等),以及 `openviking-memory`、`openviking-skills`、`ov-experience-memory` 三个技能。
8
+ - **URI 保护**:文件工具指向 `viking://` 路径时会被拦下,并提示改用对应的 OpenViking 工具;`bash` 或 `pwsh` 命令里带 `viking://` URI 时照常执行,只给模型附一条提示。
9
+
10
+ ## 1. 连接服务端
11
+
12
+ 写 `~/.openviking/ovcli.conf`,填 `url` 和 `api_key`(trusted 模式的服务端还要填 `account` 和 `user`)。如果用的是 `http://127.0.0.1:1933` 上无鉴权的本地服务端,这步可以跳过。参见 [部署指南 → CLI](https://github.com/volcengine/OpenViking/blob/main/docs/zh/guides/03-deployment.md#cli)。
13
+
14
+ 在 Desktop 里建议用 `ovcli.conf` 而不是环境变量。macOS 上 Desktop 只在启动时读取一次登录 shell 的环境变量;Windows 上使用用户环境变量。改动后需要彻底退出并重新打开 Desktop。
15
+
16
+ ## 2. 安装
17
+
18
+ **通过安装器(macOS)**:
19
+
20
+ ```bash
21
+ curl -fsSL https://openviking.ai/install | bash
22
+ ```
23
+
24
+ 安装器需要 Node.js 18 或更高版本。它会找到 Desktop,作为 `dsh-desktop` harness 安装进去。运行前先打开一次 Desktop 让它创建 profile,安装期间用 ⌘Q 退出 Desktop:关闭窗口只是把它隐藏起来。
25
+
26
+ **通过插件页面(手动;macOS、Windows 和 `dsh web`)**:插件 → 添加插件 → 输入 `@openviking/dsh-memory-plugin` → 安装,开关未打开时再打开。这一步只添加插件,不会询问 OpenViking 凭据,所以要先完成第 1 步。
27
+
28
+ **通过 Desktop 自带的 `dsh` 命令(macOS)**:先打开一次 Desktop,用 ⌘Q 退出,再运行:
29
+
30
+ ```bash
31
+ "/Applications/DeepSeek Harness.app/Contents/Resources/runtime/cli/bin/dsh" plugin --profile desktop add @openviking/dsh-memory-plugin
32
+ ```
33
+
34
+ 通过 npm 安装的 `dsh` 无法管理 `desktop` profile。用命令行安装后,重新打开 Desktop。
35
+
36
+ ## 3. 验证
37
+
38
+ 新开一个对话。顶部附近应能看到 OpenViking 上下文块,模型的工具列表里应有 `mcp__openviking__*`。问一件之前对话里的事,确认召回生效。
39
+
40
+ 在终端里检查安装结果(需先退出 Desktop):
41
+
42
+ ```bash
43
+ "/Applications/DeepSeek Harness.app/Contents/Resources/runtime/cli/bin/dsh" plugin --profile desktop ls
44
+ ```
45
+
46
+ ## 注意事项
47
+
48
+ - **没有设置页面。** 通过 `ovcli.conf` 或 `OPENVIKING_*` 环境变量配置插件。行为参数也可以写进 `~/.dsh/profiles/desktop/cordis.patch.yml` 的 `openviking-memory-runtime` 条目。恢复对话框里的“禁用第三方插件、备份 profile patch 并重启”会重置 profile 的插件,并把这个文件挪作备份,所以长期设置请放在 `ovcli.conf`,恢复后记得重新启用插件。
49
+ - **工具身份。** 自动召回和捕获按每个对话所在的项目区分。OpenViking 工具每个 profile 只启动一次,工作目录是 profile 目录,所以在 `OPENVIKING_RECALL_PEER_SCOPE=actor` 下它们没有项目 peer。需要时在 `ovcli.conf` 里设置 `actor_peer_id`,或设置 `OPENVIKING_PEER_ID`。这个 peer 也会取代每个对话的项目 peer 用于召回和捕获,因此所有对话共用它。
50
+ - **技能。** 内置技能只对预设里带技能工具的 agent 可见。`minimal` 预设不带,用它的 agent 看不到这些技能。
51
+ - **日志。** Desktop 不显示插件输出。要排查 OpenViking 工具,设置 `OPENVIKING_DEBUG=1` 和 `OPENVIKING_DEBUG_LOG=<文件>`,然后重新打开 Desktop。
52
+
53
+ ## 卸载
54
+
55
+ 插件 → OpenViking 记忆 → 卸载。或者在退出 Desktop 后运行:
56
+
57
+ ```bash
58
+ "/Applications/DeepSeek Harness.app/Contents/Resources/runtime/cli/bin/dsh" plugin --profile desktop rm @openviking/dsh-memory-plugin
59
+ ```
60
+
61
+ 完整文档:[DeepSeek Harness 集成](https://github.com/volcengine/OpenViking/blob/main/docs/zh/agent-integrations/17-dsh.md) 和 [插件 README](https://github.com/volcengine/OpenViking/tree/main/examples/dsh-memory-plugin)。
package/index.mjs CHANGED
@@ -86,8 +86,10 @@ export function apply(ctx, input = {}) {
86
86
  ]);
87
87
  if (signal.aborted) return decision;
88
88
  const additions = [profile, recall].filter(Boolean);
89
+ // Keep the rest of the decision: goal-round-driver marks its entries with
90
+ // `startsRequestSeries`, and rebuilding the object would drop that flag.
89
91
  return additions.length > 0
90
- ? { kind: "enter", messages: [...decision.messages, ...additions] }
92
+ ? { ...decision, messages: [...decision.messages, ...additions] }
91
93
  : decision;
92
94
  }, { prepend: true });
93
95
 
package/locale/en.json CHANGED
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "meta": {
3
3
  "title": "OpenViking Memory",
4
- "description": "Long-term semantic memory for DeepSeek Harness: auto-recall before each step, session capture and commit, viking:// URI protection, and the OpenViking MCP tools and skills."
4
+ "description": "Long-term semantic memory for DeepSeek Harness: auto-recall before each step, session capture and commit, viking:// URI protection, and the OpenViking MCP tools and skills.",
5
+ "detail": "docs/DETAIL.md"
5
6
  }
6
7
  }
package/locale/zh.json CHANGED
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "meta": {
3
3
  "title": "OpenViking 记忆",
4
- "description": "为 DeepSeek Harness 提供长期语义记忆:每步自动召回、会话采集与提交、viking:// URI 保护,以及 OpenViking MCP 工具与技能。"
4
+ "description": "为 DeepSeek Harness 提供长期语义记忆:每步自动召回、会话采集与提交、viking:// URI 保护,以及 OpenViking MCP 工具与技能。",
5
+ "detail": "docs/DETAIL.zh.md"
5
6
  }
6
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openviking/dsh-memory-plugin",
3
- "version": "0.5.29",
3
+ "version": "0.5.31",
4
4
  "description": "OpenViking memory and context bundle for DeepSeek Harness",
5
5
  "icon": "./icon.svg",
6
6
  "type": "module",
@@ -27,6 +27,7 @@
27
27
  "shared/",
28
28
  "skills/",
29
29
  "locale/",
30
+ "docs/",
30
31
  "cordis.patch.yml",
31
32
  "README.md"
32
33
  ],
package/runtime.mjs CHANGED
@@ -7,7 +7,6 @@ import {
7
7
  listPending,
8
8
  replayPending,
9
9
  } from "./shared/pending-queue.mjs";
10
- import { redactPayload } from "./shared/redact.mjs";
11
10
  import { isRetryableFailure } from "./shared/retryable.mjs";
12
11
  import { resolveEffectivePeerId } from "./shared/workspace-peer.mjs";
13
12
  import {
@@ -151,13 +150,9 @@ export class OpenVikingRuntime {
151
150
  capture(session, event) {
152
151
  const state = this.stateFor(session);
153
152
  if (!isCaptureEnabled(state.config)) return;
154
- const captured = captureEvent(event, state.config, state.toolNames);
155
- if (!captured) return;
153
+ const payload = captureEvent(event, state.config, state.toolNames);
154
+ if (!payload) return;
156
155
  this.enqueueWrite(state, async () => {
157
- // Redacted once, inside the write chain so a slow scan never blocks the
158
- // host's event: the direct POST and the pending queue both carry this
159
- // copy, never the plaintext.
160
- const payload = redactPayload(captured, { tier: state.config.captureRedact });
161
156
  if (state.hasPendingWrites) {
162
157
  await this.enqueuePendingMessage(state, payload);
163
158
  return;
@@ -176,7 +171,6 @@ export class OpenVikingRuntime {
176
171
  state.ovSessionId,
177
172
  payload,
178
173
  state.config.peerId,
179
- { redacted: true },
180
174
  );
181
175
  if (isRetryableFailure(response)) {
182
176
  await this.enqueuePendingMessage(state, payload);
@@ -271,10 +265,7 @@ export class OpenVikingRuntime {
271
265
  async enqueuePending(state, type, payload) {
272
266
  const createdAt = Math.max(Date.now(), state.pendingCreatedAt + 1);
273
267
  state.pendingCreatedAt = createdAt;
274
- const result = await enqueue(type, state.ovSessionId, payload, {
275
- createdAt,
276
- redactTier: state.config.captureRedact,
277
- });
268
+ const result = await enqueue(type, state.ovSessionId, payload, { createdAt });
278
269
  if (result.ok) {
279
270
  // Log the latch transition only: every message that follows while the
280
271
  // latch holds takes the cheap enqueue path, so this fires once per
@@ -343,7 +334,7 @@ export class OpenVikingRuntime {
343
334
  await replayPending(
344
335
  (path, init) => this.client.fetchJSON(path, init),
345
336
  (stage, data) => this.log(stage, data),
346
- { redactTier: this.config.captureRedact, ...options },
337
+ options,
347
338
  );
348
339
  }
349
340
 
@@ -24,11 +24,6 @@
24
24
  * harness per-harness default, where one genuinely differs
25
25
  * min/max clamped, not rejected: a config file must not kill a hook
26
26
  * values the enum's members; anything else falls back to the default
27
- * boolValues enum only: the member a boolean-ish value (`true`/`yes`/`on`,
28
- * `false`/`no`/`off`/`0`) stands for, so `false` can mean "off"
29
- * unknownToDefault
30
- * enum only: a value naming no member resolves to the default
31
- * instead of leaving the lower layer's value standing
32
27
  * env OPENVIKING_* variable, the highest-priority layer
33
28
  * aliases older spellings, honoured forever; the doctor names them
34
29
  * workspace dotted key in `.openviking/config.json`
@@ -156,23 +151,6 @@ export const KNOBS = [
156
151
  // tool results, so it captures them by default.
157
152
  { name: "captureToolResults", type: "bool", default: false, harness: { dsh: true }, env: "OPENVIKING_CAPTURE_TOOL_RESULTS", capability: "capture" },
158
153
  { name: "captureFilters", type: "list", default: [], env: "OPENVIKING_CAPTURE_FILTERS", capability: "capture" },
159
- // Secret redaction of every captured payload before it is sent or queued
160
- // (lib/redact.mjs); the tiers are REDACT_TIERS there, in the same order.
161
- // User-level only — deliberately no `workspace` key, so a repository's
162
- // `.openviking/config.json` cannot switch redaction off for whoever opens it.
163
- // `false` means off rather than "unparseable"; a tier this build does not
164
- // know (a newer config read by an older plugin) means the default, never a
165
- // weaker value left over from a lower layer.
166
- {
167
- name: "captureRedact",
168
- type: "enum",
169
- values: ["off", "standard", "strict"],
170
- default: "standard",
171
- boolValues: { true: "standard", false: "off" },
172
- unknownToDefault: true,
173
- env: "OPENVIKING_CAPTURE_REDACT",
174
- capability: "capture",
175
- },
176
154
  // 0 means "derive from timeoutMs": a write gets a longer budget than a read.
177
155
  { name: "captureTimeoutMs", type: "int", default: 0, min: 0, max: 600000, env: "OPENVIKING_CAPTURE_TIMEOUT_MS", capability: "capture" },
178
156
  { name: "commitTokenThreshold", type: "int", default: 20000, min: 1000, max: 1000000, env: "OPENVIKING_COMMIT_TOKEN_THRESHOLD", workspace: "capture.commit_token_threshold", capability: "capture" },
@@ -284,6 +262,7 @@ export const WORKSPACE_RANGES = Object.fromEntries(
284
262
  */
285
263
  export const HARNESS_KEYS = {
286
264
  claudeCode: "claude_code",
265
+ codebuddy: "codebuddy",
287
266
  codex: "codex",
288
267
  cursor: "cursor",
289
268
  kimicode: "kimicode",
@@ -339,16 +318,8 @@ export function coerceKnobValue(knob, raw, fallback) {
339
318
  return knob.max === undefined ? floored : Math.min(knob.max, floored);
340
319
  }
341
320
  case "enum": {
342
- const values = knob.values || [];
343
321
  const word = String(raw ?? "").trim();
344
- if (values.includes(word)) return word;
345
- if (knob.boolValues) {
346
- const lower = word.toLowerCase();
347
- if (values.includes(lower)) return lower;
348
- if (raw === true || TRUE_WORDS.includes(lower)) return knob.boolValues.true;
349
- if (raw === false || FALSE_WORDS.includes(lower)) return knob.boolValues.false;
350
- }
351
- return knob.unknownToDefault && word ? knobDefault(knob) : fallback;
322
+ return (knob.values || []).includes(word) ? word : fallback;
352
323
  }
353
324
  // A peer template may be one string or an ordered list of fallbacks, and
354
325
  // `String([a, b])` would quietly turn the list into one bogus template.
@@ -11,12 +11,6 @@
11
11
  *
12
12
  * Each file contains: { type, sessionId, payload, createdAt, retries, dedupKey }
13
13
  *
14
- * An addMessage payload is secret-redacted (lib/redact.mjs) before it is
15
- * written, and again before it is replayed: the queue is plaintext on disk, and
16
- * an entry written by an older plugin, or by a caller that skipped redaction,
17
- * must not reach the server as it was. Redaction is idempotent, so replaying an
18
- * already-redacted entry sends the same bytes.
19
- *
20
14
  * Config (env vars):
21
15
  * OPENVIKING_PENDING_DIR pending queue directory
22
16
  * (default: ~/.openviking/pending)
@@ -31,7 +25,6 @@ import { mkdir, readdir, readFile, rename, writeFile, unlink, stat, chmod, utime
31
25
  import { createHash } from "node:crypto";
32
26
  import { join } from "node:path";
33
27
  import { homedir } from "node:os";
34
- import { redactPayload } from "./redact.mjs";
35
28
  import { isRetryableFailure } from "./retryable.mjs";
36
29
 
37
30
  const DEFAULT_MAX_RETRIES = 3;
@@ -191,21 +184,8 @@ async function recoverStaleProcessing(dir) {
191
184
  * @param {object} payload - the data that failed to send
192
185
  * @param {object} options
193
186
  * @param {number} options.createdAt - optional queue timestamp override
194
- * @param {string} [options.redactTier] - the captureRedact tier an addMessage
195
- * payload is redacted under before it is written (default "standard")
196
- * @param {boolean} [options.redacted] - the caller already redacted `payload`
197
- * under its configured tier, so it is written as it is
198
187
  */
199
188
  export async function enqueue(type, sessionId, payload, options = {}) {
200
- if (type === "addMessage" && options.redacted !== true) {
201
- try {
202
- payload = redactPayload(payload, { tier: options.redactTier });
203
- } catch (err) {
204
- // redactPayload fails closed on its own; this is the last line before
205
- // plaintext would be written to disk, so refuse rather than write it.
206
- return { ok: false, error: `redaction failed: ${err?.message || String(err)}` };
207
- }
208
- }
209
189
  const dir = getPendingDir();
210
190
  const now = Number.isFinite(options.createdAt) ? options.createdAt : Date.now();
211
191
  const dedupKey = makeDedupKey(type, sessionId, payload);
@@ -398,8 +378,6 @@ export async function cleanStale() {
398
378
  * a background drainer can keep retrying a transient failure without
399
379
  * burning the session-start retry budget. Exhausted and non-retryable
400
380
  * entries are deleted exactly as in the default mode.
401
- * @param {string} [options.redactTier="standard"] - the captureRedact tier
402
- * every replayed addMessage payload is redacted under before it is sent
403
381
  * @returns {{ replayed: number, failed: number, skipped: number, deferred: number }}
404
382
  */
405
383
  export async function replayPending(fetchJSON, log, options = {}) {
@@ -444,7 +422,7 @@ export async function replayPending(fetchJSON, log, options = {}) {
444
422
  if (entry.type === "addMessage") {
445
423
  res = await fetchJSON(`/api/v1/sessions/${encodedSid}/messages`, {
446
424
  method: "POST",
447
- body: JSON.stringify(redactPayload(entry.payload, { tier: options.redactTier })),
425
+ body: JSON.stringify(entry.payload),
448
426
  });
449
427
  } else if (entry.type === "commitSession") {
450
428
  res = await fetchJSON(`/api/v1/sessions/${encodedSid}/commit`, {