@pellux/goodvibes-agent 0.1.116 → 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 (285) hide show
  1. package/CHANGELOG.md +48 -661
  2. package/README.md +64 -57
  3. package/bin/goodvibes-agent.ts +16 -2
  4. package/dist/package/main.js +199180 -192185
  5. package/docs/README.md +15 -8
  6. package/docs/channels-remote-and-api.md +50 -0
  7. package/docs/connected-host.md +59 -0
  8. package/docs/getting-started.md +61 -50
  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 +48 -11
  13. package/docs/tools-and-commands.md +123 -0
  14. package/docs/voice-and-live-tts.md +51 -0
  15. package/package.json +3 -6
  16. package/src/agent/behavior-discovery-summary.ts +1 -3
  17. package/src/agent/channel-delivery.ts +201 -0
  18. package/src/agent/media-generation.ts +159 -0
  19. package/src/agent/memory-prompt.ts +0 -1
  20. package/src/agent/note-registry.ts +329 -0
  21. package/src/agent/operator-actions.ts +343 -0
  22. package/src/agent/persona-discovery.ts +1 -3
  23. package/src/agent/persona-registry.ts +19 -16
  24. package/src/agent/record-labels.ts +107 -0
  25. package/src/agent/reminder-schedule-format.ts +33 -24
  26. package/src/agent/reminder-schedule.ts +27 -26
  27. package/src/agent/routine-registry.ts +54 -14
  28. package/src/agent/routine-schedule-args.ts +2 -1
  29. package/src/agent/routine-schedule-format.ts +77 -53
  30. package/src/agent/routine-schedule-promotion.ts +35 -33
  31. package/src/agent/routine-schedule-receipts.ts +29 -27
  32. package/src/agent/runtime-profile-starters.ts +5 -5
  33. package/src/agent/runtime-profile.ts +91 -12
  34. package/src/agent/skill-registry.ts +210 -32
  35. package/src/cli/agent-knowledge-args.ts +5 -1
  36. package/src/cli/agent-knowledge-command.ts +40 -34
  37. package/src/cli/agent-knowledge-format.ts +80 -67
  38. package/src/cli/agent-knowledge-methods.ts +1 -1
  39. package/src/cli/agent-knowledge-runtime.ts +32 -26
  40. package/src/cli/bundle-command.ts +14 -9
  41. package/src/cli/config-overrides.ts +37 -36
  42. package/src/cli/entrypoint.ts +16 -7
  43. package/src/cli/external-runtime.ts +10 -4
  44. package/src/cli/help.ts +54 -29
  45. package/src/cli/local-library-command.ts +203 -83
  46. package/src/cli/management-commands.ts +105 -68
  47. package/src/cli/management.ts +55 -74
  48. package/src/cli/memory-command.ts +66 -32
  49. package/src/cli/parser.ts +37 -3
  50. package/src/cli/profiles-command.ts +166 -31
  51. package/src/cli/provider-auth-routes.ts +2 -1
  52. package/src/cli/routines-command.ts +176 -40
  53. package/src/cli/service-posture.ts +16 -16
  54. package/src/cli/status.ts +56 -135
  55. package/src/core/conversation-message-snapshot.ts +131 -0
  56. package/src/input/agent-workspace-access-command-editor-submission.ts +149 -0
  57. package/src/input/agent-workspace-access-command-editors.ts +170 -0
  58. package/src/input/agent-workspace-activation.ts +35 -8
  59. package/src/input/agent-workspace-basic-command-editor-submission.ts +351 -94
  60. package/src/input/agent-workspace-basic-command-editors.ts +502 -9
  61. package/src/input/agent-workspace-categories.ts +423 -51
  62. package/src/input/agent-workspace-channel-command-editor-submission.ts +83 -0
  63. package/src/input/agent-workspace-channel-command-editors.ts +65 -0
  64. package/src/input/agent-workspace-channels.ts +35 -2
  65. package/src/input/agent-workspace-command-editor.ts +41 -3
  66. package/src/input/agent-workspace-config-reader.ts +16 -0
  67. package/src/input/agent-workspace-delegation-editor-submission.ts +55 -0
  68. package/src/input/agent-workspace-editors.ts +166 -1
  69. package/src/input/agent-workspace-knowledge-command-editor-submission.ts +132 -0
  70. package/src/input/agent-workspace-knowledge-command-editors.ts +110 -0
  71. package/src/input/agent-workspace-knowledge-query-editor.ts +1 -1
  72. package/src/input/agent-workspace-learned-behavior.ts +67 -0
  73. package/src/input/agent-workspace-library-command-editor-submission.ts +50 -0
  74. package/src/input/agent-workspace-library-command-editors.ts +35 -0
  75. package/src/input/agent-workspace-local-operations.ts +218 -0
  76. package/src/input/agent-workspace-local-selection.ts +75 -0
  77. package/src/input/agent-workspace-mcp-command-editor-submission.ts +95 -0
  78. package/src/input/agent-workspace-media-command-editor-submission.ts +62 -0
  79. package/src/input/agent-workspace-media-command-editors.ts +27 -0
  80. package/src/input/agent-workspace-memory-command-editor-submission.ts +232 -0
  81. package/src/input/agent-workspace-memory-command-editors.ts +180 -0
  82. package/src/input/agent-workspace-memory-editor.ts +2 -2
  83. package/src/input/agent-workspace-navigation.ts +81 -0
  84. package/src/input/agent-workspace-notify-editor-submission.ts +121 -0
  85. package/src/input/agent-workspace-operations-command-editor-submission.ts +208 -0
  86. package/src/input/agent-workspace-operations-command-editors.ts +196 -0
  87. package/src/input/agent-workspace-panel-route.ts +43 -0
  88. package/src/input/agent-workspace-provider-command-editor-submission.ts +155 -0
  89. package/src/input/agent-workspace-provider-command-editors.ts +93 -0
  90. package/src/input/agent-workspace-reminder-schedule-editor.ts +1 -1
  91. package/src/input/agent-workspace-requirements.ts +11 -0
  92. package/src/input/agent-workspace-routine-schedule-editor.ts +2 -2
  93. package/src/input/agent-workspace-search.ts +169 -0
  94. package/src/input/agent-workspace-secret-editor-submission.ts +153 -0
  95. package/src/input/agent-workspace-session-command-editor-submission.ts +199 -0
  96. package/src/input/agent-workspace-session-command-editors.ts +249 -0
  97. package/src/input/agent-workspace-setup.ts +37 -16
  98. package/src/input/agent-workspace-skill-bundle-command-editor-submission.ts +101 -0
  99. package/src/input/agent-workspace-skill-bundle-command-editors.ts +110 -0
  100. package/src/input/agent-workspace-snapshot.ts +162 -21
  101. package/src/input/agent-workspace-task-command-editor-submission.ts +61 -0
  102. package/src/input/agent-workspace-task-command-editors.ts +47 -0
  103. package/src/input/agent-workspace-token.ts +18 -2
  104. package/src/input/agent-workspace-types.ts +212 -4
  105. package/src/input/agent-workspace-voice-media.ts +4 -7
  106. package/src/input/agent-workspace-web-research-editor.ts +104 -0
  107. package/src/input/agent-workspace-workplan-editor-submission.ts +153 -0
  108. package/src/input/agent-workspace.ts +178 -240
  109. package/src/input/command-registry.ts +5 -2
  110. package/src/input/commands/agent-runtime-profile-runtime.ts +126 -37
  111. package/src/input/commands/agent-skills-runtime.ts +149 -72
  112. package/src/input/commands/agent-workspace-runtime.ts +23 -6
  113. package/src/input/commands/brief-runtime.ts +55 -25
  114. package/src/input/commands/channels-runtime.ts +147 -33
  115. package/src/input/commands/compat-runtime.ts +32 -0
  116. package/src/input/commands/delegation-runtime.ts +29 -23
  117. package/src/input/commands/experience-runtime.ts +6 -4
  118. package/src/input/commands/guidance-runtime.ts +4 -4
  119. package/src/input/commands/health-runtime.ts +149 -126
  120. package/src/input/commands/knowledge.ts +82 -60
  121. package/src/input/commands/local-provider-runtime.ts +43 -21
  122. package/src/input/commands/local-runtime.ts +138 -16
  123. package/src/input/commands/local-setup-review.ts +10 -20
  124. package/src/input/commands/mcp-runtime.ts +63 -46
  125. package/src/input/commands/notify-runtime.ts +38 -9
  126. package/src/input/commands/operator-actions-runtime.ts +138 -0
  127. package/src/input/commands/operator-runtime.ts +6 -76
  128. package/src/input/commands/personas-runtime.ts +46 -31
  129. package/src/input/commands/planning-runtime.ts +1 -1
  130. package/src/input/commands/platform-access-runtime.ts +35 -98
  131. package/src/input/commands/product-runtime.ts +2 -2
  132. package/src/input/commands/provider-accounts-runtime.ts +60 -39
  133. package/src/input/commands/qrcode-runtime.ts +50 -9
  134. package/src/input/commands/recall-bundle.ts +11 -11
  135. package/src/input/commands/recall-capture.ts +13 -11
  136. package/src/input/commands/recall-query.ts +29 -21
  137. package/src/input/commands/recall-review.ts +2 -1
  138. package/src/input/commands/routines-runtime.ts +99 -45
  139. package/src/input/commands/runtime-services.ts +1 -14
  140. package/src/input/commands/schedule-runtime.ts +33 -20
  141. package/src/input/commands/security-runtime.ts +6 -11
  142. package/src/input/commands/session-content.ts +80 -78
  143. package/src/input/commands/session-workflow.ts +134 -104
  144. package/src/input/commands/session.ts +3 -174
  145. package/src/input/commands/shell-core.ts +38 -17
  146. package/src/input/commands/subscription-runtime.ts +54 -185
  147. package/src/input/commands/support-bundle-runtime.ts +53 -0
  148. package/src/input/commands/tasks-runtime.ts +21 -21
  149. package/src/input/commands/work-plan-runtime.ts +33 -8
  150. package/src/input/commands.ts +6 -2
  151. package/src/input/feed-context-factory.ts +2 -2
  152. package/src/input/file-picker.ts +3 -2
  153. package/src/input/handler-command-route.ts +4 -7
  154. package/src/input/handler-content-actions.ts +89 -26
  155. package/src/input/handler-feed-routes.ts +19 -12
  156. package/src/input/handler-feed.ts +6 -5
  157. package/src/input/handler-interactions.ts +9 -36
  158. package/src/input/handler-modal-stack.ts +3 -3
  159. package/src/input/handler-onboarding.ts +52 -91
  160. package/src/input/handler-shortcuts.ts +16 -7
  161. package/src/input/handler.ts +50 -23
  162. package/src/input/input-history.ts +5 -6
  163. package/src/input/keybindings.ts +27 -16
  164. package/src/input/mcp-workspace.ts +90 -26
  165. package/src/input/onboarding/handler-onboarding-routes.ts +3 -1
  166. package/src/input/onboarding/onboarding-wizard-apply.ts +62 -0
  167. package/src/input/onboarding/onboarding-wizard-constants.ts +1 -0
  168. package/src/input/onboarding/onboarding-wizard-helpers.ts +1 -1
  169. package/src/input/onboarding/onboarding-wizard-operator-steps.ts +223 -55
  170. package/src/input/onboarding/onboarding-wizard-steps.ts +59 -35
  171. package/src/input/onboarding/onboarding-wizard-types.ts +4 -1
  172. package/src/input/onboarding/onboarding-wizard.ts +87 -2
  173. package/src/input/profile-picker-modal.ts +31 -12
  174. package/src/input/session-picker-modal.ts +21 -4
  175. package/src/input/settings-modal-agent-policy.ts +6 -6
  176. package/src/input/settings-modal-behavior.ts +0 -3
  177. package/src/input/settings-modal-subscriptions.ts +3 -3
  178. package/src/input/settings-modal-types.ts +2 -13
  179. package/src/input/settings-modal.ts +20 -66
  180. package/src/input/submission-intent.ts +0 -1
  181. package/src/input/submission-router.ts +3 -3
  182. package/src/main.ts +18 -10
  183. package/src/panels/approval-panel.ts +8 -8
  184. package/src/panels/automation-control-panel.ts +4 -4
  185. package/src/panels/base-panel.ts +1 -1
  186. package/src/panels/builtin/agent.ts +1 -1
  187. package/src/panels/builtin/operations.ts +3 -12
  188. package/src/panels/builtin/session.ts +32 -24
  189. package/src/panels/builtin/shared.ts +7 -7
  190. package/src/panels/cost-tracker-panel.ts +1 -1
  191. package/src/panels/docs-panel.ts +5 -3
  192. package/src/panels/index.ts +0 -1
  193. package/src/panels/knowledge-panel.ts +6 -5
  194. package/src/panels/memory-panel.ts +7 -6
  195. package/src/panels/panel-list-panel.ts +36 -80
  196. package/src/panels/project-planning-panel.ts +19 -12
  197. package/src/panels/provider-account-snapshot.ts +51 -25
  198. package/src/panels/provider-accounts-panel.ts +33 -18
  199. package/src/panels/provider-health-domains.ts +48 -7
  200. package/src/panels/provider-health-panel.ts +5 -4
  201. package/src/panels/qr-panel.ts +44 -20
  202. package/src/panels/schedule-panel.ts +9 -17
  203. package/src/panels/security-panel.ts +8 -8
  204. package/src/panels/session-browser-panel.ts +10 -10
  205. package/src/panels/subscription-panel.ts +6 -6
  206. package/src/panels/system-messages-panel.ts +3 -3
  207. package/src/panels/tasks-panel.ts +21 -14
  208. package/src/panels/tool-inspector-panel.ts +19 -12
  209. package/src/panels/work-plan-panel.ts +5 -5
  210. package/src/planning/project-planning-coordinator.ts +3 -3
  211. package/src/provider-auth-route-display.ts +9 -0
  212. package/src/renderer/agent-workspace-style.ts +34 -0
  213. package/src/renderer/agent-workspace.ts +254 -57
  214. package/src/renderer/autocomplete-overlay.ts +25 -6
  215. package/src/renderer/block-actions.ts +1 -3
  216. package/src/renderer/bookmark-modal.ts +19 -4
  217. package/src/renderer/buffer.ts +4 -2
  218. package/src/renderer/context-inspector.ts +50 -13
  219. package/src/renderer/diff.ts +1 -1
  220. package/src/renderer/file-picker-overlay.ts +19 -6
  221. package/src/renderer/help-overlay.ts +112 -34
  222. package/src/renderer/history-search-overlay.ts +19 -4
  223. package/src/renderer/live-tail-modal.ts +27 -5
  224. package/src/renderer/mcp-workspace.ts +176 -43
  225. package/src/renderer/model-picker-overlay.ts +58 -3
  226. package/src/renderer/model-workspace.ts +104 -22
  227. package/src/renderer/onboarding/onboarding-wizard.ts +20 -4
  228. package/src/renderer/process-modal.ts +27 -6
  229. package/src/renderer/profile-picker-modal.ts +21 -5
  230. package/src/renderer/search-overlay.ts +25 -5
  231. package/src/renderer/selection-modal-overlay.ts +46 -14
  232. package/src/renderer/session-picker-modal.ts +18 -1
  233. package/src/renderer/settings-modal-helpers.ts +2 -40
  234. package/src/renderer/settings-modal.ts +88 -55
  235. package/src/renderer/system-message.ts +1 -1
  236. package/src/renderer/tool-call.ts +20 -11
  237. package/src/runtime/agent-runtime-events.ts +129 -0
  238. package/src/runtime/bootstrap-command-context.ts +7 -1
  239. package/src/runtime/bootstrap-command-parts.ts +11 -8
  240. package/src/runtime/bootstrap-core.ts +23 -65
  241. package/src/runtime/bootstrap-hook-bridge.ts +7 -18
  242. package/src/runtime/bootstrap-shell.ts +46 -8
  243. package/src/runtime/bootstrap.ts +36 -46
  244. package/src/runtime/connected-host-auth.ts +47 -0
  245. package/src/runtime/diagnostics/panels/index.ts +2 -2
  246. package/src/runtime/diagnostics/panels/panel-resources.ts +1 -1
  247. package/src/runtime/diagnostics/panels/policy.ts +7 -7
  248. package/src/runtime/index.ts +2 -5
  249. package/src/runtime/onboarding/apply-file-helpers.ts +66 -0
  250. package/src/runtime/onboarding/apply.ts +288 -74
  251. package/src/runtime/onboarding/derivation.ts +10 -13
  252. package/src/runtime/onboarding/snapshot.ts +2 -17
  253. package/src/runtime/onboarding/types.ts +34 -20
  254. package/src/runtime/onboarding/verify.ts +105 -4
  255. package/src/runtime/operator-token-cleanup.ts +3 -3
  256. package/src/runtime/services.ts +95 -11
  257. package/src/runtime/store/selectors/index.ts +3 -3
  258. package/src/runtime/store/state.ts +1 -4
  259. package/src/runtime/surface-feature-flags.ts +41 -6
  260. package/src/runtime/ui-read-models.ts +3 -4
  261. package/src/runtime/ui-services.ts +6 -6
  262. package/src/shell/blocking-input.ts +2 -1
  263. package/src/shell/service-settings-sync.ts +7 -7
  264. package/src/shell/ui-openers.ts +17 -38
  265. package/src/tools/agent-analysis-registry-policy.ts +0 -1
  266. package/src/tools/agent-channel-send-tool.ts +133 -0
  267. package/src/tools/agent-context-policy.ts +1 -1
  268. package/src/tools/agent-knowledge-ingest-tool.ts +405 -0
  269. package/src/tools/agent-knowledge-tool.ts +170 -0
  270. package/src/tools/agent-local-registry-tool.ts +279 -73
  271. package/src/tools/agent-media-generate-tool.ts +133 -0
  272. package/src/tools/agent-notify-tool.ts +143 -0
  273. package/src/tools/agent-operator-action-tool.ts +137 -0
  274. package/src/tools/agent-operator-briefing-tool.ts +217 -0
  275. package/src/tools/agent-reminder-schedule-tool.ts +237 -0
  276. package/src/tools/agent-tool-policy-guard.ts +13 -15
  277. package/src/tools/agent-work-plan-tool.ts +256 -0
  278. package/src/version.ts +1 -1
  279. package/docs/connected-services.md +0 -51
  280. package/src/cli/package-verification.ts +0 -274
  281. package/src/input/commands/policy-dispatch.ts +0 -339
  282. package/src/input/commands/policy.ts +0 -17
  283. package/src/panels/panel-picker.ts +0 -105
  284. package/src/panels/policy-panel.ts +0 -308
  285. package/src/renderer/panel-picker-overlay.ts +0 -202
