@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
@@ -0,0 +1,138 @@
1
+ import type { CommandContext, CommandRegistry } from '../command-registry.ts';
2
+ import {
3
+ buildOperatorActionRequest,
4
+ formatOperatorActionFailure,
5
+ formatOperatorActionPreview,
6
+ formatOperatorActionSuccess,
7
+ postOperatorAction,
8
+ type OperatorActionId,
9
+ } from '../../agent/operator-actions.ts';
10
+ import { resolveAgentConnectedHostConnection } from '../../agent/routine-schedule-promotion.ts';
11
+ import { requireShellPaths } from './runtime-services.ts';
12
+ import { stripYesFlag } from './confirmation.ts';
13
+
14
+ interface OperatorActionOptionParse {
15
+ readonly note?: string;
16
+ readonly remember?: boolean;
17
+ readonly errors: readonly string[];
18
+ }
19
+
20
+ function parseOperatorActionOptions(args: readonly string[]): OperatorActionOptionParse {
21
+ const errors: string[] = [];
22
+ let note: string | undefined;
23
+ let remember: boolean | undefined;
24
+ for (let index = 0; index < args.length; index += 1) {
25
+ const token = args[index];
26
+ if (token === '--note') {
27
+ const value = args[index + 1];
28
+ if (!value) {
29
+ errors.push('--note requires text');
30
+ continue;
31
+ }
32
+ note = value;
33
+ index += 1;
34
+ continue;
35
+ }
36
+ if (token === '--remember') {
37
+ remember = true;
38
+ continue;
39
+ }
40
+ if (token === '--no-remember') {
41
+ remember = false;
42
+ continue;
43
+ }
44
+ errors.push(`Unknown option ${token}`);
45
+ }
46
+ return { note, remember, errors };
47
+ }
48
+
49
+ export async function executeConfirmedOperatorAction(
50
+ ctx: CommandContext,
51
+ action: OperatorActionId,
52
+ targetField: 'approvalId' | 'jobId' | 'runId' | 'scheduleId',
53
+ targetId: string,
54
+ rawArgs: readonly string[],
55
+ usage: string,
56
+ ): Promise<void> {
57
+ const parsed = stripYesFlag(rawArgs);
58
+ const options = parseOperatorActionOptions(parsed.rest);
59
+ if (options.errors.length > 0) {
60
+ ctx.print([`Usage: ${usage}`, ...options.errors.map((error) => ` ${error}`)].join('\n'));
61
+ return;
62
+ }
63
+ const request = buildOperatorActionRequest({
64
+ action,
65
+ [targetField]: targetId,
66
+ note: options.note,
67
+ remember: options.remember,
68
+ });
69
+ if (!request.ok) {
70
+ ctx.print(request.error);
71
+ return;
72
+ }
73
+ const requestSummary = `/${action} ${targetId}`;
74
+ if (!parsed.yes) {
75
+ ctx.print(`${formatOperatorActionPreview(request, requestSummary)}\nUsage: ${usage}`);
76
+ return;
77
+ }
78
+ const shellPaths = requireShellPaths(ctx);
79
+ const connection = resolveAgentConnectedHostConnection(ctx.platform.configManager, shellPaths.homeDirectory);
80
+ const result = await postOperatorAction(connection, request);
81
+ ctx.print(result.ok ? formatOperatorActionSuccess(connection.baseUrl, result) : formatOperatorActionFailure(result));
82
+ }
83
+
84
+ function approvalActionFromSubcommand(sub: string): OperatorActionId | null {
85
+ if (sub === 'approve') return 'approvals.approve';
86
+ if (sub === 'deny') return 'approvals.deny';
87
+ if (sub === 'cancel') return 'approvals.cancel';
88
+ return null;
89
+ }
90
+
91
+ function automationActionFromParts(scope: string, verb: string): {
92
+ readonly action: OperatorActionId;
93
+ readonly targetField: 'jobId' | 'runId' | 'scheduleId';
94
+ } | null {
95
+ if ((scope === 'job' || scope === 'jobs') && verb === 'run') return { action: 'automation.jobs.run', targetField: 'jobId' };
96
+ if ((scope === 'job' || scope === 'jobs') && verb === 'pause') return { action: 'automation.jobs.pause', targetField: 'jobId' };
97
+ if ((scope === 'job' || scope === 'jobs') && verb === 'resume') return { action: 'automation.jobs.resume', targetField: 'jobId' };
98
+ if ((scope === 'run' || scope === 'runs') && verb === 'cancel') return { action: 'automation.runs.cancel', targetField: 'runId' };
99
+ if ((scope === 'run' || scope === 'runs') && verb === 'retry') return { action: 'automation.runs.retry', targetField: 'runId' };
100
+ if ((scope === 'schedule' || scope === 'schedules') && verb === 'run') return { action: 'schedules.run', targetField: 'scheduleId' };
101
+ return null;
102
+ }
103
+
104
+ export async function handleApprovalOperatorAction(args: readonly string[], ctx: CommandContext): Promise<boolean> {
105
+ const sub = (args[0] ?? '').toLowerCase();
106
+ const action = approvalActionFromSubcommand(sub);
107
+ if (!action) return false;
108
+ const approvalId = args[1] ?? '';
109
+ const usage = `/approval ${sub} <approval-id> [--note <text>] [--remember|--no-remember] --yes`;
110
+ if (!approvalId) {
111
+ ctx.print(`Usage: ${usage}`);
112
+ return true;
113
+ }
114
+ await executeConfirmedOperatorAction(ctx, action, 'approvalId', approvalId, args.slice(2), usage);
115
+ return true;
116
+ }
117
+
118
+ export function registerOperatorActionRuntimeCommands(registry: CommandRegistry): void {
119
+ registry.register({
120
+ name: 'automation',
121
+ aliases: ['auto'],
122
+ description: 'Run confirmed connected-host automation actions from the Agent TUI',
123
+ usage: 'job <run|pause|resume> <job-id> --yes | run <cancel|retry> <run-id> --yes | schedule run <schedule-id> --yes',
124
+ argsHint: 'job run <id> --yes | run cancel <id> --yes | schedule run <id> --yes',
125
+ async handler(args, ctx) {
126
+ const scope = (args[0] ?? '').toLowerCase();
127
+ const verb = (args[1] ?? '').toLowerCase();
128
+ const targetId = args[2] ?? '';
129
+ const mapping = automationActionFromParts(scope, verb);
130
+ const usage = '/automation job <run|pause|resume> <job-id> --yes | /automation run <cancel|retry> <run-id> --yes | /automation schedule run <schedule-id> --yes';
131
+ if (!mapping || !targetId) {
132
+ ctx.print(`Usage: ${usage}`);
133
+ return;
134
+ }
135
+ await executeConfirmedOperatorAction(ctx, mapping.action, mapping.targetField, targetId, args.slice(3), usage);
136
+ },
137
+ });
138
+ }
@@ -57,21 +57,6 @@ export function registerOperatorRuntimeCommands(registry: CommandRegistry): void
57
57
  else ctx.scrollToLine?.(nextLine);
