@pellux/goodvibes-agent 0.1.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 (398) hide show
  1. package/.goodvibes/GOODVIBES.md +35 -0
  2. package/.goodvibes/agents/reviewer.md +48 -0
  3. package/.goodvibes/skills/add-provider/SKILL.md +199 -0
  4. package/CHANGELOG.md +25 -0
  5. package/README.md +74 -0
  6. package/bin/goodvibes-agent.ts +2 -0
  7. package/docs/README.md +23 -0
  8. package/docs/deployment-and-services.md +57 -0
  9. package/docs/getting-started.md +53 -0
  10. package/docs/release-and-publishing.md +46 -0
  11. package/package.json +134 -0
  12. package/scripts/check-bun.sh +20 -0
  13. package/src/audio/player.ts +156 -0
  14. package/src/audio/spoken-turn-controller.ts +203 -0
  15. package/src/audio/spoken-turn-model-routing.ts +117 -0
  16. package/src/audio/spoken-turn-wiring.ts +44 -0
  17. package/src/audio/text-chunker.ts +110 -0
  18. package/src/cli/bundle-command.ts +227 -0
  19. package/src/cli/completion.ts +90 -0
  20. package/src/cli/config-overrides.ts +159 -0
  21. package/src/cli/endpoints.ts +63 -0
  22. package/src/cli/entrypoint.ts +172 -0
  23. package/src/cli/help.ts +299 -0
  24. package/src/cli/index.ts +11 -0
  25. package/src/cli/management-commands.ts +426 -0
  26. package/src/cli/management.ts +744 -0
  27. package/src/cli/network-posture.ts +46 -0
  28. package/src/cli/package-verification.ts +123 -0
  29. package/src/cli/parser.ts +369 -0
  30. package/src/cli/provider-auth-routes.ts +22 -0
  31. package/src/cli/provider-classification.ts +107 -0
  32. package/src/cli/redaction.ts +105 -0
  33. package/src/cli/service-command.ts +26 -0
  34. package/src/cli/service-posture.ts +482 -0
  35. package/src/cli/status.ts +383 -0
  36. package/src/cli/surface-command.ts +247 -0
  37. package/src/cli/tui-startup.ts +32 -0
  38. package/src/cli/types.ts +69 -0
  39. package/src/cli-flags.ts +21 -0
  40. package/src/config/goodvibes-home-audit.ts +465 -0
  41. package/src/config/index.ts +57 -0
  42. package/src/config/provider-model.ts +23 -0
  43. package/src/config/secret-config.ts +119 -0
  44. package/src/config/secrets.ts +71 -0
  45. package/src/config/surface.ts +1 -0
  46. package/src/core/composer-state.ts +61 -0
  47. package/src/core/conversation-rendering.ts +359 -0
  48. package/src/core/conversation.ts +551 -0
  49. package/src/core/history.ts +45 -0
  50. package/src/core/orchestrator.ts +7 -0
  51. package/src/core/system-message-router.ts +171 -0
  52. package/src/daemon/cli.ts +55 -0
  53. package/src/daemon/safe-serve.ts +61 -0
  54. package/src/input/agent-workspace.ts +428 -0
  55. package/src/input/autocomplete.ts +96 -0
  56. package/src/input/bookmark-modal.ts +115 -0
  57. package/src/input/command-args-hint.ts +36 -0
  58. package/src/input/command-registry.ts +329 -0
  59. package/src/input/commands/agent-externalized-tui.ts +73 -0
  60. package/src/input/commands/agent-workspace-runtime.ts +17 -0
  61. package/src/input/commands/branch-runtime.ts +72 -0
  62. package/src/input/commands/cloudflare-runtime.ts +370 -0
  63. package/src/input/commands/config.ts +18 -0
  64. package/src/input/commands/control-room-runtime.ts +255 -0
  65. package/src/input/commands/conversation-runtime.ts +207 -0
  66. package/src/input/commands/discovery-runtime.ts +52 -0
  67. package/src/input/commands/eval.ts +204 -0
  68. package/src/input/commands/experience-runtime.ts +278 -0
  69. package/src/input/commands/guidance-runtime.ts +106 -0
  70. package/src/input/commands/health-runtime.ts +434 -0
  71. package/src/input/commands/hooks-runtime.ts +148 -0
  72. package/src/input/commands/incident-runtime.ts +95 -0
  73. package/src/input/commands/integration-runtime.ts +394 -0
  74. package/src/input/commands/intelligence-runtime.ts +223 -0
  75. package/src/input/commands/knowledge.ts +531 -0
  76. package/src/input/commands/local-auth-runtime.ts +105 -0
  77. package/src/input/commands/local-provider-runtime.ts +170 -0
  78. package/src/input/commands/local-runtime.ts +392 -0
  79. package/src/input/commands/local-setup-review.ts +199 -0
  80. package/src/input/commands/local-setup-transfer.ts +135 -0
  81. package/src/input/commands/local-setup.ts +282 -0
  82. package/src/input/commands/managed-runtime.ts +209 -0
  83. package/src/input/commands/marketplace-runtime.ts +290 -0
  84. package/src/input/commands/mcp-runtime.ts +432 -0
  85. package/src/input/commands/memory-product-runtime.ts +111 -0
  86. package/src/input/commands/memory.ts +151 -0
  87. package/src/input/commands/notify-runtime.ts +83 -0
  88. package/src/input/commands/onboarding-runtime.ts +14 -0
  89. package/src/input/commands/operator-panel-runtime.ts +146 -0
  90. package/src/input/commands/operator-runtime.ts +392 -0
  91. package/src/input/commands/planning-runtime.ts +205 -0
  92. package/src/input/commands/platform-access-runtime.ts +422 -0
  93. package/src/input/commands/platform-services-runtime.ts +246 -0
  94. package/src/input/commands/policy-dispatch.ts +339 -0
  95. package/src/input/commands/policy.ts +17 -0
  96. package/src/input/commands/product-runtime.ts +351 -0
  97. package/src/input/commands/profile-sync-runtime.ts +99 -0
  98. package/src/input/commands/provider-accounts-runtime.ts +113 -0
  99. package/src/input/commands/provider.ts +363 -0
  100. package/src/input/commands/qrcode-runtime.ts +20 -0
  101. package/src/input/commands/quit-shared.ts +162 -0
  102. package/src/input/commands/recall-bundle.ts +132 -0
  103. package/src/input/commands/recall-capture.ts +152 -0
  104. package/src/input/commands/recall-query.ts +229 -0
  105. package/src/input/commands/recall-review.ts +98 -0
  106. package/src/input/commands/recall-shared.ts +22 -0
  107. package/src/input/commands/remote-runtime-pool.ts +106 -0
  108. package/src/input/commands/remote-runtime-setup.ts +199 -0
  109. package/src/input/commands/remote-runtime.ts +431 -0
  110. package/src/input/commands/replay-runtime.ts +18 -0
  111. package/src/input/commands/runtime-services.ts +291 -0
  112. package/src/input/commands/schedule-runtime.ts +91 -0
  113. package/src/input/commands/services-runtime.ts +209 -0
  114. package/src/input/commands/session-content.ts +408 -0
  115. package/src/input/commands/session-workflow.ts +464 -0
  116. package/src/input/commands/session.ts +375 -0
  117. package/src/input/commands/settings-sync-runtime.ts +174 -0
  118. package/src/input/commands/share-runtime.ts +119 -0
  119. package/src/input/commands/shell-core.ts +307 -0
  120. package/src/input/commands/skills-runtime.ts +221 -0
  121. package/src/input/commands/subscription-runtime.ts +434 -0
  122. package/src/input/commands/tasks-runtime.ts +230 -0
  123. package/src/input/commands/teamwork-runtime.ts +339 -0
  124. package/src/input/commands/teleport-runtime.ts +57 -0
  125. package/src/input/commands/tts-runtime.ts +29 -0
  126. package/src/input/commands/work-plan-runtime.ts +169 -0
  127. package/src/input/commands.ts +131 -0
  128. package/src/input/feed-context-factory.ts +254 -0
  129. package/src/input/file-picker.ts +192 -0
  130. package/src/input/handler-command-route.ts +180 -0
  131. package/src/input/handler-content-actions.ts +497 -0
  132. package/src/input/handler-feed-routes.ts +648 -0
  133. package/src/input/handler-feed.ts +452 -0
  134. package/src/input/handler-interactions.ts +281 -0
  135. package/src/input/handler-modal-routes.ts +418 -0
  136. package/src/input/handler-modal-stack.ts +263 -0
  137. package/src/input/handler-modal-token-routes.ts +329 -0
  138. package/src/input/handler-onboarding-cloudflare.ts +391 -0
  139. package/src/input/handler-onboarding.ts +620 -0
  140. package/src/input/handler-picker-routes.ts +472 -0
  141. package/src/input/handler-prompt-buffer.ts +320 -0
  142. package/src/input/handler-shortcuts.ts +213 -0
  143. package/src/input/handler-ui-state.ts +372 -0
  144. package/src/input/handler.ts +729 -0
  145. package/src/input/input-history.ts +297 -0
  146. package/src/input/keybindings.ts +292 -0
  147. package/src/input/mcp-workspace.ts +554 -0
  148. package/src/input/model-picker-provider-filter.ts +28 -0
  149. package/src/input/model-picker-types.ts +137 -0
  150. package/src/input/model-picker.ts +797 -0
  151. package/src/input/onboarding/handler-onboarding-routes.ts +125 -0
  152. package/src/input/onboarding/onboarding-runtime-status.ts +87 -0
  153. package/src/input/onboarding/onboarding-wizard-apply.ts +277 -0
  154. package/src/input/onboarding/onboarding-wizard-cloudflare-step.ts +494 -0
  155. package/src/input/onboarding/onboarding-wizard-cloudflare.ts +204 -0
  156. package/src/input/onboarding/onboarding-wizard-constants.ts +158 -0
  157. package/src/input/onboarding/onboarding-wizard-external-surface-extra-specs.ts +130 -0
  158. package/src/input/onboarding/onboarding-wizard-external-surfaces.ts +762 -0
  159. package/src/input/onboarding/onboarding-wizard-helpers.ts +167 -0
  160. package/src/input/onboarding/onboarding-wizard-rules.ts +256 -0
  161. package/src/input/onboarding/onboarding-wizard-state.ts +365 -0
  162. package/src/input/onboarding/onboarding-wizard-steps.ts +798 -0
  163. package/src/input/onboarding/onboarding-wizard-types.ts +195 -0
  164. package/src/input/onboarding/onboarding-wizard.ts +711 -0
  165. package/src/input/panel-integration-actions.ts +78 -0
  166. package/src/input/profile-picker-modal.ts +222 -0
  167. package/src/input/search.ts +100 -0
  168. package/src/input/selection-modal.ts +163 -0
  169. package/src/input/selection.ts +135 -0
  170. package/src/input/session-picker-modal.ts +136 -0
  171. package/src/input/settings-modal-behavior.ts +37 -0
  172. package/src/input/settings-modal-secrets.ts +41 -0
  173. package/src/input/settings-modal-subscriptions.ts +95 -0
  174. package/src/input/settings-modal-types.ts +91 -0
  175. package/src/input/settings-modal.ts +793 -0
  176. package/src/input/submission-intent.ts +17 -0
  177. package/src/input/submission-router.ts +59 -0
  178. package/src/input/tts-settings-actions.ts +100 -0
  179. package/src/main.ts +792 -0
  180. package/src/mcp/runtime-reload.ts +81 -0
  181. package/src/panels/agent-inspector-panel.ts +521 -0
  182. package/src/panels/agent-inspector-shared.ts +94 -0
  183. package/src/panels/agent-logs-panel.ts +559 -0
  184. package/src/panels/agent-logs-shared.ts +129 -0
  185. package/src/panels/approval-panel.ts +150 -0
  186. package/src/panels/automation-control-panel.ts +212 -0
  187. package/src/panels/base-panel.ts +254 -0
  188. package/src/panels/builtin/agent.ts +117 -0
  189. package/src/panels/builtin/development.ts +31 -0
  190. package/src/panels/builtin/knowledge.ts +26 -0
  191. package/src/panels/builtin/operations.ts +349 -0
  192. package/src/panels/builtin/session.ts +129 -0
  193. package/src/panels/builtin/shared.ts +274 -0
  194. package/src/panels/builtin-panels.ts +23 -0
  195. package/src/panels/cockpit-panel.ts +183 -0
  196. package/src/panels/communication-panel.ts +153 -0
  197. package/src/panels/confirm-state.ts +61 -0
  198. package/src/panels/context-visualizer-panel.ts +204 -0
  199. package/src/panels/control-plane-panel.ts +211 -0
  200. package/src/panels/cost-tracker-panel.ts +444 -0
  201. package/src/panels/debug-panel.ts +432 -0
  202. package/src/panels/diff-panel.ts +520 -0
  203. package/src/panels/docs-panel.ts +283 -0
  204. package/src/panels/eval-panel.ts +399 -0
  205. package/src/panels/file-explorer-panel.ts +584 -0
  206. package/src/panels/file-preview-panel.ts +434 -0
  207. package/src/panels/forensics-panel.ts +364 -0
  208. package/src/panels/git-panel.ts +638 -0
  209. package/src/panels/hooks-panel.ts +239 -0
  210. package/src/panels/incident-review-panel.ts +197 -0
  211. package/src/panels/index.ts +46 -0
  212. package/src/panels/intelligence-panel.ts +176 -0
  213. package/src/panels/knowledge-panel.ts +345 -0
  214. package/src/panels/local-auth-panel.ts +130 -0
  215. package/src/panels/marketplace-panel.ts +212 -0
  216. package/src/panels/memory-panel.ts +225 -0
  217. package/src/panels/ops-control-panel.ts +150 -0
  218. package/src/panels/ops-strategy-panel.ts +235 -0
  219. package/src/panels/orchestration-panel.ts +273 -0
  220. package/src/panels/panel-list-panel.ts +509 -0
  221. package/src/panels/panel-manager.ts +570 -0
  222. package/src/panels/panel-picker.ts +106 -0
  223. package/src/panels/plan-dashboard-panel.ts +274 -0
  224. package/src/panels/plugins-panel.ts +178 -0
  225. package/src/panels/policy-panel.ts +308 -0
  226. package/src/panels/polish.ts +717 -0
  227. package/src/panels/project-planning-panel.ts +711 -0
  228. package/src/panels/provider-account-snapshot.ts +259 -0
  229. package/src/panels/provider-accounts-panel.ts +218 -0
  230. package/src/panels/provider-health-domains.ts +215 -0
  231. package/src/panels/provider-health-panel.ts +727 -0
  232. package/src/panels/provider-health-tracker.ts +115 -0
  233. package/src/panels/provider-stats-panel.ts +366 -0
  234. package/src/panels/qr-panel.ts +182 -0
  235. package/src/panels/remote-panel.ts +449 -0
  236. package/src/panels/routes-panel.ts +178 -0
  237. package/src/panels/sandbox-panel.ts +283 -0
  238. package/src/panels/schedule-panel.ts +329 -0
  239. package/src/panels/scrollable-list-panel.ts +491 -0
  240. package/src/panels/search-focus.ts +32 -0
  241. package/src/panels/security-panel.ts +295 -0
  242. package/src/panels/services-panel.ts +231 -0
  243. package/src/panels/session-browser-panel.ts +400 -0
  244. package/src/panels/session-maintenance.ts +125 -0
  245. package/src/panels/settings-sync-panel.ts +120 -0
  246. package/src/panels/skills-panel.ts +431 -0
  247. package/src/panels/subscription-panel.ts +263 -0
  248. package/src/panels/symbol-outline-panel.ts +486 -0
  249. package/src/panels/system-messages-panel.ts +230 -0
  250. package/src/panels/tasks-panel.ts +399 -0
  251. package/src/panels/thinking-panel.ts +304 -0
  252. package/src/panels/token-budget-panel.ts +475 -0
  253. package/src/panels/tool-inspector-panel.ts +429 -0
  254. package/src/panels/types.ts +54 -0
  255. package/src/panels/watchers-panel.ts +193 -0
  256. package/src/panels/work-plan-panel.ts +175 -0
  257. package/src/panels/worktree-panel.ts +182 -0
  258. package/src/panels/wrfc-panel.ts +609 -0
  259. package/src/permissions/prompt.ts +165 -0
  260. package/src/planning/project-planning-coordinator.ts +543 -0
  261. package/src/plugins/loader.ts +15 -0
  262. package/src/renderer/agent-detail-modal.ts +331 -0
  263. package/src/renderer/agent-workspace.ts +238 -0
  264. package/src/renderer/ansi-sanitize.ts +76 -0
  265. package/src/renderer/autocomplete-overlay.ts +154 -0
  266. package/src/renderer/block-actions.ts +76 -0
  267. package/src/renderer/bookmark-modal.ts +101 -0
  268. package/src/renderer/bottom-bar.ts +58 -0
  269. package/src/renderer/buffer.ts +113 -0
  270. package/src/renderer/code-block.ts +373 -0
  271. package/src/renderer/compositor.ts +283 -0
  272. package/src/renderer/context-inspector.ts +219 -0
  273. package/src/renderer/conversation-layout.ts +67 -0
  274. package/src/renderer/conversation-overlays.ts +140 -0
  275. package/src/renderer/conversation-surface.ts +260 -0
  276. package/src/renderer/diff-view.ts +132 -0
  277. package/src/renderer/diff.ts +130 -0
  278. package/src/renderer/file-picker-overlay.ts +101 -0
  279. package/src/renderer/file-tree.ts +153 -0
  280. package/src/renderer/fullscreen-primitives.ts +130 -0
  281. package/src/renderer/fullscreen-workspace.ts +199 -0
  282. package/src/renderer/git-status.ts +89 -0
  283. package/src/renderer/help-overlay.ts +267 -0
  284. package/src/renderer/history-search-overlay.ts +73 -0
  285. package/src/renderer/layout-engine.ts +97 -0
  286. package/src/renderer/layout.ts +32 -0
  287. package/src/renderer/live-tail-modal.ts +156 -0
  288. package/src/renderer/markdown.ts +635 -0
  289. package/src/renderer/mcp-workspace.ts +237 -0
  290. package/src/renderer/modal-factory.ts +467 -0
  291. package/src/renderer/modal-utils.ts +24 -0
  292. package/src/renderer/model-picker-overlay.ts +473 -0
  293. package/src/renderer/model-workspace.ts +488 -0
  294. package/src/renderer/onboarding/onboarding-wizard.ts +615 -0
  295. package/src/renderer/overlay-box.ts +146 -0
  296. package/src/renderer/overlay-viewport.ts +104 -0
  297. package/src/renderer/panel-composite.ts +158 -0
  298. package/src/renderer/panel-picker-overlay.ts +202 -0
  299. package/src/renderer/panel-tab-bar.ts +69 -0
  300. package/src/renderer/panel-workspace-bar.ts +42 -0
  301. package/src/renderer/process-indicator.ts +96 -0
  302. package/src/renderer/process-modal.ts +656 -0
  303. package/src/renderer/process-summary.ts +67 -0
  304. package/src/renderer/profile-picker-modal.ts +129 -0
  305. package/src/renderer/progress.ts +98 -0
  306. package/src/renderer/qr-renderer.ts +120 -0
  307. package/src/renderer/search-overlay.ts +54 -0
  308. package/src/renderer/selection-modal-overlay.ts +214 -0
  309. package/src/renderer/semantic-diff.ts +369 -0
  310. package/src/renderer/session-picker-modal.ts +127 -0
  311. package/src/renderer/settings-modal-helpers.ts +193 -0
  312. package/src/renderer/settings-modal.ts +537 -0
  313. package/src/renderer/shell-surface.ts +88 -0
  314. package/src/renderer/status-glyphs.ts +21 -0
  315. package/src/renderer/status-token.ts +67 -0
  316. package/src/renderer/surface-layout.ts +101 -0
  317. package/src/renderer/syntax-highlighter.ts +542 -0
  318. package/src/renderer/system-message.ts +83 -0
  319. package/src/renderer/tab-strip.ts +108 -0
  320. package/src/renderer/text-layout.ts +31 -0
  321. package/src/renderer/thinking.ts +17 -0
  322. package/src/renderer/tool-call.ts +234 -0
  323. package/src/renderer/ui-factory.ts +524 -0
  324. package/src/renderer/ui-primitives.ts +96 -0
  325. package/src/runtime/bootstrap-command-context.ts +278 -0
  326. package/src/runtime/bootstrap-command-parts.ts +386 -0
  327. package/src/runtime/bootstrap-core.ts +540 -0
  328. package/src/runtime/bootstrap-hook-bridge.ts +112 -0
  329. package/src/runtime/bootstrap-shell.ts +283 -0
  330. package/src/runtime/bootstrap.ts +575 -0
  331. package/src/runtime/cloudflare-control-plane.ts +349 -0
  332. package/src/runtime/context.ts +142 -0
  333. package/src/runtime/diagnostics/panels/index.ts +24 -0
  334. package/src/runtime/diagnostics/panels/ops.ts +156 -0
  335. package/src/runtime/diagnostics/panels/panel-resources.ts +118 -0
  336. package/src/runtime/diagnostics/panels/policy.ts +177 -0
  337. package/src/runtime/index.ts +662 -0
  338. package/src/runtime/onboarding/apply.ts +642 -0
  339. package/src/runtime/onboarding/derivation.ts +534 -0
  340. package/src/runtime/onboarding/index.ts +7 -0
  341. package/src/runtime/onboarding/markers.ts +148 -0
  342. package/src/runtime/onboarding/snapshot.ts +406 -0
  343. package/src/runtime/onboarding/state.ts +141 -0
  344. package/src/runtime/onboarding/types.ts +404 -0
  345. package/src/runtime/onboarding/verify.ts +171 -0
  346. package/src/runtime/operator-token-cleanup.ts +27 -0
  347. package/src/runtime/perf/panel-contracts.ts +32 -0
  348. package/src/runtime/perf/panel-health-monitor.ts +18 -0
  349. package/src/runtime/sandbox-public-gaps.ts +358 -0
  350. package/src/runtime/services.ts +670 -0
  351. package/src/runtime/store/domains/domain-read-matrix.ts +15 -0
  352. package/src/runtime/store/domains/index.ts +222 -0
  353. package/src/runtime/store/domains/panels.ts +117 -0
  354. package/src/runtime/store/domains/ui-perf.ts +103 -0
  355. package/src/runtime/store/index.ts +305 -0
  356. package/src/runtime/store/selectors/index.ts +359 -0
  357. package/src/runtime/store/state.ts +145 -0
  358. package/src/runtime/surface-feature-flags.ts +65 -0
  359. package/src/runtime/terminal-output-guard.ts +228 -0
  360. package/src/runtime/ui/index.ts +39 -0
  361. package/src/runtime/ui/model-picker/data-provider.ts +182 -0
  362. package/src/runtime/ui/model-picker/health-enrichment.ts +228 -0
  363. package/src/runtime/ui/model-picker/index.ts +59 -0
  364. package/src/runtime/ui/model-picker/types.ts +149 -0
  365. package/src/runtime/ui/provider-health/data-provider.ts +244 -0
  366. package/src/runtime/ui/provider-health/fallback-visualizer.ts +71 -0
  367. package/src/runtime/ui/provider-health/index.ts +46 -0
  368. package/src/runtime/ui/provider-health/types.ts +146 -0
  369. package/src/runtime/ui-events.ts +1 -0
  370. package/src/runtime/ui-read-model-helpers.ts +1 -0
  371. package/src/runtime/ui-read-models-observability-maintenance.ts +1 -0
  372. package/src/runtime/ui-read-models-observability-options.ts +1 -0
  373. package/src/runtime/ui-read-models-observability-remote.ts +1 -0
  374. package/src/runtime/ui-read-models-observability-security.ts +1 -0
  375. package/src/runtime/ui-read-models-observability-system.ts +1 -0
  376. package/src/runtime/ui-read-models-observability.ts +1 -0
  377. package/src/runtime/ui-read-models.ts +61 -0
  378. package/src/runtime/ui-service-queries.ts +1 -0
  379. package/src/runtime/ui-services.ts +190 -0
  380. package/src/scripts/process-messages.ts +42 -0
  381. package/src/shell/blocking-input.ts +98 -0
  382. package/src/shell/service-settings-sync.ts +273 -0
  383. package/src/shell/ui-openers.ts +352 -0
  384. package/src/tools/index.ts +1 -0
  385. package/src/tools/wrfc-agent-guard.ts +49 -0
  386. package/src/types/grid.ts +48 -0
  387. package/src/types/sql-js.d.ts +15 -0
  388. package/src/utils/clipboard.ts +22 -0
  389. package/src/utils/splash-lines.ts +46 -0
  390. package/src/utils/terminal-width.ts +185 -0
  391. package/src/verification/live-verifier.ts +430 -0
  392. package/src/verification/verification-ledger.ts +242 -0
  393. package/src/version.ts +17 -0
  394. package/src/widget/index.ts +2 -0
  395. package/src/widget/types.ts +9 -0
  396. package/src/widget/widget.ts +8 -0
  397. package/src/work-plans/work-plan-store.ts +374 -0
  398. package/tsconfig.json +18 -0
