@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,199 @@
1
+ import { dirname, join, resolve } from 'node:path';
2
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
3
+ import type { CommandContext } from '../command-registry.ts';
4
+ import { discoverSkills } from '../../panels/skills-panel.ts';
5
+ import { buildSandboxReview, isRunningInWsl } from '@/runtime/index.ts';
6
+ import { getPluginDirectories } from '../../plugins/loader';
7
+ import { listBuiltinSubscriptionProviders } from '@pellux/goodvibes-sdk/platform/config';
8
+ import type { SetupReviewSnapshot } from './local-setup-transfer.ts';
9
+ import { requireProviderApi, requireReadModels, requireServiceRegistry, requireShellPaths, requireSubscriptionManager } from './runtime-services.ts';
10
+ import { GOODVIBES_AGENT_SURFACE_ROOT } from '../../config/surface.ts';
11
+
12
+ export async function buildSetupReviewSnapshot(ctx: CommandContext): Promise<SetupReviewSnapshot> {
13
+ const shellPaths = requireShellPaths(ctx);
14
+ const serviceRegistry = requireServiceRegistry(ctx);
15
+ const services = Object.keys(serviceRegistry.getAll()).sort((a, b) => a.localeCompare(b));
16
+ const serviceConfigs = serviceRegistry.getAll();
17
+ const serviceIssues: string[] = [];
18
+ for (const name of services) {
19
+ const inspection = await serviceRegistry.inspect(name);
20
+ if (!inspection?.hasPrimaryCredential) {
21
+ serviceIssues.push(`${name}: missing primary credential`);
22
+ }
23
+ }
24
+
25
+ const skills = await discoverSkills(shellPaths);
26
+ const security = requireReadModels(ctx).security.getSnapshot();
27
+ const plugins = security.plugins;
28
+ const mcpServers = security.mcpServers;
29
+ const pluginDirectories = getPluginDirectories({
30
+ cwd: shellPaths.workingDirectory,
31
+ homeDir: shellPaths.homeDirectory,
32
+ });
33
+ const providerCount = (await requireProviderApi(ctx).listModels()).length;
34
+ const remoteRunnerCount = ctx.ops.remoteRuntime?.listContracts().length ?? 0;
35
+ const oauthProviderCount = Object.values(serviceConfigs).filter((service) => service.authType === 'oauth' && service.oauth).length;
36
+ const builtinSubscriptionProviderCount = listBuiltinSubscriptionProviders().length;
37
+ const subscriptionManager = requireSubscriptionManager(ctx);
38
+ const activeSubscriptionCount = subscriptionManager.list().length;
39
+ const pendingSubscriptionCount = subscriptionManager.listPending().length;
40
+ const sandboxReplIsolation = String(ctx.platform.configManager.get('sandbox.replIsolation'));
41
+ const sandboxMcpIsolation = String(ctx.platform.configManager.get('sandbox.mcpIsolation'));
42
+ const sandboxReview = buildSandboxReview(ctx.platform.configManager);
43
+ const sandboxSecureModeReady = sandboxReview.host.secureSandboxReady;
44
+ const quarantinedPluginCount = plugins.filter((plugin) => plugin.quarantined).length;
45
+ const quarantinedMcpCount = mcpServers.filter((server) => server.schemaFreshness === 'quarantined').length;
46
+ const elevatedMcpCount = mcpServers.filter((server) => server.trustMode === 'allow-all').length;
47
+ const hooksPath = shellPaths.resolveProjectPath('hooks.managed.json');
48
+ let managedHookCount = 0;
49
+ let managedHookChainCount = 0;
50
+ if (existsSync(hooksPath)) {
51
+ try {
52
+ const parsed = JSON.parse(readFileSync(hooksPath, 'utf-8')) as { hooks?: unknown[]; chains?: unknown[] };
53
+ managedHookCount = parsed.hooks?.length ?? 0;
54
+ managedHookChainCount = parsed.chains?.length ?? 0;
55
+ } catch {
56
+ // Ignore malformed hook config during snapshot collection.
57
+ }
58
+ }
59
+
60
+ const issues: SetupReviewSnapshot['issues'] = [
61
+ {
62
+ severity: providerCount > 0 ? 'pass' : 'fail',
63
+ area: 'providers',
64
+ message: providerCount > 0 ? `${providerCount} model(s) available` : 'no models available',
65
+ },
66
+ {
67
+ severity: (services.length === 0 && oauthProviderCount === 0 && builtinSubscriptionProviderCount === 0) ? 'warn' : serviceIssues.length === 0 ? 'pass' : 'warn',
68
+ area: 'services',
69
+ message: (services.length === 0 && oauthProviderCount === 0 && builtinSubscriptionProviderCount === 0)
70
+ ? 'no services configured'
71
+ : serviceIssues.length === 0
72
+ ? `${services.length} service(s), ${oauthProviderCount + builtinSubscriptionProviderCount} oauth provider(s), ${activeSubscriptionCount} active subscription override(s)`
73
+ : `${serviceIssues.length} service configuration issue(s)`,
74
+ },
75
+ {
76
+ severity: quarantinedPluginCount === 0 ? 'pass' : 'warn',
77
+ area: 'plugins',
78
+ message: quarantinedPluginCount === 0
79
+ ? `${plugins.length} plugin(s) discovered`
80
+ : `${quarantinedPluginCount} plugin(s) quarantined`,
81
+ },
82
+ {
83
+ severity: quarantinedMcpCount === 0 && elevatedMcpCount === 0 ? 'pass' : 'warn',
84
+ area: 'mcp',
85
+ message: quarantinedMcpCount > 0 || elevatedMcpCount > 0
86
+ ? `${quarantinedMcpCount} quarantined, ${elevatedMcpCount} elevated`
87
+ : `${mcpServers.length} server(s) known`,
88
+ },
89
+ {
90
+ severity: managedHookCount > 0 || managedHookChainCount > 0 ? 'pass' : 'warn',
91
+ area: 'hooks',
92
+ message: `${managedHookCount} managed hook(s), ${managedHookChainCount} chain(s)`,
93
+ },
94
+ {
95
+ severity: remoteRunnerCount > 0 ? 'pass' : 'warn',
96
+ area: 'remote',
97
+ message: remoteRunnerCount > 0 ? `${remoteRunnerCount} remote runner contract(s)` : 'no remote runner contracts registered',
98
+ },
99
+ {
100
+ severity: sandboxSecureModeReady || `${ctx.platform.configManager.get('sandbox.vmBackend')}` === 'local' ? 'pass' : 'warn',
101
+ area: 'sandbox',
102
+ message: `${ctx.platform.configManager.get('sandbox.vmBackend')}` === 'local'
103
+ ? 'local mode (virtualization disabled by default)'
104
+ : sandboxSecureModeReady
105
+ ? `QEMU enabled: REPL=${sandboxReplIsolation}, MCP=${sandboxMcpIsolation}`
106
+ : 'QEMU sandboxing requires running GoodVibes inside WSL on Windows',
107
+ },
108
+ ];
109
+
110
+ return {
111
+ sessionId: ctx.session.runtime.sessionId,
112
+ providerCount,
113
+ serviceCount: services.length,
114
+ oauthProviderCount,
115
+ builtinSubscriptionProviderCount,
116
+ activeSubscriptionCount,
117
+ pendingSubscriptionCount,
118
+ serviceIssues,
119
+ skillCount: skills.length,
120
+ pluginCount: plugins.length,
121
+ quarantinedPluginCount,
122
+ pluginDirectories,
123
+ managedHookCount,
124
+ managedHookChainCount,
125
+ mcpServerCount: mcpServers.length,
126
+ quarantinedMcpCount,
127
+ elevatedMcpCount,
128
+ remoteRunnerCount,
129
+ sandboxReplIsolation,
130
+ sandboxMcpIsolation,
131
+ sandboxSecureModeReady,
132
+ issues,
133
+ services,
134
+ };
135
+ }
136
+
137
+ export function renderSetupSandboxReview(ctx: CommandContext, snapshot: SetupReviewSnapshot): string {
138
+ const backend = `${ctx.platform.configManager.get('sandbox.vmBackend')}`;
139
+ const image = String(ctx.platform.configManager.get('sandbox.qemuImagePath') ?? '').trim();
140
+ const wrapper = String(ctx.platform.configManager.get('sandbox.qemuExecWrapper') ?? '').trim();
141
+ const host = String(ctx.platform.configManager.get('sandbox.qemuGuestHost') ?? '').trim();
142
+ const workspace = String(ctx.platform.configManager.get('sandbox.qemuWorkspacePath') ?? '').trim();
143
+ const lines = [
144
+ 'Setup Sandbox Review',
145
+ ` backend: ${backend}`,
146
+ ` repl isolation: ${snapshot.sandboxReplIsolation}`,
147
+ ` mcp isolation: ${snapshot.sandboxMcpIsolation}`,
148
+ ` secure mode ready: ${snapshot.sandboxSecureModeReady ? 'yes' : 'no'}`,
149
+ ` qemu image: ${image || '(not configured)'}`,
150
+ ` qemu wrapper: ${wrapper || '(not configured)'}`,
151
+ ` guest host: ${host || '(not configured)'}`,
152
+ ` guest workspace: ${workspace || '(not configured)'}`,
153
+ '',
154
+ ' next:',
155
+ ];
156
+ if (backend === 'local') {
157
+ lines.push(' sandbox/QEMU setup is externalized to GoodVibes TUI');
158
+ lines.push(' use GoodVibes TUI for coding/runtime isolation work');
159
+ } else if (!image || !wrapper) {
160
+ lines.push(' sandbox/QEMU setup is externalized to GoodVibes TUI');
161
+ lines.push(' use GoodVibes TUI for coding/runtime isolation work');
162
+ } else {
163
+ lines.push(' sandbox sessions are blocked in Agent');
164
+ lines.push(' delegate build/fix/review work to GoodVibes TUI');
165
+ }
166
+ if (process.platform === 'win32' && !isRunningInWsl()) {
167
+ lines.push(' Run GoodVibes inside WSL before enabling QEMU sandboxing.');
168
+ }
169
+ return lines.join('\n');
170
+ }
171
+
172
+ export function exportSetupSupportBundle(
173
+ targetDirArg: string,
174
+ snapshot: SetupReviewSnapshot,
175
+ ctx: CommandContext,
176
+ ): string {
177
+ const shellPaths = requireShellPaths(ctx);
178
+ const targetDir = shellPaths.resolveWorkspacePath(targetDirArg);
179
+ mkdirSync(targetDir, { recursive: true });
180
+ writeFileSync(join(targetDir, 'startup-review.json'), JSON.stringify(snapshot, null, 2) + '\n', 'utf-8');
181
+ const servicesPath = shellPaths.resolveProjectPath(GOODVIBES_AGENT_SURFACE_ROOT, 'services.json');
182
+ if (existsSync(servicesPath)) {
183
+ writeFileSync(join(targetDir, 'services.json'), readFileSync(servicesPath, 'utf-8'), 'utf-8');
184
+ }
185
+ const hooksPath = shellPaths.resolveProjectPath('hooks.managed.json');
186
+ if (existsSync(hooksPath)) {
187
+ writeFileSync(join(targetDir, 'hooks.managed.json'), readFileSync(hooksPath, 'utf-8'), 'utf-8');
188
+ }
189
+ writeFileSync(
190
+ join(targetDir, 'sandbox-externalized.txt'),
191
+ [
192
+ 'GoodVibes Agent does not ship or manage QEMU sandbox wrappers.',
193
+ 'Delegate build, fix, review, and runtime-isolation work to GoodVibes TUI.',
194
+ '',
195
+ ].join('\n'),
196
+ 'utf-8',
197
+ );
198
+ return targetDir;
199
+ }
@@ -0,0 +1,135 @@
1
+ import { dirname, join, resolve } from 'node:path';
2
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
3
+ import type { CommandContext } from '../command-registry.ts';
4
+ import type { ConfigKey } from '../../config/index.ts';
5
+ import { CONFIG_SCHEMA } from '../../config/index.ts';
6
+ import { requireShellPaths } from './runtime-services.ts';
7
+ import { GOODVIBES_AGENT_SURFACE_ROOT } from '../../config/surface.ts';
8
+
9
+ export interface SetupReviewSnapshot {
10
+ readonly sessionId: string;
11
+ readonly providerCount: number;
12
+ readonly serviceCount: number;
13
+ readonly oauthProviderCount: number;
14
+ readonly builtinSubscriptionProviderCount: number;
15
+ readonly activeSubscriptionCount: number;
16
+ readonly pendingSubscriptionCount: number;
17
+ readonly serviceIssues: string[];
18
+ readonly skillCount: number;
19
+ readonly pluginCount: number;
20
+ readonly quarantinedPluginCount: number;
21
+ readonly pluginDirectories: string[];
22
+ readonly managedHookCount: number;
23
+ readonly managedHookChainCount: number;
24
+ readonly mcpServerCount: number;
25
+ readonly quarantinedMcpCount: number;
26
+ readonly elevatedMcpCount: number;
27
+ readonly remoteRunnerCount: number;
28
+ readonly sandboxReplIsolation: string;
29
+ readonly sandboxMcpIsolation: string;
30
+ readonly sandboxSecureModeReady: boolean;
31
+ readonly issues: Array<{ severity: 'pass' | 'warn' | 'fail'; area: string; message: string }>;
32
+ readonly services: string[];
33
+ }
34
+
35
+ export interface SetupTransferBundle {
36
+ readonly schemaVersion: 'v1';
37
+ readonly exportedAt: number;
38
+ readonly startupReview: SetupReviewSnapshot;
39
+ readonly config: Record<string, unknown>;
40
+ readonly services?: Record<string, unknown>;
41
+ readonly ecosystem?: {
42
+ readonly plugins?: Record<string, unknown>;
43
+ readonly skills?: Record<string, unknown>;
44
+ };
45
+ }
46
+
47
+ export function inspectSetupTransferBundle(bundle: SetupTransferBundle): string {
48
+ const ecosystemPluginCount = bundle.ecosystem?.plugins && Array.isArray((bundle.ecosystem.plugins as { entries?: unknown[] }).entries)
49
+ ? ((bundle.ecosystem.plugins as { entries: unknown[] }).entries.length)
50
+ : 0;
51
+ const ecosystemSkillCount = bundle.ecosystem?.skills && Array.isArray((bundle.ecosystem.skills as { entries?: unknown[] }).entries)
52
+ ? ((bundle.ecosystem.skills as { entries: unknown[] }).entries.length)
53
+ : 0;
54
+ return [
55
+ 'Setup Transfer Review',
56
+ ` schemaVersion: ${bundle.schemaVersion}`,
57
+ ` exportedAt: ${new Date(bundle.exportedAt).toISOString()}`,
58
+ ` session: ${bundle.startupReview.sessionId}`,
59
+ ` services: ${bundle.startupReview.serviceCount}`,
60
+ ` plugins: ${bundle.startupReview.pluginCount}`,
61
+ ` skills: ${bundle.startupReview.skillCount}`,
62
+ ` remote runners: ${bundle.startupReview.remoteRunnerCount}`,
63
+ ` config keys: ${Object.keys(bundle.config ?? {}).length}`,
64
+ ` curated plugins: ${ecosystemPluginCount}`,
65
+ ` curated skills: ${ecosystemSkillCount}`,
66
+ ].join('\n');
67
+ }
68
+
69
+ export function buildSetupTransferBundle(ctx: CommandContext, snapshot: SetupReviewSnapshot): SetupTransferBundle {
70
+ const shellPaths = requireShellPaths(ctx);
71
+ const config: Record<string, unknown> = {};
72
+ for (const entry of CONFIG_SCHEMA) {
73
+ try {
74
+ config[entry.key] = structuredClone(ctx.platform.configManager.get(entry.key as ConfigKey));
75
+ } catch {
76
+ // Ignore unreadable config values in transfer bundles.
77
+ }
78
+ }
79
+ const servicesPath = shellPaths.resolveProjectPath(GOODVIBES_AGENT_SURFACE_ROOT, 'services.json');
80
+ const pluginsPath = shellPaths.resolveProjectPath(GOODVIBES_AGENT_SURFACE_ROOT, 'ecosystem', 'plugins.json');
81
+ const skillsPath = shellPaths.resolveProjectPath(GOODVIBES_AGENT_SURFACE_ROOT, 'ecosystem', 'skills.json');
82
+ const services = existsSync(servicesPath)
83
+ ? JSON.parse(readFileSync(servicesPath, 'utf-8')) as Record<string, unknown>
84
+ : undefined;
85
+ const plugins = existsSync(pluginsPath)
86
+ ? JSON.parse(readFileSync(pluginsPath, 'utf-8')) as Record<string, unknown>
87
+ : undefined;
88
+ const skills = existsSync(skillsPath)
89
+ ? JSON.parse(readFileSync(skillsPath, 'utf-8')) as Record<string, unknown>
90
+ : undefined;
91
+
92
+ return {
93
+ schemaVersion: 'v1',
94
+ exportedAt: Date.now(),
95
+ startupReview: snapshot,
96
+ config,
97
+ services,
98
+ ecosystem: {
99
+ plugins,
100
+ skills,
101
+ },
102
+ };
103
+ }
104
+
105
+ export function createSetupLink(surface: string, target?: string): string {
106
+ const encodedTarget = target ? `?target=${encodeURIComponent(target)}` : '';
107
+ return `goodvibes://open/${encodeURIComponent(surface)}${encodedTarget}`;
108
+ }
109
+
110
+ export function parseSetupLink(value: string): { surface: string; target?: string } | null {
111
+ try {
112
+ const parsed = new URL(value);
113
+ if (parsed.protocol !== 'goodvibes:') return null;
114
+ const segments = parsed.pathname.split('/').filter(Boolean);
115
+ if (parsed.hostname !== 'open' || segments.length !== 1) return null;
116
+ return {
117
+ surface: decodeURIComponent(segments[0]!),
118
+ target: parsed.searchParams.get('target') ?? undefined,
119
+ };
120
+ } catch {
121
+ return null;
122
+ }
123
+ }
124
+
125
+ export function exportSetupTransferBundle(
126
+ ctx: CommandContext,
127
+ pathArg: string,
128
+ bundle: SetupTransferBundle,
129
+ ): string {
130
+ const shellPaths = requireShellPaths(ctx);
131
+ const targetPath = shellPaths.resolveWorkspacePath(pathArg);
132
+ mkdirSync(dirname(targetPath), { recursive: true });
133
+ writeFileSync(targetPath, JSON.stringify(bundle, null, 2) + '\n', 'utf-8');
134
+ return targetPath;
135
+ }
@@ -0,0 +1,282 @@
1
+ import { dirname, join } from 'path';
2
+ import { mkdirSync, readFileSync, writeFileSync } from 'node:fs';
3
+ import type { CommandRegistry } from '../command-registry.ts';
4
+ import type { ConfigKey } from '../../config/index.ts';
5
+ import { CONFIG_SCHEMA } from '../../config/index.ts';
6
+ import { listHookPointContracts } from '@pellux/goodvibes-sdk/platform/hooks';
7
+ import type { SetupTransferBundle } from './local-setup-transfer.ts';
8
+ import {
9
+ buildSetupTransferBundle,
10
+ createSetupLink,
11
+ exportSetupTransferBundle,
12
+ inspectSetupTransferBundle,
13
+ parseSetupLink,
14
+ } from './local-setup-transfer.ts';
15
+ import { buildSetupReviewSnapshot, exportSetupSupportBundle } from './local-setup-review.ts';
16
+ import { openOnboardingWizard, requirePanelManager, requireShellPaths } from './runtime-services.ts';
17
+ import { summarizeError } from '@pellux/goodvibes-sdk/platform/utils';
18
+ import { GOODVIBES_AGENT_SURFACE_ROOT } from '../../config/surface.ts';
19
+
20
+ type SetupSnapshot = Awaited<ReturnType<typeof buildSetupReviewSnapshot>>;
21
+
22
+ export function registerLocalSetupCommands(registry: CommandRegistry): void {
23
+ registry.register({
24
+ name: 'setup',
25
+ aliases: ['startup'],
26
+ description: 'Launch the onboarding wizard and review Agent startup readiness',
27
+ usage: '[review|doctor|services|hooks|remote|sandbox|onboarding|support-bundle <dir>|export <path>|transfer <export|inspect|import> <path>|link <surface> [target]|open-link <uri>]',
28
+ async handler(args, ctx) {
29
+ const sub = args[0] ?? 'review';
30
+ let shellPaths: ReturnType<typeof requireShellPaths> | null = null;
31
+ let snapshotPromise: Promise<SetupSnapshot> | null = null;
32
+ const getShellPaths = () => (shellPaths ??= requireShellPaths(ctx));
33
+ const getSnapshot = async (): Promise<SetupSnapshot> => {
34
+ snapshotPromise ??= buildSetupReviewSnapshot(ctx);
35
+ return snapshotPromise;
36
+ };
37
+
38
+ if (sub === 'review') {
39
+ const snapshot = await getSnapshot();
40
+ ctx.print([
41
+ 'Startup Readiness Review',
42
+ ` session: ${snapshot.sessionId}`,
43
+ ` providers/models: ${snapshot.providerCount}`,
44
+ ` services configured: ${snapshot.serviceCount}`,
45
+ ` oauth providers: ${snapshot.oauthProviderCount + snapshot.builtinSubscriptionProviderCount}`,
46
+ ` active subscriptions: ${snapshot.activeSubscriptionCount}`,
47
+ ` pending subscriptions: ${snapshot.pendingSubscriptionCount}`,
48
+ ` skills discovered: ${snapshot.skillCount}`,
49
+ ` plugins discovered: ${snapshot.pluginCount}`,
50
+ ` quarantined plugins: ${snapshot.quarantinedPluginCount}`,
51
+ ` plugin search dirs: ${snapshot.pluginDirectories.length}`,
52
+ ` managed hooks: ${snapshot.managedHookCount}`,
53
+ ` managed hook chains: ${snapshot.managedHookChainCount}`,
54
+ ` mcp servers known: ${snapshot.mcpServerCount}`,
55
+ ` mcp quarantined: ${snapshot.quarantinedMcpCount}`,
56
+ ` mcp elevated: ${snapshot.elevatedMcpCount}`,
57
+ ` remote runners: ${snapshot.remoteRunnerCount}`,
58
+ ' sandbox/QEMU: externalized to GoodVibes TUI for delegated build/runtime isolation',
59
+ '',
60
+ ` service ids: ${snapshot.services.join(', ') || '(none)'}`,
61
+ ` plugin dirs: ${snapshot.pluginDirectories.join(', ') || '(none)'}`,
62
+ ].join('\n'));
63
+ return;
64
+ }
65
+
66
+ if (sub === 'doctor') {
67
+ const snapshot = await getSnapshot();
68
+ ctx.print([
69
+ 'Startup Doctor',
70
+ ...snapshot.issues.map((issue) => ` [${issue.severity.toUpperCase()}] ${issue.area}: ${issue.message}`),
71
+ ' [INFO] sandbox: GoodVibes Agent does not own sandbox/QEMU setup; delegate build/runtime isolation to GoodVibes TUI.',
72
+ ...(snapshot.serviceIssues.length > 0
73
+ ? ['', ' Service issues:', ...snapshot.serviceIssues.map((issue) => ` - ${issue}`)]
74
+ : []),
75
+ ].join('\n'));
76
+ return;
77
+ }
78
+
79
+ if (sub === 'services') {
80
+ const snapshot = await getSnapshot();
81
+ ctx.print([
82
+ 'Startup Services',
83
+ ` configured: ${snapshot.serviceCount}`,
84
+ ` oauth providers: ${snapshot.oauthProviderCount + snapshot.builtinSubscriptionProviderCount}`,
85
+ ` active subscriptions: ${snapshot.activeSubscriptionCount}`,
86
+ ` pending subscriptions: ${snapshot.pendingSubscriptionCount}`,
87
+ ` issues: ${snapshot.serviceIssues.length}`,
88
+ ...snapshot.services.map((name) => ` ${name}`),
89
+ ...(snapshot.serviceIssues.length > 0
90
+ ? ['', ...snapshot.serviceIssues.map((issue) => ` issue: ${issue}`)]
91
+ : []),
92
+ ].join('\n'));
93
+ return;
94
+ }
95
+
96
+ if (sub === 'hooks') {
97
+ const snapshot = await getSnapshot();
98
+ const contracts = listHookPointContracts();
99
+ ctx.print([
100
+ 'Startup Hooks',
101
+ ` managed hooks: ${snapshot.managedHookCount}`,
102
+ ` managed chains: ${snapshot.managedHookChainCount}`,
103
+ ` hook contracts: ${contracts.length}`,
104
+ ].join('\n'));
105
+ return;
106
+ }
107
+
108
+ if (sub === 'remote') {
109
+ const snapshot = await getSnapshot();
110
+ const runners = ctx.ops.remoteRuntime?.listContracts() ?? [];
111
+ ctx.print([
112
+ 'Startup Remote',
113
+ ` runner contracts: ${snapshot.remoteRunnerCount}`,
114
+ ...runners.map((runner) => ` ${runner.id} [${runner.trustClass}] ${runner.label}`),
115
+ ].join('\n'));
116
+ return;
117
+ }
118
+
119
+ if (sub === 'sandbox') {
120
+ ctx.print([
121
+ 'Setup Sandbox',
122
+ ' status: externalized',
123
+ ' owner: GoodVibes TUI',
124
+ ' reason: sandbox/QEMU setup and runtime isolation are coding/build execution surfaces.',
125
+ ' result: no local Agent sandbox settings, files, or sessions were changed.',
126
+ ].join('\n'));
127
+ return;
128
+ }
129
+
130
+ if (sub === 'onboarding') {
131
+ openOnboardingWizard(ctx, { mode: 'edit', reset: true });
132
+ ctx.print('Opening onboarding wizard.');
133
+ return;
134
+ }
135
+
136
+ if (sub === 'support-bundle') {
137
+ const snapshot = await getSnapshot();
138
+ const dirArg = args[1];
139
+ if (!dirArg) {
140
+ ctx.print('Usage: /setup support-bundle <dir>');
141
+ return;
142
+ }
143
+ const targetDir = exportSetupSupportBundle(dirArg, snapshot, ctx);
144
+ writeFileSync(join(targetDir, 'remote-summary.json'), JSON.stringify({
145
+ runners: ctx.ops.remoteRuntime?.listContracts() ?? [],
146
+ artifacts: (ctx.ops.remoteRuntime?.listArtifacts() ?? []).map((artifact) => ({
147
+ id: artifact.id,
148
+ runnerId: artifact.runnerId,
149
+ status: artifact.task.status,
150
+ createdAt: artifact.createdAt,
151
+ })),
152
+ }, null, 2) + '\n', 'utf-8');
153
+ ctx.print(`Exported support bundle to ${targetDir}`);
154
+ return;
155
+ }
156
+
157
+ if (sub === 'export') {
158
+ const snapshot = await getSnapshot();
159
+ const pathArg = args[1];
160
+ if (!pathArg) {
161
+ ctx.print('Usage: /setup export <path>');
162
+ return;
163
+ }
164
+ const targetPath = getShellPaths().resolveWorkspacePath(pathArg);
165
+ mkdirSync(dirname(targetPath), { recursive: true });
166
+ writeFileSync(targetPath, JSON.stringify(snapshot, null, 2) + '\n', 'utf-8');
167
+ ctx.print(`Exported startup review to ${targetPath}`);
168
+ return;
169
+ }
170
+
171
+ if (sub === 'transfer') {
172
+ const mode = args[1]?.toLowerCase();
173
+ const pathArg = args[2];
174
+ if (!mode || !pathArg) {
175
+ ctx.print('Usage: /setup transfer <export|inspect|import> <path>');
176
+ return;
177
+ }
178
+ const targetPath = getShellPaths().resolveWorkspacePath(pathArg);
179
+ if (mode === 'export') {
180
+ const snapshot = await getSnapshot();
181
+ const bundle = buildSetupTransferBundle(ctx, snapshot);
182
+ ctx.print(`Exported setup transfer bundle to ${exportSetupTransferBundle(ctx, pathArg, bundle)}`);
183
+ return;
184
+ }
185
+ if (mode === 'inspect') {
186
+ try {
187
+ const bundle = JSON.parse(readFileSync(targetPath, 'utf-8')) as SetupTransferBundle;
188
+ ctx.print(`${inspectSetupTransferBundle(bundle)}\n path: ${targetPath}`);
189
+ } catch (error) {
190
+ ctx.print(`Failed to inspect setup transfer bundle: ${summarizeError(error)}`);
191
+ }
192
+ return;
193
+ }
194
+ if (mode === 'import') {
195
+ try {
196
+ const bundle = JSON.parse(readFileSync(targetPath, 'utf-8')) as SetupTransferBundle;
197
+ for (const entry of CONFIG_SCHEMA) {
198
+ if (Object.prototype.hasOwnProperty.call(bundle.config, entry.key)) {
199
+ ctx.platform.configManager.setDynamic(entry.key as ConfigKey, (bundle.config as Record<string, unknown>)[entry.key]);
200
+ }
201
+ }
202
+ if (bundle.services) {
203
+ const servicesPath = getShellPaths().resolveProjectPath(GOODVIBES_AGENT_SURFACE_ROOT, 'services.json');
204
+ mkdirSync(dirname(servicesPath), { recursive: true });
205
+ writeFileSync(servicesPath, JSON.stringify(bundle.services, null, 2) + '\n', 'utf-8');
206
+ }
207
+ if (bundle.ecosystem?.plugins) {
208
+ const pluginsPath = getShellPaths().resolveProjectPath(GOODVIBES_AGENT_SURFACE_ROOT, 'ecosystem', 'plugins.json');
209
+ mkdirSync(dirname(pluginsPath), { recursive: true });
210
+ writeFileSync(pluginsPath, JSON.stringify(bundle.ecosystem.plugins, null, 2) + '\n', 'utf-8');
211
+ }
212
+ if (bundle.ecosystem?.skills) {
213
+ const skillsPath = getShellPaths().resolveProjectPath(GOODVIBES_AGENT_SURFACE_ROOT, 'ecosystem', 'skills.json');
214
+ mkdirSync(dirname(skillsPath), { recursive: true });
215
+ writeFileSync(skillsPath, JSON.stringify(bundle.ecosystem.skills, null, 2) + '\n', 'utf-8');
216
+ }
217
+ ctx.print(`Imported setup transfer bundle from ${targetPath}`);
218
+ } catch (error) {
219
+ ctx.print(`Failed to import setup transfer bundle: ${summarizeError(error)}`);
220
+ }
221
+ return;
222
+ }
223
+ ctx.print('Usage: /setup transfer <export|inspect|import> <path>');
224
+ return;
225
+ }
226
+
227
+ if (sub === 'link') {
228
+ const surface = args[1];
229
+ const target = args[2];
230
+ if (!surface) {
231
+ ctx.print('Usage: /setup link <cockpit|security|remote|knowledge|incident|hooks|orchestration|tasks> [target]');
232
+ return;
233
+ }
234
+ ctx.print(createSetupLink(surface, target));
235
+ return;
236
+ }
237
+
238
+ if (sub === 'open-link') {
239
+ const link = args[1];
240
+ if (!link) {
241
+ ctx.print('Usage: /setup open-link <goodvibes://...>');
242
+ return;
243
+ }
244
+ const parsed = parseSetupLink(link);
245
+ if (!parsed) {
246
+ ctx.print(`Invalid setup link: ${link}`);
247
+ return;
248
+ }
249
+ const panelOpeners: Record<string, (() => void) | undefined> = {
250
+ cockpit: ctx.openCockpitPanel,
251
+ security: ctx.openSecurityPanel,
252
+ remote: ctx.openRemotePanel,
253
+ knowledge: ctx.openKnowledgePanel,
254
+ incident: ctx.openIncidentPanel,
255
+ hooks: ctx.openHooksPanel,
256
+ orchestration: ctx.openOrchestrationPanel,
257
+ };
258
+ if (parsed.surface === 'tasks') {
259
+ if (ctx.showPanel) ctx.showPanel('tasks');
260
+ else {
261
+ const panelManager = requirePanelManager(ctx);
262
+ panelManager.open('tasks');
263
+ panelManager.show();
264
+ ctx.renderRequest();
265
+ }
266
+ ctx.print(`Opened setup link for tasks${parsed.target ? ` (${parsed.target})` : ''}.`);
267
+ return;
268
+ }
269
+ const openPanel = panelOpeners[parsed.surface];
270
+ if (!openPanel) {
271
+ ctx.print(`Unsupported setup link surface: ${parsed.surface}`);
272
+ return;
273
+ }
274
+ openPanel();
275
+ ctx.print(`Opened setup link for ${parsed.surface}${parsed.target ? ` (${parsed.target})` : ''}.`);
276
+ return;
277
+ }
278
+
279
+ ctx.print('Usage: /setup [review|doctor|services|hooks|remote|sandbox|onboarding|support-bundle <dir>|export <path>|transfer <export|inspect|import> <path>|link <surface> [target]|open-link <uri>]');
280
+ },
281
+ });
282
+ }