@openviking/opencode-plugin 2026.10.14 → 2026.10.15-1

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.
@@ -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,
@@ -301,7 +316,11 @@ export function createMemorySessionManager({ config, pluginRoot }) {
301
316
  const run = (state.flushChain ?? Promise.resolve()).then(async () => {
302
317
  const added = await flushPendingMessages(opencodeSessionId, state)
303
318
  if (commit && isCaptureEnabled(config)) {
304
- await commitOvSession(state.ovSessionId, { force: true, reason })
319
+ const result = await commitOvSession(state.ovSessionId, { force: true, reason })
320
+ // Server lost the session (reset/reinstall); drop the stale mapping.
321
+ if (result.status === "not_found" && sessions.get(opencodeSessionId) === state) {
322
+ sessions.delete(opencodeSessionId)
323
+ }
305
324
  } else if (added > 0) {
306
325
  await maybeCommitByThreshold(state)
307
326
  }
@@ -500,6 +519,14 @@ export function createMemorySessionManager({ config, pluginRoot }) {
500
519
  })
501
520
  return { status: "queued" }
502
521
  }
522
+ if (res.status === 404) {
523
+ log("WARN", "session", "OpenViking session not found", {
524
+ openviking_session: ovSessionId,
525
+ reason,
526
+ trace_id: res.traceId,
527
+ })
528
+ return { status: "not_found" }
529
+ }
503
530
  log("ERROR", "session", "Failed to commit OpenViking session", {
504
531
  openviking_session: ovSessionId,
505
532
  reason,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openviking/opencode-plugin",
3
- "version": "2026.10.14",
3
+ "version": "2026.10.15-1",
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": "e05460914532ba0a61d7bf859fc16b95e88d2194"
49
+ "openvikingSourceCommit": "a0c357417199198b45d5adf6f05f8d1551d0d41d"
50
50
  }