@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,422 @@
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 { VERSION } from '../../version.ts';
5
+ import { listBuiltinSubscriptionProviders } from '@pellux/goodvibes-sdk/platform/config';
6
+ import { handleLocalAuthCommand } from './local-auth-runtime.ts';
7
+ import { buildAuthInspectionSnapshot, inspectProviderAuth } from '@/runtime/index.ts';
8
+ import { requireProfileManager, requireSecretsManager, requireServiceRegistry, requireShellPaths, requireSubscriptionManager } from './runtime-services.ts';
9
+
10
+ interface InstallBundle {
11
+ readonly version: 1;
12
+ readonly exportedAt: number;
13
+ readonly appVersion: string;
14
+ readonly workingDirectory: string;
15
+ readonly homeDirectory: string;
16
+ readonly profileCount: number;
17
+ readonly secretKeyCount: number;
18
+ readonly setupLinks: readonly string[];
19
+ }
20
+
21
+ interface UpdateBundle {
22
+ readonly version: 1;
23
+ readonly exportedAt: number;
24
+ readonly appVersion: string;
25
+ readonly updateChannel: 'stable' | 'preview';
26
+ readonly subscriptionProviders: readonly string[];
27
+ readonly sandboxProfile: string;
28
+ readonly notes: readonly string[];
29
+ }
30
+
31
+ interface AuthReviewBundle {
32
+ readonly version: 1;
33
+ readonly exportedAt: number;
34
+ readonly daemonLoginUrl: string;
35
+ readonly listenerLoginUrl: string;
36
+ readonly secretKeys: readonly string[];
37
+ readonly activeSubscriptions: readonly string[];
38
+ readonly pendingSubscriptions: readonly string[];
39
+ }
40
+
41
+ function buildSetupLink(surface: string, target?: string): string {
42
+ const params = target ? `?target=${encodeURIComponent(target)}` : '';
43
+ return `goodvibes://open/${surface}${params}`;
44
+ }
45
+
46
+ function inspectInstallBundle(bundle: InstallBundle): string {
47
+ return [
48
+ 'Install Bundle Review',
49
+ ` appVersion: ${bundle.appVersion}`,
50
+ ` workingDirectory: ${bundle.workingDirectory}`,
51
+ ` profileCount: ${bundle.profileCount}`,
52
+ ` secretKeys: ${bundle.secretKeyCount}`,
53
+ ` setupLinks: ${bundle.setupLinks.length}`,
54
+ ].join('\n');
55
+ }
56
+
57
+ function inspectUpdateBundle(bundle: UpdateBundle): string {
58
+ return [
59
+ 'Update Bundle Review',
60
+ ` appVersion: ${bundle.appVersion}`,
61
+ ` updateChannel: ${bundle.updateChannel}`,
62
+ ` subscriptionProviders: ${bundle.subscriptionProviders.length}`,
63
+ ` sandboxProfile: ${bundle.sandboxProfile}`,
64
+ ` notes: ${bundle.notes.length}`,
65
+ ].join('\n');
66
+ }
67
+
68
+ function inspectAuthBundle(bundle: AuthReviewBundle): string {
69
+ return [
70
+ 'Auth Review Bundle',
71
+ ` exportedAt: ${new Date(bundle.exportedAt).toISOString()}`,
72
+ ` daemonLoginUrl: ${bundle.daemonLoginUrl}`,
73
+ ` listenerLoginUrl: ${bundle.listenerLoginUrl}`,
74
+ ` stored secrets: ${bundle.secretKeys.length}`,
75
+ ` active subscriptions: ${bundle.activeSubscriptions.length}`,
76
+ ` pending subscriptions: ${bundle.pendingSubscriptions.length}`,
77
+ ].join('\n');
78
+ }
79
+
80
+ export function registerPlatformAccessRuntimeCommands(registry: CommandRegistry): void {
81
+ registry.register({
82
+ name: 'login',
83
+ description: 'Front-door login flow for provider subscriptions and local service sessions',
84
+ usage: '[provider <name> start|finish <code>|service <daemon|listener> <baseUrl> <username> <password> [secretKey]]',
85
+ async handler(args, ctx) {
86
+ const shellPaths = requireShellPaths(ctx);
87
+ const target = (args[0] ?? '').toLowerCase();
88
+ if (target === 'provider') {
89
+ const provider = args[1];
90
+ const mode = args[2]?.toLowerCase();
91
+ if (!provider || !mode) {
92
+ ctx.print('Usage: /login provider <name> start|finish <code>');
93
+ return;
94
+ }
95
+ if (ctx.executeCommand) {
96
+ await ctx.executeCommand('subscription', ['login', provider, mode, ...args.slice(3)]);
97
+ return;
98
+ }
99
+ ctx.print(`Use /subscription login ${provider} ${mode}${args[3] ? ` ${args[3]}` : ''}`);
100
+ return;
101
+ }
102
+ if (target === 'service') {
103
+ if (ctx.executeCommand) {
104
+ await ctx.executeCommand('auth', ['login', ...args.slice(1)]);
105
+ return;
106
+ }
107
+ ctx.print('Use /auth login <daemon|listener> <baseUrl> <username> <password> [secretKey]');
108
+ return;
109
+ }
110
+ ctx.print('Usage: /login [provider <name> start|finish <code>|service <daemon|listener> <baseUrl> <username> <password> [secretKey]]');
111
+ },
112
+ });
113
+
114
+ registry.register({
115
+ name: 'logout',
116
+ description: 'Front-door logout flow for provider subscription sessions and supported overrides',
117
+ usage: 'provider <name>',
118
+ async handler(args, ctx) {
119
+ const target = (args[0] ?? '').toLowerCase();
120
+ if (target !== 'provider' || !args[1]) {
121
+ ctx.print('Usage: /logout provider <name>');
122
+ return;
123
+ }
124
+ if (ctx.executeCommand) {
125
+ await ctx.executeCommand('subscription', ['logout', args[1]]);
126
+ return;
127
+ }
128
+ ctx.print(`Use /subscription logout ${args[1]}`);
129
+ },
130
+ });
131
+
132
+ registry.register({
133
+ name: 'install',
134
+ description: 'Review install posture and export portable install bundles',
135
+ usage: '[review|bundle export <path>|bundle inspect <path>]',
136
+ async handler(args, ctx) {
137
+ const shellPaths = requireShellPaths(ctx);
138
+ const sub = args[0] ?? 'review';
139
+ if (sub === 'review') {
140
+ const profiles = requireProfileManager(ctx).list();
141
+ const secretKeys = await requireSecretsManager(ctx).list();
142
+ ctx.print([
143
+ 'Install Review',
144
+ ` version: ${VERSION}`,
145
+ ` profiles: ${profiles.length}`,
146
+ ` secret keys: ${secretKeys.length}`,
147
+ ` setup links: 4`,
148
+ ].join('\n'));
149
+ return;
150
+ }
151
+ if (sub === 'bundle') {
152
+ const mode = args[1];
153
+ const pathArg = args[2];
154
+ if ((mode === 'export' || mode === 'inspect') && !pathArg) {
155
+ ctx.print(`Usage: /install bundle ${mode} <path>`);
156
+ return;
157
+ }
158
+ const targetPath = shellPaths.resolveWorkspacePath(pathArg!);
159
+ if (mode === 'export') {
160
+ const profiles = requireProfileManager(ctx).list();
161
+ const secretKeys = await requireSecretsManager(ctx).list();
162
+ const bundle: InstallBundle = {
163
+ version: 1,
164
+ exportedAt: Date.now(),
165
+ appVersion: VERSION,
166
+ workingDirectory: shellPaths.workingDirectory,
167
+ homeDirectory: shellPaths.homeDirectory,
168
+ profileCount: profiles.length,
169
+ secretKeyCount: secretKeys.length,
170
+ setupLinks: [
171
+ buildSetupLink('cockpit'),
172
+ buildSetupLink('security'),
173
+ buildSetupLink('remote'),
174
+ buildSetupLink('knowledge'),
175
+ ],
176
+ };
177
+ mkdirSync(dirname(targetPath), { recursive: true });
178
+ writeFileSync(targetPath, JSON.stringify(bundle, null, 2) + '\n', 'utf-8');
179
+ ctx.print(`Install bundle exported to ${targetPath}`);
180
+ return;
181
+ }
182
+ if (mode === 'inspect') {
183
+ const bundle = JSON.parse(readFileSync(targetPath, 'utf-8')) as InstallBundle;
184
+ ctx.print(inspectInstallBundle(bundle));
185
+ return;
186
+ }
187
+ }
188
+ ctx.print('Usage: /install [review|bundle export <path>|bundle inspect <path>]');
189
+ },
190
+ });
191
+
192
+ registry.register({
193
+ name: 'update',
194
+ aliases: ['upgrade'],
195
+ description: 'Review update posture, choose release channel guidance, and package portable update bundles',
196
+ usage: '[review|channel <stable|preview>|bundle export <path>|bundle inspect <path>]',
197
+ handler(args, ctx) {
198
+ const shellPaths = requireShellPaths(ctx);
199
+ const sub = args[0] ?? 'review';
200
+ const subscriptions = requireSubscriptionManager(ctx);
201
+ const serviceRegistry = requireServiceRegistry(ctx);
202
+ const secretsManager = requireSecretsManager(ctx);
203
+ const builtinProviders = listBuiltinSubscriptionProviders().map((entry) => entry.provider);
204
+ const sandboxProfile = [
205
+ `${ctx.platform.configManager.get('sandbox.replIsolation')}`,
206
+ `${ctx.platform.configManager.get('sandbox.mcpIsolation')}`,
207
+ `${ctx.platform.configManager.get('sandbox.vmBackend')}`,
208
+ ].join('/');
209
+ const activeSubscriptions = subscriptions.list().map((entry) => entry.provider);
210
+ if (sub === 'review') {
211
+ const channel = ctx.platform.configManager.get('release.channel');
212
+ ctx.print([
213
+ 'Update Review',
214
+ ` version: ${VERSION}`,
215
+ ` channel: ${channel}`,
216
+ ` built-in subscription providers: ${builtinProviders.length}${builtinProviders.length > 0 ? ` (${builtinProviders.join(', ')})` : ''}`,
217
+ ` active subscriptions: ${activeSubscriptions.length}${activeSubscriptions.length > 0 ? ` (${activeSubscriptions.join(', ')})` : ''}`,
218
+ ` sandbox profile: ${sandboxProfile}`,
219
+ ' use /update channel <stable|preview> to change release posture',
220
+ ].join('\n'));
221
+ return;
222
+ }
223
+ if (sub === 'channel') {
224
+ const channel = args[1];
225
+ if (channel !== 'stable' && channel !== 'preview') {
226
+ ctx.print('Usage: /update channel <stable|preview>');
227
+ return;
228
+ }
229
+ ctx.platform.configManager.setDynamic('release.channel', channel);
230
+ ctx.print(`Update channel set to ${channel}.`);
231
+ return;
232
+ }
233
+ if (sub === 'bundle') {
234
+ const mode = args[1];
235
+ const pathArg = args[2];
236
+ if ((mode === 'export' || mode === 'inspect') && !pathArg) {
237
+ ctx.print(`Usage: /update bundle ${mode} <path>`);
238
+ return;
239
+ }
240
+ const targetPath = shellPaths.resolveWorkspacePath(pathArg!);
241
+ if (mode === 'export') {
242
+ const bundle: UpdateBundle = {
243
+ version: 1,
244
+ exportedAt: Date.now(),
245
+ appVersion: VERSION,
246
+ updateChannel: ctx.platform.configManager.get('release.channel') as 'stable' | 'preview',
247
+ subscriptionProviders: [...new Set([...builtinProviders, ...activeSubscriptions])],
248
+ sandboxProfile,
249
+ notes: [
250
+ 'Preview channel is recommended only when operator review and sandbox isolation are enabled.',
251
+ 'OAuth-backed provider subscriptions survive channel changes and continue to apply to supported provider surfaces.',
252
+ ],
253
+ };
254
+ mkdirSync(dirname(targetPath), { recursive: true });
255
+ writeFileSync(targetPath, JSON.stringify(bundle, null, 2) + '\n', 'utf-8');
256
+ ctx.print(`Update bundle exported to ${targetPath}`);
257
+ return;
258
+ }
259
+ if (mode === 'inspect') {
260
+ const bundle = JSON.parse(readFileSync(targetPath, 'utf-8')) as UpdateBundle;
261
+ ctx.print(inspectUpdateBundle(bundle));
262
+ return;
263
+ }
264
+ }
265
+ ctx.print('Usage: /update [review|channel <stable|preview>|bundle export <path>|bundle inspect <path>]');
266
+ },
267
+ });
268
+
269
+ registry.register({
270
+ name: 'auth',
271
+ description: 'Review auth posture and exchange session login tokens with local services',
272
+ usage: '[review|show <provider>|repair <provider>|bundle export <path>|bundle inspect <path>|login <daemon|listener> <baseUrl> <username> <password> [secretKey]|local <review|panel|add-user|delete-user|rotate-password|revoke-session|clear-bootstrap-file>]',
273
+ async handler(args, ctx) {
274
+ const shellPaths = requireShellPaths(ctx);
275
+ const sub = args[0] ?? 'review';
276
+ const subscriptions = requireSubscriptionManager(ctx);
277
+ const serviceRegistry = requireServiceRegistry(ctx);
278
+ const secretsManager = requireSecretsManager(ctx);
279
+ if (sub === 'local') {
280
+ handleLocalAuthCommand(args.slice(1), ctx);
281
+ return;
282
+ }
283
+ if (sub === 'review') {
284
+ const snapshot = await buildAuthInspectionSnapshot({
285
+ serviceRegistry,
286
+ subscriptionManager: subscriptions,
287
+ secretsManager,
288
+ });
289
+ const builtinProviders = listBuiltinSubscriptionProviders().map((entry) => entry.provider);
290
+ ctx.print([
291
+ 'Auth Review',
292
+ ' daemon login route: /login',
293
+ ' listener login route: /login',
294
+ ` stored secrets: ${snapshot.secretKeyCount}`,
295
+ ` built-in providers: ${builtinProviders.length}${builtinProviders.length > 0 ? ` (${builtinProviders.join(', ')})` : ''}`,
296
+ ` active subscriptions: ${snapshot.activeSubscriptions}${snapshot.activeSubscriptions > 0 ? ` (${snapshot.providers.filter((provider) => provider.activeSubscription).map((provider) => provider.provider).join(', ')})` : ''}`,
297
+ ` pending subscriptions: ${snapshot.pendingSubscriptions}${snapshot.pendingSubscriptions > 0 ? ` (${snapshot.providers.filter((provider) => provider.pendingLogin).map((provider) => provider.provider).join(', ')})` : ''}`,
298
+ ...snapshot.providers.map((provider) => ` ${provider.provider} freshness=${provider.freshness} mode=${provider.callbackMode} configured=${provider.configured ? 'yes' : 'no'}`),
299
+ ].join('\n'));
300
+ return;
301
+ }
302
+
303
+ if (sub === 'show') {
304
+ const provider = args[1];
305
+ if (!provider) {
306
+ ctx.print('Usage: /auth show <provider>');
307
+ return;
308
+ }
309
+ const inspection = await inspectProviderAuth(provider, {
310
+ serviceRegistry,
311
+ subscriptionManager: subscriptions,
312
+ secretsManager,
313
+ });
314
+ ctx.print([
315
+ `Auth Provider ${provider}`,
316
+ ` configured: ${inspection.configured ? 'yes' : 'no'}`,
317
+ ...(inspection.source ? [` source: ${inspection.source}`] : []),
318
+ ` freshness: ${inspection.freshness}`,
319
+ ` callbackMode: ${inspection.callbackMode}`,
320
+ ...(inspection.redirectUri ? [` redirectUri: ${inspection.redirectUri}`] : []),
321
+ ...(inspection.localCallback ? [` localCallback: ${inspection.localCallback}`] : []),
322
+ ` activeSubscription: ${inspection.activeSubscription ? 'yes' : 'no'}`,
323
+ ` pendingLogin: ${inspection.pendingLogin ? 'yes' : 'no'}`,
324
+ ` overrideAmbientApiKeys: ${inspection.overrideAmbientApiKeys ? 'yes' : 'no'}`,
325
+ ...(inspection.tokenType ? [` tokenType: ${inspection.tokenType}`] : []),
326
+ ...(inspection.expiresAt ? [` expiresAt: ${new Date(inspection.expiresAt).toISOString()}`] : []),
327
+ ...inspection.issues.map((issue) => ` issue: ${issue}`),
328
+ ...inspection.nextActions.map((action) => ` next: ${action}`),
329
+ ].join('\n'));
330
+ return;
331
+ }
332
+
333
+ if (sub === 'repair') {
334
+ const provider = args[1];
335
+ if (!provider) {
336
+ ctx.print('Usage: /auth repair <provider>');
337
+ return;
338
+ }
339
+ const inspection = await inspectProviderAuth(provider, {
340
+ serviceRegistry,
341
+ subscriptionManager: subscriptions,
342
+ secretsManager,
343
+ });
344
+ ctx.print([
345
+ `Auth Repair ${provider}`,
346
+ ` configured: ${inspection.configured ? 'yes' : 'no'}`,
347
+ ` freshness: ${inspection.freshness}`,
348
+ ` callbackMode: ${inspection.callbackMode}`,
349
+ ...inspection.issues.map((issue) => ` issue: ${issue}`),
350
+ ...(inspection.nextActions.length > 0
351
+ ? [' next:', ...inspection.nextActions.map((action) => ` ${action}`)]
352
+ : [' No active repair actions suggested.']),
353
+ ].join('\n'));
354
+ return;
355
+ }
356
+
357
+ if (sub === 'bundle') {
358
+ const mode = args[1];
359
+ const pathArg = args[2];
360
+ if ((mode === 'export' || mode === 'inspect') && !pathArg) {
361
+ ctx.print(`Usage: /auth bundle ${mode} <path>`);
362
+ return;
363
+ }
364
+ const targetPath = shellPaths.resolveWorkspacePath(pathArg!);
365
+ if (mode === 'export') {
366
+ const secretKeys = await secretsManager.list();
367
+ const bundle: AuthReviewBundle = {
368
+ version: 1,
369
+ exportedAt: Date.now(),
370
+ daemonLoginUrl: 'http://127.0.0.1:3421/login',
371
+ listenerLoginUrl: 'http://127.0.0.1:3422/login',
372
+ secretKeys,
373
+ activeSubscriptions: subscriptions.list().map((entry) => entry.provider),
374
+ pendingSubscriptions: subscriptions.listPending().map((entry) => entry.provider),
375
+ };
376
+ mkdirSync(dirname(targetPath), { recursive: true });
377
+ writeFileSync(targetPath, JSON.stringify(bundle, null, 2) + '\n', 'utf-8');
378
+ ctx.print(`Auth review bundle exported to ${targetPath}`);
379
+ return;
380
+ }
381
+ if (mode === 'inspect') {
382
+ const bundle = JSON.parse(readFileSync(targetPath, 'utf-8')) as AuthReviewBundle;
383
+ ctx.print(inspectAuthBundle(bundle));
384
+ return;
385
+ }
386
+ }
387
+
388
+ if (sub === 'login') {
389
+ const target = args[1];
390
+ const baseUrl = args[2];
391
+ const username = args[3];
392
+ const password = args[4];
393
+ const secretKey = args[5] ?? `${target?.toUpperCase() ?? 'SERVICE'}_SESSION_TOKEN`;
394
+ if ((target !== 'daemon' && target !== 'listener') || !baseUrl || !username || !password) {
395
+ ctx.print('Usage: /auth login <daemon|listener> <baseUrl> <username> <password> [secretKey]');
396
+ return;
397
+ }
398
+ const url = new URL('/login', baseUrl).toString();
399
+ const response = await fetch(url, {
400
+ method: 'POST',
401
+ headers: { 'Content-Type': 'application/json' },
402
+ body: JSON.stringify({ username, password }),
403
+ });
404
+ if (!response.ok) {
405
+ const body = await response.text();
406
+ ctx.print(`Auth login failed (${response.status}): ${body}`);
407
+ return;
408
+ }
409
+ const body = await response.json() as { token?: unknown };
410
+ if (typeof body.token !== 'string') {
411
+ ctx.print('Auth login response did not include a session token.');
412
+ return;
413
+ }
414
+ await requireSecretsManager(ctx).set(secretKey, body.token);
415
+ ctx.print(`Stored ${target} session token in secure storage as ${secretKey}.`);
416
+ return;
417
+ }
418
+
419
+ ctx.print('Usage: /auth [review|show <provider>|bundle export <path>|bundle inspect <path>|login <daemon|listener> <baseUrl> <username> <password> [secretKey]|local <review|panel|add-user|delete-user|rotate-password|revoke-session|clear-bootstrap-file>]');
420
+ },
421
+ });
422
+ }
@@ -0,0 +1,246 @@
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 { requireSecretsManager, requireShellPaths } from './runtime-services.ts';
5
+
6
+ interface SecureStorageBundle {
7
+ readonly version: 1;
8
+ readonly exportedAt: number;
9
+ readonly storedKeys: readonly string[];
10
+ readonly envBackedKeys: readonly string[];
11
+ }
12
+
13
+ interface DeepLinkBundle {
14
+ readonly version: 1;
15
+ readonly exportedAt: number;
16
+ readonly links: readonly string[];
17
+ }
18
+
19
+ interface IntegrationHelperBundle {
20
+ readonly version: 1;
21
+ readonly exportedAt: number;
22
+ readonly apiFamilies: readonly string[];
23
+ readonly routes: readonly string[];
24
+ }
25
+
26
+ function buildSetupLink(surface: string, target?: string): string {
27
+ const params = target ? `?target=${encodeURIComponent(target)}` : '';
28
+ return `goodvibes://open/${surface}${params}`;
29
+ }
30
+
31
+ function inspectStorageBundle(bundle: SecureStorageBundle): string {
32
+ return [
33
+ 'Secure Storage Bundle Review',
34
+ ` exportedAt: ${new Date(bundle.exportedAt).toISOString()}`,
35
+ ` storedKeys: ${bundle.storedKeys.length}`,
36
+ ` envBackedKeys: ${bundle.envBackedKeys.length}`,
37
+ ].join('\n');
38
+ }
39
+
40
+ function inspectDeepLinkBundle(bundle: DeepLinkBundle): string {
41
+ return [
42
+ 'Deep Link Bundle Review',
43
+ ` exportedAt: ${new Date(bundle.exportedAt).toISOString()}`,
44
+ ` links: ${bundle.links.length}`,
45
+ ].join('\n');
46
+ }
47
+
48
+ function inspectIntegrationHelperBundle(bundle: IntegrationHelperBundle): string {
49
+ return [
50
+ 'Integration Helper Review',
51
+ ` exportedAt: ${new Date(bundle.exportedAt).toISOString()}`,
52
+ ` apiFamilies: ${bundle.apiFamilies.length}`,
53
+ ` routes: ${bundle.routes.length}`,
54
+ ].join('\n');
55
+ }
56
+
57
+ export function registerPlatformServicesRuntimeCommands(registry: CommandRegistry): void {
58
+ registry.register({
59
+ name: 'storage',
60
+ description: 'Review secure storage posture and export portable storage metadata bundles',
61
+ usage: '[review|list|delete <key>|bundle export <path>|bundle inspect <path>]',
62
+ async handler(args, ctx) {
63
+ const shellPaths = requireShellPaths(ctx);
64
+ const manager = requireSecretsManager(ctx);
65
+ const sub = args[0] ?? 'review';
66
+ const review = await manager.inspect();
67
+ const storedKeys = await manager.list();
68
+ const detailedKeys = await manager.listDetailed();
69
+ const envBackedKeys = [...new Set(detailedKeys.filter((record) => record.source === 'env').map((record) => record.key))];
70
+
71
+ if (sub === 'review') {
72
+ ctx.print([
73
+ 'Secure Storage Review',
74
+ ` policy: ${review.policy}`,
75
+ ` stored keys: ${storedKeys.length}`,
76
+ ` env-backed keys: ${envBackedKeys.length}`,
77
+ ` secure keys: ${review.secureKeys}`,
78
+ ` plaintext keys: ${review.plaintextKeys}`,
79
+ ...review.locations.map((location) => ` ${location.source}: ${location.exists ? 'present' : 'absent'} (${location.path})`),
80
+ ...(review.warnings.length > 0 ? review.warnings.map((warning) => ` warning: ${warning}`) : []),
81
+ ].join('\n'));
82
+ return;
83
+ }
84
+ if (sub === 'list') {
85
+ ctx.print(detailedKeys.filter((record) => record.source !== 'env').length > 0
86
+ ? ['Secure Storage Keys', ...detailedKeys.filter((record) => record.source !== 'env').map((record) => ` ${record.key} (${record.source}${record.refSource ? `, ref:${record.refSource}` : ''}${record.overriddenByEnv ? ', env override' : ''})`)].join('\n')
87
+ : 'Secure Storage Keys\n No stored secrets yet.');
88
+ return;
89
+ }
90
+ if (sub === 'delete') {
91
+ const key = args[1];
92
+ if (!key) {
93
+ ctx.print('Usage: /storage delete <key>');
94
+ return;
95
+ }
96
+ await manager.delete(key);
97
+ ctx.print(`Deleted secure storage key ${key}.`);
98
+ return;
99
+ }
100
+ if (sub === 'bundle') {
101
+ const mode = args[1];
102
+ const pathArg = args[2];
103
+ if ((mode === 'export' || mode === 'inspect') && !pathArg) {
104
+ ctx.print(`Usage: /storage bundle ${mode} <path>`);
105
+ return;
106
+ }
107
+ const targetPath = shellPaths.resolveWorkspacePath(pathArg!);
108
+ if (mode === 'export') {
109
+ const bundle: SecureStorageBundle = {
110
+ version: 1,
111
+ exportedAt: Date.now(),
112
+ storedKeys,
113
+ envBackedKeys,
114
+ };
115
+ mkdirSync(dirname(targetPath), { recursive: true });
116
+ writeFileSync(targetPath, `${JSON.stringify(bundle, null, 2)}\n`, 'utf-8');
117
+ ctx.print(`Secure storage bundle exported to ${targetPath}`);
118
+ return;
119
+ }
120
+ if (mode === 'inspect') {
121
+ const bundle = JSON.parse(readFileSync(targetPath, 'utf-8')) as SecureStorageBundle;
122
+ ctx.print(inspectStorageBundle(bundle));
123
+ return;
124
+ }
125
+ }
126
+ ctx.print('Usage: /storage [review|list|delete <key>|bundle export <path>|bundle inspect <path>]');
127
+ },
128
+ });
129
+
130
+ registry.register({
131
+ name: 'helpers',
132
+ aliases: ['integration-api'],
133
+ description: 'Review local integration helper API surfaces for remote clients and future web frontends',
134
+ usage: '[review|bundle export <path>|bundle inspect <path>]',
135
+ handler(args, ctx) {
136
+ const shellPaths = requireShellPaths(ctx);
137
+ const sub = args[0] ?? 'review';
138
+ const review = ctx.extensions.integrationHelpers?.buildReview();
139
+ if (!review) {
140
+ ctx.print('Integration helper service unavailable in this runtime.');
141
+ return;
142
+ }
143
+ if (sub === 'review') {
144
+ ctx.print([
145
+ 'Integration Helper Review',
146
+ ` sessions: ${review.sessions}`,
147
+ ` tasks: ${review.tasks}`,
148
+ ` pending approvals: ${review.pendingApprovals}`,
149
+ ` remote contracts: ${review.remoteContracts}`,
150
+ ` registered panels: ${review.panels}`,
151
+ ' api families:',
152
+ ...review.apiFamilies.map((family) => ` - ${family}`),
153
+ ' routes:',
154
+ ...review.routes.map((route) => ` - ${route}`),
155
+ ].join('\n'));
156
+ return;
157
+ }
158
+ if (sub === 'bundle') {
159
+ const mode = args[1];
160
+ const pathArg = args[2];
161
+ if ((mode === 'export' || mode === 'inspect') && !pathArg) {
162
+ ctx.print(`Usage: /helpers bundle ${mode} <path>`);
163
+ return;
164
+ }
165
+ const targetPath = shellPaths.resolveWorkspacePath(pathArg!);
166
+ if (mode === 'export') {
167
+ const bundle: IntegrationHelperBundle = {
168
+ version: 1,
169
+ exportedAt: Date.now(),
170
+ apiFamilies: review.apiFamilies,
171
+ routes: review.routes,
172
+ };
173
+ mkdirSync(dirname(targetPath), { recursive: true });
174
+ writeFileSync(targetPath, `${JSON.stringify(bundle, null, 2)}\n`, 'utf-8');
175
+ ctx.print(`Integration helper bundle exported to ${targetPath}`);
176
+ return;
177
+ }
178
+ if (mode === 'inspect') {
179
+ const bundle = JSON.parse(readFileSync(targetPath, 'utf-8')) as IntegrationHelperBundle;
180
+ ctx.print(inspectIntegrationHelperBundle(bundle));
181
+ return;
182
+ }
183
+ }
184
+ ctx.print('Usage: /helpers [review|bundle export <path>|bundle inspect <path>]');
185
+ },
186
+ });
187
+
188
+ registry.register({
189
+ name: 'deeplink',
190
+ aliases: ['link'],
191
+ description: 'Review and package deep-link entrypoints for setup and operator surfaces',
192
+ usage: '[review|open <surface> [target]|bundle export <path>|bundle inspect <path>]',
193
+ handler(args, ctx) {
194
+ const shellPaths = requireShellPaths(ctx);
195
+ const sub = args[0] ?? 'review';
196
+ const links = [
197
+ buildSetupLink('cockpit'),
198
+ buildSetupLink('security'),
199
+ buildSetupLink('remote'),
200
+ buildSetupLink('knowledge'),
201
+ buildSetupLink('marketplace'),
202
+ buildSetupLink('sandbox'),
203
+ ];
204
+ if (sub === 'review') {
205
+ ctx.print(['Deep Link Review', ...links.map((link) => ` ${link}`)].join('\n'));
206
+ return;
207
+ }
208
+ if (sub === 'open') {
209
+ const surface = args[1];
210
+ const target = args[2];
211
+ if (!surface) {
212
+ ctx.print('Usage: /deeplink open <surface> [target]');
213
+ return;
214
+ }
215
+ ctx.print(buildSetupLink(surface, target));
216
+ return;
217
+ }
218
+ if (sub === 'bundle') {
219
+ const mode = args[1];
220
+ const pathArg = args[2];
221
+ if ((mode === 'export' || mode === 'inspect') && !pathArg) {
222
+ ctx.print(`Usage: /deeplink bundle ${mode} <path>`);
223
+ return;
224
+ }
225
+ const targetPath = shellPaths.resolveWorkspacePath(pathArg!);
226
+ if (mode === 'export') {
227
+ const bundle: DeepLinkBundle = {
228
+ version: 1,
229
+ exportedAt: Date.now(),
230
+ links,
231
+ };
232
+ mkdirSync(dirname(targetPath), { recursive: true });
233
+ writeFileSync(targetPath, `${JSON.stringify(bundle, null, 2)}\n`, 'utf-8');
234
+ ctx.print(`Deep link bundle exported to ${targetPath}`);
235
+ return;
236
+ }
237
+ if (mode === 'inspect') {
238
+ const bundle = JSON.parse(readFileSync(targetPath, 'utf-8')) as DeepLinkBundle;
239
+ ctx.print(inspectDeepLinkBundle(bundle));
240
+ return;
241
+ }
242
+ }
243
+ ctx.print('Usage: /deeplink [review|open <surface> [target]|bundle export <path>|bundle inspect <path>]');
244
+ },
245
+ });
246
+ }