@pellux/goodvibes-agent 0.1.117 → 1.0.1

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 (255) hide show
  1. package/CHANGELOG.md +20 -4
  2. package/README.md +35 -14
  3. package/bin/goodvibes-agent.ts +16 -2
  4. package/dist/package/main.js +176093 -171065
  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 +159 -73
  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 +59 -39
  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-knowledge-url-editor.ts +4 -11
  66. package/src/input/agent-workspace-learned-behavior.ts +2 -2
  67. package/src/input/agent-workspace-library-command-editor-submission.ts +1 -1
  68. package/src/input/agent-workspace-library-command-editors.ts +2 -2
  69. package/src/input/agent-workspace-local-operations.ts +218 -0
  70. package/src/input/agent-workspace-local-selection.ts +75 -0
  71. package/src/input/agent-workspace-media-command-editor-submission.ts +62 -0
  72. package/src/input/agent-workspace-media-command-editors.ts +27 -0
  73. package/src/input/agent-workspace-memory-command-editors.ts +1 -1
  74. package/src/input/agent-workspace-memory-editor.ts +2 -2
  75. package/src/input/agent-workspace-navigation.ts +38 -2
  76. package/src/input/agent-workspace-notify-editor-submission.ts +16 -2
  77. package/src/input/agent-workspace-operations-command-editor-submission.ts +63 -1
  78. package/src/input/agent-workspace-operations-command-editors.ts +80 -3
  79. package/src/input/agent-workspace-panel-route.ts +43 -0
  80. package/src/input/agent-workspace-reminder-schedule-editor.ts +1 -1
  81. package/src/input/agent-workspace-routine-schedule-editor.ts +2 -2
  82. package/src/input/agent-workspace-search.ts +169 -0
  83. package/src/input/agent-workspace-setup.ts +22 -11
  84. package/src/input/agent-workspace-skill-bundle-command-editor-submission.ts +6 -6
  85. package/src/input/agent-workspace-skill-bundle-command-editors.ts +10 -10
  86. package/src/input/agent-workspace-snapshot.ts +112 -13
  87. package/src/input/agent-workspace-task-command-editors.ts +4 -4
  88. package/src/input/agent-workspace-token.ts +18 -2
  89. package/src/input/agent-workspace-types.ts +92 -4
  90. package/src/input/agent-workspace-voice-media.ts +3 -6
  91. package/src/input/agent-workspace-web-research-editor.ts +104 -0
  92. package/src/input/agent-workspace.ts +136 -208
  93. package/src/input/command-registry.ts +4 -1
  94. package/src/input/commands/agent-local-library-args.ts +52 -0
  95. package/src/input/commands/agent-runtime-profile-runtime.ts +45 -41
  96. package/src/input/commands/agent-skills-runtime.ts +87 -99
  97. package/src/input/commands/agent-workspace-runtime.ts +23 -7
  98. package/src/input/commands/brief-runtime.ts +25 -24
  99. package/src/input/commands/channels-runtime.ts +145 -31
  100. package/src/input/commands/delegation-runtime.ts +29 -23
  101. package/src/input/commands/experience-runtime.ts +6 -4
  102. package/src/input/commands/guidance-runtime.ts +4 -4
  103. package/src/input/commands/health-runtime.ts +140 -115
  104. package/src/input/commands/knowledge.ts +57 -56
  105. package/src/input/commands/local-provider-runtime.ts +36 -18
  106. package/src/input/commands/local-runtime.ts +138 -16
  107. package/src/input/commands/local-setup-review.ts +7 -7
  108. package/src/input/commands/mcp-runtime.ts +118 -50
  109. package/src/input/commands/notify-runtime.ts +38 -9
  110. package/src/input/commands/operator-actions-runtime.ts +138 -0
  111. package/src/input/commands/operator-runtime.ts +6 -17
  112. package/src/input/commands/personas-runtime.ts +49 -59
  113. package/src/input/commands/planning-runtime.ts +1 -1
  114. package/src/input/commands/platform-access-runtime.ts +29 -29
  115. package/src/input/commands/provider-accounts-runtime.ts +60 -39
  116. package/src/input/commands/qrcode-runtime.ts +45 -6
  117. package/src/input/commands/recall-bundle.ts +11 -11
  118. package/src/input/commands/recall-capture.ts +13 -11
  119. package/src/input/commands/recall-query.ts +29 -21
  120. package/src/input/commands/recall-review.ts +2 -1
  121. package/src/input/commands/routines-runtime.ts +63 -72
  122. package/src/input/commands/schedule-runtime.ts +33 -20
  123. package/src/input/commands/security-runtime.ts +4 -4
  124. package/src/input/commands/session-content.ts +80 -78
  125. package/src/input/commands/session-workflow.ts +132 -93
  126. package/src/input/commands/session.ts +3 -174
  127. package/src/input/commands/shell-core.ts +32 -17
  128. package/src/input/commands/subscription-runtime.ts +53 -179
  129. package/src/input/commands/tasks-runtime.ts +20 -20
  130. package/src/input/commands/work-plan-runtime.ts +33 -8
  131. package/src/input/commands.ts +2 -2
  132. package/src/input/feed-context-factory.ts +2 -1
  133. package/src/input/file-picker.ts +3 -2
  134. package/src/input/handler-command-route.ts +4 -7
  135. package/src/input/handler-content-actions.ts +89 -1
  136. package/src/input/handler-feed-routes.ts +19 -12
  137. package/src/input/handler-feed.ts +6 -3
  138. package/src/input/handler-interactions.ts +7 -5
  139. package/src/input/handler-modal-stack.ts +3 -3
  140. package/src/input/handler-onboarding.ts +24 -80
  141. package/src/input/handler-shortcuts.ts +15 -4
  142. package/src/input/handler.ts +47 -17
  143. package/src/input/input-history.ts +5 -6
  144. package/src/input/keybindings.ts +22 -11
  145. package/src/input/onboarding/onboarding-wizard-apply.ts +13 -0
  146. package/src/input/onboarding/onboarding-wizard-constants.ts +1 -0
  147. package/src/input/onboarding/onboarding-wizard-operator-steps.ts +147 -57
  148. package/src/input/onboarding/onboarding-wizard-steps.ts +46 -29
  149. package/src/input/onboarding/onboarding-wizard-types.ts +3 -1
  150. package/src/input/onboarding/onboarding-wizard.ts +68 -0
  151. package/src/input/profile-picker-modal.ts +31 -12
  152. package/src/input/session-picker-modal.ts +22 -4
  153. package/src/input/settings-modal-behavior.ts +0 -3
  154. package/src/input/settings-modal-subscriptions.ts +3 -3
  155. package/src/input/settings-modal-types.ts +2 -13
  156. package/src/input/settings-modal.ts +6 -52
  157. package/src/input/submission-intent.ts +0 -1
  158. package/src/input/submission-router.ts +3 -3
  159. package/src/main.ts +18 -8
  160. package/src/panels/approval-panel.ts +8 -8
  161. package/src/panels/automation-control-panel.ts +2 -2
  162. package/src/panels/base-panel.ts +1 -1
  163. package/src/panels/builtin/agent.ts +1 -1
  164. package/src/panels/builtin/operations.ts +1 -10
  165. package/src/panels/builtin/session.ts +9 -9
  166. package/src/panels/builtin/shared.ts +2 -2
  167. package/src/panels/cost-tracker-panel.ts +1 -1
  168. package/src/panels/docs-panel.ts +5 -3
  169. package/src/panels/index.ts +0 -1
  170. package/src/panels/knowledge-panel.ts +6 -5
  171. package/src/panels/memory-panel.ts +7 -6
  172. package/src/panels/panel-list-panel.ts +36 -80
  173. package/src/panels/project-planning-panel.ts +18 -11
  174. package/src/panels/provider-account-snapshot.ts +51 -25
  175. package/src/panels/provider-accounts-panel.ts +33 -18
  176. package/src/panels/provider-health-domains.ts +45 -4
  177. package/src/panels/provider-health-panel.ts +5 -4
  178. package/src/panels/qr-panel.ts +1 -1
  179. package/src/panels/schedule-panel.ts +9 -17
  180. package/src/panels/security-panel.ts +8 -8
  181. package/src/panels/session-browser-panel.ts +10 -10
  182. package/src/panels/subscription-panel.ts +3 -3
  183. package/src/panels/system-messages-panel.ts +1 -1
  184. package/src/panels/tasks-panel.ts +20 -13
  185. package/src/panels/tool-inspector-panel.ts +19 -12
  186. package/src/panels/work-plan-panel.ts +5 -5
  187. package/src/planning/project-planning-coordinator.ts +1 -1
  188. package/src/provider-auth-route-display.ts +9 -0
  189. package/src/renderer/agent-workspace-style.ts +34 -0
  190. package/src/renderer/agent-workspace.ts +228 -52
  191. package/src/renderer/autocomplete-overlay.ts +25 -6
  192. package/src/renderer/bookmark-modal.ts +19 -4
  193. package/src/renderer/buffer.ts +4 -2
  194. package/src/renderer/context-inspector.ts +50 -13
  195. package/src/renderer/diff.ts +1 -1
  196. package/src/renderer/file-picker-overlay.ts +19 -6
  197. package/src/renderer/help-overlay.ts +106 -33
  198. package/src/renderer/history-search-overlay.ts +19 -4
  199. package/src/renderer/live-tail-modal.ts +27 -5
  200. package/src/renderer/mcp-workspace.ts +164 -50
  201. package/src/renderer/model-picker-overlay.ts +58 -2
  202. package/src/renderer/model-workspace.ts +104 -20
  203. package/src/renderer/process-modal.ts +27 -6
  204. package/src/renderer/profile-picker-modal.ts +20 -4
  205. package/src/renderer/search-overlay.ts +25 -5
  206. package/src/renderer/selection-modal-overlay.ts +46 -14
  207. package/src/renderer/session-picker-modal.ts +18 -1
  208. package/src/renderer/settings-modal-helpers.ts +2 -40
  209. package/src/renderer/settings-modal.ts +83 -50
  210. package/src/renderer/tool-call.ts +20 -11
  211. package/src/runtime/agent-runtime-events.ts +6 -6
  212. package/src/runtime/bootstrap-command-context.ts +7 -1
  213. package/src/runtime/bootstrap-command-parts.ts +9 -7
  214. package/src/runtime/bootstrap-core.ts +19 -1
  215. package/src/runtime/bootstrap-hook-bridge.ts +7 -18
  216. package/src/runtime/bootstrap-shell.ts +4 -4
  217. package/src/runtime/bootstrap.ts +31 -22
  218. package/src/runtime/connected-host-auth.ts +7 -2
  219. package/src/runtime/diagnostics/panels/index.ts +2 -2
  220. package/src/runtime/diagnostics/panels/policy.ts +7 -7
  221. package/src/runtime/index.ts +2 -1
  222. package/src/runtime/onboarding/apply-file-helpers.ts +66 -0
  223. package/src/runtime/onboarding/apply.ts +80 -79
  224. package/src/runtime/onboarding/derivation.ts +5 -8
  225. package/src/runtime/onboarding/snapshot.ts +0 -15
  226. package/src/runtime/onboarding/types.ts +8 -19
  227. package/src/runtime/onboarding/verify.ts +32 -10
  228. package/src/runtime/operator-token-cleanup.ts +1 -1
  229. package/src/runtime/services.ts +91 -22
  230. package/src/runtime/store/selectors/index.ts +3 -3
  231. package/src/runtime/store/state.ts +1 -4
  232. package/src/runtime/surface-feature-flags.ts +41 -6
  233. package/src/runtime/ui-read-models.ts +3 -4
  234. package/src/runtime/ui-services.ts +6 -6
  235. package/src/shell/blocking-input.ts +2 -1
  236. package/src/shell/ui-openers.ts +3 -13
  237. package/src/tools/agent-analysis-registry-policy.ts +0 -1
  238. package/src/tools/agent-channel-send-tool.ts +133 -0
  239. package/src/tools/agent-context-policy.ts +1 -1
  240. package/src/tools/agent-knowledge-ingest-tool.ts +405 -0
  241. package/src/tools/agent-knowledge-tool.ts +170 -0
  242. package/src/tools/agent-local-registry-tool.ts +269 -69
  243. package/src/tools/agent-media-generate-tool.ts +133 -0
  244. package/src/tools/agent-notify-tool.ts +143 -0
  245. package/src/tools/agent-operator-action-tool.ts +137 -0
  246. package/src/tools/agent-operator-briefing-tool.ts +217 -0
  247. package/src/tools/agent-reminder-schedule-tool.ts +237 -0
  248. package/src/tools/agent-tool-policy-guard.ts +8 -8
  249. package/src/tools/agent-work-plan-tool.ts +256 -0
  250. package/src/version.ts +1 -1
  251. package/src/input/commands/policy-dispatch.ts +0 -339
  252. package/src/input/commands/policy.ts +0 -13
  253. package/src/panels/panel-picker.ts +0 -105
  254. package/src/panels/policy-panel.ts +0 -308
  255. package/src/renderer/panel-picker-overlay.ts +0 -202