@@ -17,6 +17,7 @@ import {
17
17
  type ProvenanceLinkKind,
18
18
  } from '@pellux/goodvibes-sdk/platform/state';
19
19
  import { assertNoSecretLikeMemoryText } from '../agent/memory-safety.ts';
20
+ import { formatAgentRecordReference, formatAgentRecordReviewState } from '../agent/record-labels.ts';
20
21
  import { GOODVIBES_AGENT_SURFACE_ROOT } from '../config/surface.ts';
21
22
  import type { CliCommandOutput } from './types.ts';
22
23
  import type { CliCommandRuntime } from './management.ts';
@@ -172,12 +173,12 @@ function isProvenanceKind(value: string): value is ProvenanceLinkKind {
172
173
  }
173
174
 
174
175
  function requireClass(value: string | undefined): MemoryClass {
175
- if (!value || !isMemoryClass(value)) throw new Error(`Invalid memory class "${value ?? ''}". Valid: ${VALID_CLASSES.join(', ')}`);
176
+ if (!value || !isMemoryClass(value)) throw new Error(`Invalid memory class "${value ?? ''}". Valid values ${VALID_CLASSES.join(', ')}`);
176
177
  return value;
177
178
  }
178
179
 
179
180
  function requireScope(value: string | undefined): MemoryScope {
180
- if (!value || !isMemoryScope(value)) throw new Error(`Invalid memory scope "${value ?? ''}". Valid: ${VALID_SCOPES.join(', ')}`);
181
+ if (!value || !isMemoryScope(value)) throw new Error(`Invalid memory scope "${value ?? ''}". Valid values ${VALID_SCOPES.join(', ')}`);
181
182
  return value;
182
183
  }
