SIGN IN SIGN UP

fix(opencode): lock down hidden subagent tool permissions

Historian, dreamer, and sidekick are registered with `mode: "subagent"` but
their `permission` field was never set, so each spawned session inherited
the full primary-agent tool surface (`task`, `bash`, `edit`, `webfetch`,
`websearch`, `read`, `grep`, `glob`, all MCP tools, etc.).

`mode: "subagent"` + `hidden: true` only control visibility in the agent
picker — they do NOT restrict tool access. The auto-`task`-deny in
OpenCode's `deriveSubagentSessionPermission` (subagent-permissions.ts)
fires only when an agent is INVOKED via the parent's `task()` tool, not
when spawned directly via `client.session.prompt(...)` like we do.

Result observed in the wild: historian sometimes used
`task(subagent_type=explore)` to fan out, which it should never do.

Fix mirrors OpenCode's own `explore` agent (`packages/opencode/src/
agent/agent.ts:179-201`): set `permission: { "*": "deny", ...allows }`
on each hidden-agent config. `Permission.fromConfig` converts the flat
map to a `Rule[]` ruleset, and `evaluate` uses `findLast` so named
allows defeat the wildcard deny.

Allow-lists per agent:
  - historian / historian-editor: `read` (state-file offload only)
  - dreamer: `read` (key-files) + `ctx_memory`, `ctx_search`, `ctx_note`
  - sidekick: `ctx_search`, `ctx_memory` (read-only memory retrieval)

User-supplied `pluginConfig.<agent>.permission` overrides still merge on
top via object-spread, so advanced users can extend the allow-list in
`magic-context.jsonc` if they really need to grant more tools.

Pi side already restricts via `--no-extensions --no-skills` on the spawn
command line, so no Pi-side change is needed.

Tests: 16 new unit tests in agents/permissions.test.ts covering the
helper's deny-first ordering, the per-agent allow-list shapes, and
locking in the "no task / bash / edit" invariant. Full plugin suite:
1473 pass / 0 fail.
U
ualtinok committed
571d0141049e72e86004885e618839e513a8337d
Parent: 1bf4a64