toolCapabilities method
The host wiring as capabilities: the hard floor below config.
Implementation
Map<String, ToolCapability> toolCapabilities() {
const on = ToolCapability.available();
// One decision for both browser ids: attached is the hard floor, so a
// disconnected bridge disables the whole family with the same reason.
final browserCapability = config.browserController?.attached ?? false
? on
: const ToolCapability.absent(
'no browser extension connected — run /browser connect and pair',
);
return {
'read': on,
'write': on,
'edit': on,
'ls': on,
'bash': on,
'bash_job': on,
'sqlite': config.sqliteEngine != null
? on
: const ToolCapability.absent('SQLite engine not wired by this host'),
'lsp': config.lspConfig != null
? on
: const ToolCapability.absent('language-server transport not wired'),
'web_search': config.webSearchConfig != null
? on
: const ToolCapability.absent('web search not wired'),
'mcp': _mcp.manager != null
? on
: const ToolCapability.absent('no mcp: config'),
'memory': on,
'schedule_message': on,
'session_search': on,
'ask': on,
'request_secret': on,
'task': on,
'checkpoint': on,
'rewind': on,
'generate_image': on,
'generate_video': on,
'decide': on,
'inspect_image': config.visionConfig != null
? on
: const ToolCapability.absent('no vision model configured'),
'transcribe_audio': config.transcribeConfig != null
? on
: const ToolCapability.absent('no transcription endpoint configured'),
// Browser floor (issue #23): the family exists only while a browser
// controller is attached (CLI: an extension is paired on the bridge).
// Disconnect hides both ids live with an actionable reason (AC5).
'browser': browserCapability,
'browser_eval': browserCapability,
'dap': (_toolGroupsById['dap']?.isNotEmpty ?? false)
? on
: const ToolCapability.absent('no hub configured'),
// Office tools are office-host-bound (issue #327 AC5): the CLI never
// hosts Office.js — the gated row names the host that does.
'outlook': const ToolCapability.absent(
'available in the Outlook add-in host only',
),
};
}