@@ -9,6 +9,10 @@ import { BUILTIN_SECRET_PROVIDER_SOURCES, describeSecretRef, isSecretRefInput, r
9
9
  import { requireBookmarkManager, requireProviderApi, requireSecretsManager } from './runtime-services.ts';
10
10
  import { summarizeError } from '@pellux/goodvibes-sdk/platform/utils';
11
11
  import { requireYesFlag, stripYesFlag } from './confirmation.ts';
12
+ import {
13
+ formatAgentMediaGenerationResult,
14
+ generateAgentMedia,
15
+ } from '../../agent/media-generation.ts';
12
16
 
13
17
  function isGoodVibesSecretRefInput(value: string): boolean {
14
18
  const normalized = value.trim();
@@ -23,7 +27,7 @@ function isMalformedGoodVibesSecretRefInput(value: string): boolean {
23
27
  function toggleBlocks(typeFilter: string, collapsed: boolean, ctx: CommandContext): void {
24
28
  const VALID_TYPES = ['all', 'thinking', 'tool', 'code'] as const;
25
29
  if (!VALID_TYPES.includes(typeFilter as typeof VALID_TYPES[number])) {
26
- ctx.print(`Unknown type: ${typeFilter}\nValid types: ${VALID_TYPES.join(', ')}`);
30
+ ctx.print(`Unknown type ${typeFilter}\nValid types ${VALID_TYPES.join(', ')}`);
27
31
  return;
28
32
  }
29
33
  const blockRegistry = ctx.session.conversationManager.getBlockRegistry();
@@ -49,6 +53,60 @@ function toggleBlocks(typeFilter: string, collapsed: boolean, ctx: CommandContex
49
53
  ctx.renderRequest();
50
54
  }
51
55
 
56
+ interface MediaGenerateArgs {
57
+ readonly prompt: string;
58
+ readonly providerId?: string;
59
+ readonly modelId?: string;
60
+ readonly outputMimeType?: string;
61
+ readonly yes: boolean;
62
+ readonly errors: readonly string[];
63
+ }
64
+
65
+ function readFlagValue(args: readonly string[], index: number, flag: string, errors: string[]): string | null {
66
+ const value = args[index + 1];
67
+ if (!value || value.startsWith('--')) {
68
+ errors.push(`${flag} requires a value.`);
69
+ return null;
70
+ }
71
+ return value;
72
+ }
73
+
74
+ function parseMediaGenerateArgs(args: readonly string[]): MediaGenerateArgs {
75
+ const parsed = stripYesFlag([...args]);
76
+ const errors: string[] = [];
77
+ const promptParts: string[] = [];
78
+ let providerId: string | undefined;
79
+ let modelId: string | undefined;
80
+ let outputMimeType: string | undefined;
81
+ for (let index = 0; index < parsed.rest.length; index += 1) {
82
+ const arg = parsed.rest[index];
83
+ if (arg === '--provider') {
84
+ providerId = readFlagValue(parsed.rest, index, arg, errors) ?? providerId;
85
+ index += 1;
86
+ } else if (arg === '--model') {
87
+ modelId = readFlagValue(parsed.rest, index, arg, errors) ?? modelId;
88
+ index += 1;
89
+ } else if (arg === '--mime') {
90
+ outputMimeType = readFlagValue(parsed.rest, index, arg, errors) ?? outputMimeType;
91
+ index += 1;
92
+ } else if (arg?.startsWith('--')) {
93
+ errors.push(`Unknown media generation flag ${arg}`);
94
+ } else if (arg) {
95
+ promptParts.push(arg);
96
+ }
97
+ }
98
+ const prompt = promptParts.join(' ').trim();
99
+ if (!prompt) errors.push('Media generation prompt is required.');
100
+ return {
101
+ prompt,
102
+ ...(providerId ? { providerId } : {}),
103
+ ...(modelId ? { modelId } : {}),
104
+ ...(outputMimeType ? { outputMimeType } : {}),
105
+ yes: parsed.yes,
106
+ errors,
107
+ };
108
+ }
109
+
52
110
  export function registerLocalRuntimeCommands(registry: CommandRegistry): void {
53
111
  registry.register({ name: 'expand', description: 'Expand blocks by type', usage: '[all|thinking|tool|code]', argsHint: '[all|thinking|tool|code]', handler(args, ctx) { toggleBlocks(args[0] || 'all', false, ctx); } });
54
112
  registry.register({ name: 'collapse', description: 'Collapse blocks by type', usage: '[all|thinking|tool|code]', argsHint: '[all|thinking|tool|code]', handler(args, ctx) { toggleBlocks(args[0] || 'all', true, ctx); } });
@@ -130,9 +188,12 @@ export function registerLocalRuntimeCommands(registry: CommandRegistry): void {
130
188
  }
131
189
  try {
132
190
  const resolved = await resolveSecretRef(refText, { resolveLocalSecret: (key) => mgr.get(key) });
133
- ctx.print(`[secrets] ${describeSecretRef(refText)}: ${resolved.value ? 'resolved <redacted>' : 'missing'}`);
191
+ ctx.print([
192
+ `[secrets] ${describeSecretRef(refText)}`,
193
+ ` status ${resolved.value ? 'resolved <redacted>' : 'missing'}`,
194
+ ].join('\n'));
134
195
  } catch (error) {
135
- ctx.print(`[secrets] ${describeSecretRef(refText)} failed: ${summarizeError(error)}`);
196
+ ctx.print(`[secrets] ${describeSecretRef(refText)} failed ${summarizeError(error)}`);
136
197
  }
137
198
  return;
138
199
  }
@@ -190,7 +251,10 @@ export function registerLocalRuntimeCommands(registry: CommandRegistry): void {
190
251
  scope: flags.has('--user') ? 'user' : flags.has('--project') ? 'project' : undefined,
191
252
  medium: flags.has('--plaintext') ? 'plaintext' : flags.has('--secure') ? 'secure' : undefined,
192
253
  });
193
- ctx.print(`[secrets] Deleted: ${key}`);
254
+ ctx.print([
255
+ '[secrets] Deleted',
256
+ ` key ${key}`,
257
+ ].join('\n'));
194
258
  return;
195
259
  }
196
260
  ctx.print('[secrets] Usage: /secrets set <KEY> <value> [--user|--project] [--secure|--plaintext] --yes | link <KEY> <secret-ref> [--user|--project] [--secure|--plaintext] --yes | get <KEY> | test <secret-ref> | providers | list | delete <KEY> [--user|--project] [--secure|--plaintext] --yes');
@@ -212,36 +276,42 @@ export function registerLocalRuntimeCommands(registry: CommandRegistry): void {
212
276
  const promptText = args.slice(1).join(' ') || `Attached image: ${rawPath.split('/').pop() ?? rawPath}`;
213
277
  const projectRoot = ctx.workspace.shellPaths?.workingDirectory ?? ctx.platform.configManager.getWorkingDirectory();
214
278
  if (!projectRoot) {
215
- ctx.print('Error: working directory is unavailable.');
279
+ ctx.print([
280
+ 'Error',
281
+ ' message working directory is unavailable.',
282
+ ].join('\n'));
216
283
  return;
217
284
  }
218
285
  let resolvedPath: string;
219
286
  try {
220
287
  resolvedPath = resolveAndValidatePath(rawPath, projectRoot);
221
288
  } catch (err) {
222
- ctx.print(`Error: ${summarizeError(err)}`);
289
+ ctx.print([
290
+ 'Error',
291
+ ` message ${summarizeError(err)}`,
292
+ ].join('\n'));
223
293
  return;
224
294
  }
225
295
  if (!existsSync(resolvedPath)) {
226
- ctx.print(`File not found: ${rawPath}`);
296
+ ctx.print(`File not found ${rawPath}`);
227
297
  return;
228
298
  }
229
299
  const ext = resolvedPath.slice(resolvedPath.lastIndexOf('.')).toLowerCase();
230
300
  const mediaType = ({ '.png': 'image/png', '.jpg': 'image/jpeg', '.jpeg': 'image/jpeg', '.webp': 'image/webp', '.gif': 'image/gif' } as Record<string, string>)[ext];
231
301
  if (!mediaType) {
232
- ctx.print(`Unsupported image format: ${ext}\nSupported: .png, .jpg, .jpeg, .webp, .gif`);
302
+ ctx.print(`Unsupported image format ${ext}\nSupported .png, .jpg, .jpeg, .webp, .gif`);
233
303
  return;
234
304
  }
235
305
  const stat = statSync(resolvedPath);
236
306
  if (stat.size > 20 * 1024 * 1024) {
237
- ctx.print(`Image too large (${(stat.size / 1024 / 1024).toFixed(1)}MB). Maximum: 20MB`);
307
+ ctx.print(`Image too large (${(stat.size / 1024 / 1024).toFixed(1)}MB). Maximum 20MB`);
238
308
  return;
239
309
  }
240
310
  let data: string;
241
311
  try {
242
312
  data = (await readFile(resolvedPath)).toString('base64');
243
313
  } catch (err) {
244
- ctx.print(`Failed to read image: ${summarizeError(err)}`);
314
+ ctx.print(`Failed to read image ${summarizeError(err)}`);
245
315
  return;
246
316
  }
247
317
  const currentModel = await requireProviderApi(ctx).getCurrentModel();
@@ -253,6 +323,53 @@ export function registerLocalRuntimeCommands(registry: CommandRegistry): void {
253
323
  },
254
324
  });
255
325
 
326
+ registry.register({
327
+ name: 'media',
328
+ description: 'Inspect media providers or generate media through configured providers',
329
+ usage: 'providers | generate [--provider <id>] [--model <id>] [--mime <mime>] <prompt> --yes',
330
+ argsHint: '<providers|generate>',
331
+ async handler(args, ctx) {
332
+ const subcommand = args[0]?.toLowerCase() || 'providers';
333
+ const registry = ctx.platform.mediaProviderRegistry;
334
+ if (!registry) {
335
+ ctx.print('[media] Media providers are not available in this runtime.');
336
+ return;
337
+ }
338
+ if (subcommand === 'providers' || subcommand === 'status' || subcommand === 'list') {
339
+ const statuses = await registry.status();
340
+ ctx.print([
341
+ '[media] Providers:',
342
+ ...statuses.map((provider) => ` ${provider.id}: ${provider.state}${provider.configured ? '' : ' (setup needed)'} - ${provider.capabilities.join(', ')}${provider.detail ? ` - ${provider.detail}` : ''}`),
343
+ ].join('\n'));
344
+ return;
345
+ }
346
+ if (subcommand !== 'generate') {
347
+ ctx.print('[media] Usage: /media providers | /media generate [--provider <id>] [--model <id>] [--mime <mime>] <prompt> --yes');
348
+ return;
349
+ }
350
+ const artifactStore = ctx.platform.artifactStore;
351
+ if (!artifactStore) {
352
+ ctx.print('[media] Artifact storage is not available in this runtime.');
353
+ return;
354
+ }
355
+ const parsed = parseMediaGenerateArgs(args.slice(1));
356
+ if (parsed.errors.length > 0) {
357
+ ctx.print(`[media] ${parsed.errors.join('\n[media] ')}`);
358
+ return;
359
+ }
360
+ if (!parsed.yes) {
361
+ requireYesFlag(ctx, `generate media for "${parsed.prompt}"`, '/media generate [--provider <id>] [--model <id>] [--mime <mime>] <prompt> --yes');
362
+ return;
363
+ }
364
+ try {
365
+ const result = await generateAgentMedia(registry, artifactStore, parsed);
366
+ ctx.print(formatAgentMediaGenerationResult(result));
367
+ } catch (error) {
368
+ ctx.print(`[media] Generation failed ${summarizeError(error)}`);
369
+ }
370
+ },
371
+ });
372
+
256
373
  registry.register({
257
374
  name: 'refresh-models',
258
375
  description: 'Refresh model catalog, benchmarks, and token limits',
@@ -267,15 +384,17 @@ export function registerLocalRuntimeCommands(registry: CommandRegistry): void {
267
384
  catalogOk = true;
268
385
  ctx.print(`Model catalog refreshed: ${catalog.modelCount} models from ${catalog.providerCount} providers`);
269
386
  } catch (e) {
270
- ctx.print(`Catalog refresh failed: ${summarizeError(e)}`);
387
+ ctx.print(`Catalog refresh failed ${summarizeError(e)}`);
271
388
  }
272
389
  ctx.print('Refreshing benchmarks...');
273
390
  try {
274
391
  const benchmarkCount = await providerApi.refreshBenchmarks();
275
392
  benchmarksOk = true;
276
- ctx.print(`Benchmarks refreshed${benchmarkCount > 0 ? `: ${benchmarkCount} model records available.` : '.'}`);
393
+ ctx.print(benchmarkCount > 0
394
+ ? `Benchmarks refreshed: ${benchmarkCount} model records available.`
395
+ : 'Benchmarks refreshed.');
277
396
  } catch (e) {
278
- ctx.print(`Benchmarks refresh failed: ${summarizeError(e)}`);
397
+ ctx.print(`Benchmarks refresh failed ${summarizeError(e)}`);
279
398
  }
280
399
  ctx.print('Refreshing token limits...');
281
400
  try {
@@ -283,7 +402,7 @@ export function registerLocalRuntimeCommands(registry: CommandRegistry): void {
283
402
  limitsOk = true;
284
403
  ctx.print(`Token limits refreshed: ${count} models updated.`);
285
404
  } catch (e) {
286
- ctx.print(`Token limits refresh failed: ${summarizeError(e)}`);
405
+ ctx.print(`Token limits refresh failed ${summarizeError(e)}`);
287
406
  }
288
407
  if (!catalogOk || !benchmarksOk || !limitsOk) ctx.print('Some refreshes failed — see messages above.');
289
408
  },
@@ -308,14 +427,17 @@ export function registerLocalRuntimeCommands(registry: CommandRegistry): void {
308
427
  }
309
428
  const favorites = await providerApi.getFavorites();
310
429
  if (favorites.pinned.some((entry) => entry.modelId === modelId || entry.registryKey === modelId)) {
311
- ctx.print(`Model already pinned: ${modelId}`);
430
+ ctx.print(`Model already pinned ${modelId}`);
312
431
  return;
313
432
  }
314
433
  try {
315
434
  await providerApi.pinModel(modelId);
316
435
  ctx.print(`Pinned: ${modelId}`);
317
436
  } catch (e) {
318
- ctx.print(`Error: ${summarizeError(e)}`);
437
+ ctx.print([
438
+ 'Error',
439
+ ` message ${summarizeError(e)}`,
440
+ ].join('\n'));
319
441
  }
320
442
  },
321
443
  });
