@pellux/goodvibes-agent 1.0.35 → 1.0.36

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.
Files changed (88) hide show
  1. package/CHANGELOG.md +15 -9
  2. package/README.md +8 -7
  3. package/dist/package/{ast-grep-napi.linux-x64-gnu-swtppvy9.node → ast-grep-napi.linux-x64-gnu-mkk8xwww.node} +0 -0
  4. package/dist/package/{ast-grep-napi.linux-x64-musl-ttfcdtap.node → ast-grep-napi.linux-x64-musl-ryqtgdv6.node} +0 -0
  5. package/dist/package/main.js +51504 -49337
  6. package/docs/README.md +6 -5
  7. package/docs/channels-remote-and-api.md +3 -3
  8. package/docs/connected-host.md +3 -3
  9. package/docs/getting-started.md +12 -7
  10. package/docs/knowledge-artifacts-and-multimodal.md +9 -4
  11. package/docs/project-planning.md +3 -3
  12. package/docs/providers-and-routing.md +2 -2
  13. package/docs/release-and-publishing.md +8 -8
  14. package/docs/tools-and-commands.md +31 -18
  15. package/docs/voice-and-live-tts.md +1 -1
  16. package/package.json +1 -1
  17. package/release/live-verification/live-verification.json +3 -3
  18. package/release/live-verification/live-verification.md +2 -4
  19. package/release/release-notes.md +4 -4
  20. package/release/release-readiness.json +46 -46
  21. package/src/agent/harness-control.ts +35 -9
  22. package/src/agent/reminder-schedule-format.ts +2 -5
  23. package/src/agent/reminder-schedule.ts +4 -11
  24. package/src/agent/routine-schedule-format.ts +3 -6
  25. package/src/agent/routine-schedule-promotion.ts +5 -14
  26. package/src/agent/routine-schedule-receipts.ts +4 -9
  27. package/src/cli/agent-knowledge-command.ts +6 -11
  28. package/src/cli/agent-knowledge-format.ts +4 -9
  29. package/src/cli/agent-knowledge-runtime.ts +7 -14
  30. package/src/cli/external-runtime.ts +3 -46
  31. package/src/cli/help.ts +2 -2
  32. package/src/cli/status.ts +6 -7
  33. package/src/input/agent-workspace-categories.ts +23 -23
  34. package/src/input/agent-workspace-channels.ts +3 -3
  35. package/src/input/agent-workspace-operations-command-editors.ts +1 -1
  36. package/src/input/command-registry.ts +1 -1
  37. package/src/input/commands/compat-runtime.ts +1 -1
  38. package/src/input/commands/planning-runtime.ts +1 -1
  39. package/src/input/commands/runtime-services.ts +1 -1
  40. package/src/input/mcp-workspace.ts +1 -1
  41. package/src/input/submission-router.ts +1 -1
  42. package/src/panels/builtin/shared.ts +1 -1
  43. package/src/panels/project-planning-panel.ts +4 -4
  44. package/src/panels/qr-panel.ts +2 -2
  45. package/src/renderer/conversation-overlays.ts +1 -0
  46. package/src/runtime/bootstrap-command-parts.ts +1 -1
  47. package/src/runtime/bootstrap-core.ts +1 -1
  48. package/src/runtime/bootstrap-hook-bridge.ts +1 -1
  49. package/src/runtime/bootstrap-shell.ts +1 -1
  50. package/src/runtime/bootstrap.ts +5 -4
  51. package/src/runtime/context.ts +2 -2
  52. package/src/runtime/index.ts +88 -5
  53. package/src/runtime/store/state.ts +1 -1
  54. package/src/tools/agent-channel-send-tool.ts +1 -1
  55. package/src/tools/agent-harness-channel-metadata.ts +36 -25
  56. package/src/tools/agent-harness-cli-metadata.ts +19 -1
  57. package/src/tools/agent-harness-command-catalog.ts +15 -4
  58. package/src/tools/agent-harness-connected-host-status.ts +7 -6
  59. package/src/tools/agent-harness-delegation-posture.ts +15 -4
  60. package/src/tools/agent-harness-keybinding-metadata.ts +67 -16
  61. package/src/tools/agent-harness-mcp-metadata.ts +11 -3
  62. package/src/tools/agent-harness-media-posture.ts +25 -14
  63. package/src/tools/agent-harness-metadata.ts +97 -6
  64. package/src/tools/agent-harness-mode-catalog.ts +81 -28
  65. package/src/tools/agent-harness-model-routing.ts +18 -3
  66. package/src/tools/agent-harness-model-tool-catalog.ts +85 -7
  67. package/src/tools/agent-harness-notification-metadata.ts +30 -19
  68. package/src/tools/agent-harness-operator-methods.ts +13 -8
  69. package/src/tools/agent-harness-pairing-posture.ts +17 -5
  70. package/src/tools/agent-harness-panel-metadata.ts +10 -4
  71. package/src/tools/agent-harness-provider-account-metadata.ts +46 -35
  72. package/src/tools/agent-harness-release-evidence.ts +31 -3
  73. package/src/tools/agent-harness-release-readiness.ts +30 -0
  74. package/src/tools/agent-harness-security-posture.ts +18 -4
  75. package/src/tools/agent-harness-service-posture.ts +8 -1
  76. package/src/tools/agent-harness-session-metadata.ts +24 -8
  77. package/src/tools/agent-harness-setup-posture.ts +32 -21
  78. package/src/tools/agent-harness-text.ts +6 -0
  79. package/src/tools/agent-harness-tool.ts +26 -34
  80. package/src/tools/agent-harness-ui-surface-metadata.ts +84 -84
  81. package/src/tools/agent-harness-workspace-actions.ts +64 -3
  82. package/src/tools/agent-knowledge-ingest-tool.ts +1 -1
  83. package/src/tools/agent-knowledge-tool.ts +1 -1
  84. package/src/tools/agent-media-generate-tool.ts +2 -2
  85. package/src/tools/agent-notify-tool.ts +1 -1
  86. package/src/tools/agent-reminder-schedule-tool.ts +1 -1
  87. package/src/tools/tool-definition-compaction.ts +35 -8
  88. package/src/version.ts +2 -8