183
184
 
@@ -217,23 +218,23 @@ async function withMemory<T>(runtime: CliCommandRuntime, fn: (context: MemoryCon
217
218
  }
218
219
 
219
220
  function renderRecordLine(record: MemoryRecord, semanticEntry?: MemorySemanticSearchResult): string {
220
- const tags = record.tags.length > 0 ? ` tags=${record.tags.join(',')}` : '';
221
- const score = semanticEntry ? ` sim=${Math.round(semanticEntry.similarity * 100)}%` : '';
222
- return ` ${record.id} ${record.scope}/${record.cls} ${record.reviewState} ${record.confidence}%${score}${tags} ${record.summary}`;
221
+ const tags = record.tags.length > 0 ? ` tags ${record.tags.join(', ')}` : '';
222
+ const score = semanticEntry ? ` similarity ${Math.round(semanticEntry.similarity * 100)}%` : '';
223
+ return ` ${record.id} ${record.scope}/${record.cls} ${formatAgentRecordReviewState(record.reviewState)} ${record.confidence}%${score}${tags} ${record.summary}`;
223
224
  }
224
225
 
225
226
  function renderRecordList(title: string, path: string, records: readonly MemoryRecord[], semanticResults: readonly MemorySemanticSearchResult[] = []): string {
226
227
  if (records.length === 0) {
227
228
  return [
228
229
  title,
229
- ` store: ${path}`,
230
+ ` store ${path}`,
230
231
  ' No Agent memory records found.',
231
232
  ' Add one with: goodvibes-agent memory add fact "Useful durable fact" --scope project',
232
233
  ].join('\n');
233
234
  }
234
235
  return [
235
236
  `${title} (${records.length})`,
236
- ` store: ${path}`,
237
+ ` store ${path}`,
237
238
  ...records.map((record) => renderRecordLine(record, semanticResults.find((entry) => entry.record.id === record.id))),
238
239
  ].join('\n');
239
240
  }
@@ -243,7 +244,7 @@ function renderRecord(record: MemoryRecord, links: readonly MemoryLink[]): strin
243
244
  `Memory ${record.id}`,
244
245
  ` scope: ${record.scope}`,
245
246
  ` class: ${record.cls}`,
246
- ` review: ${record.reviewState}`,
247
+ ` review: ${formatAgentRecordReviewState(record.reviewState)}`,
247
248
  ` confidence: ${record.confidence}`,
248
249
  ` tags: ${record.tags.join(', ') || '(none)'}`,
249
250
  ` created: ${timestamp(record.createdAt)}`,
@@ -253,9 +254,9 @@ function renderRecord(record: MemoryRecord, links: readonly MemoryLink[]): strin
253
254
  '',
254
255
  record.summary,
255
256
  record.detail ? `\n${record.detail}` : '',
256
- record.provenance.length > 0 ? '\nProvenance:' : '',
257
- ...record.provenance.map((entry) => ` ${entry.kind}:${entry.ref}${entry.label ? ` (${entry.label})` : ''}`),
258
- links.length > 0 ? '\nLinks:' : '',
257
+ record.provenance.length > 0 ? '\nProvenance' : '',
258
+ ...record.provenance.map((entry) => ` ${formatAgentRecordReference(entry)}`),
259
+ links.length > 0 ? '\nLinks' : '',
259
260
  ...links.map((link) => ` ${link.fromId} -> ${link.toId} [${link.relation}]`),
260
261
  ].filter((line): line is string => Boolean(line)).join('\n');