@@ -0,0 +1,291 @@
1
+ import type {
2
+ CommandContext,
3
+ CommandExtensionServices,
4
+ CommandOpsServices,
5
+ CommandPlatformServices,
6
+ CommandProviderServices,
7
+ CommandSessionServices,
8
+ CommandWorkspaceServices,
9
+ } from '../command-registry.ts';
10
+ import type { UiReadModels } from '../../runtime/ui-read-models.ts';
11
+ import type { ShellPathService } from '@/runtime/index.ts';
12
+ import type { EcosystemCatalogPathOptions } from '@/runtime/index.ts';
13
+ import type { PluginPathOptions } from '../../plugins/loader';
14
+ import type { DirectTransport } from '@/runtime/index.ts';
15
+ import type { KnowledgeApi } from '@pellux/goodvibes-sdk/platform/knowledge';
16
+ import type { HookApi } from '@pellux/goodvibes-sdk/platform/hooks';
17
+ import type { McpApi } from '@pellux/goodvibes-sdk/platform/mcp';
18
+ import type { OperatorClient } from '@/runtime/index.ts';
19
+ import type { OpsApi } from '@/runtime/index.ts';
20
+ import type { PeerClient } from '@/runtime/index.ts';
21
+ import { GOODVIBES_AGENT_SURFACE_ROOT } from '../../config/surface.ts';
22
+ import type { ProviderApi } from '@pellux/goodvibes-sdk/platform/providers';
23
+ import type {
24
+ ShellAgentManagerService,
25
+ ShellAcpManagerService,
26
+ ShellAutomationManagerService,
27
+ ShellAutomationManagerRuntimeService,
28
+ ShellModeManagerService,
29
+ ShellPlanManagerService,
30
+ ShellSessionOrchestrationService,
31
+ } from '@/runtime/index.ts';
32
+
33
+ function requireContextValue<T>(value: T | null | undefined, name: string): T {
34
+ if (value == null) {
35
+ throw new Error(`commandContext.${name} is required but was not wired at bootstrap`);
36
+ }
37
+ return value;
38
+ }
39
+
40
+ export function requireSession(context: CommandContext): CommandSessionServices {
41
+ return context.session;
42
+ }
43
+
44
+ export function requireProvider(context: CommandContext): CommandProviderServices {
45
+ return context.provider;
46
+ }
47
+
48
+ export function requireWorkspace(context: CommandContext): CommandWorkspaceServices {
49
+ return context.workspace;
50
+ }
51
+
52
+ export function requirePlatform(context: CommandContext): CommandPlatformServices {
53
+ return context.platform;
54
+ }
55
+
56
+ export function requireOps(context: CommandContext): CommandOpsServices {
57
+ return context.ops;
58
+ }
59
+
60
+ export function requireExtensions(context: CommandContext): CommandExtensionServices {
61
+ return context.extensions;
62
+ }
63
+
64
+ export function requireReadModels(context: CommandContext): UiReadModels {
65
+ return requireContextValue(context.platform.readModels, 'platform.readModels');
66
+ }
67
+
68
+ export function requireShellPaths(context: Pick<CommandContext, 'workspace'>): ShellPathService {
69
+ return requireContextValue(context.workspace.shellPaths, 'workspace.shellPaths');
70
+ }
71
+
72
+ export function requireEcosystemCatalogPaths(
73
+ context: CommandContext,
74
+ ): EcosystemCatalogPathOptions {
75
+ const shellPaths = requireShellPaths(context);
76
+ return {
77
+ cwd: shellPaths.workingDirectory,
78
+ homeDir: shellPaths.homeDirectory,
79
+ projectCatalogRoot: shellPaths.resolveProjectPath(GOODVIBES_AGENT_SURFACE_ROOT, 'ecosystem'),
80
+ userCatalogRoot: shellPaths.resolveUserPath(GOODVIBES_AGENT_SURFACE_ROOT, 'ecosystem'),
81
+ };
82
+ }
83
+
84
+ export function requirePluginPathOptions(
85
+ context: CommandContext,
86
+ ): PluginPathOptions {
87
+ const shellPaths = requireShellPaths(context);
88
+ return {
89
+ cwd: shellPaths.workingDirectory,
90
+ homeDir: shellPaths.homeDirectory,
91
+ };
92
+ }
93
+
94
+ export function openCommandPanel(
95
+ context: Pick<CommandContext, 'showPanel'>,
96
+ panelId: string,
97
+ pane?: 'top' | 'bottom',
98
+ ): void {
99
+ const showPanel = requireContextValue(context.showPanel, 'showPanel');
100
+ showPanel(panelId, pane);
101
+ }
102
+
103
+ export function openOnboardingWizard(
104
+ context: Pick<CommandContext, 'openOnboardingWizard'>,
105
+ modeOrOptions?: import('../onboarding/onboarding-wizard.ts').OnboardingWizardMode
106
+ | import('../handler-ui-state.ts').OpenOnboardingWizardOptions,
107
+ ): void {
108
+ const openWizard = requireContextValue(context.openOnboardingWizard, 'openOnboardingWizard');
109
+ openWizard(modeOrOptions);
110
+ }
111
+
112
+ export function requireKeybindingsManager(context: CommandContext) {
113
+ return requireContextValue(context.workspace.keybindingsManager, 'workspace.keybindingsManager');
114
+ }
115
+
116
+ export function requireProfileManager(context: CommandContext) {
117
+ return requireContextValue(context.workspace.profileManager, 'workspace.profileManager');
118
+ }
119
+
120
+ export function requirePanelManager(context: CommandContext) {
121
+ return requireContextValue(context.workspace.panelManager, 'workspace.panelManager');
122
+ }
123
+
124
+ export function requireBookmarkManager(context: CommandContext) {
125
+ return requireContextValue(context.workspace.bookmarkManager, 'workspace.bookmarkManager');
126
+ }
127
+
128
+ export function requireSessionManager(context: CommandContext) {
129
+ return requireContextValue(context.session.sessionManager, 'session.sessionManager');
130
+ }
131
+
132
+ export function requireSecretsManager(context: CommandContext) {
133
+ return requireContextValue(context.platform.secretsManager, 'platform.secretsManager');
134
+ }
135
+
136
+ export function requireSubscriptionManager(context: CommandContext) {
137
+ return requireContextValue(context.platform.subscriptionManager, 'platform.subscriptionManager');
138
+ }
139
+
140
+ export function requireServiceRegistry(context: CommandContext) {
141
+ return requireContextValue(context.platform.serviceRegistry, 'platform.serviceRegistry');
142
+ }
143
+
144
+ export function requireLocalUserAuthManager(context: CommandContext) {
145
+ return requireContextValue(context.platform.localUserAuthManager, 'platform.localUserAuthManager');
146
+ }
147
+
148
+ export function requireTokenAuditor(context: CommandContext) {
149
+ return requireContextValue(context.platform.tokenAuditor, 'platform.tokenAuditor');
150
+ }
151
+
152
+ export function requireReplayEngine(context: CommandContext) {
153
+ return requireContextValue(context.platform.replayEngine, 'platform.replayEngine');
154
+ }
155
+
156
+ export function requireWebhookNotifier(context: CommandContext) {
157
+ return requireContextValue(context.platform.webhookNotifier, 'platform.webhookNotifier');
158
+ }
159
+
160
+ export function requireSessionMemoryStore(context: CommandContext) {
161
+ return requireContextValue(context.session.sessionMemoryStore, 'session.sessionMemoryStore');
162
+ }
163
+
164
+ export function requireSessionLineageTracker(context: CommandContext) {
165
+ return requireContextValue(context.session.sessionLineageTracker, 'session.sessionLineageTracker');
166
+ }
167
+
168
+ export function requireSessionChangeTracker(context: CommandContext) {
169
+ return requireContextValue(context.session.changeTracker, 'session.changeTracker');
170
+ }
171
+
172
+ export function requirePlanManager(context: CommandContext): ShellPlanManagerService {
173
+ return requireContextValue(context.ops.planManager, 'ops.planManager') as ShellPlanManagerService;
174
+ }
175
+
176
+ export function requireAdaptivePlanner(context: CommandContext): unknown {
177
+ return requireContextValue(context.ops.adaptivePlanner, 'ops.adaptivePlanner');
178
+ }
179
+
180
+ export function requireSessionOrchestration(context: CommandContext): ShellSessionOrchestrationService {
181
+ return requireContextValue(context.ops.sessionOrchestration, 'ops.sessionOrchestration') as ShellSessionOrchestrationService;
182
+ }
183
+
184
+ export function requireForensicsRegistry(context: CommandContext) {
185
+ return requireContextValue(context.extensions.forensicsRegistry, 'extensions.forensicsRegistry');
186
+ }
187
+
188
+ export function requirePluginManager(context: CommandContext) {
189
+ return requireContextValue(context.extensions.pluginManager, 'extensions.pluginManager');
190
+ }
191
+
192
+ export function requirePolicyRuntimeState(context: CommandContext) {
193
+ return requireContextValue(context.extensions.policyRuntimeState, 'extensions.policyRuntimeState');
194
+ }
195
+
196
+ export function requireMcpRegistry(context: CommandContext) {
197
+ return requireContextValue(context.extensions.mcpRegistry, 'extensions.mcpRegistry');
198
+ }
199
+
200
+ export function requireToolRegistry(context: CommandContext) {
201
+ return requireContextValue(context.extensions.toolRegistry, 'extensions.toolRegistry');
202
+ }
203
+
204
+ export function requireHookWorkbench(context: CommandContext) {
205
+ return requireContextValue(context.extensions.hookWorkbench, 'extensions.hookWorkbench');
206
+ }
207
+
208
+ export function requireIntegrationHelpers(context: CommandContext) {
209
+ return requireContextValue(context.extensions.integrationHelpers, 'extensions.integrationHelpers');
210
+ }
211
+
212
+ export function requireProviderOptimizer(context: CommandContext) {
213
+ return requireContextValue(context.provider.providerOptimizer, 'provider.providerOptimizer');
214
+ }
215
+
216
+ export function requireFavoritesStore(context: CommandContext) {
217
+ return requireContextValue(context.provider.favoritesStore, 'provider.favoritesStore');
218
+ }
219
+
220
+ export function requireBenchmarkStore(context: CommandContext) {
221
+ return requireContextValue(context.provider.benchmarkStore, 'provider.benchmarkStore');
222
+ }
223
+
224
+ export function requireRemoteRuntime(context: CommandContext) {
225
+ return requireContextValue(context.ops.remoteRuntime, 'ops.remoteRuntime');
226
+ }
227
+
228
+ export function requireOperatorClient(context: CommandContext): OperatorClient {
229
+ return requireContextValue(context.clients?.operator, 'clients.operator');
230
+ }
231
+
232
+ export function requirePeerClient(context: CommandContext): PeerClient {
233
+ return requireContextValue(context.clients?.peer, 'clients.peer');
234
+ }
235
+
236
+ export function requireProviderApi(context: CommandContext): ProviderApi {
237
+ return requireContextValue(context.clients?.providerApi, 'clients.providerApi');
238
+ }
239
+
240
+ export async function compactConversation(context: CommandContext): Promise<void> {
241
+ await context.session.conversationManager.compact(
242
+ context.provider.providerRegistry,
243
+ context.session.runtime.model,
244
+ 'manual',
245
+ context.session.runtime.provider,
246
+ );
247
+ }
248
+
249
+ export function requireKnowledgeApi(context: CommandContext): KnowledgeApi {
250
+ return requireContextValue(context.clients?.knowledgeApi, 'clients.knowledgeApi');
251
+ }
252
+
253
+ export function requireHookApi(context: CommandContext): HookApi {
254
+ return requireContextValue(context.clients?.hookApi, 'clients.hookApi');
255
+ }
256
+
257
+ export function requireMcpApi(context: CommandContext): McpApi {
258
+ return requireContextValue(context.clients?.mcpApi, 'clients.mcpApi');
259
+ }
260
+
261
+ export function requireOpsApi(context: CommandContext): OpsApi {
262
+ return requireContextValue(context.clients?.opsApi, 'clients.opsApi');
263
+ }
264
+
265
+ export function requireDirectTransport(context: CommandContext): DirectTransport {
266
+ return requireContextValue(context.clients?.transport, 'clients.transport');
267
+ }
268
+
269
+ export function requireAgentManager(context: CommandContext): ShellAgentManagerService {
270
+ return requireContextValue(context.ops.agentManager, 'ops.agentManager') as ShellAgentManagerService;
271
+ }
272
+
273
+ export function requireAcpManager(context: CommandContext): ShellAcpManagerService {
274
+ return requireContextValue(context.ops.acpManager, 'ops.acpManager') as ShellAcpManagerService;
275
+ }
276
+
277
+ export function requireModeManager(context: CommandContext): ShellModeManagerService {
278
+ return requireContextValue(context.ops.modeManager, 'ops.modeManager') as ShellModeManagerService;
279
+ }
280
+
281
+ export function requireAutomationManager(context: CommandContext): ShellAutomationManagerRuntimeService {
282
+ return requireContextValue(context.ops.automationManager, 'ops.automationManager') as ShellAutomationManagerRuntimeService;
283
+ }
284
+
285
+ export function requireSandboxSessionRegistry(context: CommandContext) {
286
+ return requireContextValue(context.workspace.sandboxSessionRegistry, 'workspace.sandboxSessionRegistry');
287
+ }
288
+
289
+ export function requireWorktreeRegistry(context: CommandContext) {
290
+ return requireContextValue(context.workspace.worktreeRegistry, 'workspace.worktreeRegistry');
291
+ }
@@ -0,0 +1,91 @@
1
+ import type { CommandRegistry } from '../command-registry.ts';
2
+ import {
3
+ formatEveryInterval,
4
+ } from '@pellux/goodvibes-sdk/platform/automation';
5
+ import type { AutomationJob } from '@pellux/goodvibes-sdk/platform/automation';
6
+ import type { AutomationScheduleDefinition } from '@pellux/goodvibes-sdk/platform/automation';
7
+
8
+ function formatSchedule(schedule: AutomationScheduleDefinition): string {
9
+ switch (schedule.kind) {
10
+ case 'cron':
11
+ return [
12
+ schedule.expression,
13
+ schedule.timezone ? `[${schedule.timezone}]` : '',
14
+ schedule.staggerMs !== undefined ? `[stagger ${schedule.staggerMs}ms]` : '',
15
+ ].filter(Boolean).join(' ');
16
+ case 'every':
17
+ return formatEveryInterval(schedule.intervalMs);
18
+ case 'at':
19
+ return new Date(schedule.at).toLocaleString();
20
+ }
21
+ }
22
+
23
+ function formatNextRun(nextRunAt?: number): string {
24
+ return nextRunAt ? new Date(nextRunAt).toLocaleString() : 'n/a';
25
+ }
26
+
27
+ function formatPrompt(job: AutomationJob): string {
28
+ const prompt = (job.execution.prompt ?? job.description ?? '').trim();
29
+ return prompt.length > 60 ? `${prompt.slice(0, 60)}...` : prompt;
30
+ }
31
+
32
+ function printReadOnlyScheduleBoundary(print: (text: string) => void, requestedAction: string): void {
33
+ print([
34
+ 'GoodVibes Agent schedule commands are read-only in this runtime.',
35
+ ` requested: ${requestedAction}`,
36
+ ' policy: no local Agent automation jobs, scheduled spawns, or immediate automation runs',
37
+ ' use: /schedule list',
38
+ ' future: mutate schedules through an Agent-safe public daemon route after explicit approval',
39
+ ].join('\n'));
40
+ }
41
+
42
+ export function registerScheduleRuntimeCommands(registry: CommandRegistry): void {
43
+ registry.register({
44
+ name: 'schedule',
45
+ aliases: ['sched'],
46
+ description: 'Inspect automation jobs and scheduled runs',
47
+ usage: 'list',
48
+ argsHint: 'list',
49
+ async handler(args, ctx) {
50
+ const manager = ctx.ops.automationManager;
51
+ if (!manager) {
52
+ ctx.print('Automation manager is not available in this runtime.');
53
+ return;
54
+ }
55
+ const sub = args[0];
56
+
57
+ if (!sub || sub === 'list') {
58
+ const jobs = manager.listJobs();
59
+ if (jobs.length === 0) {
60
+ ctx.print(
61
+ 'No automation jobs.\n'
62
+ + 'Agent schedule commands are read-only here; create/run/enable/disable/remove are blocked until an Agent-safe route exists.'
63
+ );
64
+ return;
65
+ }
66
+ const lines = ['Automation jobs:', ''];
67
+ for (const job of jobs) {
68
+ const status = job.enabled ? '● enabled ' : '○ paused ';
69
+ const next = formatNextRun(job.nextRunAt);
70
+ const last = job.lastRunAt ? new Date(job.lastRunAt).toLocaleString() : 'never';
71
+ lines.push(` ${job.id.slice(0, 12)} ${status} runs:${job.runCount} next:${next} last:${last}`);
72
+ lines.push(` name: ${job.name} schedule: ${formatSchedule(job.schedule)}`);
73
+ lines.push(` prompt: ${formatPrompt(job)}`);
74
+ }
75
+ ctx.print(lines.join('\n'));
76
+ return;
77
+ }
78
+
79
+ if (sub === 'add' || sub === 'remove' || sub === 'enable' || sub === 'disable' || sub === 'run') {
80
+ printReadOnlyScheduleBoundary(ctx.print, `/schedule ${args.join(' ')}`.trim());
81
+ return;
82
+ }
83
+
84
+ ctx.print(
85
+ 'Usage:\n'
86
+ + ' /schedule list\n'
87
+ + ' Agent schedule mutations and runs are blocked until an Agent-safe route exists.'
88
+ );
89
+ },
90
+ });
91
+ }
@@ -0,0 +1,209 @@
1
+ import { mkdirSync, readFileSync, writeFileSync } from 'node:fs';
2
+ import { dirname, join, resolve } from 'node:path';
3
+ import type { CommandRegistry } from '../command-registry.ts';
4
+ import type { SelectionAction, SelectionItem } from '../selection-modal.ts';
5
+ import { openCommandPanel, requireServiceRegistry, requireShellPaths } from './runtime-services.ts';
6
+ import { summarizeError } from '@pellux/goodvibes-sdk/platform/utils';
7
+ import { GOODVIBES_AGENT_SURFACE_ROOT } from '../../config/surface.ts';
8
+
9
+ export function registerServicesRuntimeCommands(registry: CommandRegistry): void {
10
+ registry.register({
11
+ name: 'services',
12
+ aliases: ['svc'],
13
+ description: 'Manage API service configurations',
14
+ usage: '[open|list|inspect <name>|test <name>|resolve <name>|auth <name>|auth-review|doctor|export <path>|import <path>]',
15
+ async handler(args, ctx) {
16
+ const sub = args[0] ?? 'open';
17
+ const shellPaths = requireShellPaths(ctx);
18
+ if (sub === 'open' || sub === 'panel') {
19
+ openCommandPanel(ctx, 'services');
20
+ return;
21
+ }
22
+ const svcRegistry = requireServiceRegistry(ctx);
23
+ const all = svcRegistry.getAll();
24
+ const keys = Object.keys(all);
25
+ if (sub === 'inspect') {
26
+ const name = args[1];
27
+ if (!name) {
28
+ ctx.print('Usage: /services inspect <name>');
29
+ return;
30
+ }
31
+ const inspection = await svcRegistry.inspect(name);
32
+ if (!inspection) {
33
+ ctx.print(`Unknown service: ${name}`);
34
+ return;
35
+ }
36
+ ctx.print([
37
+ `Service ${name}`,
38
+ ` authType: ${inspection.config.authType}`,
39
+ ` baseUrl: ${inspection.config.baseUrl ?? '(none)'}`,
40
+ ` primaryCredential: ${inspection.hasPrimaryCredential ? 'present' : 'missing'}`,
41
+ ` passwordCredential: ${inspection.hasPasswordCredential ? 'present' : 'missing'}`,
42
+ ` webhookUrl: ${inspection.hasWebhookUrl ? 'present' : 'missing'}`,
43
+ ` signingSecret: ${inspection.hasSigningSecret ? 'present' : 'missing'}`,
44
+ ` publicKey: ${inspection.hasPublicKey ? 'present' : 'missing'}`,
45
+ ` appToken: ${inspection.hasAppToken ? 'present' : 'missing'}`,
46
+ ].join('\n'));
47
+ return;
48
+ }
49
+ if (sub === 'test') {
50
+ const name = args[1];
51
+ if (!name) {
52
+ ctx.print('Usage: /services test <name>');
53
+ return;
54
+ }
55
+ const result = await svcRegistry.testConnection(name);
56
+ ctx.print([
57
+ `Service test ${name}`,
58
+ ` ok: ${result.ok ? 'yes' : 'no'}`,
59
+ ` status: ${result.status ?? 'n/a'}`,
60
+ ` url: ${result.testedUrl ?? 'n/a'}`,
61
+ ` error: ${result.error ?? 'none'}`,
62
+ ].join('\n'));
63
+ return;
64
+ }
65
+ if (sub === 'resolve') {
66
+ const name = args[1];
67
+ if (!name) {
68
+ ctx.print('Usage: /services resolve <name>');
69
+ return;
70
+ }
71
+ const headers = await svcRegistry.resolveAuth(name);
72
+ if (!headers) {
73
+ ctx.print(`Service ${name} has no resolvable auth headers right now.`);
74
+ return;
75
+ }
76
+ ctx.print([
77
+ `Resolved auth headers for ${name}`,
78
+ ...Object.keys(headers).map((key) => ` ${key}: <redacted>`),
79
+ ].join('\n'));
80
+ return;
81
+ }
82
+ if (sub === 'auth') {
83
+ const name = args[1];
84
+ if (!name) {
85
+ ctx.print('Usage: /services auth <name>');
86
+ return;
87
+ }
88
+ const headers = await svcRegistry.resolveAuth(name);
89
+ if (!headers) {
90
+ ctx.print(`Service ${name} has no resolvable auth headers right now.`);
91
+ return;
92
+ }
93
+ ctx.print([
94
+ `Service auth ${name}`,
95
+ ...Object.keys(headers).map((key) => ` ${key}: <resolved>`),
96
+ ].join('\n'));
97
+ return;
98
+ }
99
+ if (sub === 'doctor') {
100
+ const inspections = await Promise.all(keys.map((name) => svcRegistry.inspect(name)));
101
+ const issues = inspections
102
+ .filter((inspection): inspection is NonNullable<typeof inspection> => inspection !== null)
103
+ .flatMap((inspection) => {
104
+ const findings: string[] = [];
105
+ if (!inspection.hasPrimaryCredential) findings.push(`${inspection.config.name}: missing primary credential`);
106
+ if (inspection.config.authType === 'basic' && !inspection.hasPasswordCredential) findings.push(`${inspection.config.name}: missing password credential`);
107
+ if (!inspection.config.baseUrl) findings.push(`${inspection.config.name}: no baseUrl configured`);
108
+ return findings;
109
+ });
110
+ ctx.print([
111
+ 'Service Doctor',
112
+ ` configured: ${keys.length}`,
113
+ ` issues: ${issues.length}`,
114
+ ...(issues.length > 0 ? issues.map((issue) => ` ${issue}`) : [' all configured services passed readiness checks']),
115
+ ].join('\n'));
116
+ return;
117
+ }
118
+ if (sub === 'auth-review') {
119
+ const inspections = await Promise.all(keys.map((name) => svcRegistry.inspect(name)));
120
+ const authCounts = new Map<string, number>();
121
+ const issues = inspections
122
+ .filter((inspection): inspection is NonNullable<typeof inspection> => inspection !== null)
123
+ .flatMap((inspection) => {
124
+ authCounts.set(inspection.config.authType, (authCounts.get(inspection.config.authType) ?? 0) + 1);
125
+ const findings: string[] = [];
126
+ if (!inspection.config.baseUrl) findings.push(`${inspection.config.name}: missing baseUrl`);
127
+ if ((inspection.config.authType === 'bearer' || inspection.config.authType === 'api-key') && !inspection.hasPrimaryCredential) {
128
+ findings.push(`${inspection.config.name}: missing primary credential`);
129
+ }
130
+ if (inspection.config.authType === 'basic' && !inspection.hasPasswordCredential) {
131
+ findings.push(`${inspection.config.name}: missing password credential`);
132
+ }
133
+ return findings;
134
+ });
135
+ ctx.print([
136
+ 'Service Auth Review',
137
+ ` configured: ${keys.length}`,
138
+ ...[...authCounts.entries()].map(([authType, count]) => ` ${authType}: ${count}`),
139
+ ...(issues.length > 0 ? ['', ...issues.map((issue) => ` issue: ${issue}`)] : ['', ' all configured services have a complete auth posture']),
140
+ ].join('\n'));
141
+ return;
142
+ }
143
+ if (sub === 'export') {
144
+ const pathArg = args[1];
145
+ if (!pathArg) {
146
+ ctx.print('Usage: /services export <path>');
147
+ return;
148
+ }
149
+ const targetPath = shellPaths.resolveWorkspacePath(pathArg);
150
+ mkdirSync(dirname(targetPath), { recursive: true });
151
+ writeFileSync(targetPath, JSON.stringify(all, null, 2) + '\n', 'utf-8');
152
+ ctx.print(`Exported services config to ${targetPath}`);
153
+ return;
154
+ }
155
+ if (sub === 'import') {
156
+ const pathArg = args[1];
157
+ if (!pathArg) {
158
+ ctx.print('Usage: /services import <path>');
159
+ return;
160
+ }
161
+ const sourcePath = shellPaths.resolveWorkspacePath(pathArg);
162
+ try {
163
+ const parsed = JSON.parse(readFileSync(sourcePath, 'utf-8')) as Record<string, unknown>;
164
+ const targetPath = shellPaths.resolveProjectPath(GOODVIBES_AGENT_SURFACE_ROOT, 'services.json');
165
+ mkdirSync(dirname(targetPath), { recursive: true });
166
+ writeFileSync(targetPath, JSON.stringify(parsed, null, 2) + '\n', 'utf-8');
167
+ ctx.print(`Imported services config from ${sourcePath}`);
168
+ } catch (error) {
169
+ ctx.print(`Failed to import services config: ${summarizeError(error)}`);
170
+ }
171
+ return;
172
+ }
173
+ if (ctx.openSelection) {
174
+ const testAction = new Map<string, SelectionAction>([['t', 'select' as const]]);
175
+ const items: SelectionItem[] = keys.length === 0
176
+ ? [{ id: '_empty', label: 'No services configured', detail: '.goodvibes/agent/services.json' }]
177
+ : keys.map((key) => ({ id: key, label: all[key].name ?? key, detail: `${all[key].authType} ${all[key].baseUrl ?? '(no url)'}`, actions: '[t] test' }));
178
+ ctx.openSelection('Services', items, { allowSearch: true, customActions: testAction }, (result) => {
179
+ if (!result || result.item.id === '_empty') return;
180
+ const svc = all[result.item.id];
181
+ if (!svc) return;
182
+ if (result.action === 'select') {
183
+ void svcRegistry.testConnection(result.item.id).then((testResult) => {
184
+ ctx.print([
185
+ `Service test ${result.item.id}`,
186
+ ` ok: ${testResult.ok ? 'yes' : 'no'}`,
187
+ ` status: ${testResult.status ?? 'n/a'}`,
188
+ ` url: ${testResult.testedUrl ?? 'n/a'}`,
189
+ ` error: ${testResult.error ?? 'none'}`,
190
+ ].join('\n'));
191
+ });
192
+ return;
193
+ }
194
+ ctx.print([
195
+ `Service ${result.item.id}`,
196
+ ` authType: ${svc.authType}`,
197
+ ` baseUrl: ${svc.baseUrl ?? '(none)'}`,
198
+ ].join('\n'));
199
+ });
200
+ return;
201
+ }
202
+ if (keys.length === 0) {
203
+ ctx.print('[services] No services configured. Add entries to .goodvibes/agent/services.json');
204
+ return;
205
+ }
206
+ ctx.print(['Services:', '', ...keys.map((key) => ` ${key.padEnd(20)} ${all[key].authType.padEnd(10)} ${all[key].baseUrl ?? '(no url)'}`)].join('\n'));
207
+ },
208
+ });
209
+ }