@pellux/goodvibes-agent 0.1.117 → 1.0.0

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 (253) hide show
  1. package/CHANGELOG.md +13 -4
  2. package/README.md +35 -14
  3. package/bin/goodvibes-agent.ts +16 -2
  4. package/dist/package/main.js +176073 -170980
  5. package/docs/README.md +11 -5
  6. package/docs/channels-remote-and-api.md +50 -0
  7. package/docs/connected-host.md +3 -3
  8. package/docs/getting-started.md +29 -15
  9. package/docs/knowledge-artifacts-and-multimodal.md +91 -0
  10. package/docs/project-planning.md +79 -0
  11. package/docs/providers-and-routing.md +46 -0
  12. package/docs/release-and-publishing.md +44 -9
  13. package/docs/tools-and-commands.md +123 -0
  14. package/docs/voice-and-live-tts.md +51 -0
  15. package/package.json +2 -5
  16. package/src/agent/channel-delivery.ts +201 -0
  17. package/src/agent/media-generation.ts +159 -0
  18. package/src/agent/memory-prompt.ts +0 -1
  19. package/src/agent/note-registry.ts +329 -0
  20. package/src/agent/operator-actions.ts +343 -0
  21. package/src/agent/persona-registry.ts +15 -14
  22. package/src/agent/record-labels.ts +107 -0
  23. package/src/agent/reminder-schedule-format.ts +33 -24
  24. package/src/agent/reminder-schedule.ts +26 -25
  25. package/src/agent/routine-registry.ts +13 -12
  26. package/src/agent/routine-schedule-args.ts +2 -1
  27. package/src/agent/routine-schedule-format.ts +77 -53
  28. package/src/agent/routine-schedule-promotion.ts +34 -32
  29. package/src/agent/routine-schedule-receipts.ts +28 -26
  30. package/src/agent/runtime-profile-starters.ts +2 -2
  31. package/src/agent/runtime-profile.ts +18 -17
  32. package/src/agent/skill-registry.ts +25 -24
  33. package/src/cli/agent-knowledge-args.ts +5 -1
  34. package/src/cli/agent-knowledge-command.ts +39 -33
  35. package/src/cli/agent-knowledge-format.ts +80 -67
  36. package/src/cli/agent-knowledge-methods.ts +1 -1
  37. package/src/cli/agent-knowledge-runtime.ts +32 -26
  38. package/src/cli/bundle-command.ts +13 -8
  39. package/src/cli/config-overrides.ts +37 -36
  40. package/src/cli/external-runtime.ts +10 -4
  41. package/src/cli/help.ts +29 -11
  42. package/src/cli/local-library-command.ts +134 -68
  43. package/src/cli/management-commands.ts +98 -62
  44. package/src/cli/management.ts +52 -26
  45. package/src/cli/memory-command.ts +66 -32
  46. package/src/cli/parser.ts +37 -24
  47. package/src/cli/profiles-command.ts +52 -35
  48. package/src/cli/provider-auth-routes.ts +2 -1
  49. package/src/cli/routines-command.ts +44 -36
  50. package/src/cli/service-posture.ts +6 -6
  51. package/src/cli/status.ts +46 -121
  52. package/src/core/conversation-message-snapshot.ts +131 -0
  53. package/src/input/agent-workspace-activation.ts +33 -7
  54. package/src/input/agent-workspace-basic-command-editor-submission.ts +7 -3
  55. package/src/input/agent-workspace-basic-command-editors.ts +30 -10
  56. package/src/input/agent-workspace-categories.ts +276 -64
  57. package/src/input/agent-workspace-channel-command-editor-submission.ts +34 -0
  58. package/src/input/agent-workspace-channel-command-editors.ts +23 -5
  59. package/src/input/agent-workspace-channels.ts +35 -2
  60. package/src/input/agent-workspace-command-editor.ts +18 -2
  61. package/src/input/agent-workspace-config-reader.ts +16 -0
  62. package/src/input/agent-workspace-delegation-editor-submission.ts +1 -1
  63. package/src/input/agent-workspace-editors.ts +140 -2
  64. package/src/input/agent-workspace-knowledge-query-editor.ts +1 -1
  65. package/src/input/agent-workspace-learned-behavior.ts +2 -2
  66. package/src/input/agent-workspace-library-command-editor-submission.ts +1 -1
  67. package/src/input/agent-workspace-library-command-editors.ts +2 -2
  68. package/src/input/agent-workspace-local-operations.ts +218 -0
  69. package/src/input/agent-workspace-local-selection.ts +75 -0
  70. package/src/input/agent-workspace-media-command-editor-submission.ts +62 -0
  71. package/src/input/agent-workspace-media-command-editors.ts +27 -0
  72. package/src/input/agent-workspace-memory-command-editors.ts +1 -1
  73. package/src/input/agent-workspace-memory-editor.ts +2 -2
  74. package/src/input/agent-workspace-navigation.ts +38 -2
  75. package/src/input/agent-workspace-notify-editor-submission.ts +16 -2
  76. package/src/input/agent-workspace-operations-command-editor-submission.ts +63 -1
  77. package/src/input/agent-workspace-operations-command-editors.ts +80 -3
  78. package/src/input/agent-workspace-panel-route.ts +43 -0
  79. package/src/input/agent-workspace-reminder-schedule-editor.ts +1 -1
  80. package/src/input/agent-workspace-routine-schedule-editor.ts +2 -2
  81. package/src/input/agent-workspace-search.ts +169 -0
  82. package/src/input/agent-workspace-setup.ts +22 -11
  83. package/src/input/agent-workspace-skill-bundle-command-editor-submission.ts +6 -6
  84. package/src/input/agent-workspace-skill-bundle-command-editors.ts +10 -10
  85. package/src/input/agent-workspace-snapshot.ts +112 -13
  86. package/src/input/agent-workspace-task-command-editors.ts +4 -4
  87. package/src/input/agent-workspace-token.ts +18 -2
  88. package/src/input/agent-workspace-types.ts +92 -4
  89. package/src/input/agent-workspace-voice-media.ts +3 -6
  90. package/src/input/agent-workspace-web-research-editor.ts +104 -0
  91. package/src/input/agent-workspace.ts +136 -208
  92. package/src/input/command-registry.ts +4 -1
  93. package/src/input/commands/agent-runtime-profile-runtime.ts +45 -41
  94. package/src/input/commands/agent-skills-runtime.ts +83 -70
  95. package/src/input/commands/agent-workspace-runtime.ts +23 -7
  96. package/src/input/commands/brief-runtime.ts +25 -24
  97. package/src/input/commands/channels-runtime.ts +145 -31
  98. package/src/input/commands/delegation-runtime.ts +29 -23
  99. package/src/input/commands/experience-runtime.ts +6 -4
  100. package/src/input/commands/guidance-runtime.ts +4 -4
  101. package/src/input/commands/health-runtime.ts +140 -115
  102. package/src/input/commands/knowledge.ts +57 -56
  103. package/src/input/commands/local-provider-runtime.ts +36 -18
  104. package/src/input/commands/local-runtime.ts +138 -16
  105. package/src/input/commands/local-setup-review.ts +7 -7
  106. package/src/input/commands/mcp-runtime.ts +56 -35
  107. package/src/input/commands/notify-runtime.ts +38 -9
  108. package/src/input/commands/operator-actions-runtime.ts +138 -0
  109. package/src/input/commands/operator-runtime.ts +6 -17
  110. package/src/input/commands/personas-runtime.ts +45 -30
  111. package/src/input/commands/planning-runtime.ts +1 -1
  112. package/src/input/commands/platform-access-runtime.ts +29 -29
  113. package/src/input/commands/provider-accounts-runtime.ts +60 -39
  114. package/src/input/commands/qrcode-runtime.ts +45 -6
  115. package/src/input/commands/recall-bundle.ts +11 -11
  116. package/src/input/commands/recall-capture.ts +13 -11
  117. package/src/input/commands/recall-query.ts +29 -21
  118. package/src/input/commands/recall-review.ts +2 -1
  119. package/src/input/commands/routines-runtime.ts +59 -43
  120. package/src/input/commands/schedule-runtime.ts +33 -20
  121. package/src/input/commands/security-runtime.ts +4 -4
  122. package/src/input/commands/session-content.ts +80 -78
  123. package/src/input/commands/session-workflow.ts +132 -93
  124. package/src/input/commands/session.ts +3 -174
  125. package/src/input/commands/shell-core.ts +32 -17
  126. package/src/input/commands/subscription-runtime.ts +53 -179
  127. package/src/input/commands/tasks-runtime.ts +20 -20
  128. package/src/input/commands/work-plan-runtime.ts +33 -8
  129. package/src/input/commands.ts +2 -2
  130. package/src/input/feed-context-factory.ts +2 -1
  131. package/src/input/file-picker.ts +3 -2
  132. package/src/input/handler-command-route.ts +4 -7
  133. package/src/input/handler-content-actions.ts +89 -1
  134. package/src/input/handler-feed-routes.ts +19 -12
  135. package/src/input/handler-feed.ts +6 -3
  136. package/src/input/handler-interactions.ts +7 -5
  137. package/src/input/handler-modal-stack.ts +3 -3
  138. package/src/input/handler-onboarding.ts +24 -80
  139. package/src/input/handler-shortcuts.ts +15 -4
  140. package/src/input/handler.ts +47 -17
  141. package/src/input/input-history.ts +5 -6
  142. package/src/input/keybindings.ts +22 -11
  143. package/src/input/onboarding/onboarding-wizard-apply.ts +13 -0
  144. package/src/input/onboarding/onboarding-wizard-constants.ts +1 -0
  145. package/src/input/onboarding/onboarding-wizard-operator-steps.ts +147 -57
  146. package/src/input/onboarding/onboarding-wizard-steps.ts +46 -29
  147. package/src/input/onboarding/onboarding-wizard-types.ts +3 -1
  148. package/src/input/onboarding/onboarding-wizard.ts +68 -0
  149. package/src/input/profile-picker-modal.ts +31 -12
  150. package/src/input/session-picker-modal.ts +21 -4
  151. package/src/input/settings-modal-behavior.ts +0 -3
  152. package/src/input/settings-modal-subscriptions.ts +3 -3
  153. package/src/input/settings-modal-types.ts +2 -13
  154. package/src/input/settings-modal.ts +6 -52
  155. package/src/input/submission-intent.ts +0 -1
  156. package/src/input/submission-router.ts +3 -3
  157. package/src/main.ts +18 -8
  158. package/src/panels/approval-panel.ts +8 -8
  159. package/src/panels/automation-control-panel.ts +2 -2
  160. package/src/panels/base-panel.ts +1 -1
  161. package/src/panels/builtin/agent.ts +1 -1
  162. package/src/panels/builtin/operations.ts +1 -10
  163. package/src/panels/builtin/session.ts +9 -9
  164. package/src/panels/builtin/shared.ts +2 -2
  165. package/src/panels/cost-tracker-panel.ts +1 -1
  166. package/src/panels/docs-panel.ts +5 -3
  167. package/src/panels/index.ts +0 -1
  168. package/src/panels/knowledge-panel.ts +6 -5
  169. package/src/panels/memory-panel.ts +7 -6
  170. package/src/panels/panel-list-panel.ts +36 -80
  171. package/src/panels/project-planning-panel.ts +18 -11
  172. package/src/panels/provider-account-snapshot.ts +51 -25
  173. package/src/panels/provider-accounts-panel.ts +33 -18
  174. package/src/panels/provider-health-domains.ts +45 -4
  175. package/src/panels/provider-health-panel.ts +5 -4
  176. package/src/panels/qr-panel.ts +1 -1
  177. package/src/panels/schedule-panel.ts +9 -17
  178. package/src/panels/security-panel.ts +8 -8
  179. package/src/panels/session-browser-panel.ts +10 -10
  180. package/src/panels/subscription-panel.ts +3 -3
  181. package/src/panels/system-messages-panel.ts +1 -1
  182. package/src/panels/tasks-panel.ts +20 -13
  183. package/src/panels/tool-inspector-panel.ts +19 -12
  184. package/src/panels/work-plan-panel.ts +5 -5
  185. package/src/planning/project-planning-coordinator.ts +1 -1
  186. package/src/provider-auth-route-display.ts +9 -0
  187. package/src/renderer/agent-workspace-style.ts +34 -0
  188. package/src/renderer/agent-workspace.ts +228 -52
  189. package/src/renderer/autocomplete-overlay.ts +25 -6
  190. package/src/renderer/bookmark-modal.ts +19 -4
  191. package/src/renderer/buffer.ts +4 -2
  192. package/src/renderer/context-inspector.ts +50 -13
  193. package/src/renderer/diff.ts +1 -1
  194. package/src/renderer/file-picker-overlay.ts +19 -6
  195. package/src/renderer/help-overlay.ts +106 -33
  196. package/src/renderer/history-search-overlay.ts +19 -4
  197. package/src/renderer/live-tail-modal.ts +27 -5
  198. package/src/renderer/mcp-workspace.ts +164 -50
  199. package/src/renderer/model-picker-overlay.ts +58 -2
  200. package/src/renderer/model-workspace.ts +104 -20
  201. package/src/renderer/process-modal.ts +27 -6
  202. package/src/renderer/profile-picker-modal.ts +20 -4
  203. package/src/renderer/search-overlay.ts +25 -5
  204. package/src/renderer/selection-modal-overlay.ts +46 -14
  205. package/src/renderer/session-picker-modal.ts +18 -1
  206. package/src/renderer/settings-modal-helpers.ts +2 -40
  207. package/src/renderer/settings-modal.ts +83 -50
  208. package/src/renderer/tool-call.ts +20 -11
  209. package/src/runtime/agent-runtime-events.ts +6 -6
  210. package/src/runtime/bootstrap-command-context.ts +7 -1
  211. package/src/runtime/bootstrap-command-parts.ts +9 -7
  212. package/src/runtime/bootstrap-core.ts +19 -1
  213. package/src/runtime/bootstrap-hook-bridge.ts +7 -18
  214. package/src/runtime/bootstrap-shell.ts +4 -4
  215. package/src/runtime/bootstrap.ts +31 -22
  216. package/src/runtime/connected-host-auth.ts +7 -2
  217. package/src/runtime/diagnostics/panels/index.ts +2 -2
  218. package/src/runtime/diagnostics/panels/policy.ts +7 -7
  219. package/src/runtime/index.ts +2 -1
  220. package/src/runtime/onboarding/apply-file-helpers.ts +66 -0
  221. package/src/runtime/onboarding/apply.ts +80 -79
  222. package/src/runtime/onboarding/derivation.ts +5 -8
  223. package/src/runtime/onboarding/snapshot.ts +0 -15
  224. package/src/runtime/onboarding/types.ts +8 -19
  225. package/src/runtime/onboarding/verify.ts +32 -10
  226. package/src/runtime/operator-token-cleanup.ts +1 -1
  227. package/src/runtime/services.ts +91 -22
  228. package/src/runtime/store/selectors/index.ts +3 -3
  229. package/src/runtime/store/state.ts +1 -4
  230. package/src/runtime/surface-feature-flags.ts +41 -6
  231. package/src/runtime/ui-read-models.ts +3 -4
  232. package/src/runtime/ui-services.ts +6 -6
  233. package/src/shell/blocking-input.ts +2 -1
  234. package/src/shell/ui-openers.ts +3 -13
  235. package/src/tools/agent-analysis-registry-policy.ts +0 -1
  236. package/src/tools/agent-channel-send-tool.ts +133 -0
  237. package/src/tools/agent-context-policy.ts +1 -1
  238. package/src/tools/agent-knowledge-ingest-tool.ts +405 -0
  239. package/src/tools/agent-knowledge-tool.ts +170 -0
  240. package/src/tools/agent-local-registry-tool.ts +269 -69
  241. package/src/tools/agent-media-generate-tool.ts +133 -0
  242. package/src/tools/agent-notify-tool.ts +143 -0
  243. package/src/tools/agent-operator-action-tool.ts +137 -0
  244. package/src/tools/agent-operator-briefing-tool.ts +217 -0
  245. package/src/tools/agent-reminder-schedule-tool.ts +237 -0
  246. package/src/tools/agent-tool-policy-guard.ts +8 -8
  247. package/src/tools/agent-work-plan-tool.ts +256 -0
  248. package/src/version.ts +1 -1
  249. package/src/input/commands/policy-dispatch.ts +0 -339
  250. package/src/input/commands/policy.ts +0 -13
  251. package/src/panels/panel-picker.ts +0 -105
  252. package/src/panels/policy-panel.ts +0 -308
  253. package/src/renderer/panel-picker-overlay.ts +0 -202