58
58
  },
59
59
  });
60
-
61
- registry.register({
62
- name: 'profiles',
63
- aliases: ['profile'],
64
- description: 'Blocked copied config-profile command; Agent uses isolated profile homes',
65
- usage: 'disabled',
66
- argsHint: 'disabled',
67
- handler(_args, ctx) {
68
- ctx.print([
69
- 'Copied config profiles are disabled in GoodVibes Agent.',
70
- 'Use /agent profiles or /agent-profile to create and manage isolated Agent profile homes.',
71
- ].join('\n'));
72
- },
73
- });
74
-
75
60
  registry.register({
76
61
  name: 'prev-error',
77
62
  aliases: ['pe'],
@@ -153,7 +138,7 @@ export function registerOperatorRuntimeCommands(registry: CommandRegistry): void
153
138
  return;
154
139
  }
155
140
  if (verbosity !== 'minimal' && verbosity !== 'normal' && verbosity !== 'verbose') {
156
- ctx.print(`Invalid verbosity "${verbosity}". Valid values: minimal, normal, verbose`);
141
+ ctx.print(`Invalid verbosity "${verbosity}". Valid values minimal, normal, verbose.`);
157
142
  return;
158
143
  }
159
144
  if (!parsed.yes) {
@@ -161,7 +146,11 @@ export function registerOperatorRuntimeCommands(registry: CommandRegistry): void
161
146
  return;
162
147
  }
163
148
  mgr.setDomainVerbosity(domain, verbosity as 'minimal' | 'normal' | 'verbose');
164
- ctx.print(`Domain "${domain}" verbosity set to: ${verbosity}`);
149
+ ctx.print([
150
+ 'Domain verbosity set',
151
+ ` domain ${domain}`,
152
+ ` verbosity ${verbosity}`,
153
+ ].join('\n'));
165
154
  return;
166
155
  }
167
156
 
@@ -1,5 +1,6 @@
1
1
  import { discoverPersonas, type DiscoveredPersonaRecord } from '../../agent/persona-discovery.ts';
2
2
  import { AgentPersonaRegistry, type AgentPersonaRecord } from '../../agent/persona-registry.ts';
3
+ import { formatAgentRecordOrigin, formatAgentRecordReviewState } from '../../agent/record-labels.ts';
3
4
  import type { CommandContext, CommandRegistry } from '../command-registry.ts';
4
5
  import { requireShellPaths } from './runtime-services.ts';
5
6
 
@@ -44,21 +45,33 @@ function registryFromContext(ctx: CommandContext): AgentPersonaRegistry {
44
45
  return AgentPersonaRegistry.fromShellPaths(requireShellPaths(ctx));
45
46
  }
46
47
 