@@ -13,7 +13,7 @@ export interface SetupReviewSnapshot {
13
13
  readonly builtinSubscriptionProviderCount: number;
14
14
  readonly activeSubscriptionCount: number;
15
15
  readonly pendingSubscriptionCount: number;
16
- readonly serviceIssues: string[];
16
+ readonly hostIntegrationIssues: string[];
17
17
  readonly skillCount: number;
18
18
  readonly pluginCount: number;
19
19
  readonly quarantinedPluginCount: number;
@@ -33,11 +33,11 @@ export async function buildSetupReviewSnapshot(ctx: CommandContext): Promise<Set
33
33
  const serviceRegistry = requireServiceRegistry(ctx);
34
34
  const services = Object.keys(serviceRegistry.getAll()).sort((a, b) => a.localeCompare(b));
35
35
  const serviceConfigs = serviceRegistry.getAll();
36
- const serviceIssues: string[] = [];
36
+ const hostIntegrationIssues: string[] = [];
37
37
  for (const name of services) {
38
38
  const inspection = await serviceRegistry.inspect(name);
39
39
  if (!inspection?.hasPrimaryCredential) {
40
- serviceIssues.push(`${name}: missing primary credential`);
40
+ hostIntegrationIssues.push(`${name}: missing primary credential`);
41
41
  }
42
42
  }
43
43
 
@@ -79,13 +79,13 @@ export async function buildSetupReviewSnapshot(ctx: CommandContext): Promise<Set
79
79
  message: providerCount > 0 ? `${providerCount} model(s) available` : 'no models available',
80
80
  },
