@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,370 @@
1
+ import {
2
+ CLOUDFLARE_COMPONENT_IDS,
3
+ CLOUDFLARE_COMPONENT_LABELS,
4
+ DEFAULT_CLOUDFLARE_COMPONENT_SELECTION,
5
+ CloudflareDaemonRouteError,
6
+ createCloudflareDaemonClient,
7
+ type CloudflareComponent,
8
+ type CloudflareComponentSelection,
9
+ type CloudflareDaemonClient,
10
+ type CloudflareProvisionStep,
11
+ } from '../../runtime/cloudflare-control-plane.ts';
12
+ import type { CommandContext, CommandRegistry } from '../command-registry.ts';
13
+ import { requireShellPaths } from './runtime-services.ts';
14
+
15
+ interface ParsedCloudflareArgs {
16
+ readonly positional: readonly string[];
17
+ readonly flags: ReadonlyMap<string, readonly string[]>;
18
+ }
19
+
20
+ export function registerCloudflareRuntimeCommands(registry: CommandRegistry): void {
21
+ registry.register({
22
+ name: 'cloudflare',
23
+ aliases: ['cf'],
24
+ description: 'Inspect and manage optional Cloudflare batch/control-plane integration through daemon SDK routes',
25
+ usage: '[status|setup|requirements|create-token|discover|validate|provision|verify|disable] [flags]',
26
+ async handler(args, ctx) {
27
+ const subcommand = (args[0] ?? 'status').toLowerCase();
28
+ const parsed = parseCloudflareArgs(args.slice(1));
29
+ if (subcommand === 'setup' || subcommand === 'onboarding') {
30
+ ctx.openOnboardingWizard?.({ mode: 'edit', reset: true });
31
+ ctx.print('Opening onboarding wizard. Select the Cloudflare batch capability to configure Cloudflare.');
32
+ return;
33
+ }
34
+
35
+ let client: CloudflareDaemonClient;
36
+ try {
37
+ client = createCloudflareClient(ctx);
38
+ } catch (error) {
39
+ ctx.print(`Cloudflare command unavailable: ${formatCloudflareError(error)}`);
40
+ return;
41
+ }
42
+
43
+ try {
44
+ if (subcommand === 'status' || subcommand === 'show') {
45
+ const status = await client.status();
46
+ ctx.print([
47
+ 'Cloudflare Status',
48
+ ` enabled: ${status.enabled ? 'yes' : 'no'}`,
49
+ ` ready: ${status.ready ? 'yes' : 'no'}`,
50
+ ` account: ${status.config.accountId || '(not set)'}`,
51
+ ` token ref: ${status.config.apiTokenRef || '(CLOUDFLARE_API_TOKEN fallback)'}`,
52
+ ` worker: ${status.config.workerName || '(not set)'}`,
53
+ ` worker URL: ${status.config.workerBaseUrl || '(not set)'}`,
54
+ ` queue: ${status.config.queueName || '(not set)'}`,
55
+ ` DLQ: ${status.config.deadLetterQueueName || '(not set)'}`,
56
+ ` tunnel: ${status.config.tunnelName || '(not set)'} ${status.config.tunnelId ? `(${status.config.tunnelId})` : ''}`.trimEnd(),
57
+ ` access app: ${status.config.accessAppId || '(not set)'}`,
58
+ ` batch mode: ${String(ctx.platform.configManager.get('batch.mode') ?? 'off')}`,
59
+ ` queue backend: ${String(ctx.platform.configManager.get('batch.queueBackend') ?? 'local')}`,
60
+ ...status.warnings.map((warning) => ` warning: ${warning}`),
61
+ ].join('\n'));
62
+ return;
63
+ }
64
+
65
+ if (subcommand === 'requirements') {
66
+ const result = await client.tokenRequirements({
67
+ components: componentsFromArgs(parsed),
68
+ includeBootstrap: true,
69
+ });
70
+ ctx.print([
71
+ 'Cloudflare Token Requirements',
72
+ ` components: ${formatComponents(result.components)}`,
73
+ ' permissions:',
74
+ ...result.permissions.map((permission) => ` ${permission.scope}: ${permission.permission} (${permission.component}) - ${permission.reason}`),
75
+ ...(result.bootstrapToken.instructions.length > 0
76
+ ? [' bootstrap token:', ...result.bootstrapToken.instructions.map((line) => ` ${line}`)]
77
+ : []),
78
+ ].join('\n'));
79
+ return;
80
+ }
81
+
82
+ if (subcommand === 'create-token') {
83
+ const bootstrapToken = getFlag(parsed, 'bootstrap-token') || readTokenEnv(parsed, 'bootstrap-env');
84
+ if (!bootstrapToken) {
85
+ ctx.print('Usage: /cloudflare create-token --account <account-id> --bootstrap-token <token> or --bootstrap-env <env-name>');
86
+ return;
87
+ }
88
+ const result = await client.createOperationalToken({
89
+ components: componentsFromArgs(parsed),
90
+ ...optionalString('accountId', getFlag(parsed, 'account') || getFlag(parsed, 'account-id')),
91
+ ...optionalString('zoneId', getFlag(parsed, 'zone-id')),
92
+ ...optionalString('zoneName', getFlag(parsed, 'zone') || getFlag(parsed, 'zone-name')),
93
+ bootstrapToken,
94
+ storeApiToken: true,
95
+ persistConfig: true,
96
+ });
97
+ ctx.print([
98
+ 'Cloudflare Operational Token Created',
99
+ ` token: ${result.tokenName}${result.tokenId ? ` (${result.tokenId})` : ''}`,
100
+ ` account: ${result.accountId}`,
101
+ ` zone: ${result.zoneId || '(none)'}`,
102
+ ` stored ref: ${result.apiTokenRef ?? '(not stored)'}`,
103
+ ' revoke or expire the temporary bootstrap token after validation.',
104
+ ].join('\n'));
105
+ return;
106
+ }
107
+
108
+ if (subcommand === 'discover') {
109
+ const result = await client.discover({
110
+ ...cloudflareAuthInput(parsed),
111
+ components: componentsFromArgs(parsed),
112
+ ...optionalString('zoneId', getFlag(parsed, 'zone-id')),
113
+ ...optionalString('zoneName', getFlag(parsed, 'zone') || getFlag(parsed, 'zone-name')),
114
+ includeResources: !hasFlag(parsed, 'fast'),
115
+ });
116
+ ctx.print([
117
+ 'Cloudflare Discovery',
118
+ ` token source: ${result.tokenSource}`,
119
+ ` accounts: ${result.accounts.length}`,
120
+ ...result.accounts.slice(0, 12).map((account) => ` account ${account.id}: ${account.name}`),
121
+ ` zones: ${result.zones.length}`,
122
+ ...result.zones.slice(0, 12).map((zone) => ` zone ${zone.id}: ${zone.name}${zone.status ? ` (${zone.status})` : ''}`),
123
+ ` worker subdomain: ${result.workerSubdomain || '(not detected)'}`,
124
+ ` queues: ${result.queues?.length ?? 0}`,
125
+ ` KV namespaces: ${result.kvNamespaces?.length ?? 0}`,
126
+ ` R2 buckets: ${result.r2Buckets?.length ?? 0}`,
127
+ ...result.warnings.map((warning) => ` warning: ${warning}`),
128
+ ].join('\n'));
129
+ return;
130
+ }
131
+
132
+ if (subcommand === 'validate') {
133
+ const result = await client.validate(cloudflareAuthInput(parsed));
134
+ ctx.print([
135
+ 'Cloudflare Token Validation',
136
+ ` ok: ${result.ok ? 'yes' : 'no'}`,
137
+ ` token source: ${result.tokenSource}`,
138
+ result.account ? ` account: ${result.account.name} (${result.account.id})` : ' account: not resolved',
139
+ ].join('\n'));
140
+ return;
141
+ }
142
+
143
+ if (subcommand === 'provision') {
144
+ const result = await client.provision({
145
+ ...cloudflareAuthInput(parsed),
146
+ components: componentsFromArgs(parsed),
147
+ ...optionalString('accountId', getFlag(parsed, 'account') || getFlag(parsed, 'account-id')),
148
+ ...optionalString('zoneId', getFlag(parsed, 'zone-id')),
149
+ ...optionalString('zoneName', getFlag(parsed, 'zone') || getFlag(parsed, 'zone-name')),
150
+ ...optionalString('daemonBaseUrl', getFlag(parsed, 'daemon-url')),
151
+ ...optionalString('daemonHostname', getFlag(parsed, 'daemon-hostname')),
152
+ ...optionalString('workerName', getFlag(parsed, 'worker-name')),
153
+ ...optionalString('workerSubdomain', getFlag(parsed, 'worker-subdomain')),
154
+ ...optionalString('workerHostname', getFlag(parsed, 'worker-hostname')),
155
+ ...optionalString('workerBaseUrl', getFlag(parsed, 'worker-url')),
156
+ ...optionalString('queueName', getFlag(parsed, 'queue') || getFlag(parsed, 'queue-name')),
157
+ ...optionalString('deadLetterQueueName', getFlag(parsed, 'dlq') || getFlag(parsed, 'dead-letter-queue')),
158
+ ...optionalString('tunnelName', getFlag(parsed, 'tunnel-name')),
159
+ ...optionalString('tunnelId', getFlag(parsed, 'tunnel-id')),
160
+ ...optionalString('tunnelServiceUrl', getFlag(parsed, 'tunnel-service-url')),
161
+ ...optionalString('tunnelTokenRef', getFlag(parsed, 'tunnel-token-ref')),
162
+ ...optionalString('accessAppId', getFlag(parsed, 'access-app-id')),
163
+ ...optionalString('accessServiceTokenId', getFlag(parsed, 'access-service-token-id')),
164
+ ...optionalString('accessServiceTokenRef', getFlag(parsed, 'access-service-token-ref')),
165
+ ...optionalString('kvNamespaceName', getFlag(parsed, 'kv-namespace-name')),
166
+ ...optionalString('kvNamespaceId', getFlag(parsed, 'kv-namespace-id')),
167
+ ...optionalString('durableObjectNamespaceName', getFlag(parsed, 'do-namespace-name') || getFlag(parsed, 'durable-object-namespace-name')),
168
+ ...optionalString('durableObjectNamespaceId', getFlag(parsed, 'do-namespace-id') || getFlag(parsed, 'durable-object-namespace-id')),
169
+ ...optionalString('r2BucketName', getFlag(parsed, 'r2-bucket-name')),
170
+ ...optionalString('secretsStoreName', getFlag(parsed, 'secrets-store-name')),
171
+ ...optionalString('secretsStoreId', getFlag(parsed, 'secrets-store-id')),
172
+ ...optionalString('workerCron', getFlag(parsed, 'worker-cron')),
173
+ ...optionalString('operatorToken', getFlag(parsed, 'operator-token')),
174
+ ...optionalString('operatorTokenRef', getFlag(parsed, 'operator-token-ref')),
175
+ ...optionalString('workerClientToken', getFlag(parsed, 'worker-client-token')),
176
+ ...optionalString('workerClientTokenRef', getFlag(parsed, 'worker-client-token-ref')),
177
+ ...optionalBatchMode(readBatchMode(parsed)),
178
+ persistConfig: true,
179
+ verify: !hasFlag(parsed, 'no-verify'),
180
+ storeApiToken: !hasFlag(parsed, 'no-store-token'),
181
+ enableWorkersDev: !hasFlag(parsed, 'no-workers-dev'),
182
+ });
183
+ ctx.print([
184
+ 'Cloudflare Provisioning',
185
+ ` ok: ${result.ok ? 'yes' : 'no'}`,
186
+ ...(result.worker ? [` worker: ${result.worker.name}${result.worker.baseUrl ? ` at ${result.worker.baseUrl}` : ''}`] : []),
187
+ ...(result.queues ? [` queues: ${result.queues.queueName}; DLQ ${result.queues.deadLetterQueueName}`] : []),
188
+ ...(result.tunnel ? [` tunnel: ${result.tunnel.name} (${result.tunnel.id})${result.tunnel.hostname ? ` ${result.tunnel.hostname}` : ''}`] : []),
189
+ ...(result.access ? [` access: app=${result.access.appId || '(none)'} serviceToken=${result.access.serviceTokenId || '(none)'}`] : []),
190
+ ...(result.dns ? [` dns: ${result.dns.zoneName || result.dns.zoneId} records=${result.dns.records.length}`] : []),
191
+ ...(result.kv ? [` kv: ${result.kv.namespaceName} (${result.kv.namespaceId})`] : []),
192
+ ...(result.r2 ? [` r2: ${result.r2.bucketName}`] : []),
193
+ ...(result.secretsStore ? [` secrets store: ${result.secretsStore.storeName} (${result.secretsStore.storeId})`] : []),
194
+ ...formatProvisionSteps(result.steps),
195
+ ].join('\n'));
196
+ return;
197
+ }
198
+
199
+ if (subcommand === 'verify') {
200
+ const result = await client.verify({
201
+ ...optionalString('workerBaseUrl', getFlag(parsed, 'worker-url')),
202
+ ...optionalString('workerClientToken', getFlag(parsed, 'worker-token')),
203
+ ...optionalString('workerClientTokenRef', getFlag(parsed, 'worker-token-ref')),
204
+ });
205
+ ctx.print([
206
+ 'Cloudflare Verification',
207
+ ` ok: ${result.ok ? 'yes' : 'no'}`,
208
+ ` worker health: ${result.workerHealth.ok ? 'ok' : 'failed'} (HTTP ${result.workerHealth.status})${result.workerHealth.error ? ` - ${result.workerHealth.error}` : ''}`,
209
+ ...(result.daemonBatchProxy ? [` daemon batch proxy: ${result.daemonBatchProxy.ok ? 'ok' : 'failed'} (HTTP ${result.daemonBatchProxy.status})${result.daemonBatchProxy.error ? ` - ${result.daemonBatchProxy.error}` : ''}`] : []),
210
+ ].join('\n'));
211
+ return;
212
+ }
213
+
214
+ if (subcommand === 'disable') {
215
+ const result = await client.disable({
216
+ ...cloudflareAuthInput(parsed),
217
+ ...optionalString('workerName', getFlag(parsed, 'worker-name')),
218
+ disableWorkerSubdomain: hasFlag(parsed, 'disable-worker-subdomain'),
219
+ disableCron: !hasFlag(parsed, 'keep-cron'),
220
+ persistConfig: true,
221
+ });
222
+ ctx.print([
223
+ 'Cloudflare Disabled',
224
+ ` ok: ${result.ok ? 'yes' : 'no'}`,
225
+ ...formatProvisionSteps(result.steps),
226
+ ].join('\n'));
227
+ return;
228
+ }
229
+
230
+ ctx.print('Usage: /cloudflare [status|setup|requirements|create-token|discover|validate|provision|verify|disable] [flags]');
231
+ } catch (error) {
232
+ ctx.print(`Cloudflare ${subcommand} failed: ${formatCloudflareError(error)}`);
233
+ }
234
+ },
235
+ });
236
+ }
237
+
238
+ function createCloudflareClient(ctx: CommandContext): CloudflareDaemonClient {
239
+ const shellPaths = requireShellPaths(ctx);
240
+ return createCloudflareDaemonClient({
241
+ configManager: ctx.platform.configManager,
242
+ homeDirectory: shellPaths.homeDirectory,
243
+ });
244
+ }
245
+
246
+ function parseCloudflareArgs(args: readonly string[]): ParsedCloudflareArgs {
247
+ const positional: string[] = [];
248
+ const flags = new Map<string, string[]>();
249
+ for (let index = 0; index < args.length; index += 1) {
250
+ const arg = args[index]!;
251
+ if (!arg.startsWith('--')) {
252
+ positional.push(arg);
253
+ continue;
254
+ }
255
+ const raw = arg.slice(2);
256
+ const equalsIndex = raw.indexOf('=');
257
+ if (equalsIndex >= 0) {
258
+ const key = raw.slice(0, equalsIndex);
259
+ const value = raw.slice(equalsIndex + 1);
260
+ flags.set(key, [...(flags.get(key) ?? []), value]);
261
+ continue;
262
+ }
263
+ const next = args[index + 1];
264
+ if (next && !next.startsWith('--')) {
265
+ flags.set(raw, [...(flags.get(raw) ?? []), next]);
266
+ index += 1;
267
+ } else {
268
+ flags.set(raw, [...(flags.get(raw) ?? []), 'true']);
269
+ }
270
+ }
271
+ return { positional, flags };
272
+ }
273
+
274
+ function hasFlag(args: ParsedCloudflareArgs, key: string): boolean {
275
+ return args.flags.has(key);
276
+ }
277
+
278
+ function getFlag(args: ParsedCloudflareArgs, key: string): string {
279
+ const values = args.flags.get(key);
280
+ const value = values?.[values.length - 1] ?? '';
281
+ return value === 'true' ? '' : value.trim();
282
+ }
283
+
284
+ function getFlagValues(args: ParsedCloudflareArgs, key: string): readonly string[] {
285
+ return args.flags.get(key)?.map((value) => value.trim()).filter(Boolean) ?? [];
286
+ }
287
+
288
+ function componentsFromArgs(args: ParsedCloudflareArgs): Record<CloudflareComponent, boolean> {
289
+ const components: Record<CloudflareComponent, boolean> = { ...DEFAULT_CLOUDFLARE_COMPONENT_SELECTION };
290
+ if (hasFlag(args, 'all') || hasFlag(args, 'advanced')) {
291
+ for (const component of CLOUDFLARE_COMPONENT_IDS) components[component] = true;
292
+ }
293
+ for (const raw of [...args.positional, ...getFlagValues(args, 'component')]) {
294
+ const normalized = normalizeComponent(raw);
295
+ if (normalized) components[normalized] = true;
296
+ }
297
+ for (const raw of getFlagValues(args, 'no-component')) {
298
+ const normalized = normalizeComponent(raw);
299
+ if (normalized) components[normalized] = false;
300
+ }
301
+ return components;
302
+ }
303
+
304
+ function normalizeComponent(value: string): CloudflareComponent | null {
305
+ const normalized = value.trim().toLowerCase().replace(/[-_]/g, '');
306
+ for (const component of CLOUDFLARE_COMPONENT_IDS) {
307
+ if (component.toLowerCase() === normalized) return component;
308
+ }
309
+ if (normalized === 'workerscript' || normalized === 'worker') return 'workers';
310
+ if (normalized === 'queue') return 'queues';
311
+ if (normalized === 'tunnel') return 'zeroTrustTunnel';
312
+ if (normalized === 'access') return 'zeroTrustAccess';
313
+ if (normalized === 'domain' || normalized === 'hostname') return 'dns';
314
+ if (normalized === 'do' || normalized === 'durableobject') return 'durableObjects';
315
+ if (normalized === 'secret' || normalized === 'secrets') return 'secretsStore';
316
+ return null;
317
+ }
318
+
319
+ function formatComponents(components: CloudflareComponentSelection): string {
320
+ const selected = CLOUDFLARE_COMPONENT_IDS
321
+ .filter((component) => components[component] === true)
322
+ .map((component) => CLOUDFLARE_COMPONENT_LABELS[component]);
323
+ return selected.length > 0 ? selected.join(', ') : 'none';
324
+ }
325
+
326
+ function cloudflareAuthInput(args: ParsedCloudflareArgs): {
327
+ readonly accountId?: string;
328
+ readonly apiToken?: string;
329
+ readonly apiTokenRef?: string;
330
+ } {
331
+ const token = getFlag(args, 'token') || readTokenEnv(args, 'token-env');
332
+ const tokenRef = getFlag(args, 'token-ref');
333
+ return {
334
+ ...optionalString('accountId', getFlag(args, 'account') || getFlag(args, 'account-id')),
335
+ ...(token ? { apiToken: token } : tokenRef ? { apiTokenRef: tokenRef } : {}),
336
+ };
337
+ }
338
+
339
+ function readTokenEnv(args: ParsedCloudflareArgs, key: string): string {
340
+ const envName = getFlag(args, key);
341
+ if (!envName) return '';
342
+ return process.env[envName] ?? '';
343
+ }
344
+
345
+ function readBatchMode(args: ParsedCloudflareArgs): 'off' | 'explicit' | 'eligible-by-default' | undefined {
346
+ const value = getFlag(args, 'batch-mode');
347
+ if (value === 'off' || value === 'explicit' || value === 'eligible-by-default') return value;
348
+ return undefined;
349
+ }
350
+
351
+ function optionalString<K extends string>(key: K, value: string): Partial<Record<K, string>> {
352
+ return value.trim().length > 0 ? { [key]: value.trim() } as Partial<Record<K, string>> : {};
353
+ }
354
+
355
+ function optionalBatchMode(value: ReturnType<typeof readBatchMode>): { readonly batchMode?: 'off' | 'explicit' | 'eligible-by-default' } {
356
+ return value ? { batchMode: value } : {};
357
+ }
358
+
359
+ function formatProvisionSteps(steps: readonly CloudflareProvisionStep[]): string[] {
360
+ return steps.length > 0
361
+ ? steps.map((step) => ` ${step.status}: ${step.name}${step.message ? ` - ${step.message}` : ''}`)
362
+ : [' no steps returned'];
363
+ }
364
+
365
+ function formatCloudflareError(error: unknown): string {
366
+ if (error instanceof CloudflareDaemonRouteError) {
367
+ return `${error.message} (HTTP ${error.status}, ${error.code})`;
368
+ }
369
+ return error instanceof Error ? error.message : String(error);
370
+ }
@@ -0,0 +1,18 @@
1
+ import type { CommandRegistry } from '../command-registry.ts';
2
+
3
+ export function registerConfigCommand(registry: CommandRegistry): void {
4
+ registry.register({
5
+ name: 'config',
6
+ aliases: ['cfg'],
7
+ description: 'Open the fullscreen configuration workspace',
8
+ usage: '[category|key]',
9
+ argsHint: '[category|key]',
10
+ handler(args, ctx) {
11
+ if (ctx.openSettingsModal) {
12
+ ctx.openSettingsModal(args[0]);
13
+ return;
14
+ }
15
+ ctx.print('Fullscreen config workspace is not available in this runtime.');
16
+ },
17
+ });
18
+ }
@@ -0,0 +1,255 @@
1
+ import type { CommandRegistry } from '../command-registry.ts';
2
+ import { buildMcpAttackPathReview } from '@/runtime/index.ts';
3
+ import { buildKnowledgeInjectionPrompt, selectKnowledgeForTask } from '@pellux/goodvibes-sdk/platform/state';
4
+ import { listBuiltinSubscriptionProviders } from '@pellux/goodvibes-sdk/platform/config';
5
+ import { requireReadModels, requireSubscriptionManager, requireTokenAuditor } from './runtime-services.ts';
6
+ import { getMemoryApi } from './recall-query.ts';
7
+
8
+ export function registerControlRoomRuntimeCommands(registry: CommandRegistry): void {
9
+ registry.register({
10
+ name: 'cockpit',
11
+ aliases: [],
12
+ description: 'Open the unified operator cockpit',
13
+ usage: '',
14
+ handler(_args, ctx) {
15
+ if (ctx.openCockpitPanel) {
16
+ ctx.openCockpitPanel();
17
+ return;
18
+ }
19
+ ctx.print('Cockpit panel is not available in this runtime.');
20
+ },
21
+ });
22
+
23
+ registry.register({
24
+ name: 'orchestration',
25
+ aliases: ['orch'],
26
+ description: 'Inspect orchestration graphs and cancel active graphs or subtrees',
27
+ usage: '[show [graphId] | cancel graph <graphId> | cancel subtree <agentId>]',
28
+ handler(args, ctx) {
29
+ const graphs = [...requireReadModels(ctx).orchestration.getSnapshot().graphs];
30
+ if (args.length === 0) {
31
+ if (ctx.openOrchestrationPanel) {
32
+ ctx.openOrchestrationPanel();
33
+ return;
34
+ }
35
+ if (graphs.length === 0) {
36
+ ctx.print('Orchestration panel is not available in this runtime.');
37
+ return;
38
+ }
39
+ }
40
+ const subcommand = args[0]?.toLowerCase() ?? 'show';
41
+
42
+ if (subcommand === 'show') {
43
+ const graphId = args[1];
44
+ const graph = graphId ? graphs.find((entry) => entry.id === graphId) : graphs[0];
45
+ if (!graph) {
46
+ ctx.print(graphId ? `Unknown orchestration graph: ${graphId}` : 'No orchestration graphs recorded yet.');
47
+ return;
48
+ }
49
+ const lines = [
50
+ `Graph ${graph.id}`,
51
+ ` title: ${graph.title}`,
52
+ ` status: ${graph.status}`,
53
+ ` mode: ${graph.mode}`,
54
+ ` nodes: ${graph.nodeOrder.length}`,
55
+ ];
56
+ if (graph.lastRecursionGuard) {
57
+ lines.push(` last guard: depth ${graph.lastRecursionGuard.depth}, active ${graph.lastRecursionGuard.activeAgents}, ${graph.lastRecursionGuard.reason}`);
58
+ }
59
+ for (const nodeId of graph.nodeOrder.slice(0, 12)) {
60
+ const node = graph.nodes.get(nodeId);
61
+ if (!node) continue;
62
+ lines.push(` - ${node.id} ${node.role} ${node.status} ${node.title}`);
63
+ }
64
+ ctx.print(lines.join('\n'));
65
+ return;
66
+ }
67
+
68
+ if (subcommand === 'cancel') {
69
+ const mode = args[1]?.toLowerCase();
70
+ const target = args[2];
71
+ const manager = ctx.ops.agentManager;
72
+ if (!manager) {
73
+ ctx.print('Agent manager is not available in this runtime.');
74
+ return;
75
+ }
76
+ if (!mode || !target) {
77
+ ctx.print('Usage: /orchestration cancel graph <graphId> | /orchestration cancel subtree <agentId>');
78
+ return;
79
+ }
80
+ if (mode === 'graph') {
81
+ const cancelled = manager.cancelGraph(target);
82
+ ctx.print(cancelled.length > 0
83
+ ? `Cancelled ${cancelled.length} agent${cancelled.length !== 1 ? 's' : ''} in graph ${target}.`
84
+ : `No cancellable agents found in graph ${target}.`);
85
+ return;
86
+ }
87
+ if (mode === 'subtree') {
88
+ const cancelled = manager.cancelSubtree(target);
89
+ ctx.print(cancelled.length > 0
90
+ ? `Cancelled ${cancelled.length} agent${cancelled.length !== 1 ? 's' : ''} in subtree rooted at ${target}.`
91
+ : `No cancellable agents found in subtree rooted at ${target}.`);
92
+ return;
93
+ }
94
+ ctx.print(`Unknown orchestration cancel target: ${mode}`);
95
+ return;
96
+ }
97
+
98
+ ctx.print(`Unknown orchestration subcommand: ${subcommand}`);
99
+ },
100
+ });
101
+
102
+ registry.register({
103
+ name: 'communication',
104
+ aliases: ['comms'],
105
+ description: 'Inspect structured agent communication routes and recent activity',
106
+ usage: '',
107
+ handler(_args, ctx) {
108
+ if (ctx.openCommunicationPanel) {
109
+ ctx.openCommunicationPanel();
110
+ return;
111
+ }
112
+ ctx.print('Communication panel is not available in this runtime.');
113
+ },
114
+ });
115
+
116
+ registry.register({
117
+ name: 'security',
118
+ aliases: [],
119
+ description: 'Inspect security posture, attack paths, and review state',
120
+ usage: '[review | attack-paths | tokens]',
121
+ handler(args, ctx) {
122
+ if (args.length === 0) {
123
+ if (ctx.openSecurityPanel) {
124
+ ctx.openSecurityPanel();
125
+ return;
126
+ }
127
+ ctx.print('Security panel is not available in this runtime.');
128
+ return;
129
+ }
130
+
131
+ const subcommand = args[0]?.toLowerCase() ?? 'review';
132
+ const audit = requireTokenAuditor(ctx).auditAll(Date.now());
133
+ const securitySnapshot = requireReadModels(ctx).security.getSnapshot();
134
+ const policySnapshot = ctx.extensions.policyRuntimeState?.getSnapshot();
135
+ if (!policySnapshot) {
136
+ ctx.print('Policy runtime state is not available in this runtime.');
137
+ return;
138
+ }
139
+ const attackPaths = buildMcpAttackPathReview({
140
+ servers: securitySnapshot.mcpServers,
141
+ recentDecisions: securitySnapshot.recentMcpDecisions,
142
+ });
143
+
144
+ if (subcommand === 'tokens') {
145
+ if (audit.results.length === 0) {
146
+ ctx.print('No registered API tokens are currently under audit.');
147
+ return;
148
+ }
149
+ ctx.print([
150
+ `Token Audit (${audit.results.length})`,
151
+ ...audit.results.map((result) => (
152
+ ` ${result.label} policy=${result.scope.policyId} scope=${result.scope.outcome} rotation=${result.rotation.outcome} blocked=${result.blocked ? 'yes' : 'no'}`
153
+ )),
154
+ ].join('\n'));
155
+ return;
156
+ }
157
+
158
+ if (subcommand === 'attack-paths') {
159
+ if (attackPaths.findings.length === 0) {
160
+ ctx.print('No MCP attack-path findings are currently active.');
161
+ return;
162
+ }
163
+ ctx.print([
164
+ `MCP Attack-Path Review`,
165
+ ` summary: ${attackPaths.summary}`,
166
+ ...attackPaths.findings.slice(0, 12).map((finding) => (
167
+ ` ${finding.severity.toUpperCase()} ${finding.serverName} ${finding.route}\n ${finding.reason}`
168
+ )),
169
+ ].join('\n'));
170
+ return;
171
+ }
172
+
173
+ const plugins = ctx.extensions.pluginManager?.list() ?? [];
174
+ const subscriptions = requireSubscriptionManager(ctx);
175
+ const builtinProviders = listBuiltinSubscriptionProviders();
176
+ ctx.print([
177
+ 'Security Review',
178
+ ` tokens: ${audit.results.length}`,
179
+ ` blocked tokens: ${audit.blocked.length}`,
180
+ ` scope violations: ${audit.scopeViolations.length}`,
181
+ ` rotation overdue: ${audit.rotationOverdue.length}`,
182
+ ` rotation warnings: ${audit.rotationWarnings.length}`,
183
+ ` built-in subscription providers: ${builtinProviders.length}`,
184
+ ` active subscriptions: ${subscriptions.list().length}`,
185
+ ` pending subscriptions: ${subscriptions.listPending().length}`,
186
+ ` policy lint findings: ${policySnapshot.lintFindings.length}`,
187
+ ` policy preflight: ${policySnapshot.lastPreflightReview?.status ?? 'n/a'}`,
188
+ ` mcp servers: ${securitySnapshot.mcpServers.length}`,
189
+ ` mcp quarantined: ${securitySnapshot.mcpServers.filter((server) => server.schemaFreshness === 'quarantined').length}`,
190
+ ` mcp elevated: ${securitySnapshot.mcpServers.filter((server) => server.trustMode === 'allow-all').length}`,
191
+ ` mcp attack-path findings: ${attackPaths.findings.length}`,
192
+ ` quarantined plugins: ${plugins.filter((plugin) => plugin.quarantined).length}`,
193
+ ` untrusted plugins: ${plugins.filter((plugin) => plugin.trustTier === 'untrusted').length}`,
194
+ ].join('\n'));
195
+ },
196
+ });
197
+
198
+ registry.register({
199
+ name: 'knowledge',
200
+ aliases: ['know'],
201
+ description: 'Inspect durable project knowledge, risks, runbooks, and architecture notes',
202
+ usage: '[open | queue [limit] | explain <task...> [--scope <path> ...]]',
203
+ handler(args, ctx) {
204
+ const subcommand = (args[0] ?? 'open').toLowerCase();
205
+ if (subcommand === 'open') {
206
+ if (ctx.openKnowledgePanel) {
207
+ ctx.openKnowledgePanel();
208
+ return;
209
+ }
210
+ ctx.print('Knowledge panel is not available in this runtime.');
211
+ return;
212
+ }
213
+ const memory = getMemoryApi(ctx);
214
+ if (!memory) return;
215
+ if (subcommand === 'queue') {
216
+ const limit = Math.max(1, parseInt(args[1] ?? '10', 10) || 10);
217
+ const queue = memory.reviewQueue(limit);
218
+ if (queue.length === 0) {
219
+ ctx.print('Knowledge review queue is empty.');
220
+ return;
221
+ }
222
+ ctx.print([
223
+ `Knowledge Review Queue (${queue.length})`,
224
+ ...queue.map((record) => ` ${record.id} [${record.scope}/${record.cls}] ${record.reviewState} ${record.confidence}% ${record.summary}`),
225
+ ].join('\n'));
226
+ return;
227
+ }
228
+ if (subcommand === 'explain') {
229
+ const scopeIdx = args.indexOf('--scope');
230
+ const scopeValues = scopeIdx !== -1
231
+ ? args.slice(scopeIdx + 1).filter((token) => !token.startsWith('--'))
232
+ : [];
233
+ const taskTokens = args.slice(1).filter((token, index) => {
234
+ if (token === '--scope') return false;
235
+ if (scopeIdx !== -1 && index + 1 > scopeIdx) return false;
236
+ return true;
237
+ });
238
+ const task = taskTokens.join(' ').trim();
239
+ if (!task) {
240
+ ctx.print('Usage: /knowledge explain <task...> [--scope <path> ...]');
241
+ return;
242
+ }
243
+ const injections = selectKnowledgeForTask(memory, task, scopeValues);
244
+ const prompt = buildKnowledgeInjectionPrompt(injections);
245
+ ctx.print(prompt ?? 'No reviewed project knowledge matched that task.');
246
+ return;
247
+ }
248
+ if (ctx.openKnowledgePanel) {
249
+ ctx.openKnowledgePanel();
250
+ return;
251
+ }
252
+ ctx.print(`Unknown knowledge subcommand: ${subcommand}`);
253
+ },
254
+ });
255
+ }