@@ -1,18 +1,34 @@
1
- import type { CommandRegistry } from '../command-registry.ts';
1
+ import type { CommandContext, CommandRegistry } from '../command-registry.ts';
2
+ import { AGENT_WORKSPACE_CATEGORY_IDS } from '../agent-workspace-types.ts';
3
+
4
+ const AGENT_WORKSPACE_ARGS_HINT = `${AGENT_WORKSPACE_CATEGORY_IDS.join('|')}|connected-host`;
2
5
 
3
6
  export function registerAgentWorkspaceRuntimeCommands(registry: CommandRegistry): void {
7
+ function openAgentWorkspace(ctx: CommandContext, categoryId: string | undefined): void {
8
+ if (!ctx.openAgentWorkspace) {
9
+ ctx.print('Agent operator workspace is not available in this runtime.');
10
+ return;
11
+ }
12
+ ctx.openAgentWorkspace(categoryId);
13
+ }
14
+
4
15
  registry.register({
5
16
  name: 'agent',
6
17
  aliases: ['home', 'operator'],
7
18
  description: 'Open the GoodVibes Agent operator workspace',
8
19
  usage: '[category]',
9
- argsHint: 'home|setup|channels|tools|knowledge|voice-media|profiles|memory|personas|skills|routines|work|automation|delegate',
20
+ argsHint: AGENT_WORKSPACE_ARGS_HINT,
10
21
  handler(args, ctx) {
11
- if (!ctx.openAgentWorkspace) {
12
- ctx.print('Agent operator workspace is not available in this runtime.');
13
- return;
14
- }
15
- ctx.openAgentWorkspace(args[0]);
22
+ openAgentWorkspace(ctx, args[0]);
23
+ },
24
+ });
25
+ registry.register({
26
+ name: 'notes',
27
+ aliases: ['scratchpad'],
28
+ description: 'Open Agent-local scratchpad notes in the operator workspace',
29
+ usage: '',
30
+ handler(_args, ctx) {
31
+ openAgentWorkspace(ctx, 'notes');
16
32
  },
17
33
  });
18
34
  }
