quoxcli 0.0.0-stage → 0.3.1

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 (516) hide show
  1. package/LICENSE +35 -0
  2. package/README.md +144 -2
  3. package/bin/quox.js +265 -0
  4. package/bin/quoxon.js +8 -0
  5. package/lib/api/endpoints/admin.js +151 -0
  6. package/lib/api/endpoints/aee.js +38 -0
  7. package/lib/api/endpoints/agent-attach.js +126 -0
  8. package/lib/api/endpoints/agent-schedules.js +26 -0
  9. package/lib/api/endpoints/agents.js +63 -0
  10. package/lib/api/endpoints/assistants.js +62 -0
  11. package/lib/api/endpoints/audit.js +14 -0
  12. package/lib/api/endpoints/auth.js +50 -0
  13. package/lib/api/endpoints/awareness.js +34 -0
  14. package/lib/api/endpoints/away.js +15 -0
  15. package/lib/api/endpoints/backup-schedules.js +20 -0
  16. package/lib/api/endpoints/backups.js +86 -0
  17. package/lib/api/endpoints/brain.js +140 -0
  18. package/lib/api/endpoints/budgets.js +62 -0
  19. package/lib/api/endpoints/calendarq.js +71 -0
  20. package/lib/api/endpoints/catalog.js +14 -0
  21. package/lib/api/endpoints/chat.js +61 -0
  22. package/lib/api/endpoints/consent.js +26 -0
  23. package/lib/api/endpoints/contactsq.js +68 -0
  24. package/lib/api/endpoints/conversations.js +46 -0
  25. package/lib/api/endpoints/custom-roles.js +92 -0
  26. package/lib/api/endpoints/divisions.js +56 -0
  27. package/lib/api/endpoints/domains.js +38 -0
  28. package/lib/api/endpoints/engagement.js +231 -0
  29. package/lib/api/endpoints/engine.js +11 -0
  30. package/lib/api/endpoints/entity.js +50 -0
  31. package/lib/api/endpoints/executions.js +45 -0
  32. package/lib/api/endpoints/fetchAllowlist.js +27 -0
  33. package/lib/api/endpoints/file.js +20 -0
  34. package/lib/api/endpoints/files.js +40 -0
  35. package/lib/api/endpoints/github.js +21 -0
  36. package/lib/api/endpoints/governance.js +43 -0
  37. package/lib/api/endpoints/hat.js +66 -0
  38. package/lib/api/endpoints/inbox.js +52 -0
  39. package/lib/api/endpoints/inboxq.js +120 -0
  40. package/lib/api/endpoints/index.js +242 -0
  41. package/lib/api/endpoints/invites.js +19 -0
  42. package/lib/api/endpoints/llm-policy.js +43 -0
  43. package/lib/api/endpoints/lucid.js +89 -0
  44. package/lib/api/endpoints/members.js +32 -0
  45. package/lib/api/endpoints/memory.js +94 -0
  46. package/lib/api/endpoints/mfa.js +32 -0
  47. package/lib/api/endpoints/mind.js +13 -0
  48. package/lib/api/endpoints/mon.js +184 -0
  49. package/lib/api/endpoints/notesq.js +43 -0
  50. package/lib/api/endpoints/objectives.js +68 -0
  51. package/lib/api/endpoints/orgs.js +38 -0
  52. package/lib/api/endpoints/plugins.js +152 -0
  53. package/lib/api/endpoints/powers.js +75 -0
  54. package/lib/api/endpoints/presence.js +33 -0
  55. package/lib/api/endpoints/prompts.js +69 -0
  56. package/lib/api/endpoints/qlarity.js +122 -0
  57. package/lib/api/endpoints/quoxbox.js +55 -0
  58. package/lib/api/endpoints/quoxchat.js +54 -0
  59. package/lib/api/endpoints/quoxflow.js +32 -0
  60. package/lib/api/endpoints/quoxplan.js +121 -0
  61. package/lib/api/endpoints/quoxseo.js +114 -0
  62. package/lib/api/endpoints/reach.js +47 -0
  63. package/lib/api/endpoints/router.js +17 -0
  64. package/lib/api/endpoints/runs.js +38 -0
  65. package/lib/api/endpoints/safety.js +53 -0
  66. package/lib/api/endpoints/scim.js +46 -0
  67. package/lib/api/endpoints/scopes.js +14 -0
  68. package/lib/api/endpoints/security.js +69 -0
  69. package/lib/api/endpoints/setup.js +90 -0
  70. package/lib/api/endpoints/skills.js +200 -0
  71. package/lib/api/endpoints/sso.js +67 -0
  72. package/lib/api/endpoints/stepup.js +20 -0
  73. package/lib/api/endpoints/tags.js +32 -0
  74. package/lib/api/endpoints/teams.js +56 -0
  75. package/lib/api/endpoints/telephony.js +46 -0
  76. package/lib/api/endpoints/tg.js +56 -0
  77. package/lib/api/endpoints/tools.js +50 -0
  78. package/lib/api/endpoints/traces.js +157 -0
  79. package/lib/api/endpoints/triggers.js +96 -0
  80. package/lib/api/endpoints/user-library.js +41 -0
  81. package/lib/api/endpoints/users.js +20 -0
  82. package/lib/api/endpoints/v1.js +585 -0
  83. package/lib/api/endpoints/vault.js +192 -0
  84. package/lib/api/endpoints/voice.js +22 -0
  85. package/lib/api/endpoints/volt.js +84 -0
  86. package/lib/api/endpoints/ward.js +47 -0
  87. package/lib/api/endpoints/webhooks.js +46 -0
  88. package/lib/api/endpoints/workflows.js +169 -0
  89. package/lib/api/endpoints/x.js +32 -0
  90. package/lib/api/endpoints.js +15 -0
  91. package/lib/commands/actions.js +61 -0
  92. package/lib/commands/admin.js +375 -0
  93. package/lib/commands/aee.js +99 -0
  94. package/lib/commands/agent.js +337 -0
  95. package/lib/commands/agentAttach.js +1528 -0
  96. package/lib/commands/approvals.js +119 -0
  97. package/lib/commands/aside.js +24 -0
  98. package/lib/commands/ask.js +144 -0
  99. package/lib/commands/assistant.js +169 -0
  100. package/lib/commands/auth.js +464 -0
  101. package/lib/commands/awareness.js +88 -0
  102. package/lib/commands/backup.js +377 -0
  103. package/lib/commands/brain.js +1085 -0
  104. package/lib/commands/budget.js +241 -0
  105. package/lib/commands/build.js +170 -0
  106. package/lib/commands/calendar.js +216 -0
  107. package/lib/commands/capabilities.js +34 -0
  108. package/lib/commands/chat.js +295 -0
  109. package/lib/commands/claude.js +380 -0
  110. package/lib/commands/config-cmd.js +106 -0
  111. package/lib/commands/consent.js +84 -0
  112. package/lib/commands/contacts.js +1016 -0
  113. package/lib/commands/contactsSelftest.js +132 -0
  114. package/lib/commands/conversation.js +105 -0
  115. package/lib/commands/dashboard.js +43 -0
  116. package/lib/commands/department.js +96 -0
  117. package/lib/commands/dev.js +620 -0
  118. package/lib/commands/devResident.js +326 -0
  119. package/lib/commands/devSupervisor.js +1062 -0
  120. package/lib/commands/discord.js +132 -0
  121. package/lib/commands/doctor.js +181 -0
  122. package/lib/commands/domain.js +114 -0
  123. package/lib/commands/done.js +347 -0
  124. package/lib/commands/engagement.js +597 -0
  125. package/lib/commands/entity.js +119 -0
  126. package/lib/commands/facebook.js +212 -0
  127. package/lib/commands/fetchAllowlist.js +71 -0
  128. package/lib/commands/file.js +165 -0
  129. package/lib/commands/fleet.js +1189 -0
  130. package/lib/commands/governance.js +647 -0
  131. package/lib/commands/gripe.js +355 -0
  132. package/lib/commands/hat.js +374 -0
  133. package/lib/commands/helpers.js +96 -0
  134. package/lib/commands/hyperion.js +58 -0
  135. package/lib/commands/inbox.js +173 -0
  136. package/lib/commands/instagram.js +264 -0
  137. package/lib/commands/integration.js +100 -0
  138. package/lib/commands/inventory.js +115 -0
  139. package/lib/commands/invites.js +45 -0
  140. package/lib/commands/licence.js +139 -0
  141. package/lib/commands/linkedin.js +178 -0
  142. package/lib/commands/llm-policy.js +117 -0
  143. package/lib/commands/llm.js +45 -0
  144. package/lib/commands/lucid.js +597 -0
  145. package/lib/commands/mail.js +531 -0
  146. package/lib/commands/memory.js +361 -0
  147. package/lib/commands/mind.js +71 -0
  148. package/lib/commands/mon.js +581 -0
  149. package/lib/commands/monitoring.js +86 -0
  150. package/lib/commands/motion.js +22 -0
  151. package/lib/commands/notes.js +1246 -0
  152. package/lib/commands/notesBatch.js +160 -0
  153. package/lib/commands/notesBridges.js +56 -0
  154. package/lib/commands/notesLinks.js +60 -0
  155. package/lib/commands/notification.js +57 -0
  156. package/lib/commands/nucleus.js +123 -0
  157. package/lib/commands/objective.js +240 -0
  158. package/lib/commands/offload.js +89 -0
  159. package/lib/commands/onboard.js +329 -0
  160. package/lib/commands/open.js +56 -0
  161. package/lib/commands/org.js +276 -0
  162. package/lib/commands/peek.js +28 -0
  163. package/lib/commands/plan.js +944 -0
  164. package/lib/commands/plugin-doctor.js +1091 -0
  165. package/lib/commands/plugin.js +649 -0
  166. package/lib/commands/policy.js +78 -0
  167. package/lib/commands/powers.js +296 -0
  168. package/lib/commands/presence.js +89 -0
  169. package/lib/commands/prompt.js +350 -0
  170. package/lib/commands/provider.js +159 -0
  171. package/lib/commands/qlarity.js +706 -0
  172. package/lib/commands/quoxbox.js +270 -0
  173. package/lib/commands/quoxchat.js +275 -0
  174. package/lib/commands/quoxseo.js +378 -0
  175. package/lib/commands/reach.js +159 -0
  176. package/lib/commands/role.js +286 -0
  177. package/lib/commands/router.js +77 -0
  178. package/lib/commands/rows.js +358 -0
  179. package/lib/commands/run.js +187 -0
  180. package/lib/commands/safety.js +107 -0
  181. package/lib/commands/scim.js +88 -0
  182. package/lib/commands/scope.js +58 -0
  183. package/lib/commands/security.js +157 -0
  184. package/lib/commands/server.js +292 -0
  185. package/lib/commands/service.js +89 -0
  186. package/lib/commands/settings.js +99 -0
  187. package/lib/commands/setup.js +569 -0
  188. package/lib/commands/skillManifest.js +113 -0
  189. package/lib/commands/skillRightsFormat.js +38 -0
  190. package/lib/commands/skills.js +687 -0
  191. package/lib/commands/slot.js +1451 -0
  192. package/lib/commands/sso.js +229 -0
  193. package/lib/commands/status.js +137 -0
  194. package/lib/commands/tag.js +91 -0
  195. package/lib/commands/team.js +142 -0
  196. package/lib/commands/tg.js +240 -0
  197. package/lib/commands/tiktok.js +218 -0
  198. package/lib/commands/tips.js +23 -0
  199. package/lib/commands/tool.js +304 -0
  200. package/lib/commands/trace.js +530 -0
  201. package/lib/commands/trigger.js +223 -0
  202. package/lib/commands/update.js +46 -0
  203. package/lib/commands/vault.js +1447 -0
  204. package/lib/commands/vm.js +237 -0
  205. package/lib/commands/voice.js +213 -0
  206. package/lib/commands/volt.js +570 -0
  207. package/lib/commands/walkthrough.js +32 -0
  208. package/lib/commands/watch.js +167 -0
  209. package/lib/commands/webhook.js +137 -0
  210. package/lib/commands/welcome.js +14 -0
  211. package/lib/commands/workflow.js +660 -0
  212. package/lib/commands/x.js +448 -0
  213. package/lib/core/actingAs.js +136 -0
  214. package/lib/core/activeSummary.js +186 -0
  215. package/lib/core/aee.js +53 -0
  216. package/lib/core/agentAlias.js +163 -0
  217. package/lib/core/approvalContext.js +61 -0
  218. package/lib/core/aside.js +54 -0
  219. package/lib/core/askDecision.js +60 -0
  220. package/lib/core/auth.js +501 -0
  221. package/lib/core/banner.js +143 -0
  222. package/lib/core/brainPrime.js +90 -0
  223. package/lib/core/callerSource.js +129 -0
  224. package/lib/core/claudeLs.js +94 -0
  225. package/lib/core/cliBuild.js +62 -0
  226. package/lib/core/client.js +693 -0
  227. package/lib/core/commandRegistrars.js +121 -0
  228. package/lib/core/completions.js +163 -0
  229. package/lib/core/config.js +669 -0
  230. package/lib/core/confirm.js +37 -0
  231. package/lib/core/customHats.js +168 -0
  232. package/lib/core/deeplinks.js +76 -0
  233. package/lib/core/doneEngineFetch.js +227 -0
  234. package/lib/core/errors.js +441 -0
  235. package/lib/core/global-flags.js +190 -0
  236. package/lib/core/governedSession.js +402 -0
  237. package/lib/core/hyperion.js +102 -0
  238. package/lib/core/inboxResolution.js +65 -0
  239. package/lib/core/lazyCommands.js +122 -0
  240. package/lib/core/liveSessionsReport.js +112 -0
  241. package/lib/core/offload.js +504 -0
  242. package/lib/core/org-override.js +52 -0
  243. package/lib/core/orgResolve.js +70 -0
  244. package/lib/core/output.js +239 -0
  245. package/lib/core/peek.js +126 -0
  246. package/lib/core/prodEnv.js +7 -0
  247. package/lib/core/profileUsers.js +51 -0
  248. package/lib/core/promptCancel.js +18 -0
  249. package/lib/core/quoxglyph.js +158 -0
  250. package/lib/core/repoPath.js +11 -0
  251. package/lib/core/residentAlarm.js +282 -0
  252. package/lib/core/residentAuth.js +243 -0
  253. package/lib/core/residentPump.js +229 -0
  254. package/lib/core/residentSeed.js +106 -0
  255. package/lib/core/rootOptions.js +39 -0
  256. package/lib/core/router.js +168 -0
  257. package/lib/core/selfUpdate.js +188 -0
  258. package/lib/core/sessionHeartbeat.js +192 -0
  259. package/lib/core/sessionsOverview.js +224 -0
  260. package/lib/core/slotKeeper.js +527 -0
  261. package/lib/core/slotWake.js +120 -0
  262. package/lib/core/supervisorEngine.js +933 -0
  263. package/lib/core/systemdInstaller.js +256 -0
  264. package/lib/core/version.js +87 -0
  265. package/lib/core/vm.js +361 -0
  266. package/lib/core/vmTui.js +86 -0
  267. package/lib/core/walkthrough.js +35 -0
  268. package/lib/hyperion/deck.js +29 -0
  269. package/lib/lucid/LucidCard.jsx +68 -0
  270. package/lib/lucid/LucidIntro.jsx +92 -0
  271. package/lib/lucid/blind.js +71 -0
  272. package/lib/lucid/cards.js +86 -0
  273. package/lib/lucid/deck.js +32 -0
  274. package/lib/lucid/fmt.js +139 -0
  275. package/lib/lucid/markdown.js +81 -0
  276. package/lib/lucid/motion.js +56 -0
  277. package/lib/lucid/sitrep.js +173 -0
  278. package/lib/plugins/loader.js +93 -0
  279. package/lib/quoxon/activity.js +116 -0
  280. package/lib/quoxon/aocl.js +117 -0
  281. package/lib/quoxon/api.js +952 -0
  282. package/lib/quoxon/app.js +4032 -0
  283. package/lib/quoxon/approvalFacts.js +94 -0
  284. package/lib/quoxon/approvalsView.js +325 -0
  285. package/lib/quoxon/asideView.js +40 -0
  286. package/lib/quoxon/ask.js +121 -0
  287. package/lib/quoxon/away.js +52 -0
  288. package/lib/quoxon/bang.js +224 -0
  289. package/lib/quoxon/bulkRisk.js +17 -0
  290. package/lib/quoxon/capabilities.js +82 -0
  291. package/lib/quoxon/cells.js +53 -0
  292. package/lib/quoxon/commandShort.js +112 -0
  293. package/lib/quoxon/commands.js +479 -0
  294. package/lib/quoxon/connect.js +654 -0
  295. package/lib/quoxon/connectCard.js +45 -0
  296. package/lib/quoxon/consent.js +86 -0
  297. package/lib/quoxon/context.js +68 -0
  298. package/lib/quoxon/copy.js +34 -0
  299. package/lib/quoxon/countdownLine.js +11 -0
  300. package/lib/quoxon/demo.autoplay.js +29 -0
  301. package/lib/quoxon/demo.fixtures.js +24 -0
  302. package/lib/quoxon/demo.js +76 -0
  303. package/lib/quoxon/devObserver.js +20 -0
  304. package/lib/quoxon/dividerAocl.js +191 -0
  305. package/lib/quoxon/dividerRule.js +57 -0
  306. package/lib/quoxon/dragonModes.js +150 -0
  307. package/lib/quoxon/dragonView.js +41 -0
  308. package/lib/quoxon/earlyInput.js +40 -0
  309. package/lib/quoxon/echo.js +15 -0
  310. package/lib/quoxon/egg.js +36 -0
  311. package/lib/quoxon/events.js +677 -0
  312. package/lib/quoxon/feedback.js +50 -0
  313. package/lib/quoxon/gallery.js +237 -0
  314. package/lib/quoxon/handoffOffer.js +78 -0
  315. package/lib/quoxon/hatSwitch.js +37 -0
  316. package/lib/quoxon/headless.js +161 -0
  317. package/lib/quoxon/hostUrls.js +41 -0
  318. package/lib/quoxon/indicator.js +197 -0
  319. package/lib/quoxon/intent.js +52 -0
  320. package/lib/quoxon/keys.js +164 -0
  321. package/lib/quoxon/launcher.js +103 -0
  322. package/lib/quoxon/main.js +176 -0
  323. package/lib/quoxon/markdown.js +341 -0
  324. package/lib/quoxon/markdownSettle.js +19 -0
  325. package/lib/quoxon/matrixDomains.json +46 -0
  326. package/lib/quoxon/mentions.js +90 -0
  327. package/lib/quoxon/mind.js +103 -0
  328. package/lib/quoxon/mode.js +46 -0
  329. package/lib/quoxon/model.js +311 -0
  330. package/lib/quoxon/modelPrefs.js +345 -0
  331. package/lib/quoxon/motion/clock.js +70 -0
  332. package/lib/quoxon/motion/color.js +35 -0
  333. package/lib/quoxon/motion/frame.js +14 -0
  334. package/lib/quoxon/motion/level.js +91 -0
  335. package/lib/quoxon/motion/reveal.js +54 -0
  336. package/lib/quoxon/motion/ring.js +79 -0
  337. package/lib/quoxon/mouse.js +211 -0
  338. package/lib/quoxon/noai.js +57 -0
  339. package/lib/quoxon/objects/agent.js +61 -0
  340. package/lib/quoxon/objects/away.js +72 -0
  341. package/lib/quoxon/objects/crystal.js +100 -0
  342. package/lib/quoxon/objects/fetch.js +182 -0
  343. package/lib/quoxon/objects/fleet.js +149 -0
  344. package/lib/quoxon/objects/health.js +186 -0
  345. package/lib/quoxon/objects/index.js +106 -0
  346. package/lib/quoxon/objects/ladder.js +71 -0
  347. package/lib/quoxon/objects/memory.js +44 -0
  348. package/lib/quoxon/objects/mirror.js +137 -0
  349. package/lib/quoxon/objects/model.js +118 -0
  350. package/lib/quoxon/objects/peek.js +17 -0
  351. package/lib/quoxon/objects/proof.js +110 -0
  352. package/lib/quoxon/objects/prove.js +130 -0
  353. package/lib/quoxon/objects/replay.js +125 -0
  354. package/lib/quoxon/objects/sitrep.js +58 -0
  355. package/lib/quoxon/objects/skill.js +105 -0
  356. package/lib/quoxon/objects/view.js +87 -0
  357. package/lib/quoxon/objects/workflow.js +119 -0
  358. package/lib/quoxon/observers.js +42 -0
  359. package/lib/quoxon/onboarding/copy.js +263 -0
  360. package/lib/quoxon/onboarding/credential.js +108 -0
  361. package/lib/quoxon/onboarding/detect.js +22 -0
  362. package/lib/quoxon/onboarding/dockerOffer.js +45 -0
  363. package/lib/quoxon/onboarding/failureCause.js +33 -0
  364. package/lib/quoxon/onboarding/finish.js +134 -0
  365. package/lib/quoxon/onboarding/index.js +94 -0
  366. package/lib/quoxon/onboarding/installRunner.js +284 -0
  367. package/lib/quoxon/onboarding/intent.js +53 -0
  368. package/lib/quoxon/onboarding/journey.js +73 -0
  369. package/lib/quoxon/onboarding/preflight.js +156 -0
  370. package/lib/quoxon/onboarding/probe.js +65 -0
  371. package/lib/quoxon/onboarding/runner.js +58 -0
  372. package/lib/quoxon/onboarding/view.js +682 -0
  373. package/lib/quoxon/orgLabel.js +10 -0
  374. package/lib/quoxon/orgSwitch.js +33 -0
  375. package/lib/quoxon/ownBroadcast.js +22 -0
  376. package/lib/quoxon/palette.js +43 -0
  377. package/lib/quoxon/print.js +98 -0
  378. package/lib/quoxon/profileSwitch.js +53 -0
  379. package/lib/quoxon/promptHistory.js +41 -0
  380. package/lib/quoxon/providers.js +48 -0
  381. package/lib/quoxon/qart.js +348 -0
  382. package/lib/quoxon/qdragon.js +410 -0
  383. package/lib/quoxon/qdragonFly.js +61 -0
  384. package/lib/quoxon/qdragonScenes.js +282 -0
  385. package/lib/quoxon/qeyes.js +213 -0
  386. package/lib/quoxon/qglyph.js +143 -0
  387. package/lib/quoxon/qhello.js +58 -0
  388. package/lib/quoxon/qmotion.js +132 -0
  389. package/lib/quoxon/render.js +1167 -0
  390. package/lib/quoxon/resend.js +72 -0
  391. package/lib/quoxon/roster.js +307 -0
  392. package/lib/quoxon/route.js +39 -0
  393. package/lib/quoxon/rows.js +711 -0
  394. package/lib/quoxon/rowsStore.js +80 -0
  395. package/lib/quoxon/rules.js +130 -0
  396. package/lib/quoxon/screenContext.js +150 -0
  397. package/lib/quoxon/screenFrames.js +254 -0
  398. package/lib/quoxon/session.js +238 -0
  399. package/lib/quoxon/sessionDead.js +17 -0
  400. package/lib/quoxon/signin.js +125 -0
  401. package/lib/quoxon/skills.js +30 -0
  402. package/lib/quoxon/slash/agents.js +112 -0
  403. package/lib/quoxon/slash/argSources.js +65 -0
  404. package/lib/quoxon/slash/args.js +65 -0
  405. package/lib/quoxon/slash/automate.js +89 -0
  406. package/lib/quoxon/slash/broadcast.js +140 -0
  407. package/lib/quoxon/slash/broadcastRun.js +108 -0
  408. package/lib/quoxon/slash/card.js +30 -0
  409. package/lib/quoxon/slash/challenge.js +114 -0
  410. package/lib/quoxon/slash/cliCommand.js +53 -0
  411. package/lib/quoxon/slash/cliLeaves.json +948 -0
  412. package/lib/quoxon/slash/compact.js +90 -0
  413. package/lib/quoxon/slash/confirm.js +30 -0
  414. package/lib/quoxon/slash/crystallize.js +69 -0
  415. package/lib/quoxon/slash/dashboard.js +136 -0
  416. package/lib/quoxon/slash/draft.js +54 -0
  417. package/lib/quoxon/slash/hatWalk.js +206 -0
  418. package/lib/quoxon/slash/inverses.js +77 -0
  419. package/lib/quoxon/slash/killer.js +24 -0
  420. package/lib/quoxon/slash/killerApi.js +16 -0
  421. package/lib/quoxon/slash/ledger.js +88 -0
  422. package/lib/quoxon/slash/listView.js +30 -0
  423. package/lib/quoxon/slash/modelCmd.js +261 -0
  424. package/lib/quoxon/slash/palette.js +118 -0
  425. package/lib/quoxon/slash/paletteController.js +169 -0
  426. package/lib/quoxon/slash/panels.js +116 -0
  427. package/lib/quoxon/slash/picker.js +56 -0
  428. package/lib/quoxon/slash/restart.js +202 -0
  429. package/lib/quoxon/slash/resume.js +59 -0
  430. package/lib/quoxon/slash/rowCmd.js +157 -0
  431. package/lib/quoxon/slash/rowWalk.js +175 -0
  432. package/lib/quoxon/slash/settings.js +60 -0
  433. package/lib/quoxon/slash/spawn.js +177 -0
  434. package/lib/quoxon/slash/stepUp.js +274 -0
  435. package/lib/quoxon/slash/stepUpCard.js +60 -0
  436. package/lib/quoxon/slash/stepUpCmds.js +78 -0
  437. package/lib/quoxon/slash/undoApi.js +38 -0
  438. package/lib/quoxon/slash/undoCmd.js +49 -0
  439. package/lib/quoxon/slash/undoWish.js +15 -0
  440. package/lib/quoxon/slash/watch.js +164 -0
  441. package/lib/quoxon/slash/wish.js +23 -0
  442. package/lib/quoxon/slash/wishCmd.js +32 -0
  443. package/lib/quoxon/slotChat.js +300 -0
  444. package/lib/quoxon/slotFormat.js +195 -0
  445. package/lib/quoxon/slotRun.js +131 -0
  446. package/lib/quoxon/sound/index.js +186 -0
  447. package/lib/quoxon/sound/mapping.js +120 -0
  448. package/lib/quoxon/sound/output.js +52 -0
  449. package/lib/quoxon/sound/synth.js +122 -0
  450. package/lib/quoxon/stray.js +22 -0
  451. package/lib/quoxon/suggestCommand.js +59 -0
  452. package/lib/quoxon/term.js +141 -0
  453. package/lib/quoxon/textBuffer.js +416 -0
  454. package/lib/quoxon/theme.js +286 -0
  455. package/lib/quoxon/tips.js +433 -0
  456. package/lib/quoxon/toolError.js +41 -0
  457. package/lib/quoxon/transcript.js +188 -0
  458. package/lib/quoxon/web/qface.js +89 -0
  459. package/lib/quoxon/welcome.js +52 -0
  460. package/lib/quoxon/whatsnew.js +136 -0
  461. package/lib/quoxon/whatsnew.jsonl +89 -0
  462. package/lib/quoxon/windowOrg.js +113 -0
  463. package/lib/server/diag.js +129 -0
  464. package/lib/server/doctor.js +71 -0
  465. package/lib/server/install.js +149 -0
  466. package/lib/server/pluginEnable.js +161 -0
  467. package/lib/server/skew.js +56 -0
  468. package/lib/server/snapshot.js +131 -0
  469. package/lib/server/status.js +128 -0
  470. package/lib/server/sys.js +65 -0
  471. package/lib/server/uninstall.js +63 -0
  472. package/lib/server/update.js +234 -0
  473. package/lib/toolOutputShape.js +315 -0
  474. package/lib/tui/app.jsx +289 -0
  475. package/lib/tui/components/Breadcrumb.jsx +42 -0
  476. package/lib/tui/components/ChatInput.jsx +68 -0
  477. package/lib/tui/components/Confirm.jsx +32 -0
  478. package/lib/tui/components/DataTable.jsx +270 -0
  479. package/lib/tui/components/DetailPanel.jsx +241 -0
  480. package/lib/tui/components/HelpOverlay.jsx +67 -0
  481. package/lib/tui/components/Layout.jsx +129 -0
  482. package/lib/tui/components/Palette.jsx +141 -0
  483. package/lib/tui/components/SearchInput.jsx +125 -0
  484. package/lib/tui/components/Sparkline.jsx +55 -0
  485. package/lib/tui/components/StatusBar.jsx +133 -0
  486. package/lib/tui/components/Toast.jsx +52 -0
  487. package/lib/tui/hooks/useApi.js +44 -0
  488. package/lib/tui/hooks/useHealth.js +90 -0
  489. package/lib/tui/hooks/usePolledApi.js +86 -0
  490. package/lib/tui/hooks/useTerminalSize.js +46 -0
  491. package/lib/tui/index.js +56 -0
  492. package/lib/tui/intro/Intro.jsx +332 -0
  493. package/lib/tui/jsx-loader.js +32 -0
  494. package/lib/tui/keys.js +87 -0
  495. package/lib/tui/registry.js +49 -0
  496. package/lib/tui/theme.js +103 -0
  497. package/lib/tui/views/AdminView.jsx +398 -0
  498. package/lib/tui/views/AgentView.jsx +204 -0
  499. package/lib/tui/views/BackupView.jsx +225 -0
  500. package/lib/tui/views/BrainView.jsx +223 -0
  501. package/lib/tui/views/ChatView.jsx +468 -0
  502. package/lib/tui/views/FilesView.jsx +218 -0
  503. package/lib/tui/views/FleetView.jsx +234 -0
  504. package/lib/tui/views/GovernanceView.jsx +453 -0
  505. package/lib/tui/views/HealthView.jsx +216 -0
  506. package/lib/tui/views/HyperionDeck.jsx +79 -0
  507. package/lib/tui/views/InboxView.jsx +228 -0
  508. package/lib/tui/views/LucidDeck.jsx +719 -0
  509. package/lib/tui/views/MainMenu.jsx +123 -0
  510. package/lib/tui/views/MemoryView.jsx +377 -0
  511. package/lib/tui/views/ObjectivesView.jsx +230 -0
  512. package/lib/tui/views/OrgView.jsx +229 -0
  513. package/lib/tui/views/ToolView.jsx +221 -0
  514. package/lib/tui/views/VaultView.jsx +422 -0
  515. package/lib/tui/views/WorkflowView.jsx +329 -0
  516. package/package.json +75 -4