261
262
  }
@@ -283,7 +284,7 @@ function provenanceFromOptions(options: ParsedOptions): readonly ProvenanceLink[
283
284
  addProvenance(provenance, 'turn', optionValue(options, 'turn'));
284
285
  addProvenance(provenance, 'task', optionValue(options, 'task'));
285
286
  addProvenance(provenance, 'file', optionValue(options, 'file'));
286
- if (provenance.length === 0) provenance.push({ kind: 'event', ref: 'cli' });
287
+ if (provenance.length === 0) provenance.push({ kind: 'event', ref: 'Command' });
287
288
  return provenance;
288
289
  }
289
290
 
@@ -306,7 +307,7 @@ function usage(): string {
306
307
  ' handoff-inspect <path>',
307
308
  ' vector [status|doctor|rebuild]',
308
309
  '',
309
- 'Agent memory is local to GoodVibes Agent and never falls back to default Knowledge/Wiki or non-Agent knowledge segments.',
310
+ 'Agent memory is local to GoodVibes Agent and never falls back to default knowledge or non-Agent knowledge segments.',
310
311
  ].join('\n');
311
312
  }
312
313
 
@@ -391,11 +392,11 @@ function writeBundle(path: string, bundle: MemoryBundle): void {
391
392
  function renderBundleInspection(path: string, bundle: MemoryBundle): string {
392
393
  return [
393
394
  'Agent memory handoff bundle',
394
- ` path: ${path}`,
395
- ` scope: ${bundle.scope}`,
396
- ` records: ${bundle.recordCount}`,
397
- ` links: ${bundle.linkCount}`,
398
- ...bundle.records.slice(0, 20).map((record) => ` ${record.id} ${record.scope}/${record.cls} ${record.reviewState} ${record.summary}`),
395
+ ` path ${path}`,
396
+ ` scope ${bundle.scope}`,
397
+ ` records ${bundle.recordCount}`,
398
+ ` links ${bundle.linkCount}`,
399
+ ...bundle.records.slice(0, 20).map((record) => ` ${record.id} ${record.scope}/${record.cls} ${formatAgentRecordReviewState(record.reviewState)} ${record.summary}`),
399
400
  bundle.records.length > 20 ? ` ... ${bundle.records.length - 20} more` : '',
400
401
  ].filter((line): line is string => Boolean(line)).join('\n');
401
402
  }
@@ -441,7 +442,7 @@ async function handleAdd(runtime: CliCommandRuntime, context: MemoryContext, arg
441
442
  assertNoSecretLikeMemoryText([summary, detail ?? '', ...(tags ?? [])]);
442
443
  const reviewState = optionValue(options, 'review-state');
443
444
  if (reviewState !== undefined && !isReviewState(reviewState)) {
444
- return failure(runtime, 'invalid_memory_command', `Invalid review state "${reviewState}". Valid: ${VALID_REVIEW_STATES.join(', ')}`, 2);
445
+ return failure(runtime, 'invalid_memory_command', `Invalid review state "${reviewState}". Valid values ${VALID_REVIEW_STATES.join(', ')}`, 2);
445
446
  }
446
447
  const record = await context.registry.add({
447
448
  scope: optionalScope(optionValue(options, 'scope')) ?? 'project',
@@ -456,14 +457,17 @@ async function handleAdd(runtime: CliCommandRuntime, context: MemoryContext, arg
456
457
  reviewedBy: optionValue(options, 'by'),
457
458
  },
458
459
  });
459
- return success(runtime, 'agent.memory.add', record, `Agent memory added: ${record.id}`);
460
+ return success(runtime, 'agent.memory.add', record, [
461
+ 'Agent memory added',
462
+ ` id ${record.id}`,
463
+ ].join('\n'));
460
464
  }
461
465
 
462
466
  async function handleShow(runtime: CliCommandRuntime, context: MemoryContext, args: readonly string[]): Promise<CliCommandOutput> {
463
467
  const id = args[0];
464
468
  if (!id) return failure(runtime, 'invalid_memory_command', 'Usage: goodvibes-agent memory show <id>', 2);
465
469
  const record = context.registry.get(id);
466
- if (!record) return failure(runtime, 'memory_not_found', `Memory record not found: ${id}`, 1);
470
+ if (!record) return failure(runtime, 'memory_not_found', `Memory record not found ${id}`, 1);
467
471
  return success(runtime, 'agent.memory.show', { record, links: context.registry.linksFor(id) }, renderRecord(record, context.registry.linksFor(id)));
468
472
  }
469
473
 
@@ -485,8 +489,13 @@ async function handleReview(runtime: CliCommandRuntime, context: MemoryContext,
485
489
  reviewedBy: optionValue(options, 'by') ?? 'operator',
486
490
  staleReason: optionValue(options, 'reason'),
487
491
  });
488
- if (!record) return failure(runtime, 'memory_not_found', `Memory record not found: ${id}`, 1);
489
- return success(runtime, 'agent.memory.review', record, `Agent memory reviewed: ${record.id} ${record.reviewState} ${record.confidence}%`);
492
+ if (!record) return failure(runtime, 'memory_not_found', `Memory record not found ${id}`, 1);
493
+ return success(runtime, 'agent.memory.review', record, [
494
+ 'Agent memory reviewed',
495
+ ` id ${record.id}`,
496
+ ` review ${formatAgentRecordReviewState(record.reviewState)}`,
497
+ ` confidence ${record.confidence}%`,
498
+ ].join('\n'));
490
499
  }
