@openviking/dsh-memory-plugin 0.5.23 → 0.5.25

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/config.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  import { buildPluginConfig } from "./shared/plugin-config.mjs";
2
2
  import { loadCredentialFiles } from "./shared/credentials.mjs";
3
3
 
4
- export const PLUGIN_VERSION = "0.5.23";
4
+ export const PLUGIN_VERSION = "0.5.25";
5
5
 
6
6
  /**
7
7
  * Namespace for the bridged OpenViking MCP tools. DSH publishes every MCP tool
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openviking/dsh-memory-plugin",
3
- "version": "0.5.23",
3
+ "version": "0.5.25",
4
4
  "description": "OpenViking memory and context bundle for DeepSeek Harness",
5
5
  "icon": "./icon.svg",
6
6
  "type": "module",
package/runtime.mjs CHANGED
@@ -179,22 +179,27 @@ export class OpenVikingRuntime {
179
179
  }
180
180
 
181
181
  maybeCommit(session, event) {
182
- if (event.type !== "turn/end") return;
182
+ // DSH appends compaction/start before it summarizes and rewrites history,
183
+ // so commit there regardless of the threshold, like PreCompact elsewhere.
184
+ const boundary = event.type === "compaction/start";
185
+ if (event.type !== "turn/end" && !boundary) return;
183
186
  const state = this.stateFor(session);
184
187
  if (!isCaptureEnabled(state.config)) return;
185
188
  this.enqueueWrite(state, async () => {
186
189
  if (state.hasPendingWrites) return;
187
190
  if (!state.ready && !(await this.ensureState(state)).ready) return;
188
- const metadata = await this.client.getSession(
189
- state.ovSessionId,
190
- state.config.peerId,
191
- );
192
- if (Number(metadata?.pending_tokens || 0) < state.config.commitTokenThreshold) return;
191
+ if (!boundary) {
192
+ const metadata = await this.client.getSession(
193
+ state.ovSessionId,
194
+ state.config.peerId,
195
+ );
196
+ if (Number(metadata?.pending_tokens || 0) < state.config.commitTokenThreshold) return;
197
+ }
193
198
  const response = await this.client.commitSession(
194
199
  state.ovSessionId,
195
200
  state.config.peerId,
196
201
  );
197
- this.log("commit", {
202
+ this.log(boundary ? "compaction_commit" : "commit", {
198
203
  sessionId: state.ovSessionId,
199
204
  ok: response.ok,
200
205
  trace_id: response.result?.trace_id || response.traceId,
@@ -102,7 +102,7 @@ function parseSseMessages(text) {
102
102
  messages.push(JSON.parse(data));
103
103
  }
104
104
 
105
- for (const rawLine of String(text || "").split(/\r?\n/)) {
105
+ for (const rawLine of String(text || "").split(/\r\n|\r|\n/)) {
106
106
  if (rawLine === "") {
107
107
  flush();
108
108
  continue;
@@ -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,