48
+ function formatPersonaReceipt(title: string, persona: Pick<AgentPersonaRecord, 'id' | 'name'>, extra: readonly string[] = []): string {
49
+ const activeSuffix = extra.some((line) => line.includes('active yes') || line.includes('active: yes')) ? ' (active)' : '';
50
+ const normalizedExtra = extra.map((line) => line.replace(/^ active /, ' active: '));
51
+ return [
52
+ `${title} ${persona.id}: ${persona.name}${activeSuffix}`,
53
+ ` id ${persona.id}`,
54
+ ` name ${persona.name}`,
55
+ ...normalizedExtra,
56
+ ].join('\n');
57
+ }
58
+
47
59
  function summarizePersona(persona: AgentPersonaRecord, activePersonaId: string | null): string {
48
60
  const active = persona.id === activePersonaId ? 'active' : 'inactive';
49
- const tags = persona.tags.length > 0 ? ` tags=${persona.tags.join(',')}` : '';
50
- return ` ${persona.id} ${active} ${persona.reviewState} ${persona.name} - ${persona.description}${tags}`;
61
+ const review = formatAgentRecordReviewState(persona.reviewState);
62
+ const tags = persona.tags.length > 0 ? ` tags ${persona.tags.join(', ')}` : '';
63
+ return ` ${persona.id} ${active} ${review} ${persona.name} - ${persona.description}${tags}`;
51
64
  }
52
65
 
53
66
  function renderList(title: string, registry: AgentPersonaRegistry, personas: readonly AgentPersonaRecord[]): string {
54
67
  const snapshot = registry.snapshot();
55
68
  if (personas.length === 0) {
56
- return `${title}\n No local Agent personas yet. Create one with /personas create --name <name> --description <summary> --body <instructions>.`;
69
+ return `${title}\n No local Agent personas yet.\n No Agent-local personas yet. Create one with /personas create --name <name> --description <summary> --body <instructions>.`;
57
70
  }
58
71
  return [
59
72
  `${title} (${personas.length})`,
60
- ` store: ${snapshot.path}`,
61
- ` active: ${snapshot.activePersona?.name ?? '(none)'}`,
73
+ ` store ${snapshot.path}`,
74
+ ` active ${snapshot.activePersona?.name ?? '(none)'}`,
62
75
  ...personas.map((persona) => summarizePersona(persona, snapshot.activePersonaId)),
63
76
  ].join('\n');
64
77
  }