491
500
 
492
501
  async function handleReviewShortcut(runtime: CliCommandRuntime, context: MemoryContext, state: Extract<MemoryReviewState, 'stale' | 'contradicted'>, args: readonly string[]): Promise<CliCommandOutput> {
@@ -499,8 +508,11 @@ async function handleReviewShortcut(runtime: CliCommandRuntime, context: MemoryC
499
508
  reviewedBy: 'operator',
500
509
  staleReason: reasonParts.join(' '),
501
510
  });
502
- if (!record) return failure(runtime, 'memory_not_found', `Memory record not found: ${id}`, 1);
503
- return success(runtime, `agent.memory.${state}`, record, `Agent memory marked ${state}: ${record.id}`);
511
+ if (!record) return failure(runtime, 'memory_not_found', `Memory record not found ${id}`, 1);
512
+ return success(runtime, `agent.memory.${state}`, record, [
513
+ `Agent memory marked ${state}`,
514
+ ` id ${record.id}`,
515
+ ].join('\n'));
504
516
  }
505
517
 
506
518
  async function handlePromote(runtime: CliCommandRuntime, context: MemoryContext, args: readonly string[]): Promise<CliCommandOutput> {
@@ -509,8 +521,12 @@ async function handlePromote(runtime: CliCommandRuntime, context: MemoryContext,
509
521
  if (!id || !scopeRaw) return failure(runtime, 'invalid_memory_command', 'Usage: goodvibes-agent memory promote <id> <session|project|team> --yes', 2);
510
522
  if (!hasFlag(options, 'yes')) return failure(runtime, 'confirmation_required', `Refusing to promote memory record ${id} without --yes.`, 2);
511
523
  const record = context.registry.update(id, { scope: requireScope(scopeRaw) });
512
- if (!record) return failure(runtime, 'memory_not_found', `Memory record not found: ${id}`, 1);
513
- return success(runtime, 'agent.memory.promote', record, `Agent memory promoted: ${record.id} -> ${record.scope}`);
524
+ if (!record) return failure(runtime, 'memory_not_found', `Memory record not found ${id}`, 1);
525
+ return success(runtime, 'agent.memory.promote', record, [
526
+ 'Agent memory promoted',
527
+ ` id ${record.id}`,
528
+ ` scope ${record.scope}`,
529
+ ].join('\n'));
514
530
  }
515
531
 
516
532
  async function handleLink(runtime: CliCommandRuntime, context: MemoryContext, args: readonly string[]): Promise<CliCommandOutput> {
@@ -520,7 +536,12 @@ async function handleLink(runtime: CliCommandRuntime, context: MemoryContext, ar
520
536
  if (!hasFlag(options, 'yes')) return failure(runtime, 'confirmation_required', `Refusing to link memory records ${fromId} and ${toId} without --yes.`, 2);
521
537
  const link = await context.registry.link(fromId, toId, relation);
522
538
  if (!link) return failure(runtime, 'memory_link_failed', 'Memory link failed; check that both records exist.', 1);
523
- return success(runtime, 'agent.memory.link', link, `Agent memory linked: ${fromId} -> ${toId} [${relation}]`);
539
+ return success(runtime, 'agent.memory.link', link, [
540
+ 'Agent memory linked',
541
+ ` from ${fromId}`,
542
+ ` to ${toId}`,
543
+ ` relation ${relation}`,
544
+ ].join('\n'));
524
545
  }
525
546
 
526
547
  async function handleDelete(runtime: CliCommandRuntime, context: MemoryContext, args: readonly string[]): Promise<CliCommandOutput> {
@@ -528,8 +549,11 @@ async function handleDelete(runtime: CliCommandRuntime, context: MemoryContext,
528
549
  const id = options.positionals[0];
529
550
  if (!id) return failure(runtime, 'invalid_memory_command', 'Usage: goodvibes-agent memory delete <id> --yes', 2);
530
551
  if (!hasFlag(options, 'yes')) return failure(runtime, 'confirmation_required', `Refusing to delete memory record ${id} without --yes.`, 2);
531
- if (!context.registry.delete(id)) return failure(runtime, 'memory_not_found', `Memory record not found: ${id}`, 1);
532
- return success(runtime, 'agent.memory.delete', { id }, `Agent memory deleted: ${id}`);
552
+ if (!context.registry.delete(id)) return failure(runtime, 'memory_not_found', `Memory record not found ${id}`, 1);
553
+ return success(runtime, 'agent.memory.delete', { id }, [
554
+ `Agent memory deleted: ${id}`,
555
+ ` id ${id}`,
556
+ ].join('\n'));
533
557
  }
534
558
 
535
559
  async function handleExport(runtime: CliCommandRuntime, context: MemoryContext, args: readonly string[]): Promise<CliCommandOutput> {
@@ -541,7 +565,12 @@ async function handleExport(runtime: CliCommandRuntime, context: MemoryContext,
541
565
  const path = resolvePath(runtime, pathArg);
542
566
  const bundle = context.registry.exportBundle(filter);
543
567
  writeBundle(path, bundle);
544
- return success(runtime, 'agent.memory.export', { path, bundle }, `Agent memory exported: ${bundle.recordCount} record(s), ${bundle.linkCount} link(s) -> ${path}`);
568
+ return success(runtime, 'agent.memory.export', { path, bundle }, [
569
+ 'Agent memory exported',
570
+ ` records ${bundle.recordCount}`,
571
+ ` links ${bundle.linkCount}`,
572
+ ` path ${path}`,
573
+ ].join('\n'));
545
574
  }
546
575
 
547
576
  async function handleImport(runtime: CliCommandRuntime, context: MemoryContext, args: readonly string[]): Promise<CliCommandOutput> {
@@ -552,7 +581,12 @@ async function handleImport(runtime: CliCommandRuntime, context: MemoryContext,
552
581
  const path = resolvePath(runtime, pathArg);
553
582
  const bundle = readBundle(path);
554
583
  const result = await context.registry.importBundle(bundle);
555
- return success(runtime, 'agent.memory.import', { path, result }, `Agent memory imported: ${result.importedRecords} record(s), ${result.importedLinks} link(s); skipped ${result.skippedRecords}`);
584
+ return success(runtime, 'agent.memory.import', { path, result }, [
585
+ `Agent memory imported: ${result.importedRecords} record${result.importedRecords === 1 ? '' : 's'}`,
586
+ ` records: ${result.importedRecords}`,
587
+ ` links: ${result.importedLinks}`,
588
+ ` skipped: ${result.skippedRecords}`,
589
+ ].join('\n'));
556
590
  }
557
591
 
558
592
  async function handleInspect(runtime: CliCommandRuntime, args: readonly string[]): Promise<CliCommandOutput> {
package/src/cli/parser.ts CHANGED
@@ -58,7 +58,40 @@ const COMMAND_ALIASES: Readonly<Record<string, GoodVibesCliCommand>> = {
58
58
  version: 'version',
59
59
  };
60
60
 
61
- const RETIRED_LAUNCHER_ALIASES = new Set(['app', 'launch', 'start', 'tui']);
61
+ const BLOCKED_PRODUCT_COMMAND_HINTS: Readonly<Partial<Record<string, (binary: string) => string>>> = {
62
+ app: (binary) => `Unsupported command: app. Launch the Agent TUI with "${binary}" and no command.`,
63
+ bridge: () => 'Unsupported command: bridge. GoodVibes Agent connects to an externally managed GoodVibes host and does not expose bridge processes.',
64
+ 'control-plane': () => 'Unsupported command: control-plane. GoodVibes Agent can inspect connected-host posture, but it does not manage host endpoints.',
65
+ controlplane: () => 'Unsupported command: controlplane. GoodVibes Agent can inspect connected-host posture, but it does not manage host endpoints.',
66
+ cp: () => 'Unsupported command: cp. GoodVibes Agent can inspect connected-host posture, but it does not manage host endpoints.',
67
+ daemon: () => 'Unsupported command: daemon. GoodVibes Agent connects to an externally managed GoodVibes host and does not start or manage host processes.',
68
+ 'http-listener': () => 'Unsupported command: http-listener. GoodVibes Agent does not start listeners or expose inbound host endpoints.',
69
+ launch: (binary) => `Unsupported command: launch. Launch the Agent TUI with "${binary}" and no command.`,
70
+ listener: () => 'Unsupported command: listener. GoodVibes Agent does not start listeners or expose inbound host endpoints.',
71
+ remote: () => 'Unsupported command: remote. GoodVibes Agent uses explicit connected-host routes and does not manage remote host transport.',
72
+ serve: () => 'Unsupported command: serve. GoodVibes Agent connects to an externally managed GoodVibes host and does not start server processes.',
73
+ server: () => 'Unsupported command: server. GoodVibes Agent connects to an externally managed GoodVibes host and does not start server processes.',
74
+ service: () => 'Unsupported command: service. GoodVibes Agent keeps host lifecycle ownership outside this product.',
75
+ services: () => 'Unsupported command: services. GoodVibes Agent keeps host lifecycle ownership outside this product.',
76
+ start: (binary) => `Unsupported command: start. Launch the Agent TUI with "${binary}" and no command; Agent does not start connected-host processes.`,
77
+ surface: () => 'Unsupported command: surface. GoodVibes Agent does not manage connected-host surfaces.',
78
+ surfaces: () => 'Unsupported command: surfaces. GoodVibes Agent does not manage connected-host surfaces.',
79
+ tui: (binary) => `Unsupported command: tui. Launch the Agent TUI with "${binary}" and no command.`,
80
+ web: () => 'Unsupported command: web. GoodVibes Agent does not start web servers or expose browser routes.',
81
+ webhook: () => 'Unsupported command: webhook. GoodVibes Agent can send explicit channel messages, but it does not create webhook listeners.',
82
+ };
83
+
84
+ export function listGoodVibesCliCommandTokens(): readonly string[] {
85
+ return Object.keys(COMMAND_ALIASES).sort();
86
+ }
87
+
88
+ export function listGoodVibesCliCommands(): readonly GoodVibesCliCommand[] {
89
+ return [...new Set<GoodVibesCliCommand>(['tui', ...Object.values(COMMAND_ALIASES)])].sort();
90
+ }
91
+
92
+ export function listBlockedGoodVibesCliCommandTokens(): readonly string[] {
93
+ return Object.keys(BLOCKED_PRODUCT_COMMAND_HINTS).sort();
94
+ }
62
95
 
63
96
  function createDefaultFlags(): GoodVibesCliFlags {
64
97
  return {
@@ -200,7 +233,7 @@ export function parseGoodVibesCli(
200
233
  if (!token.startsWith('-') || token === '-') {
201
234
  if (!sawCommand) {
202
235
  const commandToken = token.toLowerCase();
203
- if (RETIRED_LAUNCHER_ALIASES.has(commandToken)) {
236
+ if (BLOCKED_PRODUCT_COMMAND_HINTS[commandToken]) {
204
237
  command = 'unknown';
205
238
  rawCommand = token;
206
239
  sawCommand = true;
@@ -373,7 +406,8 @@ export function parseGoodVibesCli(
373
406
  }
374
407
 
375
408
  if (rawCommand !== undefined && command === 'unknown') {
376
- errors.push(`Unknown command: ${rawCommand}`);
409
+ const blockedHint = BLOCKED_PRODUCT_COMMAND_HINTS[rawCommand.toLowerCase()];
410
+ errors.push(blockedHint ? blockedHint(binary) : `Unknown command ${rawCommand}`);
377
411
  }
378
412
 
379
413
  return {
@@ -2,17 +2,21 @@ import {
2
2
  createAgentRuntimeProfile,
3
3
  createAgentRuntimeProfileFromDiscovered,
4
4
  createAgentRuntimeProfileTemplateFromDiscovered,
5
+ clearAgentRuntimeProfileSelection,
5
6
  deleteAgentRuntimeProfile,
6
7
  exportAgentRuntimeProfileTemplate,
7
8
  importAgentRuntimeProfileTemplate,
8
9
  isAgentRuntimeProfileTemplateId,
9
10
  listAgentRuntimeProfiles,
10
11
  listAgentRuntimeProfileTemplates,
12
+ readAgentRuntimeProfileSelection,
11
13
  resolveAgentRuntimeProfileHome,
14
+ setAgentRuntimeProfileSelection,
12
15
  type AgentRuntimeProfileTemplateId,
13
16
  type AgentRuntimeProfileCommandResult,
14
17
  type AgentRuntimeProfileInfo,
15
18
  } from '../agent/runtime-profile.ts';
19
+ import { formatAgentRecordSource } from '../agent/record-labels.ts';
16
20
  import type { CliCommandOutput, GoodVibesCliParseResult } from './types.ts';
17
21
 
18
22
  interface ProfilesCommandRuntime {
@@ -53,7 +57,7 @@ function parseTemplate(args: readonly string[]): AgentRuntimeProfileTemplateId |
53
57
  if (!raw || raw === 'blank') return undefined;
54
58
  const normalized = raw.trim().toLowerCase().replace(/_/g, '-');
55
59
  if (isAgentRuntimeProfileTemplateId(normalized)) return normalized;
56
- throw new Error(`Unknown Agent starter profile template: ${raw}. Use profiles templates to list starters.`);
60
+ throw new Error(`Unknown Agent starter profile template ${raw}. Use profiles templates to list starters.`);
57
61
  }
58
62
 
59
63
  function parseCsvFlag(args: readonly string[], names: readonly string[]): readonly string[] | undefined {
@@ -63,16 +67,21 @@ function parseCsvFlag(args: readonly string[], names: readonly string[]): readon
63
67
  }
64
68
 
65
69
  function profileLine(profile: AgentRuntimeProfileInfo): string {
66
- const created = profile.createdAt ? ` created=${profile.createdAt}` : '';
70
+ const created = profile.createdAt ? ` created ${profile.createdAt}` : '';
67
71
  const starter = profile.starterTemplateId ? ` starter=${profile.starterTemplateId}` : '';
68
- return ` ${profile.id} home=${profile.homeDirectory}${created}${starter}`;
72
+ return ` ${profile.id} home ${profile.homeDirectory}${created}${starter}`;
69
73
  }
70
74
 
71
75
  function renderProfilesResult(result: AgentRuntimeProfileCommandResult): string {
72
76
  if (!result.ok) return result.error ?? 'Agent profile command failed.';
73
77
  if (result.kind === 'agent.profiles.list') {
74
78
  const profiles = result.data?.profiles ?? [];
75
- if (profiles.length === 0) return 'No Agent profiles. Use: goodvibes-agent profiles create <name> --template <id> --yes';
79
+ if (profiles.length === 0) {
80
+ return [
81
+ 'No Agent profiles',
82
+ ' next goodvibes-agent profiles create <name> --template <id> --yes',
83
+ ].join('\n');
84
+ }
76
85
  return [
77
86
  `Agent profiles (${profiles.length})`,
78
87
  ...profiles.map(profileLine),
@@ -83,49 +92,71 @@ function renderProfilesResult(result: AgentRuntimeProfileCommandResult): string
83
92
  return [
84
93
  `Agent starter profile templates (${templates.length})`,
85
94
  ...templates.map((template) => [
86
- ` ${template.id} ${template.name} [${template.source}]`,
95
+ ` ${template.id} ${template.name} [${formatAgentRecordSource(template.source).toLowerCase()}]`,
87
96
  ` ${template.description}`,
88
- ` persona: ${template.personaName}`,
89
- ` skills: ${template.skillNames.join(', ')}`,
90
- ` routines: ${template.routineNames.join(', ')}`,
97
+ ` persona ${template.personaName}`,
98
+ ` skills ${template.skillNames.join(', ')}`,
99
+ ` routines ${template.routineNames.join(', ')}`,
91
100
  ].join('\n')),
92
- 'Use: goodvibes-agent profiles create <name> --template <id> --yes',
93
- 'Export/edit/import: goodvibes-agent profiles templates export <id> <path> --yes',
101
+ 'Use goodvibes-agent profiles create <name> --template <id> --yes',
102
+ 'Export/edit/import with goodvibes-agent profiles templates export <id> <path> --yes',
94
103
  ].join('\n');
95
104
  }
96
105
  if (result.kind === 'agent.profiles.template.export' && result.data?.template && result.data.path) {
97
106
  return [
98
107
  `Agent starter template exported: ${result.data.template.id}`,
99
- ` path: ${result.data.path}`,
100
- ' edit the JSON, then import it with: goodvibes-agent profiles templates import <path> --yes',
108
+ ` path ${result.data.path}`,
109
+ ' edit the JSON, then import it with goodvibes-agent profiles templates import <path> --yes',
101
110
  ].join('\n');
102
111
  }
103
112
  if (result.kind === 'agent.profiles.template.import' && result.data?.template) {
104
113
  return [
105
114
  `Agent starter template imported: ${result.data.template.id}`,
106
- ` name: ${result.data.template.name}`,
107
- ` source: ${result.data.template.source}`,
108
- ` use: goodvibes-agent profiles create <name> --template ${result.data.template.id} --yes`,
115
+ ` name ${result.data.template.name}`,
116
+ ` origin ${formatAgentRecordSource(result.data.template.source)}`,
117
+ ` use goodvibes-agent profiles create <name> --template ${result.data.template.id} --yes`,
109
118
  ].join('\n');
110
119
  }
111
120
  if (result.kind === 'agent.profiles.template.from_discovered' && result.data?.template) {
112
121
  return [
113
122
  `Agent starter template created from discovered behavior: ${result.data.template.id}`,
114
- ` name: ${result.data.template.name}`,
115
- ` persona: ${result.data.template.personaName}`,
116
- ` skills: ${result.data.template.skillNames.join(', ')}`,
117
- ` routines: ${result.data.template.routineNames.join(', ')}`,
118
- ` use: goodvibes-agent profiles create <name> --template ${result.data.template.id} --yes`,
123
+ ` name ${result.data.template.name}`,
124
+ ` persona ${result.data.template.personaName}`,
125
+ ` skills ${result.data.template.skillNames.join(', ')}`,
126
+ ` routines ${result.data.template.routineNames.join(', ')}`,
127
+ ` use goodvibes-agent profiles create <name> --template ${result.data.template.id} --yes`,
128
+ ].join('\n');
129
+ }
130
+ if (result.kind === 'agent.profiles.default') {
131
+ const selected = result.data?.selectedProfile;
132
+ if (!selected) {
133
+ return [
134
+ 'No default Agent profile selected',
135
+ ' next goodvibes-agent profiles use <name> --yes',
136
+ ].join('\n');
137
+ }
138
+ return [
139
+ `Default Agent profile: ${selected.id}${selected.exists ? '' : ' (missing)'}`,
140
+ ` home ${selected.homeDirectory}`,
141
+ selected.selectedAt ? ` selected ${selected.selectedAt}` : '',
142
+ ` next launch: ${result.data?.nextCommand ?? 'goodvibes-agent'}`,
143
+ selected.exists ? '' : ' fix create the profile again or clear it with goodvibes-agent profiles default clear --yes',
144
+ ].filter(Boolean).join('\n');
145
+ }
146
+ if (result.kind === 'agent.profiles.default.clear') {
147
+ return [
148
+ 'Default Agent profile cleared',
149
+ ' next launch uses the base Agent home unless --agent-profile is provided',
119
150
  ].join('\n');
120
151
  }
121
152
  if (result.kind === 'agent.profiles.create_from_discovered' && result.data?.profile && result.data.template) {
122
153
  return [
123
154
  `Agent profile created from discovered behavior: ${result.data.profile.id}`,
124
- ` home: ${result.data.profile.homeDirectory}`,
155
+ ` home ${result.data.profile.homeDirectory}`,
125
156
  ` starter: ${result.data.template.id}`,
126
- ` persona: ${result.data.template.personaName}`,
127
- ` skills: ${result.data.template.skillNames.join(', ')}`,
128
- ` routines: ${result.data.template.routineNames.join(', ')}`,
157
+ ` persona ${result.data.template.personaName}`,
158
+ ` skills ${result.data.template.skillNames.join(', ')}`,
159
+ ` routines ${result.data.template.routineNames.join(', ')}`,
129
160
  ` launch: ${result.data.nextCommand ?? `goodvibes-agent --agent-profile ${result.data.profile.id}`}`,
130
161
  ].join('\n');
131
162
  }
@@ -134,16 +165,19 @@ function renderProfilesResult(result: AgentRuntimeProfileCommandResult): string
134
165
  const template = result.data?.appliedTemplate;
135
166
  return [
136
167
  `Agent profile created: ${profile.id}`,
137
- ` home: ${profile.homeDirectory}`,
168
+ ` home ${profile.homeDirectory}`,
138
169
  ...(template ? [
139
170
  ` starter: ${template.id} (${template.name})`,
140
171
  ` seeded: ${template.personaIds.length} persona, ${template.skillIds.length} skills, ${template.routineIds.length} routine`,
141
172
  ] : []),
142
- ` use: ${result.data?.nextCommand ?? `goodvibes-agent --agent-profile ${profile.id}`}`,
173
+ ` use ${result.data?.nextCommand ?? `goodvibes-agent --agent-profile ${profile.id}`}`,
143
174
  ].join('\n');
144
175
  }
145
176
  if (result.kind === 'agent.profiles.delete' && profile) {
146
- return `Agent profile deleted: ${profile.id}`;
177
+ return [
178
+ `Agent profile deleted: ${profile.id}`,
179
+ ` id ${profile.id}`,
180
+ ].join('\n');
147
181
  }
148
182
  return 'Agent profile command completed.';
149
183
  }
@@ -296,6 +330,107 @@ export async function handleProfilesCommand(runtime: ProfilesCommandRuntime): Pr
296
330
  };
297
331
  }
298
332
 
333
+ if (sub === 'default') {
334
+ const target = values[0];
335
+ if (target === 'clear' || target === 'none' || target === 'base') {
336
+ if (!hasYes(rawRest)) {
337
+ const result: AgentRuntimeProfileCommandResult = {
338
+ ok: false,
339
+ kind: 'agent.profiles.error',
340
+ error: 'Refusing to clear the default Agent profile without --yes.',
341
+ };
342
+ return {
343
+ output: renderProfilesOutput(result, runtime.cli.flags.outputFormat),
344
+ exitCode: 2,
345
+ };
346
+ }
347
+ clearAgentRuntimeProfileSelection(runtime.homeDirectory);
348
+ const result: AgentRuntimeProfileCommandResult = {
349
+ ok: true,
350
+ kind: 'agent.profiles.default.clear',
351
+ };
352
+ return {
353
+ output: renderProfilesOutput(result, runtime.cli.flags.outputFormat),
354
+ exitCode: 0,
355
+ };
356
+ }
357
+ if (target) {
358
+ if (!hasYes(rawRest)) {
359
+ const result: AgentRuntimeProfileCommandResult = {
360
+ ok: false,
361
+ kind: 'agent.profiles.error',
362
+ error: `Refusing to set default Agent profile ${target} without --yes.`,
363
+ };
364
+ return {
365
+ output: renderProfilesOutput(result, runtime.cli.flags.outputFormat),
366
+ exitCode: 2,
367
+ };
368
+ }
369
+ const selected = setAgentRuntimeProfileSelection(runtime.homeDirectory, target);
370
+ const result: AgentRuntimeProfileCommandResult = {
371
+ ok: true,
372
+ kind: 'agent.profiles.default',
373
+ data: {
374
+ selectedProfile: selected,
375
+ nextCommand: 'goodvibes-agent',
376
+ },
377
+ };
378
+ return {
379
+ output: renderProfilesOutput(result, runtime.cli.flags.outputFormat),
380
+ exitCode: 0,
381
+ };
382
+ }
383
+ const selected = readAgentRuntimeProfileSelection(runtime.homeDirectory);
384
+ const result: AgentRuntimeProfileCommandResult = {
385
+ ok: true,
386
+ kind: 'agent.profiles.default',
387
+ data: selected ? { selectedProfile: selected, nextCommand: 'goodvibes-agent' } : undefined,
388
+ };
389
+ return {
390
+ output: renderProfilesOutput(result, runtime.cli.flags.outputFormat),
391
+ exitCode: 0,
392
+ };
393
+ }
394
+
395
+ if (sub === 'use' || sub === 'select' || sub === 'switch') {
396
+ const name = values[0];
397
+ if (!name) {
398
+ const result: AgentRuntimeProfileCommandResult = {
399
+ ok: false,
400
+ kind: 'agent.profiles.error',
401
+ error: 'Usage: goodvibes-agent profiles use <name> --yes',
402
+ };
403
+ return {
404
+ output: renderProfilesOutput(result, runtime.cli.flags.outputFormat),
405
+ exitCode: 2,
406
+ };
407
+ }
408
+ if (!hasYes(rawRest)) {
409
+ const result: AgentRuntimeProfileCommandResult = {
410
+ ok: false,
411
+ kind: 'agent.profiles.error',
412
+ error: `Refusing to set default Agent profile ${name} without --yes.`,
413
+ };
414
+ return {
415
+ output: renderProfilesOutput(result, runtime.cli.flags.outputFormat),
416
+ exitCode: 2,
417
+ };
418
+ }
419
+ const selected = setAgentRuntimeProfileSelection(runtime.homeDirectory, name);
420
+ const result: AgentRuntimeProfileCommandResult = {
421
+ ok: true,
422
+ kind: 'agent.profiles.default',
423
+ data: {
424
+ selectedProfile: selected,
425
+ nextCommand: 'goodvibes-agent',
426
+ },
427
+ };
428
+ return {
429
+ output: renderProfilesOutput(result, runtime.cli.flags.outputFormat),
430
+ exitCode: 0,
431
+ };
432
+ }
433
+
299
434
  if (sub === 'show' || sub === 'path' || sub === 'home') {
300
435
  const name = values[0];
301
436
  if (!name) {
@@ -317,7 +452,7 @@ export async function handleProfilesCommand(runtime: ProfilesCommandRuntime): Pr
317
452
  data: { profile: info },
318
453
  };
319
454
  const starter = info.starterTemplateId ? [` starter: ${info.starterTemplateId} (${info.starterTemplateName ?? info.starterTemplateId})`] : [];
320
- const text = [`Agent profile: ${profile.id}`, ` home: ${profile.homeDirectory}`, ...starter, ` use: goodvibes-agent --agent-profile ${profile.id}`].join('\n');
455
+ const text = [`Agent profile: ${profile.id}`, ` home ${profile.homeDirectory}`, ...starter, ` use goodvibes-agent --agent-profile ${profile.id}`].join('\n');
321
456
  return {
322
457
  output: runtime.cli.flags.outputFormat === 'json' ? JSON.stringify(result, null, 2) : text,
323
458
  exitCode: 0,
@@ -453,8 +588,8 @@ export async function handleProfilesCommand(runtime: ProfilesCommandRuntime): Pr
453
588
  : {
454
589
  ok: false,
455
590
  kind: 'agent.profiles.error',
456
- error: `Agent profile not found: ${resolution.id}`,
457
- };
591
+ error: `Agent profile not found ${resolution.id}`,
592
+ };
458
593
  return {
459
594
  output: renderProfilesOutput(result, runtime.cli.flags.outputFormat),
460
595
  exitCode: deleted ? 0 : 1,
@@ -464,7 +599,7 @@ export async function handleProfilesCommand(runtime: ProfilesCommandRuntime): Pr
464
599
  const result: AgentRuntimeProfileCommandResult = {
465
600
  ok: false,
466
601
  kind: 'agent.profiles.error',
467
- error: 'Usage: goodvibes-agent profiles [list|templates|show <name>|create <name> [--template <id>] --yes|delete <name> --yes]',
602
+ error: 'Usage: goodvibes-agent profiles [list|templates|default [<name>|clear] --yes|use <name> --yes|show <name>|create <name> [--template <id>] --yes|delete <name> --yes]',
468
603
  };
469
604
  return {
470
605
  output: renderProfilesOutput(result, runtime.cli.flags.outputFormat),
@@ -1,4 +1,5 @@
1
1
  import type { ProviderAuthRouteDescriptor } from '@pellux/goodvibes-sdk/platform/providers';
2
+ import { formatProviderAuthRouteId, formatProviderAuthRouteLabel } from '../provider-auth-route-display.ts';
2
3
 
3
4
  function routeUsable(route: ProviderAuthRouteDescriptor): boolean {
4
5
  return route.usable ?? route.configured;
@@ -18,5 +19,5 @@ export function formatProviderAuthRoute(route: ProviderAuthRouteDescriptor): str
18
19
  route.freshness,
19
20
  ].filter((part): part is string => Boolean(part));
20
21
  const detail = route.detail?.trim();
21
- return `${route.label} [${route.route}; ${status.join(', ')}]${detail ? ` - ${detail}` : ''}`;
22
+ return `${formatProviderAuthRouteLabel(route.route, route.label)} [${formatProviderAuthRouteId(route.route)}; ${status.join(', ')}]${detail ? ` - ${detail}` : ''}`;
22
23
  }