81
81
  {
82
- severity: (services.length === 0 && oauthProviderCount === 0 && builtinSubscriptionProviderCount === 0) ? 'warn' : serviceIssues.length === 0 ? 'pass' : 'warn',
82
+ severity: (services.length === 0 && oauthProviderCount === 0 && builtinSubscriptionProviderCount === 0) ? 'warn' : hostIntegrationIssues.length === 0 ? 'pass' : 'warn',
83
83
  area: 'host',
84
84
  message: (services.length === 0 && oauthProviderCount === 0 && builtinSubscriptionProviderCount === 0)
85
85
  ? 'no connected host integrations configured'
86
- : serviceIssues.length === 0
86
+ : hostIntegrationIssues.length === 0
87
87
  ? `${services.length} host integration(s), ${oauthProviderCount + builtinSubscriptionProviderCount} oauth provider(s), ${activeSubscriptionCount} active subscription override(s)`
88
- : `${serviceIssues.length} host integration configuration issue(s)`,
88
+ : `${hostIntegrationIssues.length} host integration configuration issue(s)`,
89
89
  },
90
90
  {
91
91
  severity: quarantinedPluginCount === 0 ? 'pass' : 'warn',
@@ -111,7 +111,7 @@ export async function buildSetupReviewSnapshot(ctx: CommandContext): Promise<Set
111
111
  builtinSubscriptionProviderCount,
112
112
  activeSubscriptionCount,
113
113
  pendingSubscriptionCount,
114
- serviceIssues,
114
+ hostIntegrationIssues,
115
115
  skillCount: skills.length,
116
116
  pluginCount: plugins.length,
117
117
  quarantinedPluginCount,