@@ -0,0 +1,216 @@
1
+ /**
2
+ * HealthView — btop-style live health dashboard
3
+ *
4
+ * Single full-width panel showing:
5
+ * - Overall status dot (derived from per-service statuses)
6
+ * - A live Sparkline trend of "healthy service count" across recent polls
7
+ * - A dense list of services with status dot + status + latency
8
+ * - Recent governance incidents (best-effort, defensive)
9
+ *
10
+ * Auto-refreshes every 5 seconds via usePolledApi (only while active).
11
+ * `r` manually refreshes; Esc is handled by the parent app shell.
12
+ *
13
+ * API:
14
+ * GET /api/v1/health/aggregate (service: collector) -> { services: [...] } | { checks: [...] }
15
+ * each entry: { name, status, latency_ms }
16
+ * GET /governance/incidents (service: collector) -> { incidents: [...] } (best-effort, defensive)
17
+ */
18
+
19
+ import React, { useState, useEffect, useRef } from 'react';
20
+ import { Box, Text, useInput } from 'ink';
21
+ import { FullLayout } from '../components/Layout.jsx';
22
+ import { Sparkline } from '../components/Sparkline.jsx';
23
+ import { usePolledApi } from '../hooks/usePolledApi.js';
24
+ import { useTui } from '../app.jsx';
25
+ import { matchKey } from '../keys.js';
26
+ import { colors, styles } from '../theme.js';
27
+ import { resolveEndpoint } from '../../api/endpoints.js';
28
+
29
+ // ── Auto-refresh interval (ms) ───────────────────────────────────────
30
+ const REFRESH_INTERVAL = 5_000;
31
+
32
+ // ── History cap for the trend sparkline ──────────────────────────────
33
+ const MAX_HISTORY = 40;
34
+
35
+ // ── Statuses considered "healthy" for the overall roll-up ───────────
36
+ const HEALTHY_STATUSES = new Set(['healthy', 'online', 'active', 'up', 'ok']);
37
+
38
+ function isHealthy(status) {
39
+ return HEALTHY_STATUSES.has(status);
40
+ }
41
+
42
+ /**
43
+ * Defensively unwrap the aggregate response into a services array —
44
+ * accepts { services: [...] }, { checks: [...] }, or a bare array.
45
+ */
46
+ function unwrapServices(data) {
47
+ if (!data) return [];
48
+ if (Array.isArray(data)) return data;
49
+ if (Array.isArray(data.services)) return data.services;
50
+ if (Array.isArray(data.checks)) return data.checks;
51
+ return [];
52
+ }
53
+
54
+ /**
55
+ * Defensively unwrap an incidents response into an array.
56
+ */
57
+ function unwrapIncidents(data) {
58
+ if (!data) return [];
59
+ if (Array.isArray(data)) return data;
60
+ if (Array.isArray(data.incidents)) return data.incidents;
61
+ if (Array.isArray(data.data)) return data.data;
62
+ if (Array.isArray(data.items)) return data.items;
63
+ return [];
64
+ }
65
+
66
+ function formatServiceRow(s) {
67
+ const status = s.status || s.state || 'unknown';
68
+ const latency = s.latency_ms ?? s.latencyMs ?? s.latency;
69
+ return {
70
+ name: s.name || s.service || s.id || 'unknown',
71
+ status,
72
+ latency: latency != null ? `${Number(latency).toFixed(0)}ms` : '--',
73
+ _raw: s,
74
+ };
75
+ }
76
+
77
+ function formatIncidentRows(incidents) {
78
+ return unwrapIncidents(incidents)
79
+ .slice(0, 8)
80
+ .map((i, idx) => ({
81
+ id: i.id != null ? String(i.id) : `incident-${idx}`,
82
+ title: i.title || i.summary || i.description || 'incident',
83
+ severity: i.severity || i.level || '--',
84
+ }));
85
+ }
86
+
87
+ // ── Component ─────────────────────────────────────────────────────────
88
+ export function HealthView() {
89
+ const ctx = useTui();
90
+ const { client, screen } = ctx;
91
+ const isActive = screen === 'health';
92
+
93
+ // ── Health trend history (accumulated across polls) ──────────────────
94
+ const historyRef = useRef([]);
95
+ const [history, setHistory] = useState([]);
96
+
97
+ // ── Fetch aggregate health, polled every 5s while active ─────────────
98
+ const { data, loading, error, refresh } = usePolledApi(
99
+ async () => {
100
+ const res = await client.get(resolveEndpoint('v1.health.aggregate.list').path, { service: resolveEndpoint('v1.health.aggregate.list').service });
101
+ return res || {};
102
+ },
103
+ [client],
104
+ { intervalMs: REFRESH_INTERVAL, active: isActive }
105
+ );
106
+
107
+ // ── Fetch recent governance incidents, best-effort ────────────────────
108
+ const { data: incidentsData } = usePolledApi(
109
+ async () => {
110
+ try {
111
+ const res = await client.get(resolveEndpoint('governance.incidents.list').path, { service: resolveEndpoint('governance.incidents.list').service });
112
+ return res;
113
+ } catch {
114
+ // Endpoint may not exist / may 404 — skip silently, view still works.
115
+ return [];
116
+ }
117
+ },
118
+ [client],
119
+ { intervalMs: REFRESH_INTERVAL, active: isActive }
120
+ );
121
+
122
+ const services = unwrapServices(data);
123
+ const rows = services.map(formatServiceRow);
124
+ const incidents = formatIncidentRows(incidentsData);
125
+
126
+ // ── Accumulate a healthy-service-count trend for the sparkline ───────
127
+ useEffect(() => {
128
+ if (!data) return;
129
+ const healthyCount = services.filter((s) => isHealthy(s.status || s.state)).length;
130
+
131
+ historyRef.current = [...historyRef.current, healthyCount].slice(-MAX_HISTORY);
132
+ setHistory(historyRef.current);
133
+ // eslint-disable-next-line react-hooks/exhaustive-deps
134
+ }, [data]);
135
+
136
+ // ── Keyboard handling ──────────────────────────────────────────────
137
+ useInput((input, key) => {
138
+ if (!isActive) return;
139
+
140
+ // Manual refresh
141
+ if (matchKey('refresh', input, key)) {
142
+ refresh();
143
+ return;
144
+ }
145
+ }, { isActive });
146
+
147
+ // ── Overall roll-up status ────────────────────────────────────────
148
+ const overallStatus = rows.length === 0
149
+ ? 'unknown'
150
+ : rows.every((r) => isHealthy(r.status))
151
+ ? 'healthy'
152
+ : 'degraded';
153
+
154
+ // ── Footer hint ────────────────────────────────────────────────────
155
+ const footer = 'r: refresh Esc: back';
156
+
157
+ // ── Render ─────────────────────────────────────────────────────────
158
+ return (
159
+ <FullLayout
160
+ title="Health"
161
+ subtitle={loading ? '(refreshing...)' : `${rows.length} services`}
162
+ footer={footer}
163
+ >
164
+ <Box flexDirection="column">
165
+ {error && (
166
+ <Box marginBottom={1}>
167
+ <Text color={colors.error}>Error: {error.message}</Text>
168
+ </Box>
169
+ )}
170
+
171
+ <Box marginBottom={1}>
172
+ <Text color={colors.textMuted}>Overall: </Text>
173
+ <Text>{styles.statusDot(overallStatus)} </Text>
174
+ <Text color={colors.text}>{overallStatus}</Text>
175
+ </Box>
176
+
177
+ {history.length > 0 && (
178
+ <Box marginBottom={1}>
179
+ <Text color={colors.textMuted}>Trend: </Text>
180
+ <Sparkline data={history} width={40} color={colors.cyberBlue} />
181
+ <Text color={colors.dim}> ({history[history.length - 1]}/{rows.length} healthy)</Text>
182
+ </Box>
183
+ )}
184
+
185
+ <Box flexDirection="column" marginBottom={1}>
186
+ {loading && rows.length === 0 && (
187
+ <Text color={colors.dim}>Loading...</Text>
188
+ )}
189
+ {!loading && rows.length === 0 && (
190
+ <Text color={colors.dim}>No service health data available</Text>
191
+ )}
192
+ {rows.map((r) => (
193
+ <Box key={r.name}>
194
+ <Text>{styles.statusDot(r.status)} </Text>
195
+ <Text color={colors.text} bold>{r.name.padEnd(16)}</Text>
196
+ <Text color={colors.dim}>{String(r.status).padEnd(12)}</Text>
197
+ <Text color={colors.textMuted}>{r.latency}</Text>
198
+ </Box>
199
+ ))}
200
+ </Box>
201
+
202
+ {incidents.length > 0 && (
203
+ <Box flexDirection="column">
204
+ <Text color={colors.accent} bold>Recent Incidents</Text>
205
+ {incidents.map((i, idx) => (
206
+ <Box key={`${i.id}-${idx}`}>
207
+ <Text color={colors.warning}>{String(i.severity).padEnd(10)}</Text>
208
+ <Text color={colors.text}>{i.title}</Text>
209
+ </Box>
210
+ ))}
211
+ </Box>
212
+ )}
213
+ </Box>
214
+ </FullLayout>
215
+ );
216
+ }
@@ -0,0 +1,79 @@
1
+ /**
2
+ * HyperionDeck: the full-screen live HYPERION activity view (`quox hyperion deck`), in the Quoxon look.
3
+ * Refreshes every intervalMs; r refreshes now, q quits. A failed fetch never blanks the screen: the last
4
+ * good data stays, marked STALE, with the error named in the header. Props are injected (api, intervalMs)
5
+ * so the component is testable without a network. api = { activity() }.
6
+ *
7
+ * Refresh props live in refs so the fetch loop is created once (the LUCID deck ran out of memory when a
8
+ * changing prop restarted its loop on every redraw).
9
+ */
10
+ import React, { useState, useEffect, useRef, useCallback } from 'react';
11
+ import { Box, Text, useInput, useApp, useStdout } from 'ink';
12
+ import { statusLines, summaryText } from '../../core/hyperion.js';
13
+ import { c, gradient } from '../../quoxon/theme.js';
14
+
15
+ function roleFor(line) {
16
+ if (/^(Node load|Pool|Recent ops)/.test(line)) return 'sky';
17
+ if (/^VMID/.test(line)) return 'label';
18
+ if (/unavailable|^⚠/.test(line)) return 'warn';
19
+ return 'value';
20
+ }
21
+
22
+ export function HyperionDeck({ api, intervalMs = 10000 }) {
23
+ const { exit } = useApp();
24
+ const { stdout } = useStdout();
25
+ const rows = (stdout && stdout.rows) || 30;
26
+ const [data, setData] = useState(null);
27
+ const [err, setErr] = useState(null);
28
+ const [at, setAt] = useState(null);
29
+ const inflight = useRef(false);
30
+ const apiRef = useRef(api);
31
+ apiRef.current = api;
32
+
33
+ const refresh = useCallback(async () => {
34
+ if (inflight.current) return;
35
+ inflight.current = true;
36
+ try {
37
+ setData(await apiRef.current.activity());
38
+ setErr(null);
39
+ setAt(Date.now());
40
+ } catch (e) {
41
+ setErr(e);
42
+ } finally {
43
+ inflight.current = false;
44
+ }
45
+ }, []);
46
+
47
+ useEffect(() => {
48
+ refresh();
49
+ const t = setInterval(refresh, intervalMs);
50
+ return () => clearInterval(t);
51
+ }, [refresh, intervalMs]);
52
+
53
+ useInput((input) => {
54
+ if (input === 'q') exit();
55
+ else if (input === 'r') refresh();
56
+ });
57
+
58
+ const lines = data ? statusLines(data, { now: Date.now() }) : [];
59
+ const shown = lines.slice(0, Math.max(5, rows - 4));
60
+ const stale = err && data;
61
+ return (
62
+ <Box flexDirection="column">
63
+ <Text wrap="truncate">
64
+ {gradient(' HYPERION ').map((g, i) => <Text key={i} bold color={g.color}>{g.ch}</Text>)}
65
+ <Text color={c('value')}> {data ? summaryText(data) : 'loading'}</Text>
66
+ {stale ? <Text color={c('warn')}> STALE: {String(err.message || err).slice(0, 60)}</Text> : null}
67
+ {err && !data ? <Text color={c('error')}> unreachable: {String(err.message || err).slice(0, 60)}</Text> : null}
68
+ </Text>
69
+ <Text> </Text>
70
+ {shown.map((l, i) => <Text key={i} wrap="truncate" color={c(roleFor(l))}>{l}</Text>)}
71
+ <Text> </Text>
72
+ <Text wrap="truncate">
73
+ <Text bold color={c('key')}>r</Text><Text color={c('value')}> refresh </Text>
74
+ <Text bold color={c('key')}>q</Text><Text color={c('value')}> quit </Text>
75
+ <Text color={c('value')}>{at ? `updated ${new Date(at).toISOString().slice(11, 19)} UTC, every ${Math.round(intervalMs / 1000)}s` : ''}</Text>
76
+ </Text>
77
+ </Box>
78
+ );
79
+ }
@@ -0,0 +1,228 @@
1
+ /**
2
+ * InboxView — HITL approvals inbox
3
+ *
4
+ * Left panel: DataTable of inbox items (title, type, status, created)
5
+ * Right panel: DetailPanel with inbox item detail
6
+ *
7
+ * Features:
8
+ * - `a` key approves the selected item
9
+ * - `d` key denies the selected item
10
+ * - Auto-refreshes every 10 seconds via usePolledApi (only while active —
11
+ * never polls in the background when another screen is showing)
12
+ * - Stats header (pending/total etc) fetched separately
13
+ *
14
+ * API (org-scoped):
15
+ * GET /api/orgs/:orgId/inbox/stats (service: auth) -> stats
16
+ * GET /api/orgs/:orgId/inbox (service: auth) -> data.items
17
+ * GET /api/orgs/:orgId/inbox/:id (service: auth) -> item detail
18
+ * POST /api/orgs/:orgId/inbox/:id/respond (service: auth) -> { action, comment }
19
+ */
20
+
21
+ import React, { useState, useCallback } from 'react';
22
+ import { Box, Text, useInput } from 'ink';
23
+ import { Layout } from '../components/Layout.jsx';
24
+ import { DataTable } from '../components/DataTable.jsx';
25
+ import { DetailPanel } from '../components/DetailPanel.jsx';
26
+ import { usePolledApi } from '../hooks/usePolledApi.js';
27
+ import { useTui } from '../app.jsx';
28
+ import { matchKey } from '../keys.js';
29
+ import { colors, styles } from '../theme.js';
30
+ import { resolveEndpoint } from '../../api/endpoints.js';
31
+
32
+ // ── Helpers ───────────────────────────────────────────────────────────
33
+
34
+ /**
35
+ * Safely extract the org ID from TUI context.
36
+ */
37
+ function getOrgId(ctx) {
38
+ return ctx?.auth?.getUser?.()?.org_id
39
+ || ctx?.config?.getActiveProfile?.()?.auth?.org_id
40
+ || null;
41
+ }
42
+
43
+ // ── Column definitions ────────────────────────────────────────────────
44
+ const COLUMNS = [
45
+ { key: 'title', label: 'Title', width: 28 },
46
+ { key: 'type', label: 'Type', width: 12 },
47
+ { key: 'status', label: 'Status', width: 12 },
48
+ { key: 'created', label: 'Created', width: 12 },
49
+ ];
50
+
51
+ // ── Auto-refresh interval (ms) ───────────────────────────────────────
52
+ const REFRESH_INTERVAL = 10_000;
53
+
54
+ /**
55
+ * Format raw inbox data into table rows.
56
+ */
57
+ function formatRows(items) {
58
+ if (!Array.isArray(items)) return [];
59
+ return items.map((i) => ({
60
+ ...i,
61
+ title: i.title || i.subject || i.id,
62
+ type: i.type || i.kind || '--',
63
+ status: `${styles.statusDot(i.status || 'unknown')} ${i.status || 'unknown'}`,
64
+ created: i.created_at ? String(i.created_at).slice(0, 10) : '--',
65
+ _raw: i,
66
+ }));
67
+ }
68
+
69
+ /**
70
+ * Build a detail object for the right panel.
71
+ */
72
+ function buildDetail(raw) {
73
+ if (!raw) return null;
74
+ return {
75
+ 'Title': raw.title || raw.subject,
76
+ 'ID': raw.id,
77
+ 'Type': raw.type || raw.kind,
78
+ 'Status': raw.status,
79
+ 'Priority': raw.priority,
80
+ 'Description':raw.description || raw.body,
81
+ 'Requested By': raw.requested_by || raw.requester,
82
+ 'Created': raw.created_at,
83
+ 'Updated': raw.updated_at,
84
+ };
85
+ }
86
+
87
+ // ── Component ─────────────────────────────────────────────────────────
88
+ export function InboxView() {
89
+ const ctx = useTui();
90
+ const { client, screen, showToast, orgVersion } = ctx;
91
+ const isActive = screen === 'inbox';
92
+ const orgId = getOrgId(ctx);
93
+
94
+ const [selected, setSelected] = useState(0);
95
+
96
+ // ── Data fetching (auto-refreshes every 10s, only while active) ─────
97
+ const { data, loading, error, refresh } = usePolledApi(
98
+ async () => {
99
+ if (!orgId) return [];
100
+ const res = await client.get(resolveEndpoint('inbox.list', { orgId }).path, { service: resolveEndpoint('inbox.list', { orgId }).service, query: { status: 'all' } });
101
+ return res?.items || res?.inbox || (Array.isArray(res) ? res : []);
102
+ },
103
+ [client, orgId, orgVersion],
104
+ { intervalMs: REFRESH_INTERVAL, active: isActive }
105
+ );
106
+
107
+ // ── Stats header ──────────────────────────────────────────────────
108
+ const { data: stats } = usePolledApi(
109
+ async () => {
110
+ if (!orgId) return null;
111
+ return client.get(resolveEndpoint('inbox.stats.list', { orgId }).path, { service: resolveEndpoint('inbox.stats.list', { orgId }).service });
112
+ },
113
+ [client, orgId, orgVersion],
114
+ { intervalMs: REFRESH_INTERVAL, active: isActive }
115
+ );
116
+
117
+ // ── Formatted rows ─────────────────────────────────────────────────
118
+ const rows = formatRows(data);
119
+ const selectedRow = rows[selected];
120
+ const detail = selectedRow ? buildDetail(selectedRow._raw) : null;
121
+ const isEmptyInbox = !!orgId && !loading && !error && rows.length === 0;
122
+
123
+ // ── Respond to selected item (approve/deny) ──────────────────────────
124
+ const respond = useCallback(async (action) => {
125
+ if (!selectedRow || !orgId) return;
126
+ const itemId = selectedRow._raw.id;
127
+
128
+ try {
129
+ await client.post(resolveEndpoint('inbox.respond', { orgId, itemId }).path, {
130
+ service: resolveEndpoint('inbox.respond', { orgId, itemId }).service,
131
+ body: { action },
132
+ });
133
+ showToast(action === 'approve' ? 'Approved' : 'Denied', 'success');
134
+ refresh();
135
+ } catch (err) {
136
+ showToast(err.message, 'error');
137
+ }
138
+ }, [selectedRow, orgId, client, showToast, refresh]);
139
+
140
+ // ── Keyboard handling ──────────────────────────────────────────────
141
+ useInput((input, key) => {
142
+ if (!isActive) return;
143
+
144
+ // Manual refresh
145
+ if (matchKey('refresh', input, key)) {
146
+ refresh();
147
+ return;
148
+ }
149
+
150
+ // Approve
151
+ if (input === 'a') {
152
+ respond('approve');
153
+ return;
154
+ }
155
+
156
+ // Deny
157
+ if (input === 'd') {
158
+ respond('reject');
159
+ return;
160
+ }
161
+ }, { isActive });
162
+
163
+ // ── Stats summary line ────────────────────────────────────────────
164
+ const statsLine = stats
165
+ ? Object.entries(stats)
166
+ .filter(([, v]) => typeof v === 'number' || typeof v === 'string')
167
+ .map(([k, v]) => `${k}: ${v}`)
168
+ .join(' ')
169
+ : null;
170
+
171
+ // ── Footer hint ────────────────────────────────────────────────────
172
+ const footer = [
173
+ '↑/k ↓/j Navigate',
174
+ 'a: approve',
175
+ 'd: deny',
176
+ 'r: refresh',
177
+ 'Esc: back',
178
+ ].join(' ');
179
+
180
+ // ── Render ─────────────────────────────────────────────────────────
181
+ return (
182
+ <Layout
183
+ title="Inbox"
184
+ subtitle={orgId ? `org: ${orgId}` : '(no org)'}
185
+ footer={footer}
186
+ left={
187
+ <Box flexDirection="column">
188
+ {error && (
189
+ <Box marginBottom={1}>
190
+ <Text color={colors.error}>Error: {error.message}</Text>
191
+ </Box>
192
+ )}
193
+ {!orgId && !loading && (
194
+ <Box marginBottom={1}>
195
+ <Text color={colors.warning}>No active org. Switch orgs first.</Text>
196
+ </Box>
197
+ )}
198
+ {statsLine && (
199
+ <Box marginBottom={1}>
200
+ <Text color={colors.info}>{statsLine}</Text>
201
+ </Box>
202
+ )}
203
+ {isEmptyInbox ? (
204
+ <Box paddingY={1}>
205
+ <Text color={colors.success}>Inbox zero — nothing awaiting approval ✓</Text>
206
+ </Box>
207
+ ) : (
208
+ <DataTable
209
+ columns={COLUMNS}
210
+ rows={rows}
211
+ selected={selected}
212
+ onSelectionChange={setSelected}
213
+ loading={loading}
214
+ emptyMessage={orgId ? 'No inbox items found' : 'No active org'}
215
+ active={isActive}
216
+ />
217
+ )}
218
+ </Box>
219
+ }
220
+ right={
221
+ <DetailPanel
222
+ title={selectedRow ? (selectedRow._raw.title || selectedRow._raw.id) : undefined}
223
+ data={detail}
224
+ />
225
+ }
226
+ />
227
+ );
228
+ }