opencode-raven 1.2.6 → 1.2.7
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 +3 -2
- package/index.ts +63 -10
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -40,7 +40,7 @@ Restart opencode.
|
|
|
40
40
|
|
|
41
41
|
| Command | Action |
|
|
42
42
|
|---------|--------|
|
|
43
|
-
| `/raven` | Show status — enabled/disabled, model, reasoning effort, timeout |
|
|
43
|
+
| `/raven` | Show status — enabled/disabled, version, update availability, model, reasoning effort, timeout (no args) |
|
|
44
44
|
| `/raven on` | Enable search tool redirection (default) |
|
|
45
45
|
| `/raven off` | Disable interception — all agents can use search tools directly |
|
|
46
46
|
| `/raven update` | Check npm for a newer Raven, clear opencode's plugin cache if needed, then restart opencode |
|
|
@@ -55,7 +55,7 @@ Config persists across restarts in `~/.config/opencode/raven-config.json` (globa
|
|
|
55
55
|
|
|
56
56
|
opencode caches npm plugins, so `"opencode-raven"` / `"opencode-raven@latest"` may not automatically refresh after a new npm release.
|
|
57
57
|
|
|
58
|
-
Raven checks npm
|
|
58
|
+
Raven checks npm after the TUI starts. If an update is available, it shows a notification. `/raven` also shows the current version and update availability. To update:
|
|
59
59
|
|
|
60
60
|
```txt
|
|
61
61
|
/raven update
|
|
@@ -168,6 +168,7 @@ To disable an MCP entirely:
|
|
|
168
168
|
| `config` | Registers Raven agent, merges Context7/Exa/Grep.app MCP defaults, loads MCP guidance |
|
|
169
169
|
| `tool` | Registers `raven_seek` — creates Raven sessions with timeout, error recovery, timing, and session tree visibility. Tracks context processed for stats (both `raven_seek` and direct `@Raven`). |
|
|
170
170
|
| `chat.message` | Tracks agent ↔ session mapping for allowlist and Raven exclusion |
|
|
171
|
+
| `event` | Shows startup update notifications after the TUI event stream is ready |
|
|
171
172
|
| `command.execute.before` | Handles `/raven on\|off\|update\|model\|effort\|timeout\|stats\|status` |
|
|
172
173
|
| `tool.execute.before` | Blocks search tools for non-Raven, non-excluded agents (respects `excludeTools`). Error output gives the next `raven_seek(query="...")` call. Injects concise `<raven_guidance>` into subagent prompts. |
|
|
173
174
|
| `tool.execute.after` | Counts output bytes from direct `@Raven` calls for accurate stats. |
|
package/index.ts
CHANGED
|
@@ -263,6 +263,9 @@ export default ((input: PluginInput) => {
|
|
|
263
263
|
const ravenSessions = new Set<string>()
|
|
264
264
|
const ravenTaskCalls = new Set<string>()
|
|
265
265
|
const sessionAgents = new Map<string, string>()
|
|
266
|
+
let updateInfo: { current: string; latest?: string; available: boolean } | undefined
|
|
267
|
+
let updateCheckPromise: Promise<{ current: string; latest?: string; available: boolean }> | undefined
|
|
268
|
+
let updateToastPending = false
|
|
266
269
|
|
|
267
270
|
// ── Check if an agent is excluded from Raven enforcement (case-insensitive) ──
|
|
268
271
|
function isExcluded(agent: string | undefined): boolean {
|
|
@@ -320,12 +323,19 @@ export default ((input: PluginInput) => {
|
|
|
320
323
|
}
|
|
321
324
|
|
|
322
325
|
async function fetchLatestVersion(): Promise<string | undefined> {
|
|
323
|
-
const
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
326
|
+
const controller = new AbortController()
|
|
327
|
+
const timeout = setTimeout(() => controller.abort(), 5000)
|
|
328
|
+
try {
|
|
329
|
+
const res = await fetch(`https://registry.npmjs.org/${PACKAGE_NAME}/latest`, {
|
|
330
|
+
headers: { accept: "application/json" },
|
|
331
|
+
signal: controller.signal,
|
|
332
|
+
})
|
|
333
|
+
if (!res.ok) return undefined
|
|
334
|
+
const data = await res.json() as { version?: string }
|
|
335
|
+
return data.version
|
|
336
|
+
} finally {
|
|
337
|
+
clearTimeout(timeout)
|
|
338
|
+
}
|
|
329
339
|
}
|
|
330
340
|
|
|
331
341
|
async function checkForUpdate(): Promise<{ current: string; latest?: string; available: boolean }> {
|
|
@@ -333,6 +343,36 @@ export default ((input: PluginInput) => {
|
|
|
333
343
|
return { current: PACKAGE_VERSION, latest, available: !!latest && compareVersions(latest, PACKAGE_VERSION) > 0 }
|
|
334
344
|
}
|
|
335
345
|
|
|
346
|
+
async function getUpdateInfo(): Promise<{ current: string; latest?: string; available: boolean }> {
|
|
347
|
+
if (updateInfo) return updateInfo
|
|
348
|
+
if (!updateCheckPromise) {
|
|
349
|
+
updateCheckPromise = checkForUpdate()
|
|
350
|
+
.then((info) => {
|
|
351
|
+
updateInfo = info
|
|
352
|
+
return info
|
|
353
|
+
})
|
|
354
|
+
.catch((err) => {
|
|
355
|
+
updateCheckPromise = undefined
|
|
356
|
+
throw err
|
|
357
|
+
})
|
|
358
|
+
}
|
|
359
|
+
return updateCheckPromise
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
async function refreshUpdateInfo(): Promise<{ current: string; latest?: string; available: boolean }> {
|
|
363
|
+
updateInfo = undefined
|
|
364
|
+
updateCheckPromise = checkForUpdate()
|
|
365
|
+
.then((info) => {
|
|
366
|
+
updateInfo = info
|
|
367
|
+
return info
|
|
368
|
+
})
|
|
369
|
+
.catch((err) => {
|
|
370
|
+
updateCheckPromise = undefined
|
|
371
|
+
throw err
|
|
372
|
+
})
|
|
373
|
+
return updateCheckPromise
|
|
374
|
+
}
|
|
375
|
+
|
|
336
376
|
function clearPluginCache(): string[] {
|
|
337
377
|
const packagesDir = join(homedir(), ".cache", "opencode", "packages")
|
|
338
378
|
if (!existsSync(packagesDir)) return []
|
|
@@ -353,7 +393,7 @@ export default ((input: PluginInput) => {
|
|
|
353
393
|
|
|
354
394
|
async function notifyIfUpdateAvailable() {
|
|
355
395
|
try {
|
|
356
|
-
const info = await
|
|
396
|
+
const info = await getUpdateInfo()
|
|
357
397
|
if (!info.available || !info.latest) return
|
|
358
398
|
await (client as any).tui?.showToast?.({
|
|
359
399
|
body: {
|
|
@@ -417,7 +457,7 @@ export default ((input: PluginInput) => {
|
|
|
417
457
|
}
|
|
418
458
|
}
|
|
419
459
|
|
|
420
|
-
|
|
460
|
+
updateToastPending = true
|
|
421
461
|
},
|
|
422
462
|
|
|
423
463
|
// Register raven_seek tool — lets agents with task:false still search through Raven
|
|
@@ -510,6 +550,12 @@ export default ((input: PluginInput) => {
|
|
|
510
550
|
}
|
|
511
551
|
},
|
|
512
552
|
|
|
553
|
+
event() {
|
|
554
|
+
if (!updateToastPending) return
|
|
555
|
+
updateToastPending = false
|
|
556
|
+
setTimeout(() => void notifyIfUpdateAvailable(), 500)
|
|
557
|
+
},
|
|
558
|
+
|
|
513
559
|
// /raven on|off|model <name>|effort <value>|timeout <seconds>|stats|status
|
|
514
560
|
async "command.execute.before"(input: any, output: any) {
|
|
515
561
|
if (input.command !== "raven") return
|
|
@@ -529,7 +575,7 @@ export default ((input: PluginInput) => {
|
|
|
529
575
|
output.parts.push({ type: "text", text: `Raven context processed:\n This session: ${formatBytes(sessionBytes)} (~${formatTokens(sessionBytes)} tokens)\n All time: ${formatBytes(totalBytes)} (~${formatTokens(totalBytes)} tokens)` })
|
|
530
576
|
} else if (arg === "update") {
|
|
531
577
|
try {
|
|
532
|
-
const info = await
|
|
578
|
+
const info = await refreshUpdateInfo()
|
|
533
579
|
if (!info.latest) {
|
|
534
580
|
output.parts.push({ type: "text", text: `Could not check npm for ${PACKAGE_NAME}. Try again later.\n\n${manualUpdateText()}` })
|
|
535
581
|
} else if (!info.available) {
|
|
@@ -573,7 +619,14 @@ export default ((input: PluginInput) => {
|
|
|
573
619
|
const model = config.model || fm.model || "(default)"
|
|
574
620
|
const effort = config.reasoning_effort || fm.reasoning_effort || "(default)"
|
|
575
621
|
const timeout = config.timeout ?? 180
|
|
576
|
-
|
|
622
|
+
let update = "Update: unable to check npm."
|
|
623
|
+
try {
|
|
624
|
+
const info = await getUpdateInfo()
|
|
625
|
+
update = info.available && info.latest
|
|
626
|
+
? `Update: ${info.latest} available. Run /raven update, then restart opencode.`
|
|
627
|
+
: `Update: up to date${info.latest ? ` (latest ${info.latest})` : ""}.`
|
|
628
|
+
} catch { /* keep fallback */ }
|
|
629
|
+
output.parts.push({ type: "text", text: `Raven is ${enabled}. Version: ${PACKAGE_VERSION}. Model: ${model}. Reasoning: ${effort}. Timeout: ${timeout}s\n${update}\n\nCommands:\n /raven on — enable search interception\n /raven off — disable search interception\n /raven update — check npm, clear plugin cache if newer, then restart opencode\n /raven model <name> — change Raven's model (requires restart)\n /raven effort <value> — change Raven's reasoning effort (requires restart)\n /raven timeout <seconds> — change raven_seek timeout\n /raven stats — show blocked calls and context saved` })
|
|
577
630
|
}
|
|
578
631
|
},
|
|
579
632
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencode-raven",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.7",
|
|
4
4
|
"description": "Search-first subagent for opencode — intercepts search tools and routes them through a hidden Raven agent with Context7, Exa AI, and Grep.app MCPs",
|
|
5
5
|
"main": "./index.ts",
|
|
6
6
|
"exports": {
|