@openviking/opencode-plugin 2026.10.13 → 2026.10.15

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/INSTALL-ZH.md CHANGED
@@ -28,9 +28,19 @@ openviking-server --config ~/.openviking/ov.conf
28
28
  curl http://localhost:1933/health
29
29
  ```
30
30
 
31
- ## 安装方式一:发布包安装
31
+ ## 安装方式一:一键安装(推荐)
32
32
 
33
- 普通用户推荐通过 OpenCode 的 package plugin 机制启用:
33
+ OpenCode 与其他记忆插件共用同一个安装器。它会询问要安装的宿主和 OpenViking 凭据:
34
+
35
+ ```bash
36
+ curl -fsSL https://openviking.ai/install | bash
37
+ ```
38
+
39
+ 安装器会把插件作为本地文件插件复制到 `~/.config/opencode/plugins/`,把 `openviking` MCP server 条目写进 `~/.config/opencode/opencode.json`,并配置 `~/.openviking/ovcli.conf`。
40
+
41
+ ## 安装方式二:发布包安装
42
+
43
+ 也可以通过 OpenCode 的 package plugin 机制启用:
34
44
 
35
45
  ```json
36
46
  {
@@ -40,7 +50,7 @@ curl http://localhost:1933/health
40
50
 
41
51
  这份 `plugin` 配置同时兼容 v1 和 v2;v2 会在加载时规范化为原生的 `plugins`,无需手工迁移配置。
42
52
 
43
- ## 安装方式二:源码安装
53
+ ## 安装方式三:源码安装
44
54
 
45
55
  用于开发调试或 PR 测试。OpenCode 推荐插件目录:
46
56
 
package/INSTALL.md CHANGED
@@ -28,9 +28,19 @@ Check the service:
28
28
  curl http://localhost:1933/health
29
29
  ```
30
30
 
31
- ## Installation Method 1: Published Package
31
+ ## Installation Method 1: One-line Installer (Recommended)
32
32
 
33
- Normal users are recommended to enable it through OpenCode's package plugin mechanism:
33
+ OpenCode shares the unified installer with the other memory plugins. It asks which harnesses to install and for your OpenViking credentials:
34
+
35
+ ```bash
36
+ curl -fsSL https://openviking.ai/install | bash
37
+ ```
38
+
39
+ The installer copies the plugin into `~/.config/opencode/plugins/` as a local file plugin, writes the `openviking` MCP server entry into `~/.config/opencode/opencode.json`, and configures `~/.openviking/ovcli.conf`.
40
+
41
+ ## Installation Method 2: Published Package
42
+
43
+ To enable it through OpenCode's package plugin mechanism instead:
34
44
 
35
45
  ```json
36
46
  {
@@ -40,7 +50,7 @@ Normal users are recommended to enable it through OpenCode's package plugin mech
40
50
 
41
51
  This `plugin` entry works on both v1 and v2. OpenCode v2 normalizes it to the native `plugins` form at load time, so no manual config migration is required.
42
52
 
43
- ## Installation Method 2: Source Install
53
+ ## Installation Method 3: Source Install
44
54
 
45
55
  Use this method for development, debugging, or PR testing. OpenCode's recommended plugin directory is:
46
56
 
package/README.md CHANGED
@@ -68,9 +68,19 @@ openviking-server --config ~/.openviking/ov.conf
68
68
 
69
69
  ## Installation
70
70
 
71
+ ### One-line Installer (Recommended)
72
+
73
+ OpenCode shares the unified installer with the other memory plugins. It asks which harnesses to install and for your OpenViking credentials:
74
+
75
+ ```bash
76
+ curl -fsSL https://openviking.ai/install | bash
77
+ ```
78
+
79
+ The installer copies the plugin into `~/.config/opencode/plugins/` as a local file plugin, writes the `openviking` MCP server entry into `~/.config/opencode/opencode.json`, and configures `~/.openviking/ovcli.conf`.
80
+
71
81
  ### Published Package
72
82
 
73
- Normal users should enable it through OpenCode's package plugin mechanism:
83
+ To enable it through OpenCode's package plugin mechanism instead:
74
84
 
75
85
  The published npm package is `@openviking/opencode-plugin`; verify availability with:
76
86
 
@@ -25,6 +25,8 @@ import {
25
25
  safeStringify,
26
26
  } from "./utils.mjs"
27
27
 
28
+ const STALE_SESSION_STATE_MS = 7 * 24 * 60 * 60 * 1000
29
+
28
30
  export function createMemorySessionManager({ config, pluginRoot }) {
29
31
  const sessions = new Map()
30
32
  const statePath = path.join(pluginRoot, "openviking-session-state.json")
@@ -77,10 +79,17 @@ export function createMemorySessionManager({ config, pluginRoot }) {
77
79
  log("ERROR", "persistence", "Unsupported session map version", { version: data.version })
78
80
  return
79
81
  }
82
+ const staleBefore = Date.now() - STALE_SESSION_STATE_MS
83
+ let pruned = 0
80
84
  for (const [opencodeSessionId, persisted] of Object.entries(data.sessions ?? {})) {
85
+ if (isPrunable(persisted, staleBefore)) {
86
+ pruned += 1
87
+ continue
88
+ }
81
89
  sessions.set(opencodeSessionId, deserializeSessionState(persisted))
82
90
  }
83
- log("INFO", "persistence", "Session state loaded", { count: sessions.size })
91
+ log("INFO", "persistence", "Session state loaded", { count: sessions.size, pruned })
92
+ if (pruned > 0) await enqueueSave()
84
93
  } catch (error) {
85
94
  log("ERROR", "persistence", "Failed to load session state", { error: error?.message })
86
95
  if (fs.existsSync(statePath)) {
@@ -133,6 +142,12 @@ export function createMemorySessionManager({ config, pluginRoot }) {
133
142
  }
134
143
  }
135
144
 
145
+ // A stale session whose messages are all captured holds nothing left to send.
146
+ function isPrunable(persisted, staleBefore) {
147
+ if ((persisted.lastActivityAt ?? 0) >= staleBefore) return false
148
+ return (persisted.messages ?? []).every(([, message]) => message.captured)
149
+ }
150
+
136
151
  function deserializeSessionState(persisted) {
137
152
  return {
138
153
  ovSessionId: persisted.ovSessionId,
@@ -17,6 +17,8 @@
17
17
  // that asks for less than a second gets a second.
18
18
  const MIN_TIMEOUT_MS = 1000;
19
19
 
20
+ import { parseExtraHeaders } from "./mcp-proxy-config.mjs";
21
+
20
22
  /**
21
23
  * The headers every harness puts on every OpenViking request.
22
24
  *
@@ -59,6 +61,12 @@ export function createOvHttp(cfg = {}, {
59
61
  } = {}) {
60
62
  // dsh and pi name this field `endpoint`; every other harness names it `baseUrl`.
61
63
  const baseUrl = cfg.baseUrl || cfg.endpoint || "";
64
+ // A caller that owns its header map passes it in; every other harness gets the
65
+ // operator's escape hatch from the environment. A deployment behind an
66
+ // authenticating gateway (Cloudflare Access, oauth2-proxy, mTLS-terminating proxy)
67
+ // needs the same headers on the turn hooks as on the MCP path, and wiring each
68
+ // harness by hand is how the header blocks drifted in the first place.
69
+ const resolvedExtraHeaders = extraHeaders ?? parseExtraHeaders(process.env.OPENVIKING_EXTRA_HEADERS);
62
70
  return async function fetchJSON(path, init = {}, options = {}) {
63
71
  const timeoutMs = Math.max(MIN_TIMEOUT_MS, Number(options.timeoutMs) || Number(defaultTimeoutMs) || 0);
64
72
  const controller = new AbortController();
@@ -72,7 +80,7 @@ export function createOvHttp(cfg = {}, {
72
80
  ...buildOvHeaders(cfg, {
73
81
  actorPeerId: options.actorPeerId ?? resolveActorPeerId(),
74
82
  identityHeaders,
75
- extraHeaders,
83
+ extraHeaders: resolvedExtraHeaders,
76
84
  }),
77
85
  ...(init.headers || {}),
78
86
  };
@@ -81,6 +89,19 @@ export function createOvHttp(cfg = {}, {
81
89
  if (!(error instanceof SyntaxError)) throw error;
82
90
  return null;
83
91
  });
92
+ const contentType = response.headers.get("content-type") || "";
93
+ if (body === null && response.ok && contentType && !/json/i.test(contentType)) {
94
+ // A 2xx that is not JSON is not OpenViking. An authenticating gateway's login
95
+ // page, a captive portal or a WAF page answers with 200 and HTML; calling that a
96
+ // success makes a harness believe it is connected while every capture and recall
97
+ // is quietly dropped.
98
+ return {
99
+ ok: false,
100
+ status: response.status,
101
+ result: null,
102
+ error: { message: `non-JSON response (${contentType})` },
103
+ };
104
+ }
84
105
  if (requireJsonBody && !body) {
85
106
  return {
86
107
  ok: false,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openviking/opencode-plugin",
3
- "version": "2026.10.13",
3
+ "version": "2026.10.15",
4
4
  "author": "@openviking",
5
5
  "description": "Unified OpenCode plugin for OpenViking repository retrieval and long-term memory",
6
6
  "type": "module",
@@ -46,5 +46,5 @@
46
46
  "code-search"
47
47
  ],
48
48
  "license": "Apache-2.0",
49
- "openvikingSourceCommit": "22ea8c7b34602fddc8b6194fea361f8ed0e79e7c"
49
+ "openvikingSourceCommit": "60629f92bfd7d05c67bc50aa452f852acbc77c39"
50
50
  }