@@ -32,21 +32,21 @@ export const HARNESS_MODE_DESCRIPTORS: readonly HarnessModeDescriptor[] = [
32
32
  { id: 'modes', kind: 'discover', family: 'start', summary: 'Search all agent_harness modes by task, family, effect, or id.', next: 'Use mode for one exact mode contract.', parameters: ['query', 'target', 'limit', 'includeParameters'] },
33
33
  { id: 'mode', kind: 'inspect', family: 'start', summary: 'Inspect one agent_harness mode contract and common next step.', next: 'Use target or query with a mode id or task phrase.', parameters: ['target', 'query'] },
34
34
  { id: 'cli_commands', kind: 'discover', family: 'cli', summary: 'List top-level package CLI mirrors for discovery only.', next: 'Use cli_command for one command.', parameters: ['query', 'limit', 'includeParameters'] },
35
- { id: 'cli_command', kind: 'inspect', family: 'cli', summary: 'Inspect one top-level CLI command, parser result, policy, aliases, and safe model route.', parameters: ['cliCommand', 'command', 'commandName', 'target', 'query'] },
35
+ { id: 'cli_command', kind: 'inspect', family: 'cli', summary: 'Inspect one CLI command parser result, policy, aliases, and model route.', parameters: ['cliCommand', 'command', 'commandName', 'target', 'query'] },
36
36
  { id: 'panels', kind: 'discover', family: 'ui', summary: 'List built-in panel catalog state and workspace routes.', next: 'Use panel or open_panel.', parameters: ['query', 'category', 'limit', 'includeParameters'] },
37
- { id: 'panel', kind: 'inspect', family: 'ui', summary: 'Inspect one built-in panel, open state, workspace route, and navigation policy.', parameters: ['panelId', 'target', 'query'] },
37
+ { id: 'panel', kind: 'inspect', family: 'ui', summary: 'Inspect one built-in panel, open state, workspace route, and policy.', parameters: ['panelId', 'target', 'query'] },
38
38
  { id: 'open_panel', kind: 'effect', family: 'ui', summary: 'Route the visible shell to one built-in panel.', requiresConfirmation: true, parameters: ['panelId', 'target', 'query', 'pane', 'confirm', 'explicitUserRequest'] },
39
39
  { id: 'ui_surfaces', kind: 'discover', family: 'ui', summary: 'List modal, picker, and visible UI surfaces the model can request.', next: 'Use ui_surface or open_ui_surface.', parameters: ['query', 'limit', 'includeParameters'] },
40
40
  { id: 'ui_surface', kind: 'inspect', family: 'ui', summary: 'Inspect one visible modal or picker surface and route contract.', parameters: ['surfaceId', 'target', 'query'] },
41
- { id: 'open_ui_surface', kind: 'effect', family: 'ui', summary: 'Open one visible modal or picker through the shell bridge.', requiresConfirmation: true, parameters: ['surfaceId', 'target', 'query', 'confirm', 'explicitUserRequest'] },
41
+ { id: 'open_ui_surface', kind: 'effect', family: 'ui', summary: 'Open one visible modal, picker, or operator workspace route.', requiresConfirmation: true, parameters: ['surfaceId', 'target', 'query', 'confirm', 'explicitUserRequest'] },
42
42
  { id: 'shortcuts', kind: 'discover', family: 'keyboard', summary: 'List fixed shortcuts and keybinding overview.', next: 'Use keybindings or keybinding for configurable actions.', parameters: ['query', 'limit', 'includeParameters'] },
43
43
  { id: 'keybindings', kind: 'discover', family: 'keyboard', summary: 'List configurable keybinding actions and current/default combos.', next: 'Use keybinding, run_keybinding, set_keybinding, or reset_keybinding.', parameters: ['query', 'limit', 'includeParameters'] },
44
- { id: 'keybinding', kind: 'inspect', family: 'keyboard', summary: 'Inspect one keybinding action, route, current combos, defaults, and policy.', parameters: ['actionId', 'key', 'target', 'query'] },
45
- { id: 'run_keybinding', kind: 'effect', family: 'keyboard', summary: 'Run one supported keybinding action through the shell bridge.', requiresConfirmation: true, parameters: ['actionId', 'key', 'target', 'query', 'confirm', 'explicitUserRequest'] },
44
+ { id: 'keybinding', kind: 'inspect', family: 'keyboard', summary: 'Inspect one keybinding action, current combos, defaults, and policy.', parameters: ['actionId', 'key', 'target', 'query'] },
45
+ { id: 'run_keybinding', kind: 'effect', family: 'keyboard', summary: 'Run one supported keybinding action through the active UI route.', requiresConfirmation: true, parameters: ['actionId', 'key', 'target', 'query', 'confirm', 'explicitUserRequest'] },
46
46
  { id: 'set_keybinding', kind: 'effect', family: 'keyboard', summary: 'Set one configurable keybinding action.', requiresConfirmation: true, parameters: ['actionId', 'combo', 'combos', 'confirm', 'explicitUserRequest'] },
47
47
  { id: 'reset_keybinding', kind: 'effect', family: 'keyboard', summary: 'Reset one configurable keybinding action to defaults.', requiresConfirmation: true, parameters: ['actionId', 'confirm', 'explicitUserRequest'] },
48
48
  { id: 'commands', kind: 'discover', family: 'slash', summary: 'List registered slash commands and compact policies.', next: 'Use command or run_command.', parameters: ['query', 'limit', 'includeParameters'] },
49
- { id: 'command', kind: 'inspect', family: 'slash', summary: 'Inspect one slash command, parsed args, policy, aliases, and preferred model route.', parameters: ['command', 'commandName', 'target', 'query'] },
49
+ { id: 'command', kind: 'inspect', family: 'slash', summary: 'Inspect slash command, parsed args, policy, aliases, and model route.', parameters: ['command', 'commandName', 'target', 'query'] },
50
50
  { id: 'run_command', kind: 'effect', family: 'slash', summary: 'Run one slash command through shared command dispatch.', requiresConfirmation: true, parameters: ['command', 'commandName', 'args', 'target', 'query', 'confirm', 'explicitUserRequest'] },
51
51
  { id: 'channels', kind: 'discover', family: 'delivery', summary: 'List channel readiness, accounts, delivery posture, and safe setup keys.', next: 'Use channel or agent_channel_send.', parameters: ['query', 'limit', 'includeParameters'] },
52
52
  { id: 'channel', kind: 'inspect', family: 'delivery', summary: 'Inspect one channel readiness entry and delivery policy.', parameters: ['channelId', 'target', 'query'] },
@@ -58,9 +58,9 @@ export const HARNESS_MODE_DESCRIPTORS: readonly HarnessModeDescriptor[] = [
58
58
  { id: 'mcp_server', kind: 'inspect', family: 'tools', summary: 'Inspect one MCP server, tools, schemas, auth, and trust posture.', parameters: ['mcpServerId', 'target', 'query'] },
59
59
  { id: 'setup_posture', kind: 'discover', family: 'setup', summary: 'Inspect first-run/setup capability posture and derived readiness flags.', next: 'Use setup_item.', parameters: ['query', 'limit', 'includeParameters'] },
60
60
  { id: 'setup_item', kind: 'inspect', family: 'setup', summary: 'Inspect one setup/onboarding posture item and visible remediation route.', parameters: ['setupItemId', 'target', 'query'] },
61
- { id: 'model_routing', kind: 'discover', family: 'providers', summary: 'List current model/provider route, available models, pins, and safe route settings.', next: 'Use model_route.', parameters: ['query', 'limit', 'includeParameters'] },
61
+ { id: 'model_routing', kind: 'discover', family: 'providers', summary: 'List model/provider route, models, pins, and safe route settings.', next: 'Use model_route.', parameters: ['query', 'limit', 'includeParameters'] },
62
62
  { id: 'model_route', kind: 'inspect', family: 'providers', summary: 'Inspect one model route or model candidate and visible selection paths.', parameters: ['modelRouteId', 'target', 'query'] },
63
- { id: 'pairing_posture', kind: 'discover', family: 'companion', summary: 'List companion pairing routes, token posture, and connected-host readiness without raw token output.', next: 'Use pairing_route.', parameters: ['query', 'limit', 'includeParameters'] },
63
+ { id: 'pairing_posture', kind: 'discover', family: 'companion', summary: 'List pairing routes, token posture, and safe handoff readiness.', next: 'Use pairing_route.', parameters: ['query', 'limit', 'includeParameters'] },
64
64
  { id: 'pairing_route', kind: 'inspect', family: 'companion', summary: 'Inspect one companion pairing route and safe visible handoff.', parameters: ['pairingRouteId', 'target', 'query'] },
65
65
  { id: 'delegation_posture', kind: 'discover', family: 'delegation', summary: 'List explicit build/fix/review delegation routes and boundaries.', next: 'Use delegation_route.', parameters: ['query', 'limit', 'includeParameters'] },
66
66
  { id: 'delegation_route', kind: 'inspect', family: 'delegation', summary: 'Inspect one delegation route and exact visible submission contract.', parameters: ['delegationRouteId', 'target', 'query'] },
@@ -68,34 +68,34 @@ export const HARNESS_MODE_DESCRIPTORS: readonly HarnessModeDescriptor[] = [
68
68
  { id: 'security_finding', kind: 'inspect', family: 'security', summary: 'Inspect one security posture finding and safe remediation route.', parameters: ['findingId', 'target', 'query'] },
69
69
  { id: 'support_bundles', kind: 'discover', family: 'support', summary: 'List support bundle artifacts and redacted export/import posture.', next: 'Use support_bundle.', parameters: ['query', 'limit', 'includeParameters'] },
70
70
  { id: 'support_bundle', kind: 'inspect', family: 'support', summary: 'Inspect one support bundle artifact and redaction posture.', parameters: ['bundlePath', 'target', 'query'] },
71
- { id: 'media_posture', kind: 'discover', family: 'media', summary: 'List voice/media provider readiness, browser posture, and artifact routes.', next: 'Use media_provider or agent_media_generate.', parameters: ['query', 'limit', 'includeParameters'] },
71
+ { id: 'media_posture', kind: 'discover', family: 'media', summary: 'List media/voice readiness, browser posture, and artifact routes.', next: 'Use media_provider or agent_media_generate.', parameters: ['query', 'limit', 'includeParameters'] },
72
72
  { id: 'media_provider', kind: 'inspect', family: 'media', summary: 'Inspect one voice or media provider readiness entry.', parameters: ['mediaProviderId', 'target', 'query'] },
73
73
  { id: 'sessions', kind: 'discover', family: 'sessions', summary: 'List saved sessions, bookmarks, exports, and pending approvals posture.', next: 'Use session.', parameters: ['query', 'limit', 'includeParameters'] },
74
74
  { id: 'session', kind: 'inspect', family: 'sessions', summary: 'Inspect one saved session or bookmark entry.', parameters: ['sessionId', 'target', 'query'] },
75
75
  { id: 'settings', kind: 'discover', family: 'settings', summary: 'Search Agent settings compactly by category, prefix, or query.', next: 'Use get_setting, set_setting, or reset_setting.', parameters: ['category', 'prefix', 'query', 'includeHidden', 'limit', 'includeParameters'] },
76
- { id: 'get_setting', kind: 'inspect', family: 'settings', summary: 'Inspect one Agent setting descriptor, current value, default, and policy.', parameters: ['key', 'target', 'query'] },
76
+ { id: 'get_setting', kind: 'inspect', family: 'settings', summary: 'Inspect one Agent setting descriptor, value, default, and policy.', parameters: ['key', 'target', 'query'] },
77
77
  { id: 'set_setting', kind: 'effect', family: 'settings', summary: 'Set one Agent-owned setting through config/secret managers.', requiresConfirmation: true, parameters: ['key', 'target', 'query', 'value', 'confirm', 'explicitUserRequest'] },
78
78
  { id: 'reset_setting', kind: 'effect', family: 'settings', summary: 'Reset one Agent-owned setting and delete secret refs when needed.', requiresConfirmation: true, parameters: ['key', 'target', 'query', 'confirm', 'explicitUserRequest'] },
79
79
  { id: 'workspace', kind: 'discover', family: 'workspace', summary: 'List Agent workspace categories and action counts.', next: 'Use workspace_actions or workspace_action.' },
80
80
  { id: 'workspace_categories', kind: 'discover', family: 'workspace', summary: 'Alias of workspace for category discovery.', next: 'Use workspace_actions or workspace_action.', aliases: ['workspace'] },
81
81
  { id: 'workspace_actions', kind: 'discover', family: 'workspace', summary: 'Search all user-facing Agent workspace actions and compact model routes.', next: 'Use workspace_action or run_workspace_action.', parameters: ['categoryId', 'query', 'limit', 'includeParameters'] },
82
- { id: 'workspace_action', kind: 'inspect', family: 'workspace', summary: 'Inspect one workspace action, editor schema, route bridge, and safety policy.', parameters: ['actionId', 'command', 'target', 'query', 'recordId'] },
83
- { id: 'run_workspace_action', kind: 'effect', family: 'workspace', summary: 'Run one supported workspace action or return its concrete model execution handoff.', requiresConfirmation: true, parameters: ['actionId', 'command', 'target', 'query', 'recordId', 'fields', 'confirm', 'explicitUserRequest'] },
82
+ { id: 'workspace_action', kind: 'inspect', family: 'workspace', summary: 'Inspect one workspace action, editor schema, route, and safety policy.', parameters: ['actionId', 'command', 'target', 'query', 'recordId'] },
83
+ { id: 'run_workspace_action', kind: 'effect', family: 'workspace', summary: 'Run a workspace action or return its model execution handoff.', requiresConfirmation: true, parameters: ['actionId', 'command', 'target', 'query', 'recordId', 'fields', 'confirm', 'explicitUserRequest'] },
84
84
  { id: 'tools', kind: 'discover', family: 'tools', summary: 'List first-class model tool definitions compactly.', next: 'Use tool for full schema.', parameters: ['query', 'limit', 'includeParameters'] },
85
85
  { id: 'tool', kind: 'inspect', family: 'tools', summary: 'Inspect one first-class model tool definition and JSON schema.', parameters: ['toolName', 'target', 'query'] },
86
- { id: 'release_evidence', kind: 'discover', family: 'release', summary: 'List packaged release evidence artifacts compactly.', next: 'Use release_evidence_artifact.', parameters: ['query', 'limit', 'includeParameters'] },
87
- { id: 'release_evidence_artifact', kind: 'inspect', family: 'release', summary: 'Inspect one release evidence artifact and optional content.', parameters: ['artifactId', 'target', 'query'] },
88
- { id: 'release_readiness', kind: 'discover', family: 'release', summary: 'Search the release-quality readiness inventory.', next: 'Use release_readiness_item.', parameters: ['query', 'limit', 'includeParameters'] },
89
- { id: 'release_readiness_item', kind: 'inspect', family: 'release', summary: 'Inspect one release-quality readiness inventory item.', parameters: ['itemId', 'target', 'query'] },
90
- { id: 'operator_methods', kind: 'discover', family: 'operator', summary: 'List allowlisted public operator/Agent Knowledge methods and owning tools.', next: 'Use operator_method.', parameters: ['query', 'limit', 'includeParameters'] },
91
- { id: 'operator_method', kind: 'inspect', family: 'operator', summary: 'Inspect one allowlisted operator method and preferred first-class model tool.', parameters: ['methodId', 'target', 'query'] },
92
- { id: 'service_posture', kind: 'discover', family: 'connected-host', summary: 'Inspect connected service endpoint posture, binding, issues, and optional probes.', next: 'Use service_endpoint.', parameters: ['includeParameters'] },
93
- { id: 'service_endpoint', kind: 'inspect', family: 'connected-host', summary: 'Inspect one connected service endpoint binding and lifecycle boundary.', parameters: ['endpointId', 'target', 'query'] },
94
- { id: 'connected_host', kind: 'discover', family: 'connected-host', summary: 'Map connected-host capabilities, boundaries, and model tool availability.', next: 'Use connected_host_capability or connected_host_status.', parameters: ['includeParameters'] },
86
+ { id: 'release_evidence', kind: 'discover', family: 'operator-audit', summary: 'List packaged operator/audit release artifacts compactly.', next: 'Use release_evidence_artifact.', parameters: ['query', 'limit', 'includeParameters'] },
87
+ { id: 'release_evidence_artifact', kind: 'inspect', family: 'operator-audit', summary: 'Inspect one operator/audit release artifact and optional content.', parameters: ['artifactId', 'target', 'query'] },
88
+ { id: 'release_readiness', kind: 'discover', family: 'operator-audit', summary: 'Search the operator/audit release-quality inventory.', next: 'Use release_readiness_item.', parameters: ['query', 'limit', 'includeParameters'] },
89
+ { id: 'release_readiness_item', kind: 'inspect', family: 'operator-audit', summary: 'Inspect one operator/audit readiness inventory item.', parameters: ['itemId', 'target', 'query'] },
90
+ { id: 'operator_methods', kind: 'discover', family: 'operator', summary: 'List public operator/Agent Knowledge methods and owning tools.', next: 'Use operator_method.', parameters: ['query', 'limit', 'includeParameters'] },
91
+ { id: 'operator_method', kind: 'inspect', family: 'operator', summary: 'Inspect one operator method and preferred first-class model tool.', parameters: ['methodId', 'target', 'query'] },
92
+ { id: 'service_posture', kind: 'discover', family: 'connected-host', summary: 'Inspect service endpoint posture, binding, issues, and probes.', next: 'Use service_endpoint.', parameters: ['includeParameters'] },
93
+ { id: 'service_endpoint', kind: 'inspect', family: 'connected-host', summary: 'Inspect one service endpoint binding and lifecycle boundary.', parameters: ['endpointId', 'target', 'query'] },
94
+ { id: 'connected_host', kind: 'discover', family: 'connected-host', summary: 'Map connected-host capabilities, boundaries, and tool availability.', next: 'Use connected_host_capability or connected_host_status.', parameters: ['includeParameters'] },
95
95
  { id: 'connected_host_status', kind: 'inspect', family: 'connected-host', summary: 'Run live read-only connected-host readiness checks.', parameters: ['includeParameters'] },
96
- { id: 'connected_host_capability', kind: 'inspect', family: 'connected-host', summary: 'Inspect one connected-host capability and blocked lifecycle/non-Agent surfaces.', parameters: ['capabilityId', 'target', 'query'] },
97
- { id: 'daemon', kind: 'alias', family: 'connected-host', summary: 'Alias for connected_host posture. Does not expose lifecycle control.', next: 'Use connected_host for canonical naming.', aliases: ['connected_host'], parameters: ['includeParameters'] },
98
- { id: 'daemon_status', kind: 'alias', family: 'connected-host', summary: 'Alias for connected_host_status live readiness. Does not expose lifecycle control.', next: 'Use connected_host_status for canonical naming.', aliases: ['connected_host_status'], parameters: ['includeParameters'] },
96
+ { id: 'connected_host_capability', kind: 'inspect', family: 'connected-host', summary: 'Inspect one connected-host capability and blocked surfaces.', parameters: ['capabilityId', 'target', 'query'] },
97
+ { id: 'daemon', kind: 'alias', family: 'connected-host', summary: 'GoodVibes daemon -> connected_host; lifecycle external.', next: 'Use connected_host for canonical naming.', aliases: ['connected_host'], parameters: ['includeParameters'] },
98
+ { id: 'daemon_status', kind: 'alias', family: 'connected-host', summary: 'GoodVibes daemon status -> connected_host_status.', next: 'Use connected_host_status for canonical naming.', aliases: ['connected_host_status'], parameters: ['includeParameters'] },
99
99
  ] as const;
100
100
 
101
101
  function readString(value: unknown): string {
@@ -117,6 +117,7 @@ function describeHarnessModeDescriptor(
117
117
  kind: descriptor.kind,
118
118
  family: descriptor.family,
119
119
  summary: descriptor.summary,
120
+ modelRoute: `agent_harness mode:"${descriptor.id}"`,
120
121
  ...(descriptor.next ? { next: descriptor.next } : {}),
121
122
  ...(descriptor.requiresConfirmation ? { requiresConfirmation: true } : {}),
122
123
  ...(descriptor.aliases ? { aliases: descriptor.aliases } : {}),
@@ -141,15 +142,68 @@ function harnessModeSearchText(descriptor: HarnessModeDescriptor): string {
141
142
  ].filter(Boolean).join('\n').toLowerCase();
142
143
  }
143
144
 
145
+ function searchTokens(input: string): readonly string[] {
146
+ return input.toLowerCase().split(/[^a-z0-9]+/).filter((token) => token.length > 0);
147
+ }
148
+
144
149
  function harnessModeMatchesSearch(descriptor: HarnessModeDescriptor, input: string): boolean {
145
150
  const text = harnessModeSearchText(descriptor);
146
151
  const normalized = input.toLowerCase().trim();
147
152
  if (normalized.length === 0) return true;
148
153
  if (text.includes(normalized)) return true;
149
- const tokens = normalized.split(/[^a-z0-9]+/).filter((token) => token.length > 0);
154
+ const tokens = searchTokens(normalized);
150
155
  return tokens.length > 0 && tokens.every((token) => text.includes(token));
151
156
  }
152
157
 
158
+ function tokenScore(tokens: readonly string[], value: string | undefined, weight: number): number {
159
+ if (!value) return 0;
160
+ const text = value.toLowerCase();
161
+ return tokens.reduce((score, token) => score + (text.includes(token) ? weight : 0), 0);
162
+ }
163
+
164
+ const ACTION_VERBS = new Set(['run', 'set', 'reset', 'open', 'create', 'send', 'schedule']);
165
+
166
+ function harnessModeRelevance(descriptor: HarnessModeDescriptor, input: string): number {
167
+ const normalized = input.toLowerCase().trim();
168
+ if (!normalized) return 0;
169
+
170
+ const tokens = searchTokens(normalized);
171
+ const id = descriptor.id.toLowerCase();
172
+ const idPhrase = id.replace(/_/g, ' ');
173
+ const idLookup = normalized.replace(/\s+/g, '_');
174
+ let score = 0;
175
+
176
+ if (id === normalized || idPhrase === normalized) score += 10_000;
177
+ if (id.startsWith(idLookup) || idPhrase.startsWith(normalized)) score += 5_000;
178
+ if (id.includes(idLookup) || idPhrase.includes(normalized)) score += 2_500;
179
+
180
+ score += tokenScore(tokens, [id, idPhrase, ...(descriptor.aliases ?? [])].join('\n'), 1_000);
181
+ score += tokenScore(tokens, descriptor.family, 500);
182
+ score += tokenScore(tokens, descriptor.kind, 500);
183
+ score += tokenScore(tokens, (descriptor.parameters ?? []).join('\n'), 350);
184
+ score += tokenScore(tokens, descriptor.summary, 200);
185
+ score += tokenScore(tokens, descriptor.next, 100);
186
+
187
+ const actionVerb = tokens.find((token) => ACTION_VERBS.has(token));
188
+ if (actionVerb) {
189
+ const idTokens = searchTokens(id);
190
+ if (idTokens[0] === actionVerb) score += 2_000;
191
+ if (descriptor.kind === 'effect' && idTokens.includes(actionVerb)) score += 1_000;
192
+ }
193
+
194
+ return score;
195
+ }
196
+
197
+ function matchingHarnessModes(input: string): readonly HarnessModeDescriptor[] {
198
+ const matches = HARNESS_MODE_DESCRIPTORS
199
+ .map((descriptor, index) => ({ descriptor, index, score: harnessModeRelevance(descriptor, input) }))
200
+ .filter(({ descriptor }) => harnessModeMatchesSearch(descriptor, input));
201
+ if (!input) return matches.map(({ descriptor }) => descriptor);
202
+ return matches
203
+ .sort((left, right) => right.score - left.score || left.index - right.index)
204
+ .map(({ descriptor }) => descriptor);
205
+ }
206
+
153
207
  function modeLookupInput(args: HarnessModeCatalogArgs): { readonly source: 'target' | 'query'; readonly input: string } | null {
154
208
  const target = readString(args.target);
155
209
  if (target) return { source: 'target', input: target };
@@ -161,8 +215,7 @@ export function listHarnessModes(args: HarnessModeCatalogArgs): Record<string, u
161
215
  const lookup = modeLookupInput(args);
162
216
  const limit = readLimit(args.limit, 120);
163
217
  const normalized = lookup?.input.toLowerCase() ?? '';
164
- const modes = HARNESS_MODE_DESCRIPTORS
165
- .filter((descriptor) => harnessModeMatchesSearch(descriptor, normalized))
218
+ const modes = matchingHarnessModes(normalized)
166
219
  .map((descriptor) => describeHarnessModeDescriptor(descriptor, { includeParameters: args.includeParameters === true }))
167
220
  .slice(0, limit);
168
221
  return {
@@ -187,7 +240,7 @@ export function describeHarnessMode(args: HarnessModeCatalogArgs): HarnessModeRe
187
240
  if (exact) return { status: 'found', mode: describeHarnessModeDescriptor(exact, { includeParameters: true, lookup: { ...lookup, resolvedBy: 'id' } }) };
188
241
  const insensitive = HARNESS_MODE_DESCRIPTORS.find((descriptor) => descriptor.id.toLowerCase() === normalized);
189
242
  if (insensitive) return { status: 'found', mode: describeHarnessModeDescriptor(insensitive, { includeParameters: true, lookup: { ...lookup, resolvedBy: 'case-insensitive-id' } }) };
190
- const searched = HARNESS_MODE_DESCRIPTORS.filter((descriptor) => harnessModeMatchesSearch(descriptor, normalized));
243
+ const searched = matchingHarnessModes(normalized);
191
244
  if (searched.length === 1) {
192
245
  return { status: 'found', mode: describeHarnessModeDescriptor(searched[0]!, { includeParameters: true, lookup: { ...lookup, resolvedBy: 'search' } }) };
193
246
  }
@@ -1,5 +1,6 @@
1
1
  import type { CommandContext } from '../input/command-registry.ts';
2
2
  import { requireProviderApi } from '../input/commands/runtime-services.ts';
3
+ import { previewHarnessText } from './agent-harness-text.ts';
3
4
 
4
5
  export interface AgentHarnessModelRoutingArgs {
5
6
  readonly modelRouteId?: unknown;
@@ -314,11 +315,14 @@ function describeRoute(route: RouteCandidate, options: { readonly includeParamet
314
315
  kind: 'route',
315
316
  modelRouteId: route.id,
316
317
  label: route.label,
317
- detail: route.detail,
318
+ ...(options.includeParameters ? { detail: route.detail } : { summary: previewHarnessText(route.detail) }),
318
319
  currentValue: route.currentValue,
319
320
  settingKeys: route.settingKeys,
320
- commands: route.commands,
321
- uiSurfaces: route.uiSurfaces,
321
+ modelRoute: modelRoutingModelRoute(),
322
+ ...(options.includeParameters ? {
323
+ commands: route.commands,
324
+ uiSurfaces: route.uiSurfaces,
325
+ } : {}),
322
326
  ...(options.lookup ? { lookup: options.lookup } : {}),
323
327
  ...(options.includeParameters ? {
324
328
  policy: {
@@ -350,6 +354,7 @@ function describeModel(model: ModelCandidate, options: { readonly includeParamet
350
354
  pinned: model.pinned,
351
355
  contextWindow: model.contextWindow,
352
356
  reasoningEffort: model.reasoningEffort,
357
+ modelRoute: modelCandidateModelRoute(),
353
358
  ...(options.lookup ? { lookup: options.lookup } : {}),
354
359
  ...(options.includeParameters ? {
355
360
  capabilities: model.capabilities,
@@ -374,6 +379,7 @@ function describeCandidate(entry: RouteCandidate | ModelCandidate): Record<strin
374
379
  kind: 'route',
375
380
  modelRouteId: entry.id,
376
381
  label: entry.label,
382
+ modelRoute: modelRoutingModelRoute(),
377
383
  };
378
384
  }
379
385
  return {
@@ -383,9 +389,18 @@ function describeCandidate(entry: RouteCandidate | ModelCandidate): Record<strin
383
389
  displayName: entry.displayName,
384
390
  current: entry.current,
385
391
  pinned: entry.pinned,
392
+ modelRoute: modelCandidateModelRoute(),
386
393
  };
387
394
  }
388
395
 
396
+ function modelRoutingModelRoute(): string {
397
+ return 'agent_harness mode:"model_route" or mode:"run_command"';
398
+ }
399
+
400
+ function modelCandidateModelRoute(): string {
401
+ return 'agent_harness mode:"run_command" command:"/model"';
402
+ }
403
+
389
404
  export async function modelRoutingCatalogStatus(context: CommandContext): Promise<Record<string, unknown>> {
390
405
  const [models, providerIds] = await Promise.all([
391
406
  loadModels(context),
@@ -25,19 +25,91 @@ function readLimit(value: unknown, fallback: number): number {
25
25
  return Math.max(1, Math.min(500, Math.trunc(parsed)));
26
26
  }
27
27
 
28
- function previewText(value: string, maxLength = 120): string {
28
+ function previewText(value: string, maxLength = 56): string {
29
29
  const normalized = value.replace(/\s+/g, ' ').trim();
30
- return normalized.length <= maxLength ? normalized : `${normalized.slice(0, maxLength - 1).trimEnd()}...`;
30
+ return normalized.length <= maxLength ? normalized : `${normalized.slice(0, maxLength - 3).trimEnd()}...`;
31
+ }
32
+
33
+ function searchTokens(input: string): readonly string[] {
34
+ return input.toLowerCase().split(/[^a-z0-9]+/).filter((token) => token.length > 0);
35
+ }
36
+
37
+ function schemaSearchText(value: unknown): string {
38
+ if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') return String(value);
39
+ if (Array.isArray(value)) return value.map(schemaSearchText).filter(Boolean).join('\n');
40
+ if (!value || typeof value !== 'object') return '';
41
+ return Object.entries(value)
42
+ .map(([key, entry]) => `${key}\n${schemaSearchText(entry)}`)
43
+ .filter(Boolean)
44
+ .join('\n');
31
45
  }
32
46
 
33
47
  function modelToolSearchText(tool: HarnessModelToolDefinition): string {
34
48
  return [
35
49
  tool.name,
50
+ tool.name.replace(/_/g, ' '),
36
51
  tool.description,
37
52
  ...(tool.sideEffects ?? []),
53
+ schemaSearchText(tool.parameters),
38
54
  ].join('\n').toLowerCase();
39
55
  }
40
56
 
57
+ function modelToolMatchesSearch(tool: HarnessModelToolDefinition, input: string): boolean {
58
+ const text = modelToolSearchText(tool);
59
+ const normalized = input.toLowerCase().trim();
60
+ if (!normalized) return true;
61
+ if (text.includes(normalized)) return true;
62
+ const tokens = searchTokens(normalized);
63
+ return tokens.length > 0 && tokens.every((token) => text.includes(token));
64
+ }
65
+
66
+ function tokenScore(tokens: readonly string[], value: string | undefined, weight: number): number {
67
+ if (!value) return 0;
68
+ const text = value.toLowerCase();
69
+ return tokens.reduce((score, token) => score + (text.includes(token) ? weight : 0), 0);
70
+ }
71
+
72
+ const ACTION_VERBS = new Set(['run', 'set', 'reset', 'open', 'create', 'send', 'schedule', 'generate', 'read', 'search', 'ingest']);
73
+
74
+ function modelToolRelevance(tool: HarnessModelToolDefinition, input: string): number {
75
+ const normalized = input.toLowerCase().trim();
76
+ if (!normalized) return 0;
77
+
78
+ const tokens = searchTokens(normalized);
79
+ const name = tool.name.toLowerCase();
80
+ const namePhrase = name.replace(/_/g, ' ');
81
+ const nameLookup = normalized.replace(/\s+/g, '_');
82
+ const parameterText = schemaSearchText(tool.parameters);
83
+ let score = 0;
84
+
85
+ if (name === normalized || namePhrase === normalized) score += 10_000;
86
+ if (name.startsWith(nameLookup) || namePhrase.startsWith(normalized)) score += 5_000;
87
+ if (name.includes(nameLookup) || namePhrase.includes(normalized)) score += 2_500;
88
+
89
+ score += tokenScore(tokens, `${name}\n${namePhrase}`, 1_000);
90
+ score += tokenScore(tokens, tool.description, 300);
91
+ score += tokenScore(tokens, (tool.sideEffects ?? []).join('\n'), 250);
92
+ score += tokenScore(tokens, parameterText, 150);
93
+
94
+ const actionVerb = tokens.find((token) => ACTION_VERBS.has(token));
95
+ if (actionVerb && searchTokens(name).includes(actionVerb)) score += 1_500;
96
+
97
+ return score;
98
+ }
99
+
100
+ function matchingModelTools(tools: readonly HarnessModelToolDefinition[], input: string): readonly HarnessModelToolDefinition[] {
101
+ const query = input.toLowerCase().trim();
102
+ const matches = tools
103
+ .map((tool, index) => ({ tool, index, score: modelToolRelevance(tool, query) }))
104
+ .filter(({ tool }) => modelToolMatchesSearch(tool, query));
105
+ return matches
106
+ .sort((left, right) => {
107
+ if (!query) return left.tool.name.localeCompare(right.tool.name);
108
+ return right.score - left.score || left.tool.name.localeCompare(right.tool.name) || left.index - right.index;
109
+ })
110
+ .map(({ tool }) => tool);
111
+ }
112
+
41
113
  function modelToolLookupFromArgs(args: AgentHarnessModelToolCatalogArgs): { readonly source: ModelToolLookupSource; readonly input: string } | null {
42
114
  const toolName = readString(args.toolName);
43
115
  if (toolName) return { source: 'toolName', input: toolName };
@@ -51,6 +123,11 @@ function describeModelTool(tool: HarnessModelToolDefinition, options: { readonly
51
123
  return {
52
124
  name: tool.name,
53
125
  ...(options.includeParameters ? { description: tool.description } : { summary: previewText(tool.description) }),
126
+ modelRoute: tool.name,
127
+ modelAccess: {
128
+ inspect: `agent_harness mode:"tool" toolName:"${tool.name}"`,
129
+ invoke: tool.name,
130
+ },
54
131
  sideEffects: tool.sideEffects ?? [],
55
132
  concurrency: tool.concurrency ?? 'parallel',
56
133
  supportsProgress: tool.supportsProgress ?? false,
@@ -64,6 +141,8 @@ function describeModelToolCandidates(tools: readonly HarnessModelToolDefinition[
64
141
  return tools.slice(0, 8).map((tool) => ({
65
142
  toolName: tool.name,
66
143
  summary: previewText(tool.description),
144
+ modelRoute: tool.name,
145
+ inspectRoute: `agent_harness mode:"tool" toolName:"${tool.name}"`,
67
146
  sideEffects: tool.sideEffects ?? [],
68
147
  }));
69
148
  }
@@ -71,10 +150,8 @@ function describeModelToolCandidates(tools: readonly HarnessModelToolDefinition[
71
150
  export function listHarnessModelTools(toolRegistry: ToolRegistry, args: AgentHarnessModelToolCatalogArgs): readonly Record<string, unknown>[] {
72
151
  const query = readString(args.query).toLowerCase();
73
152
  const includeParameters = args.includeParameters === true;
74
- const limit = readLimit(args.limit, 200);
75
- return toolRegistry.getToolDefinitions()
76
- .filter((tool) => !query || modelToolSearchText(tool).includes(query))
77
- .sort((a, b) => a.name.localeCompare(b.name))
153
+ const limit = readLimit(args.limit, 500);
154
+ return matchingModelTools(toolRegistry.getToolDefinitions(), query)
78
155
  .slice(0, limit)
79
156
  .map((tool) => describeModelTool(tool, { includeParameters }));
80
157
  }
@@ -90,7 +167,8 @@ export function describeHarnessModelTool(toolRegistry: ToolRegistry, args: Agent
90
167
  : (() => {
91
168
  const insensitive = tools.find((tool) => tool.name.toLowerCase() === normalized);
92
169
  if (insensitive) return { tool: insensitive, resolvedBy: 'case-insensitive-name' };
93
- const searched = tools.filter((tool) => modelToolSearchText(tool).includes(normalized));
170
+ if (lookup.source === 'toolName') return null;
171
+ const searched = matchingModelTools(tools, normalized);
94
172
  if (searched.length === 1) return { tool: searched[0]!, resolvedBy: 'search' };
95
173
  if (searched.length > 1) return { candidates: searched };
96
174
  return null;
@@ -1,5 +1,6 @@
1
1
  import { createHash } from 'node:crypto';
2
2
  import type { CommandContext } from '../input/command-registry.ts';
3
+ import { previewHarnessText } from './agent-harness-text.ts';
3
4
 
4
5
  export interface AgentHarnessNotificationArgs {
5
6
  readonly notificationTargetId?: unknown;
@@ -114,9 +115,14 @@ function describeTargetCandidate(target: NotificationTargetDescriptor): Record<s
114
115
  fingerprint: target.fingerprint,
115
116
  validUrl: target.validUrl,
116
117
  ...(target.host ? { host: target.host } : {}),
118
+ modelRoute: notificationTargetModelRoute(),
117
119
  };
118
120
  }
119
121
 
122
+ function notificationTargetModelRoute(): string {
123
+ return 'agent_notify or agent_harness mode:"notification_target"';
124
+ }
125
+
120
126
  function describeTarget(
121
127
  target: NotificationTargetDescriptor,
122
128
  options: { readonly includeParameters?: boolean; readonly lookup?: Record<string, unknown> } = {},
@@ -131,26 +137,31 @@ function describeTarget(
131
137
  ...(target.pathDepth !== undefined ? { pathDepth: target.pathDepth } : {}),
132
138
  ...(target.hasQuery !== undefined ? { hasQuery: target.hasQuery } : {}),
133
139
  value: '<redacted>',
140
+ modelRoute: notificationTargetModelRoute(),
134
141
  ...(options.lookup ? { lookup: options.lookup } : {}),
135
- ...(options.includeParameters ? {
136
- policy: {
137
- effect: 'read-only',
138
- values: 'Full webhook URLs are not returned because they can contain bearer tokens or secret path/query values.',
139
- delivery: 'Use agent_notify only for one explicit, confirmed notification requested by the user.',
140
- management: 'Use confirmed /notify mirrors only when the user explicitly asks to add, remove, clear, test, or send notification targets.',
141
- },
142
- modelAccess: {
143
- sendTool: 'agent_notify',
144
- listCommand: '/notify list',
145
- addCommand: '/notify add <url> --yes',
146
- removeCommand: '/notify remove <url> --yes',
147
- clearCommand: '/notify clear --yes',
148
- testCommand: '/notify test --yes',
149
- settingsCategory: 'notifications.webhookUrls',
150
- targetValueRequiredForRemove: true,
151
- targetValuePolicy: 'Ask the user for the exact webhook URL before removing one target; do not infer it from redacted metadata.',
152
- },
153
- } : {}),
142
+ ...(options.includeParameters
143
+ ? {
144
+ policy: {
145
+ effect: 'read-only',
146
+ values: 'Full webhook URLs are not returned because they can contain bearer tokens or secret path/query values.',
147
+ delivery: 'Use agent_notify only for one explicit, confirmed notification requested by the user.',
148
+ management: 'Use confirmed /notify mirrors only when the user explicitly asks to add, remove, clear, test, or send notification targets.',
149
+ },
150
+ modelAccess: {
151
+ sendTool: 'agent_notify',
152
+ listCommand: '/notify list',
153
+ addCommand: '/notify add <url> --yes',
154
+ removeCommand: '/notify remove <url> --yes',
155
+ clearCommand: '/notify clear --yes',
156
+ testCommand: '/notify test --yes',
157
+ settingsCategory: 'notifications.webhookUrls',
158
+ targetValueRequiredForRemove: true,
159
+ targetValuePolicy: 'Ask the user for the exact webhook URL before removing one target; do not infer it from redacted metadata.',
160
+ },
161
+ }
162
+ : {
163
+ summary: previewHarnessText(`${target.validUrl ? 'valid' : 'invalid'} notification webhook target ${target.index}`),
164
+ }),
154
165
  };
155
166
  }
156
167
 
@@ -1,5 +1,6 @@
1
1
  import { AGENT_KNOWLEDGE_METHODS } from '../cli/agent-knowledge-methods.ts';
2
2
  import { OPERATOR_ACTIONS } from '../agent/operator-actions.ts';
3
+ import { previewHarnessText } from './agent-harness-text.ts';
3
4
 
4
5
  export interface AgentHarnessOperatorMethodArgs {
5
6
  readonly methodId?: unknown;
@@ -120,7 +121,7 @@ function agentKnowledgeMethods(): readonly OperatorMethodDescriptor[] {
120
121
  effect: readOnly ? 'read-only-network' : 'confirmed-agent-knowledge-write',
121
122
  owner: 'connected-host',
122
123
  preferredModelTool: readOnly ? 'agent_knowledge' : key === 'reindex' ? 'agent_harness mode:"run_command"' : 'agent_knowledge_ingest',
123
- confirmation: readOnly ? 'Read-only; use the owning first-class tool.' : 'Requires explicit user request and confirmation through the owning tool or command bridge.',
124
+ confirmation: readOnly ? 'Read-only; use the owning first-class tool.' : 'Requires explicit user request and confirmation through the owning tool or command route.',
124
125
  boundary: 'Isolated Agent Knowledge route family only; default knowledge and non-Agent knowledge segments are forbidden.',
125
126
  ...(readOnly ? {} : {
126
127
  parameters: [
@@ -193,23 +194,27 @@ function describeMethod(
193
194
  return {
194
195
  id: method.id,
195
196
  label: method.label,
196
- route: method.route,
197
197
  effect: method.effect,
198
198
  owner: method.owner,
199
- preferredModelTool: method.preferredModelTool,
200
- confirmation: method.confirmation,
201
- boundary: method.boundary,
199
+ modelRoute: previewHarnessText(method.preferredModelTool),
202
200
  ...(options.lookup ? { lookup: options.lookup } : {}),
203
- ...(options.includeParameters ? { parameters: method.parameters ?? [] } : {}),
201
+ ...(options.includeParameters ? {
202
+ route: method.route,
203
+ preferredModelTool: method.preferredModelTool,
204
+ confirmation: method.confirmation,
205
+ boundary: method.boundary,
206
+ parameters: method.parameters ?? [],
207
+ } : {
208
+ summary: previewHarnessText(method.boundary),
209
+ }),
204
210
  };
205
211
  }
206
212
 
207
213
  function describeCandidate(method: OperatorMethodDescriptor): Record<string, unknown> {
208
214
  return {
209
215
  methodId: method.id,
210
- route: method.route,
211
216
  effect: method.effect,
212
- preferredModelTool: method.preferredModelTool,
217
+ modelRoute: previewHarnessText(method.preferredModelTool),
213
218
  };
214
219
  }
215
220
 
@@ -4,6 +4,7 @@ import { GOODVIBES_AGENT_PAIRING_SURFACE } from '../config/surface.ts';
4
4
  import { resolveRuntimeEndpointBinding } from '../cli/endpoints.ts';
5
5
  import { connectedHostOperatorTokenFingerprint, readConnectedHostOperatorToken } from '../runtime/connected-host-auth.ts';
6
6
  import { requirePlatform, requireShellPaths } from '../input/commands/runtime-services.ts';
7
+ import { previewHarnessText } from './agent-harness-text.ts';
7
8
 
8
9
  export interface AgentHarnessPairingArgs {
9
10
  readonly pairingRouteId?: unknown;
@@ -101,7 +102,7 @@ function pairingRoutes(): readonly PairingRoute[] {
101
102
  {
102
103
  id: 'connected-host-status',
103
104
  label: 'Connected host live posture',
104
- detail: 'Read-only reachability, token posture, SDK compatibility, and route readiness used before companion setup.',
105
+ detail: 'Read-only reachability, token posture, and route readiness used before companion setup.',
105
106
  effect: 'read-only',
106
107
  harnessRoute: 'agent_harness mode:"connected_host_status"',
107
108
  capabilityIds: ['connected-host-status'],
@@ -152,6 +153,7 @@ function describeCandidate(route: PairingRoute): Record<string, unknown> {
152
153
  label: route.label,
153
154
  effect: route.effect,
154
155
  requiresConfirmation: route.requiresConfirmation === true,
156
+ modelRoute: pairingRouteModelRoute(route),
155
157
  };
156
158
  }
157
159
 
@@ -159,12 +161,15 @@ function describeRoute(route: PairingRoute, options: { readonly includeParameter
159
161
  return {
160
162
  pairingRouteId: route.id,
161
163
  label: route.label,
162
- detail: route.detail,
164
+ ...(options.includeParameters ? { detail: route.detail } : { summary: previewHarnessText(route.detail) }),
163
165
  effect: route.effect,
164
- ...(route.command ? { command: route.command } : {}),
165
- ...(route.harnessRoute ? { harnessRoute: route.harnessRoute } : {}),
166
- ...(route.capabilityIds ? { capabilityIds: route.capabilityIds } : {}),
167
166
  requiresConfirmation: route.requiresConfirmation === true,
167
+ modelRoute: pairingRouteModelRoute(route),
168
+ ...(options.includeParameters ? {
169
+ ...(route.command ? { command: route.command } : {}),
170
+ ...(route.harnessRoute ? { harnessRoute: route.harnessRoute } : {}),
171
+ ...(route.capabilityIds ? { capabilityIds: route.capabilityIds } : {}),
172
+ } : {}),
168
173
  ...(options.lookup ? { lookup: options.lookup } : {}),
169
174
  ...(options.includeParameters ? {
170
175
  policy: {
@@ -183,6 +188,13 @@ function describeRoute(route: PairingRoute, options: { readonly includeParameter
183
188
  };
184
189
  }
185
190
 
191
+ function pairingRouteModelRoute(route: PairingRoute): string {
192
+ if (route.command === '/pair') return 'agent_harness mode:"run_command" command:"/pair"';
193
+ if (route.command === '/pair --show-token --yes') return 'agent_harness mode:"run_command" command:"/pair --show-token --yes"';
194
+ if (route.id === 'pairing-ui') return 'agent_harness mode:"workspace_action" target:"pair"';
195
+ return previewHarnessText(route.harnessRoute ?? 'agent_harness mode:"pairing_route"');
196
+ }
197
+
186
198
  function pairingState(context: CommandContext): Record<string, unknown> {
187
199
  const shellPaths = requireShellPaths(context);
188
200
  const configManager = requirePlatform(context).configManager;