@@ -66,11 +79,10 @@ function renderList(title: string, registry: AgentPersonaRegistry, personas: rea
66
79
  function renderPersona(persona: AgentPersonaRecord, activePersonaId: string | null): string {
67
80
  return [
68
81
  `Persona ${persona.name}`,
69
- ` id: ${persona.id}`,
82
+ ` id ${persona.id}`,
70
83
  ` active: ${persona.id === activePersonaId ? 'yes' : 'no'}`,
71
- ` review: ${persona.reviewState}`,
72
- ` source: ${persona.source}`,
73
- ` provenance: ${persona.provenance}`,
84
+ ` review: ${formatAgentRecordReviewState(persona.reviewState)}`,
85
+ ` origin: ${formatAgentRecordOrigin(persona.source, persona.provenance)}`,
74
86
  ` tags: ${persona.tags.join(', ') || '(none)'}`,
75
87
  ` triggers: ${persona.triggers.join(', ') || '(none)'}`,
76
88
  ` created: ${persona.createdAt}`,
@@ -85,7 +97,7 @@ function renderPersona(persona: AgentPersonaRecord, activePersonaId: string | nu
85
97
 
86
98
  function summarizeDiscoveredPersona(persona: DiscoveredPersonaRecord): string {
87
99
  const description = persona.description ? ` - ${persona.description}` : '';
88
- return ` ${persona.name} ${persona.origin}${description}\n path: ${persona.path}`;
100
+ return ` ${persona.name} ${persona.origin}${description}\n path ${persona.path}`;
89
101
  }
90
102
 
91
103
  function renderDiscoveredPersonas(personas: readonly DiscoveredPersonaRecord[]): string {
@@ -131,18 +143,18 @@ async function importDiscoveredPersona(args: readonly string[], ctx: CommandCont
131
143
  }
132
144
  const discovered = findDiscoveredPersona(await discoverPersonas(requireShellPaths(ctx)), name);
133
145
  if (!discovered) {
134
- ctx.print(`Unknown discovered Agent persona: ${name}\nRun /personas discover to inspect available persona files.`);
146
+ ctx.print(`Unknown discovered Agent persona ${name}\nRun /personas discover to inspect available persona files.`);
135
147
  return;
136
148
  }
137
149
  if (!parsed.yes) {
138
150
  ctx.print([
139
151
  'Agent persona import preview',
140
- ` name: ${discovered.name}`,
141
- ` origin: ${discovered.origin}`,
142
- ` path: ${discovered.path}`,
143
- ` description: ${discovered.description || '(none)'}`,
144
- ` body characters: ${discovered.body.length}`,
145
- ' next: rerun with --yes to import into the Agent-local persona registry',
152
+ ` name ${discovered.name}`,
153
+ ` origin ${discovered.origin}`,
154
+ ` path ${discovered.path}`,
155
+ ` description ${discovered.description || '(none)'}`,
156
+ ` body characters ${discovered.body.length}`,
157
+ ' next rerun with --yes to import into the Agent-local persona registry',
146
158
  ].join('\n'));
147
159
  return;
148
160
  }
@@ -153,10 +165,10 @@ async function importDiscoveredPersona(args: readonly string[], ctx: CommandCont
153
165
  tags: frontmatterList(discovered, 'tags'),
154
166
  triggers: frontmatterList(discovered, 'triggers'),
155
167
  source: 'imported',
156
- provenance: `discovered:${discovered.origin}:${discovered.path}`,
168
+ provenance: `Imported file (${discovered.origin}): ${discovered.path}`,
157
169
  });
158
170
  if (parsed.flags.get('use') === 'true') personaRegistry.setActive(persona.id);
159
- ctx.print(`Imported Agent persona ${persona.id}: ${persona.name}${parsed.flags.get('use') === 'true' ? ' (active)' : ''}`);
171
+ ctx.print(formatPersonaReceipt('Imported Agent persona', persona, [` active ${parsed.flags.get('use') === 'true' ? 'yes' : 'no'}`]));
160
172
  }
161
173
 
162
174
  function requiredFlag(flags: ReadonlyMap<string, string>, key: string): string {
@@ -166,14 +178,17 @@ function requiredFlag(flags: ReadonlyMap<string, string>, key: string): string {
166
178
  }
167
179
 
168
180
  function printError(ctx: CommandContext, error: unknown): void {
169
- ctx.print(`Error: ${error instanceof Error ? error.message : String(error)}`);
181
+ ctx.print([
182
+ 'Error',
183
+ ` message ${error instanceof Error ? error.message : String(error)}`,
184
+ ].join('\n'));
170
185
  }
171
186
 
172
187
  export function registerPersonasRuntimeCommands(registry: CommandRegistry): void {
173
188
  registry.register({
174
189
  name: 'personas',
175
190
  aliases: ['persona'],
176
- description: 'Manage local GoodVibes Agent personas',
191
+ description: 'Manage Agent-local personas',
177
192
  usage: '[list|discover|import-discovered <name> --yes|search <query>|show <id>|create --name <name> --description <summary> --body <instructions>|update <id> [--name ...] [--description ...] [--body ...]|use <id>|active|clear|review <id>|stale <id> <reason...>|delete <id> --yes]',
178
193
  async handler(args, ctx) {
179
194
  const sub = (args[0] ?? 'list').toLowerCase();
@@ -204,7 +219,7 @@ export function registerPersonasRuntimeCommands(registry: CommandRegistry): void
204
219
  }
205
220
  const snapshot = registryStore.snapshot();
206
221
  const persona = registryStore.get(id);
207
- ctx.print(persona ? renderPersona(persona, snapshot.activePersonaId) : `Unknown persona: ${id}`);
222
+ ctx.print(persona ? renderPersona(persona, snapshot.activePersonaId) : `Unknown Agent persona ${id}`);
208
223
  return;
209
224
  }
210
225
  if (sub === 'create') {
@@ -217,9 +232,9 @@ export function registerPersonasRuntimeCommands(registry: CommandRegistry): void
217
232
  tags: splitList(parsed.flags.get('tags')),
218
233
  triggers: splitList(parsed.flags.get('triggers')),
219
234
  source: 'user',
220
- provenance: 'slash-command',
235
+ provenance: 'Command',
221
236
  });
222
- ctx.print(`Created Agent persona ${persona.id}: ${persona.name}`);
237
+ ctx.print(formatPersonaReceipt('Created Agent persona', persona));
223
238
  return;
224
239
  }
225
240
  if (sub === 'update') {
@@ -235,9 +250,9 @@ export function registerPersonasRuntimeCommands(registry: CommandRegistry): void
235
250
  body: parsed.flags.get('body'),
236
251
  tags: parsed.flags.has('tags') ? splitList(parsed.flags.get('tags')) : undefined,
237
252
  triggers: parsed.flags.has('triggers') ? splitList(parsed.flags.get('triggers')) : undefined,
238
- provenance: 'slash-command',
253
+ provenance: 'Command',
239
254
  });
240
- ctx.print(`Updated Agent persona ${updated.id}: ${updated.name}`);
255
+ ctx.print(formatPersonaReceipt('Updated Agent persona', updated));
241
256
  return;
242
257
  }
243
258
  if (sub === 'use') {
@@ -247,7 +262,7 @@ export function registerPersonasRuntimeCommands(registry: CommandRegistry): void
247
262
  return;
248
263
  }
249
264
  const persona = registryStore.setActive(id);
250
- ctx.print(`Active Agent persona: ${persona.name} (${persona.id})`);
265
+ ctx.print(`Active Agent persona: ${persona.name}\n${formatPersonaReceipt('Active Agent persona', persona)}`);
251
266
  return;
252
267
  }
253
268
  if (sub === 'active') {
@@ -267,7 +282,7 @@ export function registerPersonasRuntimeCommands(registry: CommandRegistry): void
267
282
  return;
268
283
  }
269
284
  const persona = registryStore.markReviewed(id);
270
- ctx.print(`Reviewed Agent persona ${persona.id}.`);
285
+ ctx.print(formatPersonaReceipt('Reviewed Agent persona', persona));
271
286
  return;
272
287
  }
