@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,152 @@
1
+ import type { CommandContext } from '../command-registry.ts';
2
+ import type { ProvenanceLink } from '@pellux/goodvibes-sdk/platform/state';
3
+ import {
4
+ buildIncidentMemoryAddOptions,
5
+ buildMcpSecurityMemoryAddOptions,
6
+ buildPluginSecurityMemoryAddOptions,
7
+ buildPolicyPreflightMemoryAddOptions,
8
+ } from '@pellux/goodvibes-sdk/platform/state';
9
+ import { VALID_CLASSES, VALID_SCOPES, isValidClass, isValidScope } from './recall-shared.ts';
10
+ import { getMemoryApi } from './recall-query.ts';
11
+
12
+ export async function handleRecallAdd(args: string[], context: CommandContext): Promise<void> {
13
+ const memory = getMemoryApi(context);
14
+ if (!memory) {
15
+ return;
16
+ }
17
+
18
+ const cls = args[0];
19
+ if (!cls || !isValidClass(cls)) {
20
+ context.print(`[recall] Invalid class "${cls ?? ''}". Valid: ${VALID_CLASSES.join(', ')}`);
21
+ return;
22
+ }
23
+
24
+ const flagArgs = args.slice(1);
25
+ const detailIdx = flagArgs.indexOf('--detail');
26
+ const tagsIdx = flagArgs.indexOf('--tags');
27
+ const sessionIdx = flagArgs.indexOf('--session');
28
+ const taskIdx = flagArgs.indexOf('--task');
29
+ const fileIdx = flagArgs.indexOf('--file');
30
+ const scopeIdx = flagArgs.indexOf('--scope');
31
+
32
+ const detail = detailIdx !== -1 ? flagArgs[detailIdx + 1] : undefined;
33
+ const tagsRaw = tagsIdx !== -1 ? flagArgs[tagsIdx + 1] : undefined;
34
+ const scopeRaw = scopeIdx !== -1 ? flagArgs[scopeIdx + 1] : undefined;
35
+ const tags = tagsRaw ? tagsRaw.split(',').map((token) => token.trim()).filter(Boolean) : [];
36
+ const scope = scopeRaw && isValidScope(scopeRaw) ? scopeRaw : 'project';
37
+
38
+ if (scopeRaw && !isValidScope(scopeRaw)) {
39
+ context.print(`[recall] Invalid scope "${scopeRaw}". Valid: ${VALID_SCOPES.join(', ')}`);
40
+ return;
41
+ }
42
+
43
+ const provenance: ProvenanceLink[] = [];
44
+ if (sessionIdx !== -1 && flagArgs[sessionIdx + 1]) provenance.push({ kind: 'session', ref: flagArgs[sessionIdx + 1] });
45
+ if (taskIdx !== -1 && flagArgs[taskIdx + 1]) provenance.push({ kind: 'task', ref: flagArgs[taskIdx + 1] });
46
+ if (fileIdx !== -1 && flagArgs[fileIdx + 1]) provenance.push({ kind: 'file', ref: flagArgs[fileIdx + 1] });
47
+ if (!provenance.some((entry) => entry.kind === 'session') && context.session.runtime.sessionId) {
48
+ provenance.push({ kind: 'session', ref: context.session.runtime.sessionId });
49
+ }
50
+
51
+ const summaryTokens: string[] = [];
52
+ for (const token of flagArgs) {
53
+ if (token.startsWith('--')) break;
54
+ summaryTokens.push(token);
55
+ }
56
+ const summary = summaryTokens.join(' ');
57
+ if (!summary.trim()) {
58
+ context.print('[recall] Usage: /recall add <class> <summary> [--detail <text>] [--tags <t1,t2>]');
59
+ return;
60
+ }
61
+
62
+ const record = await memory.add({ scope, cls, summary, detail, tags, provenance });
63
+ context.print(`[recall] Added ${cls}: ${record.id}`);
64
+ context.print(` Scope: ${record.scope}`);
65
+ context.print(` Summary: ${record.summary}`);
66
+ if (record.tags.length) context.print(` Tags: ${record.tags.join(', ')}`);
67
+ if (record.provenance.length) {
68
+ context.print(` Provenance: ${record.provenance.map((entry) => `${entry.kind}:${entry.ref}`).join(', ')}`);
69
+ }
70
+ }
71
+
72
+ export async function handleRecallCapture(args: string[], context: CommandContext): Promise<void> {
73
+ const memory = getMemoryApi(context);
74
+ const pluginManager = context.extensions.pluginManager;
75
+ if (!memory) {
76
+ return;
77
+ }
78
+ if (!context.extensions.forensicsRegistry) {
79
+ context.print('[recall] Forensics registry not available.');
80
+ return;
81
+ }
82
+
83
+ const target = args[0];
84
+ if (target === 'incident') {
85
+ const requestedId = args[1];
86
+ const report = !requestedId || requestedId === 'latest'
87
+ ? context.extensions.forensicsRegistry.latest()
88
+ : context.extensions.forensicsRegistry.getById(requestedId);
89
+ if (!report) {
90
+ context.print(`[recall] Incident not found: ${requestedId ?? 'latest'}`);
91
+ return;
92
+ }
93
+ const bundle = context.extensions.forensicsRegistry.buildBundle(report.id);
94
+ if (!bundle) {
95
+ context.print(`[recall] Failed to build incident bundle: ${report.id}`);
96
+ return;
97
+ }
98
+ const record = await memory.add(buildIncidentMemoryAddOptions(bundle));
99
+ context.print(`[recall] Captured incident ${report.id} into memory as ${record.id}`);
100
+ return;
101
+ }
102
+
103
+ if (target === 'policy') {
104
+ const review = context.extensions.policyRuntimeState?.getSnapshot().lastPreflightReview;
105
+ if (!review) {
106
+ context.print('[recall] No policy preflight review is available to capture.');
107
+ return;
108
+ }
109
+ const record = await memory.add(buildPolicyPreflightMemoryAddOptions(review));
110
+ context.print(`[recall] Captured policy preflight into memory as ${record.id}`);
111
+ return;
112
+ }
113
+
114
+ if (target === 'mcp') {
115
+ const serverName = args[1];
116
+ if (!serverName) {
117
+ context.print('[recall] Usage: /recall capture mcp <server>');
118
+ return;
119
+ }
120
+ const server = context.extensions.mcpRegistry.listServerSecurity().find((entry) => entry.name === serverName);
121
+ if (!server) {
122
+ context.print(`[recall] MCP server not found: ${serverName}`);
123
+ return;
124
+ }
125
+ const record = await memory.add(buildMcpSecurityMemoryAddOptions(server));
126
+ context.print(`[recall] Captured MCP server ${server.name} into memory as ${record.id}`);
127
+ return;
128
+ }
129
+
130
+ if (target === 'plugin') {
131
+ if (!pluginManager) {
132
+ context.print('[recall] Plugin manager not available.');
133
+ return;
134
+ }
135
+ const pluginName = args[1];
136
+ if (!pluginName) {
137
+ context.print('[recall] Usage: /recall capture plugin <name>');
138
+ return;
139
+ }
140
+ const plugin = pluginManager.list().find((entry) => entry.name === pluginName);
141
+ if (!plugin) {
142
+ context.print(`[recall] Plugin not found: ${pluginName}`);
143
+ return;
144
+ }
145
+ const quarantineReason = pluginManager.getQuarantineRecord(plugin.name)?.reason;
146
+ const record = await memory.add(buildPluginSecurityMemoryAddOptions(plugin, quarantineReason));
147
+ context.print(`[recall] Captured plugin ${plugin.name} into memory as ${record.id}`);
148
+ return;
149
+ }
150
+
151
+ context.print('[recall] Usage: /recall capture incident <id|latest> | /recall capture policy | /recall capture mcp <server> | /recall capture plugin <name>');
152
+ }
@@ -0,0 +1,229 @@
1
+ import type { CommandContext } from '../command-registry.ts';
2
+ import type { MemoryApi } from '@pellux/goodvibes-sdk/platform/knowledge';
3
+ import type { MemorySearchFilter } from '@pellux/goodvibes-sdk/platform/state';
4
+ import { VALID_CLASSES, VALID_SCOPES, isValidClass, isValidScope } from './recall-shared.ts';
5
+
6
+ export function getMemoryApi(context: CommandContext): MemoryApi | null {
7
+ const memoryApi = context.clients?.knowledgeApi?.memory;
8
+ if (!memoryApi) {
9
+ context.print('[recall] Memory API is not available in this runtime.');
10
+ return null;
11
+ }
12
+ return memoryApi;
13
+ }
14
+
15
+ export function handleRecallSearch(args: string[], context: CommandContext): void {
16
+ const memory = getMemoryApi(context);
17
+ if (!memory) {
18
+ return;
19
+ }
20
+
21
+ const clsIdx = args.indexOf('--cls');
22
+ const limitIdx = args.indexOf('--limit');
23
+ const semantic = args.includes('--semantic') || args.includes('--vector');
24
+ const filter: MemorySearchFilter = {};
25
+
26
+ if (clsIdx !== -1 && args[clsIdx + 1]) {
27
+ const cls = args[clsIdx + 1];
28
+ if (isValidClass(cls)) filter.cls = cls;
29
+ else {
30
+ context.print(`[recall] Unknown class "${cls}". Valid: ${VALID_CLASSES.join(', ')}`);
31
+ return;
32
+ }
33
+ }
34
+
35
+ const scopeIdx = args.indexOf('--scope');
36
+ if (scopeIdx !== -1 && args[scopeIdx + 1]) {
37
+ const scope = args[scopeIdx + 1];
38
+ if (isValidScope(scope)) filter.scope = scope;
39
+ else {
40
+ context.print(`[recall] Unknown scope "${scope}". Valid: ${VALID_SCOPES.join(', ')}`);
41
+ return;
42
+ }
43
+ }
44
+
45
+ if (limitIdx !== -1 && args[limitIdx + 1]) {
46
+ filter.limit = parseInt(args[limitIdx + 1], 10) || 20;
47
+ }
48
+
49
+ const queryTokens = args.filter((token, index) => {
50
+ if (token.startsWith('--')) return false;
51
+ if (index > 0 && ['--cls', '--limit', '--scope'].includes(args[index - 1]!)) return false;
52
+ return true;
53
+ });
54
+ if (queryTokens.length) filter.query = queryTokens.join(' ');
55
+ if (semantic) filter.semantic = true;
56
+
57
+ const semanticResults = semantic ? memory.searchSemantic(filter) : [];
58
+ const results = semantic ? semanticResults.map((entry) => entry.record) : memory.search(filter);
59
+ if (!results.length) {
60
+ context.print('[recall] No records found.');
61
+ return;
62
+ }
63
+
64
+ context.print(`[recall] ${results.length} ${semantic ? 'semantic ' : ''}record(s):`);
65
+ for (const record of results) {
66
+ const semanticEntry = semanticResults.find((entry) => entry.record.id === record.id);
67
+ const ts = new Date(record.createdAt).toISOString().slice(0, 16).replace('T', ' ');
68
+ const tagStr = record.tags.length ? ` [${record.tags.join(', ')}]` : '';
69
+ const scoreStr = semanticEntry ? ` sim ${Math.round(semanticEntry.similarity * 100)}%` : '';
70
+ context.print(` ${record.id} [${record.cls}]${tagStr} ${ts}${scoreStr}`);
71
+ context.print(` ${record.summary}`);
72
+ if (record.provenance.length) {
73
+ context.print(` via: ${record.provenance.map((entry) => `${entry.kind}:${entry.ref}`).join(', ')}`);
74
+ }
75
+ }
76
+ }
77
+
78
+ export function handleRecallVector(args: string[], context: CommandContext): void {
79
+ const memory = getMemoryApi(context);
80
+ if (!memory) {
81
+ return;
82
+ }
83
+
84
+ const sub = (args[0] ?? 'status').toLowerCase();
85
+ if (sub === 'rebuild') {
86
+ const stats = memory.rebuildVectors();
87
+ context.print(formatVectorStats(stats, 'rebuild complete'));
88
+ return;
89
+ }
90
+ if (sub === 'status' || sub === 'doctor') {
91
+ context.print(formatVectorStats(memory.vectorStats(), sub));
92
+ return;
93
+ }
94
+ context.print('[recall] Usage: /recall vector [status|doctor|rebuild]');
95
+ }
96
+
97
+ function formatVectorStats(
98
+ stats: ReturnType<MemoryApi['vectorStats']>,
99
+ label: string,
100
+ ): string {
101
+ return [
102
+ `[recall] Vector index ${label}`,
103
+ ` backend: ${stats.backend}`,
104
+ ` enabled: ${stats.enabled ? 'yes' : 'no'}`,
105
+ ` available: ${stats.available ? 'yes' : 'no'}`,
106
+ ` dimensions: ${stats.dimensions}`,
107
+ ` indexed records: ${stats.indexedRecords}`,
108
+ ...(stats.path ? [` path: ${stats.path}`] : []),
109
+ ...(stats.error ? [` error: ${stats.error}`] : []),
110
+ ].join('\n');
111
+ }
112
+
113
+ export function handleRecallGet(args: string[], context: CommandContext): void {
114
+ const memory = getMemoryApi(context);
115
+ if (!memory) {
116
+ return;
117
+ }
118
+ const id = args[0];
119
+ if (!id) {
120
+ context.print('[recall] Usage: /recall get <id>');
121
+ return;
122
+ }
123
+ const record = memory.get(id);
124
+ if (!record) {
125
+ context.print(`[recall] Record not found: ${id}`);
126
+ return;
127
+ }
128
+ const ts = new Date(record.createdAt).toISOString().slice(0, 19).replace('T', ' ');
129
+ context.print(`[recall] ${record.id}`);
130
+ context.print(` Scope: ${record.scope}`);
131
+ context.print(` Class: ${record.cls}`);
132
+ context.print(` Summary: ${record.summary}`);
133
+ if (record.detail) context.print(` Detail: ${record.detail}`);
134
+ if (record.tags.length) context.print(` Tags: ${record.tags.join(', ')}`);
135
+ context.print(` Created: ${ts}`);
136
+
137
+ if (record.provenance.length) {
138
+ context.print(' Provenance:');
139
+ for (const provenance of record.provenance) {
140
+ const label = provenance.label ? ` (${provenance.label})` : '';
141
+ context.print(` ${provenance.kind}: ${provenance.ref}${label}`);
142
+ }
143
+ }
144
+
145
+ const links = memory.linksFor(id);
146
+ if (links.length) {
147
+ context.print(' Links:');
148
+ for (const link of links) {
149
+ const dir = link.fromId === id ? '->' : '<-';
150
+ const other = link.fromId === id ? link.toId : link.fromId;
151
+ context.print(` ${dir} ${other} [${link.relation}]`);
152
+ }
153
+ }
154
+ }
155
+
156
+ export async function handleRecallLink(args: string[], context: CommandContext): Promise<void> {
157
+ const memory = getMemoryApi(context);
158
+ if (!memory) {
159
+ return;
160
+ }
161
+ const [fromId, toId, relation] = args;
162
+ if (!fromId || !toId || !relation) {
163
+ context.print('[recall] Usage: /recall link <fromId> <toId> <relation>');
164
+ return;
165
+ }
166
+ const link = await memory.link(fromId, toId, relation);
167
+ if (!link) {
168
+ context.print('[recall] Link failed — check that both IDs exist.');
169
+ return;
170
+ }
171
+ context.print(`[recall] Linked: ${fromId} -> ${toId} [${relation}]`);
172
+ }
173
+
174
+ export function handleRecallRemove(args: string[], context: CommandContext): void {
175
+ const memory = getMemoryApi(context);
176
+ if (!memory) {
177
+ return;
178
+ }
179
+ const id = args[0];
180
+ if (!id) {
181
+ context.print('[recall] Usage: /recall remove <id>');
182
+ return;
183
+ }
184
+ const removed = memory.delete(id);
185
+ if (!removed) {
186
+ context.print(`[recall] Record not found: ${id}`);
187
+ return;
188
+ }
189
+ context.print(`[recall] Deleted: ${id}`);
190
+ }
191
+
192
+ export function handleRecallList(args: string[], context: CommandContext): void {
193
+ const memory = getMemoryApi(context);
194
+ if (!memory) {
195
+ return;
196
+ }
197
+ const cls = args.find((arg) => !arg.startsWith('--'));
198
+ const filter: MemorySearchFilter = { limit: 50 };
199
+ if (cls && isValidClass(cls)) filter.cls = cls;
200
+ const scopeIdx = args.indexOf('--scope');
201
+ if (scopeIdx !== -1 && args[scopeIdx + 1]) {
202
+ const scope = args[scopeIdx + 1];
203
+ if (!isValidScope(scope)) {
204
+ context.print(`[recall] Unknown scope "${scope}". Valid: ${VALID_SCOPES.join(', ')}`);
205
+ return;
206
+ }
207
+ filter.scope = scope;
208
+ }
209
+
210
+ const records = memory.search(filter);
211
+ if (!records.length) {
212
+ context.print('[recall] No records.');
213
+ return;
214
+ }
215
+
216
+ const grouped: Record<string, Array<(typeof records)[number]>> = {};
217
+ for (const record of records) {
218
+ if (!grouped[record.cls]) grouped[record.cls] = [];
219
+ grouped[record.cls].push(record);
220
+ }
221
+
222
+ for (const [clsName, group] of Object.entries(grouped)) {
223
+ context.print(`\n[recall] ${clsName.toUpperCase()} (${group.length}):`);
224
+ for (const record of group) {
225
+ const tagStr = record.tags.length ? ` [${record.tags.join(', ')}]` : '';
226
+ context.print(` ${record.id} [${record.scope}]${tagStr} ${record.summary}`);
227
+ }
228
+ }
229
+ }
@@ -0,0 +1,98 @@
1
+ import type { CommandContext } from '../command-registry.ts';
2
+ import { VALID_REVIEW_STATES, VALID_SCOPES, isValidReviewState, isValidScope } from './recall-shared.ts';
3
+ import { getMemoryApi } from './recall-query.ts';
4
+
5
+ export function handleRecallQueue(args: string[], context: CommandContext): void {
6
+ const memory = getMemoryApi(context);
7
+ if (!memory) {
8
+ return;
9
+ }
10
+ const limit = Math.max(1, parseInt(args[0] ?? '10', 10) || 10);
11
+ const queue = memory.reviewQueue(limit);
12
+ if (!queue.length) {
13
+ context.print('[recall] Review queue is empty.');
14
+ return;
15
+ }
16
+ context.print(`[recall] Review queue (${queue.length}):`);
17
+ for (const record of queue) {
18
+ const reason = record.staleReason ? ` — ${record.staleReason}` : '';
19
+ context.print(` ${record.id} [${record.scope}/${record.cls}] ${record.reviewState} ${record.confidence}% ${record.summary}${reason}`);
20
+ }
21
+ }
22
+
23
+ export function handleRecallReview(args: string[], context: CommandContext): void {
24
+ const memory = getMemoryApi(context);
25
+ if (!memory) {
26
+ return;
27
+ }
28
+
29
+ const [id, stateRaw, ...rest] = args;
30
+ if (!id || !stateRaw || !isValidReviewState(stateRaw)) {
31
+ context.print(`[recall] Usage: /recall review <id> <${VALID_REVIEW_STATES.join('|')}> [--confidence <0-100>] [--by <name>] [--reason <text>]`);
32
+ return;
33
+ }
34
+
35
+ const confidenceIdx = rest.indexOf('--confidence');
36
+ const byIdx = rest.indexOf('--by');
37
+ const reasonIdx = rest.indexOf('--reason');
38
+ const confidence = confidenceIdx !== -1 ? parseInt(rest[confidenceIdx + 1] ?? '', 10) : undefined;
39
+ const reviewedBy = byIdx !== -1 ? rest[byIdx + 1] : 'operator';
40
+ const staleReason = reasonIdx !== -1 ? rest.slice(reasonIdx + 1).join(' ') : undefined;
41
+
42
+ const record = memory.review(id, {
43
+ state: stateRaw,
44
+ confidence: Number.isFinite(confidence) ? confidence : undefined,
45
+ reviewedBy,
46
+ staleReason,
47
+ });
48
+
49
+ if (!record) {
50
+ context.print(`[recall] Record not found: ${id}`);
51
+ return;
52
+ }
53
+ context.print(`[recall] Reviewed ${record.id}: ${record.reviewState} ${record.confidence}%`);
54
+ }
55
+
56
+ export function handleRecallExplain(args: string[], context: CommandContext): void {
57
+ const memory = getMemoryApi(context);
58
+ if (!memory) {
59
+ return;
60
+ }
61
+ const scopeIdx = args.indexOf('--scope');
62
+ const scopeValues = scopeIdx !== -1 ? args.slice(scopeIdx + 1).filter((token) => !token.startsWith('--')) : [];
63
+ const taskTokens = args.filter((token, index) => {
64
+ if (token === '--scope') return false;
65
+ if (scopeIdx !== -1 && index > scopeIdx) return false;
66
+ return true;
67
+ });
68
+ const task = taskTokens.join(' ').trim();
69
+ if (!task) {
70
+ context.print('[recall] Usage: /recall explain <task description...> [--scope <write-scope> ...]');
71
+ return;
72
+ }
73
+ const explanation = memory.explain(task, scopeValues);
74
+ if (explanation.injections.length === 0) {
75
+ context.print('[recall] No reviewed project knowledge was selected for that task.');
76
+ return;
77
+ }
78
+ context.print(explanation.prompt ?? '[recall] No explainable project knowledge was selected.');
79
+ }
80
+
81
+ export function handleRecallPromote(args: string[], context: CommandContext): void {
82
+ const memory = getMemoryApi(context);
83
+ if (!memory) {
84
+ return;
85
+ }
86
+ const id = args[0];
87
+ const scope = args[1];
88
+ if (!id || !scope || !isValidScope(scope)) {
89
+ context.print(`[recall] Usage: /recall promote <id> <${VALID_SCOPES.join('|')}>`);
90
+ return;
91
+ }
92
+ const record = memory.update(id, { scope });
93
+ if (!record) {
94
+ context.print(`[recall] Record not found: ${id}`);
95
+ return;
96
+ }
97
+ context.print(`[recall] Promoted ${record.id} to ${record.scope} scope.`);
98
+ }
@@ -0,0 +1,22 @@
1
+ import type { ShellPathService } from '@/runtime/index.ts';
2
+ import type { MemoryClass, MemoryReviewState, MemoryScope } from '@pellux/goodvibes-sdk/platform/state';
3
+
4
+ export const VALID_CLASSES: MemoryClass[] = ['decision', 'constraint', 'incident', 'pattern', 'fact', 'risk', 'runbook', 'architecture', 'ownership'];
5
+ export const VALID_SCOPES: MemoryScope[] = ['session', 'project', 'team'];
6
+ export const VALID_REVIEW_STATES: MemoryReviewState[] = ['fresh', 'reviewed', 'stale', 'contradicted'];
7
+
8
+ export function isValidClass(s: string): s is MemoryClass {
9
+ return VALID_CLASSES.includes(s as MemoryClass);
10
+ }
11
+
12
+ export function isValidScope(s: string): s is MemoryScope {
13
+ return VALID_SCOPES.includes(s as MemoryScope);
14
+ }
15
+
16
+ export function isValidReviewState(s: string): s is MemoryReviewState {
17
+ return VALID_REVIEW_STATES.includes(s as MemoryReviewState);
18
+ }
19
+
20
+ export function resolveBundlePath(pathArg: string, shellPaths: ShellPathService): string {
21
+ return shellPaths.resolveWorkspacePath(pathArg);
22
+ }
@@ -0,0 +1,106 @@
1
+ import type { CommandContext } from '../command-registry.ts';
2
+
3
+ type RemotePoolLike = {
4
+ id: string;
5
+ label: string;
6
+ trustClass: string;
7
+ preferredTemplate?: string;
8
+ maxRunners?: number;
9
+ runnerIds: readonly string[];
10
+ description?: string;
11
+ };
12
+
13
+ type RemoteRegistryLike = {
14
+ listPools(): readonly RemotePoolLike[];
15
+ getPool(id: string): RemotePoolLike | null | undefined;
16
+ createPool(input: { id: string; label: string }): RemotePoolLike;
17
+ assignRunnerToPool(poolId: string, runnerId: string): RemotePoolLike | null | undefined;
18
+ removeRunnerFromPool(poolId: string, runnerId: string): RemotePoolLike | null | undefined;
19
+ };
20
+
21
+ export function handleRemotePoolCommand(
22
+ args: string[],
23
+ ctx: Pick<CommandContext, 'print'>,
24
+ remoteRegistry: RemoteRegistryLike,
25
+ ): boolean {
26
+ const subcommand = args[0]?.toLowerCase() ?? 'show';
27
+ if (subcommand !== 'pool') return false;
28
+ const mode = args[1]?.toLowerCase() ?? 'list';
29
+ if (mode === 'list') {
30
+ const pools = remoteRegistry.listPools();
31
+ if (pools.length === 0) {
32
+ ctx.print('No remote runner pools defined yet.');
33
+ return true;
34
+ }
35
+ ctx.print([
36
+ `Remote Runner Pools (${pools.length})`,
37
+ ...pools.map((pool) => ` ${pool.id} ${pool.runnerIds.length} runners trust=${pool.trustClass} template=${pool.preferredTemplate ?? '(none)'}`),
38
+ ].join('\n'));
39
+ return true;
40
+ }
41
+ if (mode === 'show') {
42
+ const poolId = args[2];
43
+ if (!poolId) {
44
+ ctx.print('Usage: /remote pool show <poolId>');
45
+ return true;
46
+ }
47
+ const pool = remoteRegistry.getPool(poolId);
48
+ if (!pool) {
49
+ ctx.print(`Unknown remote runner pool: ${poolId}`);
50
+ return true;
51
+ }
52
+ ctx.print([
53
+ `Remote Runner Pool ${pool.id}`,
54
+ ` label: ${pool.label}`,
55
+ ` trustClass: ${pool.trustClass}`,
56
+ ` preferredTemplate: ${pool.preferredTemplate ?? '(none)'}`,
57
+ ` maxRunners: ${pool.maxRunners ?? '(unbounded)'}`,
58
+ ` runners: ${pool.runnerIds.join(', ') || '(none)'}`,
59
+ ` description: ${pool.description ?? '(none)'}`,
60
+ ].join('\n'));
61
+ return true;
62
+ }
63
+ if (mode === 'create') {
64
+ const poolId = args[2];
65
+ if (!poolId) {
66
+ ctx.print('Usage: /remote pool create <poolId> [label]');
67
+ return true;
68
+ }
69
+ const label = args.slice(3).join(' ').trim() || poolId;
70
+ const pool = remoteRegistry.createPool({ id: poolId, label });
71
+ ctx.print(`Created remote runner pool ${pool.id} (${pool.label}).`);
72
+ return true;
73
+ }
74
+ if (mode === 'assign') {
75
+ const poolId = args[2];
76
+ const runnerId = args[3];
77
+ if (!poolId || !runnerId) {
78
+ ctx.print('Usage: /remote pool assign <poolId> <runnerId>');
79
+ return true;
80
+ }
81
+ const pool = remoteRegistry.assignRunnerToPool(poolId, runnerId);
82
+ if (!pool) {
83
+ ctx.print(`Could not assign ${runnerId} to pool ${poolId}.`);
84
+ return true;
85
+ }
86
+ ctx.print(`Assigned remote runner ${runnerId} to pool ${poolId}.`);
87
+ return true;
88
+ }
89
+ if (mode === 'unassign') {
90
+ const poolId = args[2];
91
+ const runnerId = args[3];
92
+ if (!poolId || !runnerId) {
93
+ ctx.print('Usage: /remote pool unassign <poolId> <runnerId>');
94
+ return true;
95
+ }
96
+ const pool = remoteRegistry.removeRunnerFromPool(poolId, runnerId);
97
+ if (!pool) {
98
+ ctx.print(`Unknown remote runner pool: ${poolId}`);
99
+ return true;
100
+ }
101
+ ctx.print(`Removed remote runner ${runnerId} from pool ${poolId}.`);
102
+ return true;
103
+ }
104
+ ctx.print('Usage: /remote pool <list|show|create|assign|unassign> ...');
105
+ return true;
106
+ }