@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,351 @@
1
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
2
+ import { dirname, join, resolve } from 'node:path';
3
+ import type { CommandContext, CommandRegistry } from '../command-registry.ts';
4
+ import { listInstalledEcosystemEntries, loadEcosystemCatalog } from '@/runtime/index.ts';
5
+ import { BUILTIN_SUITES } from '@/runtime/index.ts';
6
+ import { requireEcosystemCatalogPaths, requireReadModels, requireSecretsManager, requireServiceRegistry, requireShellPaths } from './runtime-services.ts';
7
+
8
+ interface TrustReviewBundle {
9
+ readonly version: 1;
10
+ readonly capturedAt: number;
11
+ readonly permissionMode: string;
12
+ readonly secretKeys: readonly string[];
13
+ readonly serviceNames: readonly string[];
14
+ readonly pluginSummary: {
15
+ readonly total: number;
16
+ readonly trusted: number;
17
+ readonly limited: number;
18
+ readonly untrusted: number;
19
+ readonly quarantined: number;
20
+ };
21
+ readonly mcpSummary: {
22
+ readonly total: number;
23
+ readonly constrained: number;
24
+ readonly askOnRisk: number;
25
+ readonly allowAll: number;
26
+ readonly blocked: number;
27
+ readonly quarantined: number;
28
+ };
29
+ }
30
+
31
+ interface ReleaseBundle {
32
+ readonly version: 1;
33
+ readonly capturedAt: number;
34
+ readonly runtime: {
35
+ readonly provider: string;
36
+ readonly model: string;
37
+ readonly sessionId: string;
38
+ };
39
+ readonly evalSuites: readonly string[];
40
+ readonly incidentCount: number;
41
+ readonly remote: {
42
+ readonly pools: number;
43
+ readonly contracts: number;
44
+ readonly artifacts: number;
45
+ };
46
+ readonly ecosystem: {
47
+ readonly pluginCatalog: number;
48
+ readonly skillCatalog: number;
49
+ readonly installedPlugins: number;
50
+ readonly installedSkills: number;
51
+ };
52
+ }
53
+
54
+ function countByMode<T extends string>(values: readonly T[], mode: T): number {
55
+ return values.filter((value) => value === mode).length;
56
+ }
57
+
58
+ function buildTrustReviewBundle(ctx: CommandContext): Promise<TrustReviewBundle> {
59
+ return (async () => {
60
+ const secretKeys = await requireSecretsManager(ctx).list();
61
+ const services = Object.keys(requireServiceRegistry(ctx).getAll()).sort((a, b) => a.localeCompare(b));
62
+ const security = requireReadModels(ctx).security.getSnapshot();
63
+ const plugins = security.plugins;
64
+ const mcpServers = security.mcpServers;
65
+ return {
66
+ version: 1,
67
+ capturedAt: Date.now(),
68
+ permissionMode: String(ctx.platform.configManager.get('permissions.mode')),
69
+ secretKeys,
70
+ serviceNames: services,
71
+ pluginSummary: {
72
+ total: plugins.length,
73
+ trusted: plugins.filter((plugin) => plugin.trustTier === 'trusted').length,
74
+ limited: plugins.filter((plugin) => plugin.trustTier === 'limited').length,
75
+ untrusted: plugins.filter((plugin) => plugin.trustTier === 'untrusted').length,
76
+ quarantined: plugins.filter((plugin) => plugin.quarantined).length,
77
+ },
78
+ mcpSummary: {
79
+ total: mcpServers.length,
80
+ constrained: countByMode(mcpServers.map((server) => server.trustMode), 'constrained'),
81
+ askOnRisk: countByMode(mcpServers.map((server) => server.trustMode), 'ask-on-risk'),
82
+ allowAll: countByMode(mcpServers.map((server) => server.trustMode), 'allow-all'),
83
+ blocked: countByMode(mcpServers.map((server) => server.trustMode), 'blocked'),
84
+ quarantined: mcpServers.filter((server) => server.schemaFreshness === 'quarantined').length,
85
+ },
86
+ };
87
+ })();
88
+ }
89
+
90
+ function formatTrustReview(bundle: TrustReviewBundle): string {
91
+ return [
92
+ 'Trust Review',
93
+ ` permission mode: ${bundle.permissionMode}`,
94
+ ` secrets stored: ${bundle.secretKeys.length}`,
95
+ ` configured services: ${bundle.serviceNames.length}`,
96
+ ` plugins: ${bundle.pluginSummary.total} (trusted ${bundle.pluginSummary.trusted}, limited ${bundle.pluginSummary.limited}, untrusted ${bundle.pluginSummary.untrusted}, quarantined ${bundle.pluginSummary.quarantined})`,
97
+ ` MCP servers: ${bundle.mcpSummary.total} (constrained ${bundle.mcpSummary.constrained}, ask-on-risk ${bundle.mcpSummary.askOnRisk}, allow-all ${bundle.mcpSummary.allowAll}, blocked ${bundle.mcpSummary.blocked}, quarantined ${bundle.mcpSummary.quarantined})`,
98
+ ].join('\n');
99
+ }
100
+
101
+ function inspectTrustBundle(path: string): string {
102
+ const parsed = JSON.parse(readFileSync(path, 'utf-8')) as TrustReviewBundle;
103
+ return [
104
+ 'Trust Bundle Review',
105
+ ` captured: ${new Date(parsed.capturedAt).toISOString()}`,
106
+ ` permission mode: ${parsed.permissionMode}`,
107
+ ` secrets stored: ${parsed.secretKeys.length}`,
108
+ ` configured services: ${parsed.serviceNames.length}`,
109
+ ` plugins: ${parsed.pluginSummary.total}`,
110
+ ` MCP servers: ${parsed.mcpSummary.total}`,
111
+ ].join('\n');
112
+ }
113
+
114
+ function buildReleaseBundle(ctx: Parameters<NonNullable<CommandRegistry['register']>>[0]['handler'] extends (args: string[], context: infer C) => unknown ? C : never): ReleaseBundle {
115
+ const remoteRuntime = ctx.ops.remoteRuntime;
116
+ const incidents = ctx.extensions.forensicsRegistry?.getAll() ?? [];
117
+ const ecosystemPaths = requireEcosystemCatalogPaths(ctx);
118
+ return {
119
+ version: 1,
120
+ capturedAt: Date.now(),
121
+ runtime: {
122
+ provider: ctx.session.runtime.provider,
123
+ model: ctx.session.runtime.model,
124
+ sessionId: ctx.session.runtime.sessionId,
125
+ },
126
+ evalSuites: Object.keys(BUILTIN_SUITES),
127
+ incidentCount: incidents.length,
128
+ remote: {
129
+ pools: remoteRuntime?.listPools().length ?? 0,
130
+ contracts: remoteRuntime?.listContracts().length ?? 0,
131
+ artifacts: remoteRuntime?.listArtifacts().length ?? 0,
132
+ },
133
+ ecosystem: {
134
+ pluginCatalog: loadEcosystemCatalog('plugin', ecosystemPaths).length,
135
+ skillCatalog: loadEcosystemCatalog('skill', ecosystemPaths).length,
136
+ installedPlugins: listInstalledEcosystemEntries('plugin', ecosystemPaths).length,
137
+ installedSkills: listInstalledEcosystemEntries('skill', ecosystemPaths).length,
138
+ },
139
+ };
140
+ }
141
+
142
+ function inspectReleaseBundle(path: string): string {
143
+ const parsed = JSON.parse(readFileSync(path, 'utf-8')) as ReleaseBundle;
144
+ return [
145
+ 'Release Bundle Review',
146
+ ` provider/model: ${parsed.runtime.provider || '(unset)'}/${parsed.runtime.model || '(unset)'}`,
147
+ ` eval suites: ${parsed.evalSuites.length}`,
148
+ ` incidents: ${parsed.incidentCount}`,
149
+ ` remote pools/contracts/artifacts: ${parsed.remote.pools}/${parsed.remote.contracts}/${parsed.remote.artifacts}`,
150
+ ` ecosystem catalog plugins/skills: ${parsed.ecosystem.pluginCatalog}/${parsed.ecosystem.skillCatalog}`,
151
+ ].join('\n');
152
+ }
153
+
154
+ export function registerProductRuntimeCommands(registry: CommandRegistry): void {
155
+ registry.register({
156
+ name: 'trust',
157
+ description: 'Review trust posture and export portable trust bundles',
158
+ usage: '[review|bundle export <path>|bundle inspect <path>]',
159
+ async handler(args, ctx) {
160
+ const shellPaths = requireShellPaths(ctx);
161
+ const sub = args[0] ?? 'review';
162
+ if (sub === 'review') {
163
+ const bundle = await buildTrustReviewBundle(ctx);
164
+ ctx.print(formatTrustReview(bundle));
165
+ return;
166
+ }
167
+ if (sub === 'bundle') {
168
+ const mode = args[1];
169
+ const pathArg = args[2];
170
+ if ((mode === 'export' || mode === 'inspect') && !pathArg) {
171
+ ctx.print(`Usage: /trust bundle ${mode} <path>`);
172
+ return;
173
+ }
174
+ if (mode === 'export') {
175
+ const bundle = await buildTrustReviewBundle(ctx);
176
+ const targetPath = shellPaths.resolveWorkspacePath(pathArg!);
177
+ mkdirSync(dirname(targetPath), { recursive: true });
178
+ writeFileSync(targetPath, JSON.stringify(bundle, null, 2) + '\n', 'utf-8');
179
+ ctx.print(`Trust bundle exported to ${targetPath}`);
180
+ return;
181
+ }
182
+ if (mode === 'inspect') {
183
+ ctx.print(inspectTrustBundle(shellPaths.resolveWorkspacePath(pathArg!)));
184
+ return;
185
+ }
186
+ }
187
+ ctx.print('Usage: /trust [review|bundle export <path>|bundle inspect <path>]');
188
+ },
189
+ });
190
+ registry.register({
191
+ name: 'bridge',
192
+ description: 'Review and operate self-hosted bridge and remote runner flows',
193
+ usage: '[status|pools|assign <pool> <runner>|runner <id>|review <artifactId>|export <artifactId> [path]|import <path>]',
194
+ async handler(args, ctx) {
195
+ const shellPaths = requireShellPaths(ctx);
196
+ if (!ctx.ops.remoteRuntime) {
197
+ ctx.print('Remote runner registry is not available in this runtime.');
198
+ return;
199
+ }
200
+ const remoteRegistry = ctx.ops.remoteRuntime;
201
+ const sub = args[0] ?? 'status';
202
+ if (sub === 'status') {
203
+ const remote = requireReadModels(ctx).remote.getSnapshot();
204
+ ctx.print([
205
+ 'Bridge Status',
206
+ ` remote pools: ${remote.pools.length}`,
207
+ ` runner contracts: ${remote.contracts.length}`,
208
+ ` review artifacts: ${remote.artifacts.length}`,
209
+ ].join('\n'));
210
+ return;
211
+ }
212
+ if (sub === 'pools') {
213
+ const pools = remoteRegistry.listPools();
214
+ ctx.print(pools.length > 0
215
+ ? ['Bridge Pools', ...pools.map((pool) => ` ${pool.id} runners=${pool.runnerIds.length} trust=${pool.trustClass}`)].join('\n')
216
+ : 'Bridge Pools\n No runner pools registered yet.');
217
+ return;
218
+ }
219
+ if (sub === 'assign') {
220
+ const poolId = args[1];
221
+ const runnerId = args[2];
222
+ if (!poolId || !runnerId) {
223
+ ctx.print('Usage: /bridge assign <pool> <runner>');
224
+ return;
225
+ }
226
+ const pool = remoteRegistry.assignRunnerToPool(poolId, runnerId);
227
+ if (!pool) {
228
+ ctx.print(`Unable to assign runner ${runnerId} to pool ${poolId}.`);
229
+ return;
230
+ }
231
+ ctx.print(`Assigned runner ${runnerId} to bridge pool ${poolId}.`);
232
+ return;
233
+ }
234
+ if (sub === 'runner') {
235
+ const runnerId = args[1];
236
+ if (!runnerId) {
237
+ ctx.print('Usage: /bridge runner <id>');
238
+ return;
239
+ }
240
+ const contract = remoteRegistry.getContract(runnerId);
241
+ if (!contract) {
242
+ ctx.print(`Unknown runner contract: ${runnerId}`);
243
+ return;
244
+ }
245
+ ctx.print([
246
+ `Bridge Runner ${runnerId}`,
247
+ ` template: ${contract.template}`,
248
+ ` trustClass: ${contract.trustClass}`,
249
+ ` transport: ${contract.sourceTransport}/${contract.transport.state}`,
250
+ ` tools: ${contract.capabilityCeiling.allowedTools.join(', ') || '(none)'}`,
251
+ ` pool: ${contract.poolId ?? '(unassigned)'}`,
252
+ ].join('\n'));
253
+ return;
254
+ }
255
+ if (sub === 'review') {
256
+ const artifactId = args[1];
257
+ if (!artifactId) {
258
+ ctx.print('Usage: /bridge review <artifactId>');
259
+ return;
260
+ }
261
+ const summary = remoteRegistry.buildReviewSummary(artifactId);
262
+ ctx.print(summary ?? `Unknown remote artifact: ${artifactId}`);
263
+ return;
264
+ }
265
+ if (sub === 'export') {
266
+ const artifactId = args[1];
267
+ if (!artifactId) {
268
+ ctx.print('Usage: /bridge export <artifactId> [path]');
269
+ return;
270
+ }
271
+ const exported = await remoteRegistry.exportArtifact(
272
+ artifactId,
273
+ args[2] ? shellPaths.resolveWorkspacePath(args[2]) : undefined,
274
+ );
275
+ if (!exported) {
276
+ ctx.print(`Unknown remote artifact: ${artifactId}`);
277
+ return;
278
+ }
279
+ ctx.print(`Exported remote bridge artifact to ${exported.path}`);
280
+ return;
281
+ }
282
+ if (sub === 'import') {
283
+ const pathArg = args[1];
284
+ if (!pathArg) {
285
+ ctx.print('Usage: /bridge import <path>');
286
+ return;
287
+ }
288
+ const artifact = await remoteRegistry.importArtifact(shellPaths.resolveWorkspacePath(pathArg));
289
+ ctx.print(`Imported remote bridge artifact ${artifact.id} for runner ${artifact.runnerId}.`);
290
+ return;
291
+ }
292
+ ctx.print('Usage: /bridge [status|pools|assign <pool> <runner>|runner <id>|review <artifactId>|export <artifactId> [path]|import <path>]');
293
+ },
294
+ });
295
+
296
+ registry.register({
297
+ name: 'release',
298
+ description: 'Package certification and release-readiness operations',
299
+ usage: '[review|checklist|bundle export <path>|bundle inspect <path>]',
300
+ handler(args, ctx) {
301
+ const shellPaths = requireShellPaths(ctx);
302
+ const sub = args[0] ?? 'review';
303
+ if (sub === 'review') {
304
+ const bundle = buildReleaseBundle(ctx);
305
+ ctx.print([
306
+ 'Release Review',
307
+ ` provider/model: ${bundle.runtime.provider || '(unset)'}/${bundle.runtime.model || '(unset)'}`,
308
+ ` eval suites: ${bundle.evalSuites.length}`,
309
+ ` incidents: ${bundle.incidentCount}`,
310
+ ` remote pools/contracts/artifacts: ${bundle.remote.pools}/${bundle.remote.contracts}/${bundle.remote.artifacts}`,
311
+ ` ecosystem catalog plugins/skills: ${bundle.ecosystem.pluginCatalog}/${bundle.ecosystem.skillCatalog}`,
312
+ ` installed plugins/skills: ${bundle.ecosystem.installedPlugins}/${bundle.ecosystem.installedSkills}`,
313
+ ].join('\n'));
314
+ return;
315
+ }
316
+ if (sub === 'checklist') {
317
+ ctx.print([
318
+ 'Release Checklist',
319
+ ' 1. Run /setup review and /setup doctor',
320
+ ' 2. Run /security review and /trust review',
321
+ ' 3. Run /policy preflight and /policy simulate',
322
+ ' 4. Run /eval gate <suite> for required certification suites',
323
+ ' 5. Review /incident latest and /bridge status',
324
+ ' 6. Export /release bundle export <path> for release evidence',
325
+ ].join('\n'));
326
+ return;
327
+ }
328
+ if (sub === 'bundle') {
329
+ const mode = args[1];
330
+ const pathArg = args[2];
331
+ if ((mode === 'export' || mode === 'inspect') && !pathArg) {
332
+ ctx.print(`Usage: /release bundle ${mode} <path>`);
333
+ return;
334
+ }
335
+ if (mode === 'export') {
336
+ const bundle = buildReleaseBundle(ctx);
337
+ const targetPath = shellPaths.resolveWorkspacePath(pathArg!);
338
+ mkdirSync(dirname(targetPath), { recursive: true });
339
+ writeFileSync(targetPath, JSON.stringify(bundle, null, 2) + '\n', 'utf-8');
340
+ ctx.print(`Release bundle exported to ${targetPath}`);
341
+ return;
342
+ }
343
+ if (mode === 'inspect') {
344
+ ctx.print(inspectReleaseBundle(shellPaths.resolveWorkspacePath(pathArg!)));
345
+ return;
346
+ }
347
+ }
348
+ ctx.print('Usage: /release [review|checklist|bundle export <path>|bundle inspect <path>]');
349
+ },
350
+ });
351
+ }
@@ -0,0 +1,99 @@
1
+ import { mkdirSync, readFileSync, writeFileSync } from 'node:fs';
2
+ import { dirname, resolve } from 'node:path';
3
+ import type { CommandRegistry } from '../command-registry.ts';
4
+ import type { ProfileBundleEntry, ProfileSyncBundle } from '@/runtime/index.ts';
5
+ import { recordSettingsSyncEvent, recordSettingsSyncFailure } from '@/runtime/index.ts';
6
+ import { requireProfileManager, requireShellPaths } from './runtime-services.ts';
7
+
8
+ function inspectProfileSyncBundle(bundle: ProfileSyncBundle): string {
9
+ return [
10
+ 'Profile Sync Bundle Review',
11
+ ` exportedAt: ${new Date(bundle.exportedAt).toISOString()}`,
12
+ ` profiles: ${bundle.profiles.length}`,
13
+ ` activeProfile: ${bundle.activeProfile ?? '(none)'}`,
14
+ ].join('\n');
15
+ }
16
+
17
+ export function registerProfileSyncRuntimeCommands(registry: CommandRegistry): void {
18
+ registry.register({
19
+ name: 'profilesync',
20
+ description: 'Export, import, and inspect profile sync bundles',
21
+ usage: '[list|export <path>|inspect <path>|import <path> [prefix]]',
22
+ handler(args, ctx) {
23
+ const shellPaths = requireShellPaths(ctx);
24
+ const controlPlaneConfigDir = ctx.platform.configManager.getControlPlaneConfigDir();
25
+ const sub = args[0] ?? 'list';
26
+ const pm = requireProfileManager(ctx);
27
+ if (sub === 'list') {
28
+ const profiles = pm.list();
29
+ ctx.print(
30
+ profiles.length > 0
31
+ ? ['Profile Sync', ...profiles.map((profile) => ` ${profile.name} ${new Date(profile.timestamp).toISOString()}`)].join('\n')
32
+ : 'Profile Sync\n No profiles saved yet.',
33
+ );
34
+ return;
35
+ }
36
+
37
+ const pathArg = args[1];
38
+ if (!pathArg) {
39
+ ctx.print(`Usage: /profilesync ${sub} <path>${sub === 'import' ? ' [prefix]' : ''}`);
40
+ return;
41
+ }
42
+ const targetPath = shellPaths.resolveWorkspacePath(pathArg);
43
+
44
+ if (sub === 'export') {
45
+ const profiles = pm.list().map((profile) => {
46
+ const loaded = pm.load(profile.name);
47
+ return {
48
+ name: profile.name,
49
+ timestamp: loaded.timestamp,
50
+ data: loaded.data,
51
+ } satisfies ProfileBundleEntry;
52
+ });
53
+ const bundle: ProfileSyncBundle = {
54
+ version: 1,
55
+ exportedAt: Date.now(),
56
+ profiles,
57
+ };
58
+ mkdirSync(dirname(targetPath), { recursive: true });
59
+ writeFileSync(targetPath, JSON.stringify(bundle, null, 2) + '\n', 'utf-8');
60
+ recordSettingsSyncEvent({
61
+ surface: 'profiles',
62
+ direction: 'export',
63
+ path: targetPath,
64
+ timestamp: Date.now(),
65
+ detail: `${profiles.length} profiles exported`,
66
+ }, controlPlaneConfigDir);
67
+ ctx.print(`Profile sync bundle exported to ${targetPath}`);
68
+ return;
69
+ }
70
+
71
+ if (sub === 'inspect') {
72
+ const bundle = JSON.parse(readFileSync(targetPath, 'utf-8')) as ProfileSyncBundle;
73
+ ctx.print(inspectProfileSyncBundle(bundle));
74
+ return;
75
+ }
76
+
77
+ if (sub === 'import') {
78
+ const bundle = JSON.parse(readFileSync(targetPath, 'utf-8')) as ProfileSyncBundle;
79
+ const prefix = args[2]?.trim() ?? '';
80
+ for (const entry of bundle.profiles) {
81
+ const name = prefix ? `${prefix}-${entry.name}` : entry.name;
82
+ pm.save(name, entry.data);
83
+ }
84
+ recordSettingsSyncEvent({
85
+ surface: 'profiles',
86
+ direction: 'import',
87
+ path: targetPath,
88
+ timestamp: Date.now(),
89
+ detail: `${bundle.profiles.length} profiles imported${prefix ? ` with prefix ${prefix}` : ''}`,
90
+ }, controlPlaneConfigDir);
91
+ ctx.print(`Profile sync bundle imported from ${targetPath}`);
92
+ return;
93
+ }
94
+
95
+ recordSettingsSyncFailure('profiles', `unsupported subcommand: ${sub}`, controlPlaneConfigDir);
96
+ ctx.print('Usage: /profilesync [list|export <path>|inspect <path>|import <path> [prefix]]');
97
+ },
98
+ });
99
+ }
@@ -0,0 +1,113 @@
1
+ import type { CommandContext, CommandRegistry } from '../command-registry.ts';
2
+ import type {
3
+ ProviderAccountRecord,
4
+ ProviderAccountSnapshot,
5
+ } from '@/runtime/index.ts';
6
+ import {
7
+ openCommandPanel,
8
+ requireOperatorClient,
9
+ } from './runtime-services.ts';
10
+
11
+ async function loadProviderAccountSnapshot(context: CommandContext): Promise<ProviderAccountSnapshot> {
12
+ return await requireOperatorClient(context).providers.accountSnapshot();
13
+ }
14
+
15
+ function findProviderAccountRecord(
16
+ snapshot: ProviderAccountSnapshot,
17
+ providerId: string | undefined,
18
+ ): ProviderAccountRecord | undefined {
19
+ if (!providerId) return undefined;
20
+ return snapshot.providers.find((entry) => entry.providerId === providerId);
21
+ }
22
+
23
+ export function registerProviderAccountsRuntimeCommands(registry: CommandRegistry): void {
24
+ registry.register({
25
+ name: 'accounts',
26
+ aliases: ['account'],
27
+ description: 'Review provider auth routes, subscription windows, and billing-path safety',
28
+ usage: '[review|panel|show <provider>|routes <provider>|repair <provider>]',
29
+ async handler(args, ctx) {
30
+ const sub = (args[0] ?? 'review').toLowerCase();
31
+ if (sub === 'panel' || sub === 'open') {
32
+ openCommandPanel(ctx, 'accounts');
33
+ return;
34
+ }
35
+ const snapshot = await loadProviderAccountSnapshot(ctx);
36
+ if (sub === 'routes') {
37
+ const providerId = args[1];
38
+ const record = findProviderAccountRecord(snapshot, providerId);
39
+ if (!record) {
40
+ ctx.print(providerId ? `Unknown provider account: ${providerId}` : 'Usage: /accounts routes <provider>');
41
+ return;
42
+ }
43
+ ctx.print([
44
+ `Provider Routes ${record.providerId}`,
45
+ ` preferred: ${record.preferredRoute}`,
46
+ ` active: ${record.activeRoute}`,
47
+ ` reason: ${record.activeRouteReason}`,
48
+ ...record.routeRecords.map((route) => ` ${route.route} usable=${route.usable ? 'yes' : 'no'} freshness=${route.freshness} ${route.detail}`),
49
+ ...record.routeRecords.flatMap((route) => route.issues.map((issue) => ` issue: ${issue}`)),
50
+ ].join('\n'));
51
+ return;
52
+ }
53
+ if (sub === 'repair') {
54
+ const providerId = args[1];
55
+ const record = findProviderAccountRecord(snapshot, providerId);
56
+ if (!record) {
57
+ ctx.print(providerId ? `Unknown provider account: ${providerId}` : 'Usage: /accounts repair <provider>');
58
+ return;
59
+ }
60
+ ctx.print([
61
+ `Provider Account Repair ${record.providerId}`,
62
+ ` active route: ${record.activeRoute}`,
63
+ ` preferred route: ${record.preferredRoute}`,
64
+ ...(record.fallbackRisk ? [` fallback: ${record.fallbackRisk}`] : []),
65
+ ...(record.issues.map((issue) => ` issue: ${issue}`)),
66
+ ...(record.recommendedActions.length > 0
67
+ ? [' next:', ...record.recommendedActions.map((action) => ` ${action}`)]
68
+ : [' No active repair actions suggested.']),
69
+ ].join('\n'));
70
+ return;
71
+ }
72
+ if (sub === 'show') {
73
+ const providerId = args[1];
74
+ const record = findProviderAccountRecord(snapshot, providerId);
75
+ if (!record) {
76
+ ctx.print(providerId ? `Unknown provider account: ${providerId}` : 'Usage: /accounts show <provider>');
77
+ return;
78
+ }
79
+ ctx.print([
80
+ `Provider Account ${record.providerId}`,
81
+ ` preferredRoute: ${record.preferredRoute}`,
82
+ ` activeRoute: ${record.activeRoute}`,
83
+ ` authFreshness: ${record.authFreshness}`,
84
+ ` configured: ${record.configured ? 'yes' : 'no'}`,
85
+ ` oauthReady: ${record.oauthReady ? 'yes' : 'no'}`,
86
+ ` pendingLogin: ${record.pendingLogin ? 'yes' : 'no'}`,
87
+ ` availableRoutes: ${record.availableRoutes.join(', ')}`,
88
+ ` modelCount: ${record.modelCount}`,
89
+ ` routeReason: ${record.activeRouteReason}`,
90
+ ...(record.fallbackRoute ? [` fallbackRoute: ${record.fallbackRoute}`] : []),
91
+ ...(record.fallbackRisk ? [` fallbackRisk: ${record.fallbackRisk}`] : []),
92
+ ...(record.expiresAt ? [` expiresAt: ${new Date(record.expiresAt).toISOString()}`] : []),
93
+ ...record.routeRecords.map((route) => ` route ${route.route}: usable=${route.usable ? 'yes' : 'no'} freshness=${route.freshness} — ${route.detail}`),
94
+ ...record.routeRecords.flatMap((route) => route.issues.map((issue) => ` issue: ${issue}`)),
95
+ ...record.usageWindows.map((entry) => ` window: ${entry.label} — ${entry.detail}`),
96
+ ...record.issues.map((issue) => ` issue: ${issue}`),
97
+ ...record.notes.map((note) => ` note: ${note}`),
98
+ ...record.recommendedActions.map((action) => ` next: ${action}`),
99
+ ].join('\n'));
100
+ return;
101
+ }
102
+ ctx.print([
103
+ 'Provider Account Review',
104
+ ` providers: ${snapshot.providers.length}`,
105
+ ` configured: ${snapshot.configuredCount}`,
106
+ ` issues: ${snapshot.issueCount}`,
107
+ ...snapshot.providers.map((record) => (
108
+ ` ${record.providerId} active=${record.activeRoute} preferred=${record.preferredRoute} freshness=${record.authFreshness} models=${record.modelCount} issues=${record.issues.length}`
109
+ )),
110
+ ].join('\n'));
111
+ },
112
+ });
113
+ }