The master merge brought the tool registry's per-scope restriction layer
(tools.restrict), which makes dsh-mode's prepend assemble filter a duplicate
enforcement shape: it re-implemented the registry's SDK-section rendering
(renderToolsSdk + the RUN_CODE_NAME exclusion) and hid the exit tool from
prompts only — dispatch stayed open and the execute-time re-check was the
real gate. The service now reconciles a per-agent deny restriction on
agent.ctx at agent/created and at every boundary flush, so wire schemas, the
Code Mode tools:sdk section, AND dispatch resolve exit_plan_mode through the
one registry view (a default-mode call answers UNKNOWN_TOOL, byte-identical
to a no-dsh-mode deployment). The execute-time folded-mode re-check stays as
defense in depth for a direct foreign mode/set append no boundary has
reconciled yet.
Two zero-consumer surfaces removed per the pre-release stance:
- AgentOptions.mode creation seeding (declaration merge + agent/created
listener); a caller selects through set() before the first turn, and the
deferred subagent inheritance returns together with its consumer.
- The dropped-definition boundary notice (droppedNoticed + narration):
custom mode definitions have no production consumer, so nothing can be
dropped; fold-to-default degradation is unchanged.
The stdio removal had left plan mode ACP-only while docs still claimed a
/mode command. dsh-mode now registers /mode on the plugin-owned command
registry through an optional ctx.inject(['commands']) child (type-only peer
edge on dsh-commands), so the TUI and the ACP slash-command surface both
gain it; examples/tui-agent composes dsh-mode. ACP/TUI expected outputs
refreshed keyless for the available_commands_update delta.
Docs updated in place (mode READMEs, the plan-mode Agent Note's realization
sections); catalogs and graphs regenerated.