273
288
  if (sub === 'stale') {
@@ -277,7 +292,7 @@ export function registerPersonasRuntimeCommands(registry: CommandRegistry): void
277
292
  return;
278
293
  }
279
294
  const persona = registryStore.markStale(id, args.slice(2).join(' '));
280
- ctx.print(`Marked Agent persona ${persona.id} stale.`);
295
+ ctx.print(formatPersonaReceipt('Marked Agent persona stale', persona));
281
296
  return;
282
297
  }
283
298
  if (sub === 'delete' || sub === 'remove') {
@@ -292,7 +307,7 @@ export function registerPersonasRuntimeCommands(registry: CommandRegistry): void
292
307
  return;
293
308
  }
294
309
  const removed = registryStore.deletePersona(id);
295
- ctx.print(`Deleted Agent persona ${removed.id}: ${removed.name}`);
310
+ ctx.print(formatPersonaReceipt('Deleted Agent persona', removed));
296
311
  return;
297
312
  }
298
313
  ctx.print('Usage: /personas [list|discover|import-discovered|search <query>|show <id>|create|update|use|active|clear|review|stale|delete]');
@@ -111,7 +111,7 @@ export function registerPlanningRuntimeCommands(registry: CommandRegistry): void
111
111
  }
112
112
 
113
113
  if (args[0] === 'panel') {
114
- ctx.print('Planning panels are not part of the Agent workspace. Use /plan status or /plan list.');
114
+ ctx.print('Use /plan status or /plan list for compact command output. Open Agent Workspace -> Work -> Planning status or Saved plans for the workspace view.');
115
115
  return;
116
116
  }
117
117
 
@@ -3,6 +3,7 @@ import { dirname } from 'node:path';
3
3
  import type { CommandRegistry } from '../command-registry.ts';
4
4
  import { listBuiltinSubscriptionProviders } from '@pellux/goodvibes-sdk/platform/config';
5
5
  import { buildAuthInspectionSnapshot, inspectProviderAuth } from '@/runtime/index.ts';
6
+ import { formatAgentRecordSource } from '../../agent/record-labels.ts';
6
7
  import { requireSecretsManager, requireServiceRegistry, requireShellPaths, requireSubscriptionManager } from './runtime-services.ts';
7
8
  import { requireYesFlag, stripYesFlag } from './confirmation.ts';
8
9
 
@@ -18,11 +19,11 @@ interface AuthReviewBundle {
18
19
  function inspectAuthBundle(bundle: AuthReviewBundle): string {
19
20
  return [
20
21
  'Auth Review Bundle',
21
- ` exportedAt: ${new Date(bundle.exportedAt).toISOString()}`,
22
- ` externalRuntimeAuth: ${bundle.externalRuntimeAuth}`,
23
- ` stored secrets: ${bundle.secretKeys.length}`,
24
- ` active subscriptions: ${bundle.activeSubscriptions.length}`,
25
- ` pending subscriptions: ${bundle.pendingSubscriptions.length}`,
22
+ ` exported at ${new Date(bundle.exportedAt).toISOString()}`,
23
+ ` connected host auth ${bundle.externalRuntimeAuth}`,
24
+ ` stored secrets ${bundle.secretKeys.length}`,
25
+ ` active subscriptions ${bundle.activeSubscriptions.length}`,
26
+ ` pending subscriptions ${bundle.pendingSubscriptions.length}`,
26
27
  ].join('\n');
27
28
  }
28
29
 
@@ -66,12 +67,12 @@ export function registerPlatformAccessRuntimeCommands(registry: CommandRegistry)
66
67
  const builtinProviders = listBuiltinSubscriptionProviders().map((entry) => entry.provider);
67
68
  ctx.print([
68
69
  'Auth Review',
69
- ' connected-host auth: managed outside goodvibes-agent',
70
- ` stored secrets: ${snapshot.secretKeyCount}`,
71
- ` built-in providers: ${builtinProviders.length}${builtinProviders.length > 0 ? ` (${builtinProviders.join(', ')})` : ''}`,
72
- ` active subscriptions: ${snapshot.activeSubscriptions}${snapshot.activeSubscriptions > 0 ? ` (${snapshot.providers.filter((provider) => provider.activeSubscription).map((provider) => provider.provider).join(', ')})` : ''}`,
73
- ` pending subscriptions: ${snapshot.pendingSubscriptions}${snapshot.pendingSubscriptions > 0 ? ` (${snapshot.providers.filter((provider) => provider.pendingLogin).map((provider) => provider.provider).join(', ')})` : ''}`,
74
- ...snapshot.providers.map((provider) => ` ${provider.provider} freshness=${provider.freshness} mode=${provider.callbackMode} configured=${provider.configured ? 'yes' : 'no'}`),
70
+ ' connected host auth managed outside goodvibes-agent',
71
+ ` stored secrets ${snapshot.secretKeyCount}`,
72
+ ` built-in providers ${builtinProviders.length}${builtinProviders.length > 0 ? ` (${builtinProviders.join(', ')})` : ''}`,
73
+ ` active subscriptions ${snapshot.activeSubscriptions}${snapshot.activeSubscriptions > 0 ? ` (${snapshot.providers.filter((provider) => provider.activeSubscription).map((provider) => provider.provider).join(', ')})` : ''}`,
74
+ ` pending subscriptions ${snapshot.pendingSubscriptions}${snapshot.pendingSubscriptions > 0 ? ` (${snapshot.providers.filter((provider) => provider.pendingLogin).map((provider) => provider.provider).join(', ')})` : ''}`,
75
+ ...snapshot.providers.map((provider) => ` ${provider.provider} auth ${provider.freshness} finish manual configured ${provider.configured ? 'yes' : 'no'}`),
75
76
  ].join('\n'));
76
77
  return;
77
78
  }
