@witness-ai/opencode 0.6.0 → 0.6.1-beta.0

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.
Files changed (2) hide show
  1. package/package.json +3 -3
  2. package/witness.js +30 -10
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@witness-ai/opencode",
3
3
  "mcpName": "io.github.IngTian/witness",
4
- "version": "0.6.0",
4
+ "version": "0.6.1-beta.0",
5
5
  "description": "MCP memory / second brain for Claude Code & OpenCode — captures your coding sessions and distills how your knowledge and habits evolve over time, queryable by your agent.",
6
6
  "type": "module",
7
7
  "main": "./witness.js",
@@ -21,8 +21,8 @@
21
21
  "README.md"
22
22
  ],
23
23
  "optionalDependencies": {
24
- "@witness-ai/opencode-darwin-arm64": "0.6.0",
25
- "@witness-ai/opencode-linux-x64": "0.6.0"
24
+ "@witness-ai/opencode-darwin-arm64": "0.6.1-beta.0",
25
+ "@witness-ai/opencode-linux-x64": "0.6.1-beta.0"
26
26
  },
27
27
  "keywords": [
28
28
  "mcp",
package/witness.js CHANGED
@@ -8,6 +8,7 @@ const DOWNLOAD_RETRY_MAX = 6
8
8
  const DOWNLOAD_RETRY_BASE_MS = 1000
9
9
  const DOWNLOAD_RETRY_CAP_MS = 30000
10
10
  const IMPORT_GRACE_MS = 5000
11
+ const QUIET_PERIOD_MS = 5 * 60 * 1000
11
12
 
12
13
  const platformBin = platformWitnessBin()
13
14
  const WITNESS_BIN = globalThis.WITNESS_SHIM || process.env.WITNESS_BIN || (existsSync(platformBin) ? platformBin : "")
@@ -78,13 +79,14 @@ const plugin = async () => {
78
79
  let disposing = false
79
80
  let disposePromise = null
80
81
  let retryTimer = null
82
+ let quietTimer = null
81
83
  let download = null
82
84
  let activeImport = null
83
85
  let activeWaiters = null
84
86
  let globalImportPending = false
85
87
  const pendingSessions = new Set()
86
88
  const sessionWaiters = new Map()
87
- const modernIdleWaiters = new Map()
89
+ const idleCycles = new Map()
88
90
  const idleWaiters = []
89
91
 
90
92
  function clearRetry() {
@@ -92,6 +94,21 @@ const plugin = async () => {
92
94
  retryTimer = null
93
95
  }
94
96
 
97
+ function clearQuietTimer() {
98
+ if (quietTimer) clearTimeout(quietTimer)
99
+ quietTimer = null
100
+ }
101
+
102
+ function scheduleQuietWorker() {
103
+ clearQuietTimer()
104
+ quietTimer = setTimeout(() => {
105
+ quietTimer = null
106
+ if (disposed || disposing) return
107
+ spawnWitness(["worker-run", "--auto"])
108
+ }, QUIET_PERIOD_MS)
109
+ quietTimer.unref?.()
110
+ }
111
+
95
112
  function scheduleRetry(attempt) {
96
113
  if (disposed || disposing || process.env.WITNESS_SKIP_MODEL_DOWNLOAD === "1" || modelReady(PACKAGE_ROOT) || attempt > DOWNLOAD_RETRY_MAX) return
97
114
  clearRetry()
@@ -123,7 +140,7 @@ const plugin = async () => {
123
140
  }
124
141
 
125
142
  function syncOpenCode(sessions = []) {
126
- const args = ["import", "--agent", "opencode", "--quiet", "--auto"]
143
+ const args = ["import", "--agent", "opencode", "--quiet"]
127
144
  for (const sessionID of sessions) args.push("--session", sessionID)
128
145
  const proc = spawnWitness(args)
129
146
  if (!proc) return
@@ -225,7 +242,8 @@ const plugin = async () => {
225
242
  if (disposePromise) return disposePromise
226
243
  disposing = true
227
244
  clearRetry()
228
- modernIdleWaiters.clear()
245
+ clearQuietTimer()
246
+ idleCycles.clear()
229
247
  disposePromise = (async () => {
230
248
  let timer
231
249
  const drained = await Promise.race([
@@ -262,19 +280,21 @@ const plugin = async () => {
262
280
  const type = eventType(event)
263
281
  const sessionID = event?.properties?.sessionID
264
282
  const modernIdle = type === "session.status" && event?.properties?.status?.type === "idle"
265
- if (type === "session.idle" && sessionID && modernIdleWaiters.has(sessionID)) {
266
- const done = modernIdleWaiters.get(sessionID)
267
- modernIdleWaiters.delete(sessionID)
268
- return done
269
- }
270
283
  if ((type === "session.idle" || modernIdle) && sessionID) {
284
+ const existing = idleCycles.get(sessionID)
285
+ if (existing) return existing
271
286
  clearRetry()
272
287
  ensureDownload()
273
288
  const done = syncSessions(sessionID)
274
- if (modernIdle) modernIdleWaiters.set(sessionID, done)
289
+ idleCycles.set(sessionID, done)
290
+ scheduleQuietWorker()
275
291
  return done
276
292
  }
277
- if (type === "session.status" && sessionID) modernIdleWaiters.delete(sessionID)
293
+ const sessionActivity = sessionID && (type.startsWith("message.") || type.startsWith("session."))
294
+ if (sessionActivity) {
295
+ if (sessionID) idleCycles.delete(sessionID)
296
+ clearQuietTimer()
297
+ }
278
298
  },
279
299
  }
280
300
  }