opencode-raven 2.3.3 → 2.3.5
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/CHANGELOG.md +11 -0
- package/README.md +2 -2
- package/package.json +1 -1
- package/raven-core.ts +25 -22
- package/v2.ts +2 -11
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 2.3.5
|
|
4
|
+
|
|
5
|
+
### Changed
|
|
6
|
+
- OpenCode 2 now auto-approves any otherwise-asking permission inside Raven Search and Raven MCP, including skill loading, instead of maintaining a tool allowlist. Explicit denials, edit and nested-delegation restrictions, and other agents' permissions remain unchanged.
|
|
7
|
+
- Documented that Raven's unattended execution is trusted rather than read-only: shell commands and MCP tools can modify the system or external services.
|
|
8
|
+
|
|
9
|
+
## 2.3.4
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
- Raven Search and MCP follow-ups now validate against the calling session's project instead of the plugin's loading project, avoiding incorrect ownership rejections in OpenCode 2 while preserving parent-session and agent checks.
|
|
13
|
+
|
|
3
14
|
## 2.3.3
|
|
4
15
|
|
|
5
16
|
### Fixed
|
package/README.md
CHANGED
|
@@ -138,7 +138,7 @@ Under the hood, Raven registers two public delegation tools and one internal bri
|
|
|
138
138
|
| `raven_mcp` | Creates or resumes a Raven MCP session for online research using built-in web tools, global or on-demand MCPs, and local retrieval tools when needed for context. No MCP is required. |
|
|
139
139
|
| `raven_mcp_bridge` | Internal bridge used only by the Raven MCP agent. |
|
|
140
140
|
|
|
141
|
-
On OpenCode V2, Raven auto-approves permission checks for the public `raven_seek` and `raven_mcp` delegation tools instead of prompting on every call. Inside either Raven agent,
|
|
141
|
+
On OpenCode V2, Raven auto-approves permission checks for the public `raven_seek` and `raven_mcp` delegation tools instead of prompting on every call. Inside either Raven agent, any permission check that would otherwise ask is automatically approved, including skill loading and MCP calls. Explicit deny rules still apply. These execution-time approvals do not add a blanket agent permission or change the main agent's tool permissions, model request, or access restrictions on the internal MCP bridge.
|
|
142
142
|
|
|
143
143
|
For a related follow-up, the main agent can reuse the ID returned by the earlier call:
|
|
144
144
|
|
|
@@ -288,7 +288,7 @@ Raven is optimized for autonomous retrieval:
|
|
|
288
288
|
|
|
289
289
|
- Raven Search has read, search, unrestricted shell, external-directory, and globally configured MCP access without normal permission prompts.
|
|
290
290
|
- Raven MCP has the same retrieval access as Raven Search, plus the internal on-demand MCP bridge. It can use built-in web tools without an MCP and inspect local files for research context.
|
|
291
|
-
- Both agents deny edit tools and nested delegation, but shell access is not a read-only sandbox and can modify the system.
|
|
291
|
+
- Both agents deny edit tools and nested delegation, but shell access is not a read-only sandbox and can modify the system. MCP tools may also modify external systems; V2 auto-approval trusts the Raven agents rather than enforcing read-only execution.
|
|
292
292
|
- Queries are sent to Raven's configured model provider.
|
|
293
293
|
- Remote MCP requests are sent to their services; local MCP entries launch local commands and inherit environment values.
|
|
294
294
|
- Startup performs an npm update check and probes enabled on-demand MCPs.
|
package/package.json
CHANGED
package/raven-core.ts
CHANGED
|
@@ -1756,17 +1756,20 @@ Then restart opencode for the model change to take effect. If the task can be co
|
|
|
1756
1756
|
return kind === "mcp" ? "Raven MCP" : "Raven Seek"
|
|
1757
1757
|
}
|
|
1758
1758
|
|
|
1759
|
-
async function
|
|
1760
|
-
let current = sessionId
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
const
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1759
|
+
async function rootSessionScope(sessionId: string, signal?: AbortSignal): Promise<{ rootId: string; projectID: string }> {
|
|
1760
|
+
let current = sessionId
|
|
1761
|
+
let projectID = input.project.id
|
|
1762
|
+
const seen = new Set<string>()
|
|
1763
|
+
while (!seen.has(current)) {
|
|
1764
|
+
seen.add(current)
|
|
1765
|
+
const response = await client.session.get({ path: { id: current }, signal })
|
|
1766
|
+
const session = (response as any)?.data ?? response
|
|
1767
|
+
// V2's plugin loading project can differ from the calling session's project.
|
|
1768
|
+
if (current === sessionId) projectID = session?.projectID ?? projectID
|
|
1769
|
+
if (!session?.parentID) return { rootId: current, projectID }
|
|
1770
|
+
current = session.parentID
|
|
1771
|
+
}
|
|
1772
|
+
return { rootId: sessionId, projectID }
|
|
1770
1773
|
}
|
|
1771
1774
|
|
|
1772
1775
|
async function syncCreatedSession(sessionId: string, title: string, signal?: AbortSignal) {
|
|
@@ -1803,9 +1806,9 @@ Then restart opencode for the model change to take effect. If the task can be co
|
|
|
1803
1806
|
return { title, output: "Cannot resume Raven: sessionId must not be empty." }
|
|
1804
1807
|
}
|
|
1805
1808
|
|
|
1806
|
-
let
|
|
1807
|
-
try {
|
|
1808
|
-
|
|
1809
|
+
let scope = { rootId: context.sessionID, projectID: input.project.id }
|
|
1810
|
+
try {
|
|
1811
|
+
scope = await rootSessionScope(context.sessionID, context.abort)
|
|
1809
1812
|
} catch (error) {
|
|
1810
1813
|
if (context.abort.aborted) throw error
|
|
1811
1814
|
// Falling back preserves delegation if an older OpenCode build cannot read the caller session.
|
|
@@ -1826,8 +1829,8 @@ Then restart opencode for the model change to take effect. If the task can be co
|
|
|
1826
1829
|
if (!existingSession?.id || existingSession.id !== requestedSessionId) {
|
|
1827
1830
|
return { title, output: `Cannot resume Raven session ${requestedSessionId}: the session was not found or could not be read.` }
|
|
1828
1831
|
}
|
|
1829
|
-
const validParent = existingSession.parentID === rootId || existingSession.parentID === context.sessionID
|
|
1830
|
-
if (!validParent || existingSession.projectID !==
|
|
1832
|
+
const validParent = existingSession.parentID === scope.rootId || existingSession.parentID === context.sessionID
|
|
1833
|
+
if (!validParent || existingSession.projectID !== scope.projectID) {
|
|
1831
1834
|
return { title, output: "Cannot resume Raven: sessionId is not part of this main session's Raven tree." }
|
|
1832
1835
|
}
|
|
1833
1836
|
|
|
@@ -1859,7 +1862,7 @@ Then restart opencode for the model change to take effect. If the task can be co
|
|
|
1859
1862
|
const sessionTitle = `${toolName}: ${args.query.slice(0, 80)}`
|
|
1860
1863
|
const session = await client.session.create({
|
|
1861
1864
|
body: {
|
|
1862
|
-
parentID: rootId,
|
|
1865
|
+
parentID: scope.rootId,
|
|
1863
1866
|
title: sessionTitle,
|
|
1864
1867
|
...(host === "v2" ? { agent } : {}),
|
|
1865
1868
|
},
|
|
@@ -2124,9 +2127,9 @@ Then restart opencode for the model change to take effect. If the task can be co
|
|
|
2124
2127
|
return { title: "Raven Seek", output: "Cannot resume Raven: sessionId must not be empty." }
|
|
2125
2128
|
}
|
|
2126
2129
|
|
|
2127
|
-
let
|
|
2128
|
-
try {
|
|
2129
|
-
|
|
2130
|
+
let scope = { rootId: context.sessionID, projectID: input.project.id }
|
|
2131
|
+
try {
|
|
2132
|
+
scope = await rootSessionScope(context.sessionID, context.abort)
|
|
2130
2133
|
} catch (error) {
|
|
2131
2134
|
if (context.abort.aborted) throw error
|
|
2132
2135
|
}
|
|
@@ -2145,7 +2148,7 @@ Then restart opencode for the model change to take effect. If the task can be co
|
|
|
2145
2148
|
if (!existingSession?.id || existingSession.id !== requestedSessionId) {
|
|
2146
2149
|
return { title: "Raven Seek", output: `Cannot resume Raven session ${requestedSessionId}: the session was not found or could not be read.` }
|
|
2147
2150
|
}
|
|
2148
|
-
if ((existingSession.parentID !== rootId && existingSession.parentID !== context.sessionID) || existingSession.projectID !==
|
|
2151
|
+
if ((existingSession.parentID !== scope.rootId && existingSession.parentID !== context.sessionID) || existingSession.projectID !== scope.projectID) {
|
|
2149
2152
|
return { title: "Raven Seek", output: "Cannot resume Raven: sessionId is not a Raven child of this main session." }
|
|
2150
2153
|
}
|
|
2151
2154
|
|
|
@@ -2177,7 +2180,7 @@ Then restart opencode for the model change to take effect. If the task can be co
|
|
|
2177
2180
|
const sessionTitle = `raven_seek: ${args.query.slice(0, 80)}`
|
|
2178
2181
|
const session = await client.session.create({
|
|
2179
2182
|
body: {
|
|
2180
|
-
parentID: rootId,
|
|
2183
|
+
parentID: scope.rootId,
|
|
2181
2184
|
title: sessionTitle,
|
|
2182
2185
|
...(host === "v2" ? { agent: "raven" } : {}),
|
|
2183
2186
|
},
|
package/v2.ts
CHANGED
|
@@ -58,7 +58,6 @@ export async function setupRaven(ctx: Context): Promise<Plugin.Cleanup> {
|
|
|
58
58
|
const background = backgroundDelegations(ctx, controller.signal)
|
|
59
59
|
const location = { directory: ctx.location.directory }
|
|
60
60
|
const agents: Record<string, AgentDefinition> = {}
|
|
61
|
-
const globalMcpToolPrefixes = new Set<string>()
|
|
62
61
|
const activeSessions = new Set<string>()
|
|
63
62
|
let emitNotice: (notice: z.infer<typeof RavenRpc.events.notice.schema>) => Promise<void> = async () => {}
|
|
64
63
|
let runtime: Runtime | undefined
|
|
@@ -199,8 +198,6 @@ export async function setupRaven(ctx: Context): Promise<Plugin.Cleanup> {
|
|
|
199
198
|
registrations.push(await ctx.mcp.transform((editor) => {
|
|
200
199
|
const names = editor.list().filter(([, server]) => !server.disabled).map(([name]) => name)
|
|
201
200
|
raven.globalMcpRouting(names)
|
|
202
|
-
globalMcpToolPrefixes.clear()
|
|
203
|
-
for (const name of names) globalMcpToolPrefixes.add(`${name.replace(/[^a-zA-Z0-9_-]/g, "_")}_`)
|
|
204
201
|
}))
|
|
205
202
|
|
|
206
203
|
async function executeCommand(raw: string) {
|
|
@@ -215,17 +212,11 @@ export async function setupRaven(ctx: Context): Promise<Plugin.Cleanup> {
|
|
|
215
212
|
registrations.push(rpc)
|
|
216
213
|
emitNotice = (notice) => rpc.events.emit("notice", notice)
|
|
217
214
|
|
|
218
|
-
// Approve
|
|
219
|
-
// blanket agent allow rule that changes Raven's entire tool policy.
|
|
220
|
-
// Explicit configured denials are final and do not invoke this hook.
|
|
215
|
+
// Approve Raven's asks at execution time; explicit denials remain final.
|
|
221
216
|
registrations.push(await ctx.permission.hook("evaluate", (event) => {
|
|
222
217
|
if (event.effect !== "ask") return
|
|
223
218
|
const delegation = event.action === "raven_seek" || event.action === "raven_mcp"
|
|
224
|
-
|
|
225
|
-
event.action === "webfetch" || event.action === "websearch" || event.action === "fetch"
|
|
226
|
-
|| [...globalMcpToolPrefixes].some((prefix) => event.action.startsWith(prefix))
|
|
227
|
-
)
|
|
228
|
-
if (delegation || retrieval) {
|
|
219
|
+
if (delegation || event.agent === "raven" || event.agent === "raven-mcp") {
|
|
229
220
|
event.effect = "allow"
|
|
230
221
|
}
|
|
231
222
|
}))
|