@@ -89,19 +90,18 @@ export function registerPlatformAccessRuntimeCommands(registry: CommandRegistry)
89
90
  });
90
91
  ctx.print([
91
92
  `Auth Provider ${provider}`,
92
- ` configured: ${inspection.configured ? 'yes' : 'no'}`,
93
- ...(inspection.source ? [` source: ${inspection.source}`] : []),
94
- ` freshness: ${inspection.freshness}`,
95
- ` callbackMode: ${inspection.callbackMode}`,
96
- ...(inspection.redirectUri ? [` redirectUri: ${inspection.redirectUri}`] : []),
97
- ...(inspection.localCallback ? [` localCallback: ${inspection.localCallback}`] : []),
98
- ` activeSubscription: ${inspection.activeSubscription ? 'yes' : 'no'}`,
99
- ` pendingLogin: ${inspection.pendingLogin ? 'yes' : 'no'}`,
100
- ` overrideAmbientApiKeys: ${inspection.overrideAmbientApiKeys ? 'yes' : 'no'}`,
101
- ...(inspection.tokenType ? [` tokenType: ${inspection.tokenType}`] : []),
102
- ...(inspection.expiresAt ? [` expiresAt: ${new Date(inspection.expiresAt).toISOString()}`] : []),
103
- ...inspection.issues.map((issue) => ` issue: ${issue}`),
104
- ...inspection.nextActions.map((action) => ` next: ${action}`),
93
+ ` configured ${inspection.configured ? 'yes' : 'no'}`,
94
+ ...(inspection.source ? [` origin ${formatAgentRecordSource(inspection.source)}`] : []),
95
+ ` freshness ${inspection.freshness}`,
96
+ ' finish mode explicit manual',
97
+ ...(inspection.redirectUri ? [` redirect URI ${inspection.redirectUri}`] : []),
98
+ ` active subscription ${inspection.activeSubscription ? 'yes' : 'no'}`,
99
+ ` pending login ${inspection.pendingLogin ? 'yes' : 'no'}`,
100
+ ` ambient API key override ${inspection.overrideAmbientApiKeys ? 'yes' : 'no'}`,
101
+ ...(inspection.tokenType ? [` token type ${inspection.tokenType}`] : []),
102
+ ...(inspection.expiresAt ? [` expires at ${new Date(inspection.expiresAt).toISOString()}`] : []),
103
+ ...inspection.issues.map((issue) => ` issue ${issue}`),
104
+ ...inspection.nextActions.map((action) => ` next ${action}`),
105
105
  ].join('\n'));
106
106
  return;
107
107
  }
@@ -119,12 +119,12 @@ export function registerPlatformAccessRuntimeCommands(registry: CommandRegistry)
119
119
  });
120
120
  ctx.print([
121
121
  `Auth Repair ${provider}`,
122
- ` configured: ${inspection.configured ? 'yes' : 'no'}`,
123
- ` freshness: ${inspection.freshness}`,
124
- ` callbackMode: ${inspection.callbackMode}`,
125
- ...inspection.issues.map((issue) => ` issue: ${issue}`),
122
+ ` configured ${inspection.configured ? 'yes' : 'no'}`,
123
+ ` freshness ${inspection.freshness}`,
124
+ ' finish mode explicit manual',
125
+ ...inspection.issues.map((issue) => ` issue ${issue}`),
126
126
  ...(inspection.nextActions.length > 0
127
- ? [' next:', ...inspection.nextActions.map((action) => ` ${action}`)]
127
+ ? [' next', ...inspection.nextActions.map((action) => ` ${action}`)]
128
128
  : [' No active repair actions suggested.']),
129
129
  ].join('\n'));
130
130
  return;
@@ -2,13 +2,34 @@ import type { CommandContext, CommandRegistry } from '../command-registry.ts';
2
2
  import type {
3
3
  ProviderAccountRecord,
4
4
  ProviderAccountSnapshot,
5
- } from '@/runtime/index.ts';
5
+ ProviderAuthRoute,
6
+ ProviderRouteRecord,
7
+ } from '../../panels/provider-account-snapshot.ts';
8
+ import { buildProviderAccountSnapshot } from '../../panels/provider-account-snapshot.ts';
6
9
  import {
7
- requireOperatorClient,
10
+ requireProvider,
11
+ requireServiceRegistry,
12
+ requireSubscriptionManager,
8
13
  } from './runtime-services.ts';