@@ -39,7 +39,7 @@ function countSetupGaps(items: readonly { readonly missingRequirementCount?: num
39
39
  }
40
40
 
41
41
  function formatWorkPlanLine(total: number, counts: StatusCounts): string {
42
- if (total === 0) return ' work plan: empty';
42
+ if (total === 0) return ' work plan empty';
43
43
  const active = counts.pending + counts.in_progress + counts.blocked;
44
44
  return [
45
45
  ` work plan: ${plural(total, 'item')}`,
@@ -52,8 +52,8 @@ function formatWorkPlanLine(total: number, counts: StatusCounts): string {
52
52
  }
53
53
 
54
54
  function formatWarnings(warnings: readonly string[]): readonly string[] {
55
- if (warnings.length === 0) return [' warnings: none'];
56
- return [' warnings:', ...warnings.slice(0, 4).map((warning) => ` - ${warning}`)];
55
+ if (warnings.length === 0) return [' warnings none'];
56
+ return [' warnings', ...warnings.slice(0, 4).map((warning) => ` - ${warning}`)];
57
57
  }
58
58
 
59
59
  export function formatAgentOperatorBriefing(ctx: CommandContext): string {
@@ -76,63 +76,64 @@ export function formatAgentOperatorBriefing(ctx: CommandContext): string {
76
76
 
77
77
  const nextActions = [
78
78
  snapshot.provider === 'unknown' || snapshot.model === 'unknown'
79
- ? 'Choose the assistant model with /model.'
79
+ ? 'Choose the assistant model from Agent Workspace -> Home -> Choose model.'
80
80
  : '',
81
81
  snapshot.localMemoryCount === 0
82
- ? 'Store durable non-secret facts with /memory add or the Agent workspace memory form.'
82
+ ? 'Store durable non-secret facts from Agent Workspace -> Memory -> Add memory.'
83
83
  : snapshot.localMemoryReviewQueueCount > 0
84
- ? `Review ${plural(snapshot.localMemoryReviewQueueCount, 'memory record')} with /memory queue.`
84
+ ? `Review ${plural(snapshot.localMemoryReviewQueueCount, 'memory record')} from Agent Workspace -> Memory -> Review queue.`
85
85
  : '',
86
86
  !hasLocalSkillBehavior
87
- ? 'Create reusable procedures with /agent-skills create or import reviewed skill files.'
87
+ ? 'Create reusable procedures from Agent Workspace -> Skills or import reviewed skill files.'
88
88
  : '',
89
89
  skillSetupGaps > 0
90
- ? `Resolve ${plural(skillSetupGaps, 'skill')} with setup gaps from /agent skills.`
90
+ ? `Resolve ${plural(skillSetupGaps, 'skill')} with setup gaps from Agent Workspace -> Skills.`
91
91
  : '',
92
92
  skillBundleSetupGaps > 0
93
- ? `Resolve ${plural(skillBundleSetupGaps, 'skill bundle')} with setup gaps from /agent skills.`
93
+ ? `Resolve ${plural(skillBundleSetupGaps, 'skill bundle')} with setup gaps from Agent Workspace -> Skills.`
94
94
  : '',
95
95
  hasLocalSkillBehavior && skillSetupGaps === 0 && skillBundleSetupGaps === 0 && snapshot.activeSkillCount === 0
96
- ? 'Enable reviewed skills or bundles with /agent-skills enabled and /agent-skills bundle enabled.'
96
+ ? 'Enable reviewed skills or bundles from Agent Workspace -> Skills.'
97
97
  : '',
98
98
  snapshot.localRoutineCount === 0
99
- ? 'Create repeatable workflows with /routines create; promote schedules only with explicit confirmation.'
99
+ ? 'Create repeatable workflows from Agent Workspace -> Routines; promote schedules only with explicit confirmation.'
100
100
  : routineSetupGaps > 0
101
- ? `Resolve ${plural(routineSetupGaps, 'routine')} with setup gaps from /agent routines.`
101
+ ? `Resolve ${plural(routineSetupGaps, 'routine')} with setup gaps from Agent Workspace -> Routines.`
102
102
  : snapshot.enabledRoutineCount === 0
103
- ? 'Enable reviewed routines with /routines enable.'
103
+ ? 'Enable reviewed routines from Agent Workspace -> Routines.'
104
104
  : '',
105
105
  channelSetupGaps > 0
106
- ? `Review ${plural(channelSetupGaps, 'enabled channel')} needing setup from /agent channels.`
106
+ ? `Review ${plural(channelSetupGaps, 'enabled channel')} needing setup from Agent Workspace -> Channels.`
107
107
  : '',
108
108
  voiceSetupNeedsReview
109
- ? 'Review voice setup with /agent voice-media before relying on spoken replies.'
109
+ ? 'Review voice setup from Agent Workspace -> Voice & Media before relying on spoken replies.'
110
110
  : '',
111
111
  mediaSetupNeedsReview
112
- ? 'Review media provider setup with /agent voice-media before relying on image or media workflows.'
112
+ ? 'Review media provider setup from Agent Workspace -> Voice & Media before relying on image or media workflows.'
113
113
  : '',
114
- 'Use /agent knowledge for Agent Knowledge status, search, and explicit ingest forms.',
115
- 'Use /delegate only for explicit build, fix, implementation, or review handoff to GoodVibes TUI.',
114
+ 'Use Agent Workspace -> Knowledge for Agent Knowledge status, search, and explicit ingest forms.',
115
+ 'Use Agent Workspace -> Build Delegation only for explicit build, fix, implementation, or review handoff to GoodVibes TUI.',
116
116
  ].filter((line): line is string => line.length > 0);
117
117
 
118
118
  return [
119
119
  'Agent Briefing',
120
120
  ` chat route: ${snapshot.provider} / ${snapshot.modelDisplayName}`,
121
- ` session: ${snapshot.sessionId}`,
122
- ` profile: ${snapshot.activeRuntimeProfile}`,
123
- ` policy: ${snapshot.executionPolicy}; WRFC ${snapshot.wrfcPolicy}`,
124
- ` knowledge: ${snapshot.knowledgeRoute} (${snapshot.knowledgeIsolation}; no fallback)`,
121
+ ` session ${snapshot.sessionId}`,
122
+ ` profile ${snapshot.activeRuntimeProfile}`,
123
+ ` policy ${snapshot.executionPolicy}; delegated review ${snapshot.delegatedReviewPolicy}`,
124
+ ` knowledge ${snapshot.knowledgeRoute} (${snapshot.knowledgeIsolation}; no fallback)`,
125
125
  '',
126
126
  'Readiness',
127
- ` setup: ${setupReady}/${snapshot.setupChecklist.length} ready; ${setupRecommended} recommended; ${setupBlocked} blocked`,
127
+ ` setup ${setupReady}/${snapshot.setupChecklist.length} ready; ${setupRecommended} recommended; ${setupBlocked} blocked`,
128
128
  ` local memory: ${plural(snapshot.localMemoryCount, 'record')}; prompt-active ${snapshot.localMemoryPromptActiveCount}; review queue ${snapshot.localMemoryReviewQueueCount}`,
129
+ ` scratchpad notes: ${plural(snapshot.localNoteCount, 'note')}; review queue ${snapshot.localNoteReviewQueueCount}`,
129
130
  ` personas: ${plural(snapshot.localPersonaCount, 'persona')}; active ${snapshot.activePersonaName}`,
130
131
  ` skills: ${snapshot.enabledSkillCount}/${snapshot.localSkillCount} enabled; bundles ${snapshot.enabledSkillBundleCount}/${snapshot.localSkillBundleCount}; active ${snapshot.activeSkillCount}; setup gaps ${skillSetupGaps} skill, ${skillBundleSetupGaps} bundle`,
131
132
  ` routines: ${snapshot.enabledRoutineCount}/${snapshot.localRoutineCount} enabled; setup gaps ${routineSetupGaps}`,
132
133
  ` channels: ${readyChannels}/${snapshot.channels.length} ready; ${enabledChannels} enabled; setup gaps ${channelSetupGaps}`,
133
134
  ` voice/media: ${snapshot.voiceProviderCount} voice, ${snapshot.mediaProviderCount} media; browser tools ${snapshot.voiceMediaReadiness.browserToolState}`,
134
135
  formatWorkPlanLine(workPlan.total, workPlan.counts),
135
- ` schedules: ${enabledJobs}/${jobs.length} visible jobs enabled`,
136
+ ` schedules ${enabledJobs}/${jobs.length} visible jobs enabled`,
136
137
  '',
137
138
  'Next Actions',
138
139
  ...nextActions.map((line) => ` - ${line}`),
@@ -4,11 +4,29 @@ import type { CommandRegistry } from '../command-registry.ts';
4
4
  import type { CommandContext } from '../command-registry.ts';
5
5
  import type { AgentWorkspaceChannelStatus } from '../agent-workspace-channels.ts';
6
6
  import { buildAgentWorkspaceChannels } from '../agent-workspace-channels.ts';
7
+ import {
8
+ buildAgentChannelDeliveryPreview,
9
+ deliverAgentChannelMessage,
10
+ formatAgentChannelDeliveryPreview,
11
+ formatAgentChannelDeliveryResult,
12
+ } from '../../agent/channel-delivery.ts';
13
+ import { requireYesFlag, stripYesFlag } from './confirmation.ts';
7
14
 
8
15
  type ChannelFilter = 'all' | 'ready' | 'attention';
9
16
  type JsonRecord = Record<string, unknown>;
10
17
 
11
- interface ChannelDaemonConnection {
18
+ interface ChannelSendArgs {
19
+ readonly message: string;
20
+ readonly title?: string;
21
+ readonly channel?: string;
22
+ readonly route?: string;
23
+ readonly webhook?: string;
24
+ readonly link?: string;
25
+ readonly yes: boolean;
26
+ readonly errors: readonly string[];
27
+ }
28
+
29
+ interface ChannelConnectedHostConnection {
12
30
  readonly baseUrl: string;
13
31
  readonly token: string | null;
14
32
  readonly tokenPath: string;
@@ -23,12 +41,20 @@ interface ChannelRouteSuccess {
23
41
  interface ChannelRouteFailure {
24
42
  readonly ok: false;
25
43
  readonly route: string;
26
- readonly kind: 'auth_required' | 'daemon_unavailable' | 'route_unavailable' | 'daemon_error';
44
+ readonly kind: 'auth_required' | 'connected_host_unavailable' | 'connected_host_route_unavailable' | 'connected_host_error';
45
+ readonly baseUrl: string;
27
46
  readonly message: string;
28
47
  }
29
48
 
30
49
  type ChannelRouteResult = ChannelRouteSuccess | ChannelRouteFailure;
31
50
 
51
+ const CHANNEL_FAILURE_LABELS: Record<ChannelRouteFailure['kind'], string> = {
52
+ auth_required: 'auth required',
53
+ connected_host_unavailable: 'connected host unavailable',
54
+ connected_host_route_unavailable: 'connected host route unavailable',
55
+ connected_host_error: 'connected host error',
56
+ };
57
+
32
58
  function isRecord(value: unknown): value is JsonRecord {
33
59
  return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
34
60
  }
@@ -48,7 +74,59 @@ function readRecordArray(record: JsonRecord, key: string): readonly JsonRecord[]
48
74
  return Array.isArray(value) ? value.filter(isRecord) : [];
49
75
  }
50
76
 
51
- function resolveChannelDaemonConnection(context: CommandContext): ChannelDaemonConnection {
77
+ function readFlagValue(args: readonly string[], index: number, flag: string, errors: string[]): string | null {
78
+ const value = args[index + 1];
79
+ if (!value || value.startsWith('--')) {
80
+ errors.push(`${flag} requires a value.`);
81
+ return null;
82
+ }
83
+ return value;
84
+ }
85
+
86
+ function parseChannelSendArgs(args: readonly string[]): ChannelSendArgs {
87
+ const parsed = stripYesFlag([...args]);
88
+ const errors: string[] = [];
89
+ const messageParts: string[] = [];
90
+ let title: string | undefined;
91
+ let channel: string | undefined;
92
+ let route: string | undefined;
93
+ let webhook: string | undefined;
94
+ let link: string | undefined;
95
+
96
+ for (let index = 0; index < parsed.rest.length; index += 1) {
97
+ const arg = parsed.rest[index];
98
+ if (arg === '--title' || arg === '--message' || arg === '--channel' || arg === '--route' || arg === '--webhook' || arg === '--link') {
99
+ const value = readFlagValue(parsed.rest, index, arg, errors);
100
+ index += 1;
101
+ if (!value) continue;
102
+ if (arg === '--title') title = value;
103
+ else if (arg === '--message') messageParts.push(value);
104
+ else if (arg === '--channel') channel = value;
105
+ else if (arg === '--route') route = value;
106
+ else if (arg === '--webhook') webhook = value;
107
+ else link = value;
108
+ } else if (arg?.startsWith('--')) {
109
+ errors.push(`Unknown channel send flag ${arg}`);
110
+ } else if (arg) {
111
+ messageParts.push(arg);
112
+ }
113
+ }
114
+
115
+ const message = messageParts.join(' ').trim();
116
+ if (!message) errors.push('Channel send message is required.');
117
+ return {
118
+ message,
119
+ ...(title ? { title } : {}),
120
+ ...(channel ? { channel } : {}),
121
+ ...(route ? { route } : {}),
122
+ ...(webhook ? { webhook } : {}),
123
+ ...(link ? { link } : {}),
124
+ yes: parsed.yes,
125
+ errors,
126
+ };
127
+ }
128
+
129
+ function resolveChannelConnectedHostConnection(context: CommandContext): ChannelConnectedHostConnection {
52
130
  const hostValue = context.platform?.configManager?.get('controlPlane.host');
53
131
  const portValue = context.platform?.configManager?.get('controlPlane.port');
54
132
  const host = typeof hostValue === 'string' && hostValue.trim().length > 0 ? hostValue.trim() : '127.0.0.1';
@@ -66,13 +144,14 @@ function resolveChannelDaemonConnection(context: CommandContext): ChannelDaemonC
66
144
  }
67
145
 
68
146
  async function fetchChannelRoute(context: CommandContext, route: string): Promise<ChannelRouteResult> {
69
- const connection = resolveChannelDaemonConnection(context);
147
+ const connection = resolveChannelConnectedHostConnection(context);
70
148
  if (!connection.token) {
71
149
  return {
72
150
  ok: false,
73
151
  route,
74
152
  kind: 'auth_required',
75
- message: `No runtime operator token found at ${connection.tokenPath}`,
153
+ baseUrl: connection.baseUrl,
154
+ message: `No connected-host operator token found at ${connection.tokenPath}`,
76
155
  };
77
156
  }
78
157
 
@@ -97,8 +176,9 @@ async function fetchChannelRoute(context: CommandContext, route: string): Promis
97
176
  kind: response.status === 401 || response.status === 403
98
177
  ? 'auth_required'
99
178
  : response.status === 404
100
- ? 'route_unavailable'
101
- : 'daemon_error',
179
+ ? 'connected_host_route_unavailable'
180
+ : 'connected_host_error',
181
+ baseUrl: connection.baseUrl,
102
182
  message: `HTTP ${response.status}${detail ? `: ${detail}` : ''}`,
103
183
  };
104
184
  }
@@ -107,7 +187,8 @@ async function fetchChannelRoute(context: CommandContext, route: string): Promis
107
187
  return {
108
188
  ok: false,
109
189
  route,
110
- kind: 'daemon_unavailable',
190
+ kind: 'connected_host_unavailable',
191
+ baseUrl: connection.baseUrl,
111
192
  message: error instanceof Error ? error.message : String(error),
112
193
  };
113
194
  }
@@ -116,7 +197,9 @@ async function fetchChannelRoute(context: CommandContext, route: string): Promis
116
197
  function formatChannelRouteFailure(title: string, failure: ChannelRouteFailure): string {
117
198
  return [
118
199
  `${title}: unavailable`,
200
+ ` status: ${CHANNEL_FAILURE_LABELS[failure.kind]}`,
119
201
  ` kind: ${failure.kind}`,
202
+ ` connected host: ${failure.baseUrl}`,
120
203
  ` route: ${failure.route}`,
121
204
  ` error: ${failure.message}`,
122
205
  ' policy: read-only; no channel send/action route was called',
@@ -207,8 +290,8 @@ function formatChannelAccounts(body: unknown): string {
207
290
  const accounts = readRecordArray(root, 'accounts');
208
291
  const lines = [
209
292
  'Channel Accounts',
210
- ` accounts: ${accounts.length}`,
211
- ' policy: read-only account posture; secret values are never shown',
293
+ ` accounts ${accounts.length}`,
294
+ ' policy read-only account posture; secret values are never shown',
212
295
  '',
213
296
  ];
214
297
  if (accounts.length === 0) return [...lines, ' No channel accounts reported by connected host.'].join('\n');
@@ -218,10 +301,10 @@ function formatChannelAccounts(body: unknown): string {
218
301
  const authState = readString(account, 'authState', readString(account, 'state', 'unknown'));
219
302
  const configured = readBoolean(account, 'configured') ? 'configured' : 'not-configured';
220
303
  const linked = readBoolean(account, 'linked') ? 'linked' : 'not-linked';
221
- const secrets = readRecordArray(account, 'secrets')
222
- .map((secret) => `${readString(secret, 'field', 'secret')}:${readString(secret, 'source', 'configured')}`)
304
+ const secretFields = readRecordArray(account, 'secrets')
305
+ .map((secret) => readString(secret, 'field', 'secret'))
223
306
  .join(', ') || 'none';
224
- lines.push(` ${surface}${accountId ? `/${accountId}` : ''}: ${configured}; ${linked}; auth=${authState}; secret refs=${secrets}`);
307
+ lines.push(` ${surface}${accountId ? `/${accountId}` : ''}: ${configured}; ${linked}; auth=${authState}; secret refs=${secretFields === 'none' ? 'none' : secretFields.split(', ').map((field) => `${field}:config`).join(',')}`);
225
308
  }
226
309
  if (accounts.length > 20) lines.push(` ${accounts.length - 20} more account(s) omitted.`);
227
310
  return lines.join('\n');
@@ -232,8 +315,8 @@ function formatChannelPolicies(body: unknown): string {
232
315
  const policies = readRecordArray(root, 'policies');
233
316
  const lines = [
234
317
  'Channel Policies',
235
- ` policies: ${policies.length}`,
236
- ' policy: read-only policy posture; use exact confirmed commands for changes',
318
+ ` policies ${policies.length}`,
319
+ ' policy read-only policy posture; use exact confirmed commands for changes',
237
320
  '',
238
321
  ];
239
322
  if (policies.length === 0) return [...lines, ' No channel policies reported by connected host.'].join('\n');
@@ -254,8 +337,8 @@ function formatChannelStatus(body: unknown): string {
254
337
  const channels = readRecordArray(root, 'channels');
255
338
  const lines = [
256
339
  'Connected Channel Status',
257
- ` channels: ${channels.length}`,
258
- ' policy: read-only connected-host status',
340
+ ` channels ${channels.length}`,
341
+ ' policy read-only connected-host status',
259
342
  '',
260
343
  ];
261
344
  if (channels.length === 0) return [...lines, ' No connected channel status reported.'].join('\n');
@@ -276,9 +359,9 @@ function formatChannelDoctor(surface: string, body: unknown): string {
276
359
  const repairActions = readRecordArray(root, 'repairActions');
277
360
  const lines = [
278
361
  `Channel Doctor: ${readString(root, 'surface', surface)}`,
279
- ` checks: ${checks.length}`,
280
- ` repair actions: ${repairActions.length}`,
281
- ' policy: read-only doctor report; repair actions are not run here',
362
+ ` checks ${checks.length}`,
363
+ ` repair actions ${repairActions.length}`,
364
+ ' policy read-only doctor report; repair actions are not run here',
282
365
  '',
283
366
  ];
284
367
  if (checks.length === 0) lines.push(' No doctor checks reported.');
@@ -298,18 +381,18 @@ function formatChannelSetup(surface: string, body: unknown): string {
298
381
  const secretTargets = readRecordArray(root, 'secretTargets');
299
382
  const lines = [
300
383
  `Channel Setup Schema: ${readString(root, 'surface', surface)}`,
301
- ` version: ${typeof root.version === 'number' ? root.version : 'unknown'}`,
302
- ` fields: ${fields.length}`,
303
- ` secret targets: ${secretTargets.length}`,
304
- ' policy: read-only setup schema; no credentials or values are printed',
384
+ ` version ${typeof root.version === 'number' ? root.version : 'unknown'}`,
385
+ ` fields ${fields.length}`,
386
+ ` secret targets ${secretTargets.length}`,
387
+ ' policy read-only setup form; no credentials or values are printed',
305
388
  '',
306
389
  ];
307
390
  if (fields.length > 0) {
308
- lines.push(' Fields:');
391
+ lines.push(' Fields');
309
392
  for (const field of fields.slice(0, 20)) lines.push(` - ${readString(field, 'id', 'field')}`);
310
393
  }
311
394
  if (secretTargets.length > 0) {
312
- lines.push('', ' Secret targets:');
395
+ lines.push('', ' Secret targets');
313
396
  for (const target of secretTargets.slice(0, 12)) {
314
397
  const required = readBoolean(target, 'required') ? 'required' : 'optional';
315
398
  lines.push(` - ${readString(target, 'id', 'secret')} (${required})`);
@@ -336,9 +419,9 @@ export function registerChannelsRuntimeCommands(registry: CommandRegistry): void
336
419
  registry.register({
337
420
  name: 'channels',
338
421
  aliases: ['channel'],
339
- description: 'Inspect Agent channel readiness without sending messages',
340
- usage: '[list|readiness|ready|attention|show <id>|accounts|policies|status|doctor <id>|setup <id>]',
341
- argsHint: 'list|readiness|ready|attention|show|accounts|policies|status|doctor|setup',
422
+ description: 'Inspect Agent channel readiness or send an explicitly confirmed delivery message',
423
+ usage: '[list|readiness|ready|attention|show <id>|send --channel <id> --message <text> --yes|accounts|policies|status|doctor <id>|setup <id>]',
424
+ argsHint: 'list|readiness|ready|attention|show|send|accounts|policies|status|doctor|setup',
342
425
  async handler(args, ctx) {
343
426
  const channels = buildAgentWorkspaceChannels(ctx);
344
427
  const subcommand = (args[0] ?? 'readiness').trim().toLowerCase();
@@ -366,13 +449,44 @@ export function registerChannelsRuntimeCommands(registry: CommandRegistry): void
366
449
  }
367
450
  const channel = channels.find((entry) => entry.id.toLowerCase() === channelId || entry.label.toLowerCase() === channelId);
368
451
  if (!channel) {
369
- ctx.print(`Unknown channel: ${channelId}\nUse /channels list to see available channel ids.`);
452
+ ctx.print(`Unknown channel ${channelId}\nUse /channels list to see available channel ids.`);
370
453
  return;
371
454
  }
372
455
  printChannelDetail(ctx.print, channel);
373
456
  return;
374
457
  }
375
458
 
459
+ if (subcommand === 'send') {
460
+ const router = ctx.platform.channelDeliveryRouter;
461
+ if (!router) {
462
+ ctx.print('Channel delivery is not available in this Agent runtime.');
463
+ return;
464
+ }
465
+ const parsed = parseChannelSendArgs(args.slice(1));
466
+ if (parsed.errors.length > 0) {
467
+ ctx.print(`[channels] ${parsed.errors.join('\n[channels] ')}`);
468
+ return;
469
+ }
470
+ let preview: ReturnType<typeof buildAgentChannelDeliveryPreview>;
471
+ try {
472
+ preview = buildAgentChannelDeliveryPreview(parsed);
473
+ } catch (error) {
474
+ ctx.print(`[channels] ${error instanceof Error ? error.message : String(error)}`);
475
+ return;
476
+ }
477
+ if (!parsed.yes) {
478
+ ctx.print(formatAgentChannelDeliveryPreview(preview, router.listStrategies().length));
479
+ requireYesFlag(ctx, 'send a channel delivery message', '/channels send --channel <surface[:route[:label]]> --message <text> --yes');
480
+ return;
481
+ }
482
+ try {
483
+ ctx.print(formatAgentChannelDeliveryResult(await deliverAgentChannelMessage(router, parsed)));
484
+ } catch (error) {
485
+ ctx.print(`[channels] Send failed ${error instanceof Error ? error.message : String(error)}`);
486
+ }
487
+ return;
488
+ }
489
+
376
490
  if (subcommand === 'accounts') {
377
491
  await printReadOnlyChannelRoute(ctx, 'Channel accounts', '/api/channels/accounts', formatChannelAccounts);
378
492
  return;
@@ -403,7 +517,7 @@ export function registerChannelsRuntimeCommands(registry: CommandRegistry): void
403
517
  return;
404
518
  }
405
519
 
406
- ctx.print('Usage: /channels [list|readiness|ready|attention|show <id>|accounts|policies|status|doctor <id>|setup <id>]');
520
+ ctx.print('Usage: /channels [list|readiness|ready|attention|show <id>|send --channel <id> --message <text> --yes|accounts|policies|status|doctor <id>|setup <id>]');
407
521
  },
408
522
  });
409
523
  }
@@ -6,11 +6,15 @@ function hasFlag(args: readonly string[], flag: string): boolean {
6
6
  return args.includes(flag);
7
7
  }
8
8
 
9
+ function hasAnyFlag(args: readonly string[], flags: readonly string[]): boolean {
10
+ return flags.some((flag) => hasFlag(args, flag));
11
+ }
12
+
9
13
  function delegationTaskValues(args: readonly string[]): string[] {
10
14
  const values: string[] = [];
11
15
  for (let index = 0; index < args.length; index += 1) {
12
16
  const token = args[index]!;
13
- if (token === '--wrfc') continue;
17
+ if (token === '--review' || token === '--wrfc') continue;
14
18
  if (!token.startsWith('--')) {
15
19
  values.push(token);
16
20
  continue;
@@ -19,35 +23,35 @@ function delegationTaskValues(args: readonly string[]): string[] {
19
23
  return values;
20
24
  }
21
25
 
22
- function buildDelegationBody(task: string, wrfcRequested: boolean): string {
26
+ function buildDelegationBody(task: string, reviewRequested: boolean): string {
23
27
  return [
24
28
  'GoodVibes Agent explicit build delegation.',
25
29
  '',
26
- 'Original user ask:',
30
+ 'Original user ask',
27
31
  task,
28
32
  '',
29
- 'Agent policy:',
33
+ 'Agent policy',
30
34
  '- GoodVibes Agent is not the coding TUI.',
31
35
  '- Preserve the full original ask.',
32
- '- GoodVibes TUI owns file edits, git/worktree flows, execution isolation UX, and any WRFC owner chain.',
33
- wrfcRequested
34
- ? '- WRFC was explicitly requested by the Agent user for this build/fix/review delegation.'
35
- : '- WRFC was not explicitly requested; do not turn this into WRFC solely because it came from Agent.',
36
+ '- GoodVibes TUI owns file edits, git/worktree flows, execution isolation UX, and any delegated review owner chain.',
37
+ reviewRequested
38
+ ? '- Delegated review was explicitly requested by the Agent user for this build/fix/review handoff.'
39
+ : '- Delegated review was not explicitly requested; do not add review solely because this came from Agent.',
36
40
  ].join('\n');
37
41
  }
38
42
 
39
43
  export function registerDelegationRuntimeCommands(registry: CommandRegistry): void {
40
- const makeHandler = (defaultWrfc: boolean) => async (args: string[], ctx: CommandContext): Promise<void> => {
41
- const wrfcRequested = defaultWrfc || hasFlag(args, '--wrfc');
44
+ const makeHandler = (defaultReview: boolean) => async (args: string[], ctx: CommandContext): Promise<void> => {
45
+ const reviewRequested = defaultReview || hasAnyFlag(args, ['--review', '--wrfc']);
42
46
  const task = delegationTaskValues(args).join(' ').trim();
43
47
  if (!task) {
44
- ctx.print(defaultWrfc ? 'Usage: /wrfc <build/fix/review task>' : 'Usage: /delegate [--wrfc] <build/fix/review task>');
48
+ ctx.print(defaultReview ? 'Usage: /delegate --review <build/fix/review task>' : 'Usage: /delegate [--review] <build/fix/review task>');
45
49
  return;
46
50
  }
47
51
  const operator = ctx.clients?.operator;
48
52
  if (!operator) {
49
53
  ctx.print([
50
- 'Delegation unavailable: no operator client is attached.',
54
+ 'Delegation unavailable. No operator client is attached.',
51
55
  'Use the shared-session route from a configured Agent runtime, or open GoodVibes TUI in the target workspace.',
52
56
  ].join('\n'));
53
57
  return;
@@ -67,12 +71,13 @@ export function registerDelegationRuntimeCommands(registry: CommandRegistry): vo
67
71
  originSurface: 'goodvibes-agent',
68
72
  sourceSessionId: ctx.session.runtime.sessionId,
69
73
  task,
70
- wrfcRequested,
74
+ reviewRequested,
75
+ wrfcRequested: reviewRequested,
71
76
  },
72
77
  });
73
78
  await operator.sessions.submitMessage({
74
79
  sessionId: session.id,
75
- body: buildDelegationBody(task, wrfcRequested),
80
+ body: buildDelegationBody(task, reviewRequested),
76
81
  surfaceKind: participant.surfaceKind,
77
82
  surfaceId: participant.surfaceId,
78
83
  externalId: participant.externalId,
@@ -83,7 +88,8 @@ export function registerDelegationRuntimeCommands(registry: CommandRegistry): vo
83
88
  sourceSessionId: ctx.session.runtime.sessionId,
84
89
  kind: 'task',
85
90
  task,
86
- wrfcRequested,
91
+ reviewRequested,
92
+ wrfcRequested: reviewRequested,
87
93
  },
88
94
  routing: {
89
95
  executionIntent: {
@@ -96,16 +102,16 @@ export function registerDelegationRuntimeCommands(registry: CommandRegistry): vo
96
102
  });
97
103
  ctx.print([
98
104
  'Delegation submitted to GoodVibes TUI/shared-session routes.',
99
- ` session: ${session.id}`,
100
- ` mode: ${wrfcRequested ? 'WRFC requested' : 'direct build delegation'}`,
101
- ` task: ${task}`,
102
- ' next: check GoodVibes TUI shared-session/task status for the result.',
105
+ ` session ${session.id}`,
106
+ ` mode ${reviewRequested ? 'delegated review requested' : 'direct build delegation'}`,
107
+ ` task ${task}`,
108
+ ' next check GoodVibes TUI shared-session/task status for the result.',
103
109
  ].join('\n'));
104
110
  } catch (error) {
105
111
  ctx.print([
106
112
  'Delegation failed.',
107
- ` error: ${summarizeError(error)}`,
108
- ' fallback: open GoodVibes TUI in the target workspace and paste the original task there.',
113
+ ` error ${summarizeError(error)}`,
114
+ ' fallback open GoodVibes TUI in the target workspace and paste the original task there.',
109
115
  ].join('\n'));
110
116
  }
111
117
  };
@@ -114,8 +120,8 @@ export function registerDelegationRuntimeCommands(registry: CommandRegistry): vo
114
120
  name: 'delegate',
115
121
  aliases: ['build'],
116
122
  description: 'Explicitly delegate build/fix/review work to GoodVibes TUI through shared-session routes',
117
- usage: '[--wrfc] <task>',
118
- argsHint: '[--wrfc] <task>',
123
+ usage: '[--review] <task>',
124
+ argsHint: '[--review] <task>',
119
125
  handler: makeHandler(false),
120
126
  });
121
127
  }
@@ -3,6 +3,7 @@ import { dirname, resolve } from 'node:path';
3
3
  import type { CommandRegistry } from '../command-registry.ts';
4
4
  import { requireShellPaths } from './runtime-services.ts';
5
5
  import { requireYesFlag, stripYesFlag } from './confirmation.ts';
6
+ import { handleApprovalOperatorAction } from './operator-actions-runtime.ts';
6
7
 
7
8
  interface VoiceBundle {
8
9
  readonly version: 1;
@@ -25,18 +26,19 @@ export function registerExperienceRuntimeCommands(registry: CommandRegistry): vo
25
26
  name: 'approval',
26
27
  aliases: ['approvals'],
27
28
  description: 'Review action-specific approval classes and the specialized security UX matrix',
28
- usage: '[matrix|review <kind>]',
29
+ usage: '[matrix|review <kind>|approve <id> --yes|deny <id> --yes|cancel <id> --yes]',
29
30
  async handler(args, ctx) {
30
31
  const sub = (args[0] ?? 'matrix').toLowerCase();
32
+ if (await handleApprovalOperatorAction(args, ctx)) return;
31
33
  if (sub === 'open' || sub === 'panel') {
32
- ctx.print('Approval panels are not part of the Agent workspace. Use /approval matrix.');
34
+ ctx.print('Open Agent Workspace -> Work -> Review approvals for the workspace view, or run /approval matrix for the compact command output.');
33
35
  return;
34
36
  }
35
37
  const matrix = [
36
38
  ['shell', 'Shell execution approval with side-effect and credential review.'],
37
39
  ['file', 'File mutation approval with config/notebook differentiation.'],
38
40
  ['network', 'Network access approval with host/scope review.'],
39
- ['delegate', 'Explicit GoodVibes TUI build delegation approval; local Agent spawn is blocked.'],
41
+ ['delegate', 'Explicit GoodVibes TUI build delegation approval; Agent-owned job fanout is blocked.'],
40
42
  ['mcp', 'MCP trust escalation approval with host/path review.'],
41
43
  ['remote', 'Remote dispatch approval with trust/artifact review.'],
42
44
  ['hook', 'Hook execution approval with deny/mutate authority review.'],
@@ -63,7 +65,7 @@ export function registerExperienceRuntimeCommands(registry: CommandRegistry): vo
63
65
  ].join('\n'));
64
66
  return;
65
67
  }
66
- ctx.print('Usage: /approval [matrix|review <kind>]');
68
+ ctx.print('Usage: /approval [matrix|review <kind>|approve <id> --yes|deny <id> --yes|cancel <id> --yes]');
67
69
  },
68
70
  });
69
71
 
@@ -22,10 +22,10 @@ export function registerGuidanceRuntimeCommands(registry: CommandRegistry): void
22
22
  ' /setup - open Agent setup with current settings preloaded',
23
23
  ' /agent - open the Agent operator workspace',
24
24
  ' /knowledge - inspect isolated Agent Knowledge status, ask, and search',
25
- ' /memory - manage local Agent memory',
26
- ' /personas - manage local Agent personas',
27
- ' /agent-skills - manage reusable local Agent skills',
28
- ' /routines - manage local Agent routines',
25
+ ' /memory - manage Agent-local memory',
26
+ ' /personas - manage Agent-local personas',
27
+ ' /skills - manage reusable Agent-local skills',
28
+ ' /routines - manage Agent-local routines',
29
29
  ' /delegate - explicitly hand build/fix/review work to GoodVibes TUI',
30
30
  ].join('\n'));
31
31
  return;