14
+ import { formatProviderAuthRouteId } from '../../provider-auth-route-display.ts';
15
+
16
+ function formatRouteList(routes: readonly ProviderAuthRoute[]): string {
17
+ return routes.map((route) => formatProviderAuthRouteId(route)).join(', ');
18
+ }
19
+
20
+ function formatRouteRecord(route: ProviderRouteRecord): string {
21
+ return `${formatProviderAuthRouteId(route.route)} ${route.usable ? 'usable' : 'blocked'} auth ${route.freshness} ${route.detail}`;
22
+ }
9
23
 
10
24
  async function loadProviderAccountSnapshot(context: CommandContext): Promise<ProviderAccountSnapshot> {
11
- return await requireOperatorClient(context).providers.accountSnapshot();
25
+ return await buildProviderAccountSnapshot({
26
+ providerModels: requireProvider(context).providerRegistry,
27
+ services: requireServiceRegistry(context),
28
+ subscriptions: requireSubscriptionManager(context),
29
+ environment: {
30
+ hasEnvironmentVariable: (name: string) => Boolean(process.env[name]),
31
+ },
32
+ });
12
33
  }
13
34
 
14
35
  function findProviderAccountRecord(
@@ -28,7 +49,7 @@ export function registerProviderAccountsRuntimeCommands(registry: CommandRegistr
28
49
  async handler(args, ctx) {
29
50
  const sub = (args[0] ?? 'review').toLowerCase();
30
51
  if (sub === 'panel' || sub === 'open') {
31
- ctx.print('Provider account panels are not part of the Agent workspace. Use /accounts review.');
52
+ ctx.print('Open Agent Workspace -> Setup -> Provider accounts for the workspace view, or run /accounts review for compact command output.');
32
53
  return;
33
54
  }
34
55
  const snapshot = await loadProviderAccountSnapshot(ctx);
@@ -36,16 +57,16 @@ export function registerProviderAccountsRuntimeCommands(registry: CommandRegistr
36
57
  const providerId = args[1];
37
58
  const record = findProviderAccountRecord(snapshot, providerId);
38
59
  if (!record) {
39
- ctx.print(providerId ? `Unknown provider account: ${providerId}` : 'Usage: /accounts routes <provider>');
60
+ ctx.print(providerId ? `Unknown provider account ${providerId}` : 'Usage: /accounts routes <provider>');
40
61
  return;
41
62
  }
42
63
  ctx.print([
43
64
  `Provider Routes ${record.providerId}`,
44
- ` preferred: ${record.preferredRoute}`,
45
- ` active: ${record.activeRoute}`,
46
- ` reason: ${record.activeRouteReason}`,
47
- ...record.routeRecords.map((route) => ` ${route.route} usable=${route.usable ? 'yes' : 'no'} freshness=${route.freshness} ${route.detail}`),
48
- ...record.routeRecords.flatMap((route) => route.issues.map((issue) => ` issue: ${issue}`)),
65
+ ` preferred route ${formatProviderAuthRouteId(record.preferredRoute)}`,
66
+ ` active route ${formatProviderAuthRouteId(record.activeRoute)}`,
67
+ ` reason ${record.activeRouteReason}`,
68
+ ...record.routeRecords.map((route) => ` ${formatRouteRecord(route)}`),
69
+ ...record.routeRecords.flatMap((route) => route.issues.map((issue) => ` issue ${issue}`)),
49
70
  ].join('\n'));
50
71
  return;
51
72
  }
@@ -53,17 +74,17 @@ export function registerProviderAccountsRuntimeCommands(registry: CommandRegistr
53
74
  const providerId = args[1];
54
75
  const record = findProviderAccountRecord(snapshot, providerId);
55
76
  if (!record) {
56
- ctx.print(providerId ? `Unknown provider account: ${providerId}` : 'Usage: /accounts repair <provider>');
77
+ ctx.print(providerId ? `Unknown provider account ${providerId}` : 'Usage: /accounts repair <provider>');
57
78
  return;
58
79
  }
59
80
  ctx.print([
60
81
  `Provider Account Repair ${record.providerId}`,
61
- ` active route: ${record.activeRoute}`,
62
- ` preferred route: ${record.preferredRoute}`,
63
- ...(record.fallbackRisk ? [` fallback: ${record.fallbackRisk}`] : []),
64
- ...(record.issues.map((issue) => ` issue: ${issue}`)),
82
+ ` active route ${formatProviderAuthRouteId(record.activeRoute)}`,
83
+ ` preferred route ${formatProviderAuthRouteId(record.preferredRoute)}`,
84
+ ...(record.fallbackRisk ? [` routing risk ${record.fallbackRisk}`] : []),
85
+ ...(record.issues.map((issue) => ` issue ${issue}`)),
65
86
  ...(record.recommendedActions.length > 0
66
- ? [' next:', ...record.recommendedActions.map((action) => ` ${action}`)]
87
+ ? [' next', ...record.recommendedActions.map((action) => ` ${action}`)]
67
88
  : [' No active repair actions suggested.']),
68
89
  ].join('\n'));
69
90
  return;
@@ -72,39 +93,39 @@ export function registerProviderAccountsRuntimeCommands(registry: CommandRegistr
72
93
  const providerId = args[1];
73
94
  const record = findProviderAccountRecord(snapshot, providerId);
74
95
  if (!record) {
75
- ctx.print(providerId ? `Unknown provider account: ${providerId}` : 'Usage: /accounts show <provider>');
96
+ ctx.print(providerId ? `Unknown provider account ${providerId}` : 'Usage: /accounts show <provider>');
76
97
  return;
77
98
  }
78
99
  ctx.print([
79
100
  `Provider Account ${record.providerId}`,
80
- ` preferredRoute: ${record.preferredRoute}`,
81
- ` activeRoute: ${record.activeRoute}`,
82
- ` authFreshness: ${record.authFreshness}`,
83
- ` configured: ${record.configured ? 'yes' : 'no'}`,
84
- ` oauthReady: ${record.oauthReady ? 'yes' : 'no'}`,
85
- ` pendingLogin: ${record.pendingLogin ? 'yes' : 'no'}`,
86
- ` availableRoutes: ${record.availableRoutes.join(', ')}`,
87
- ` modelCount: ${record.modelCount}`,
88
- ` routeReason: ${record.activeRouteReason}`,
89
- ...(record.fallbackRoute ? [` fallbackRoute: ${record.fallbackRoute}`] : []),
90
- ...(record.fallbackRisk ? [` fallbackRisk: ${record.fallbackRisk}`] : []),
91
- ...(record.expiresAt ? [` expiresAt: ${new Date(record.expiresAt).toISOString()}`] : []),
92
- ...record.routeRecords.map((route) => ` route ${route.route}: usable=${route.usable ? 'yes' : 'no'} freshness=${route.freshness} — ${route.detail}`),
93
- ...record.routeRecords.flatMap((route) => route.issues.map((issue) => ` issue: ${issue}`)),
94
- ...record.usageWindows.map((entry) => ` window: ${entry.label} — ${entry.detail}`),
95
- ...record.issues.map((issue) => ` issue: ${issue}`),
96
- ...record.notes.map((note) => ` note: ${note}`),
97
- ...record.recommendedActions.map((action) => ` next: ${action}`),
101
+ ` preferred route ${formatProviderAuthRouteId(record.preferredRoute)}`,
102
+ ` active route ${formatProviderAuthRouteId(record.activeRoute)}`,
103
+ ` auth freshness ${record.authFreshness}`,
104
+ ` configured ${record.configured ? 'yes' : 'no'}`,
105
+ ` OAuth ready ${record.oauthReady ? 'yes' : 'no'}`,
106
+ ` pending login ${record.pendingLogin ? 'yes' : 'no'}`,
107
+ ` available routes ${formatRouteList(record.availableRoutes)}`,
108
+ ` model count ${record.modelCount}`,
109
+ ` route reason ${record.activeRouteReason}`,
110
+ ...(record.fallbackRoute ? [` fallback route ${formatProviderAuthRouteId(record.fallbackRoute)}`] : []),
111
+ ...(record.fallbackRisk ? [` routing risk ${record.fallbackRisk}`] : []),
112
+ ...(record.expiresAt ? [` expires at ${new Date(record.expiresAt).toISOString()}`] : []),
113
+ ...record.routeRecords.map((route) => ` route ${formatRouteRecord(route)}`),
114
+ ...record.routeRecords.flatMap((route) => route.issues.map((issue) => ` issue ${issue}`)),
115
+ ...record.usageWindows.map((entry) => ` window ${entry.label} — ${entry.detail}`),
116
+ ...record.issues.map((issue) => ` issue ${issue}`),
117
+ ...record.notes.map((note) => ` note ${note}`),
118
+ ...record.recommendedActions.map((action) => ` next ${action}`),
98
119
  ].join('\n'));
99
120
  return;
100
121
  }
101
122
  ctx.print([
102
123
  'Provider Account Review',
103
- ` providers: ${snapshot.providers.length}`,
104
- ` configured: ${snapshot.configuredCount}`,
105
- ` issues: ${snapshot.issueCount}`,
124
+ ` providers ${snapshot.providers.length}`,
125
+ ` configured ${snapshot.configuredCount}`,
126
+ ` issues ${snapshot.issueCount}`,
106
127
  ...snapshot.providers.map((record) => (
107
- ` ${record.providerId} active=${record.activeRoute} preferred=${record.preferredRoute} freshness=${record.authFreshness} models=${record.modelCount} issues=${record.issues.length}`
128
+ ` ${record.providerId} active route ${formatProviderAuthRouteId(record.activeRoute)} preferred route ${formatProviderAuthRouteId(record.preferredRoute)} auth ${record.authFreshness} models ${record.modelCount} issues ${record.issues.length}`
108
129
  )),
109
130
  ].join('\n'));
110
131
  },