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,468 @@
1
+ /**
2
+ * ChatView — Full-screen chat with CommanderQ (and any org agent)
3
+ *
4
+ * Uses FullLayout (single panel, full width) instead of the standard two-panel layout.
5
+ *
6
+ * Features:
7
+ * - Real input line: left/right cursor movement, Ctrl+A/Ctrl+E (Home/End),
8
+ * backspace/delete at the caret, and Up/Down history recall of
9
+ * previously-sent messages
10
+ * - Agent picker: Tab (with an empty input box) opens a picker of the
11
+ * org's agents fetched from GET /api/orgs/:orgId/agents; Tab/↑↓ move,
12
+ * Enter confirms. Typing `@name ` at the start of a message routes
13
+ * just that message to `name` without changing the sticky selection.
14
+ * - Scrollback: PgUp/PgDn (and Ctrl+U/Ctrl+D) scroll a viewport window
15
+ * over the message list, auto-sticking to the newest messages unless
16
+ * the user has scrolled up
17
+ * - Message history scrolls up
18
+ * - Streams from POST /chat/stream (SSE, prompt in the body) on the collector service — same
19
+ * wire contract as `quox chat` (see lib/commands/chat.js buildStreamQuery)
20
+ * - Shows the assistant reply growing token-by-token, with a live
21
+ * thinking/tool-call status line beneath it
22
+ * - Keeps conversation_id (session_id) for continuity
23
+ * - Enter sends message, Esc goes back to menu
24
+ *
25
+ * API:
26
+ * POST /chat/stream (service: collector, body: { query_id, prompt, assistant, session_id? })
27
+ * GET /api/orgs/:orgId/agents (service: auth) -> data.agents
28
+ */
29
+
30
+ import React, { useState, useCallback, useEffect, useRef } from 'react';
31
+ import { Box, Text, useInput } from 'ink';
32
+ import { FullLayout } from '../components/Layout.jsx';
33
+ import { ChatInput } from '../components/ChatInput.jsx';
34
+ import { useTui } from '../app.jsx';
35
+ import { useTerminalSize } from '../hooks/useTerminalSize.js';
36
+ import { colors } from '../theme.js';
37
+ import { resolveEndpoint } from '../../api/endpoints.js';
38
+
39
+ // Batch token appends into React state on this interval instead of a
40
+ // setState-per-chunk, which would cause Ink to re-render (and flicker)
41
+ // the whole frame for every token on long replies.
42
+ const FLUSH_INTERVAL_MS = 50;
43
+
44
+ // Rows reserved by chrome around the scrollable message list: header (1) +
45
+ // separator (1) + footer (1) + input box (3, incl. borders) + a little
46
+ // breathing room for the streaming status line.
47
+ const RESERVED_ROWS = 7;
48
+ const MIN_VIEWPORT = 3;
49
+
50
+ function getOrgId(ctx) {
51
+ return ctx?.auth?.getUser?.()?.org_id || ctx?.config?.getActiveProfile?.()?.auth?.org_id || null;
52
+ }
53
+
54
+ // ── Component ─────────────────────────────────────────────────────────
55
+ export function ChatView() {
56
+ const ctx = useTui();
57
+ const { client, screen, setInputMode } = ctx;
58
+ const isActive = screen === 'chat';
59
+ const orgId = getOrgId(ctx);
60
+ const { rows } = useTerminalSize();
61
+
62
+ const [messages, setMessages] = useState([]);
63
+ const [input, setInput] = useState('');
64
+ const [cursor, setCursor] = useState(0);
65
+ const [conversationId, setConversationId] = useState(null);
66
+
67
+ const [isStreaming, setIsStreaming] = useState(false);
68
+ const [streamText, setStreamText] = useState('');
69
+ const [streamStatus, setStreamStatus] = useState('');
70
+ const [streamLabel, setStreamLabel] = useState('');
71
+
72
+ // ── Sent-message history (Up/Down recall) ───────────────────────────
73
+ const [history, setHistory] = useState([]);
74
+ const [historyIndex, setHistoryIndex] = useState(null);
75
+ const draftRef = useRef('');
76
+
77
+ // ── Agent picker (Tab) + `@name ` per-message routing ───────────────
78
+ const [agent, setAgent] = useState(null);
79
+ const [agents, setAgents] = useState([]);
80
+ const [agentsLoaded, setAgentsLoaded] = useState(false);
81
+ const [pickerOpen, setPickerOpen] = useState(false);
82
+ const [pickerIndex, setPickerIndex] = useState(0);
83
+
84
+ // ── Scrollback viewport ──────────────────────────────────────────────
85
+ const [scrollOffset, setScrollOffset] = useState(0);
86
+ const stickRef = useRef(true);
87
+ const prevMsgLenRef = useRef(0);
88
+ const viewportSize = Math.max(MIN_VIEWPORT, rows - RESERVED_ROWS);
89
+
90
+ // Refs used by the streaming loop — not React state, so they can be
91
+ // mutated freely between throttled flushes without triggering renders.
92
+ const mountedRef = useRef(true);
93
+ const abortRef = useRef(null);
94
+ const flushTimerRef = useRef(null);
95
+ const fullTextRef = useRef('');
96
+ // Mirror of conversationId so sendMessage always reads the latest session id
97
+ // from a ref, not a possibly-stale useCallback closure — otherwise two sends
98
+ // in quick succession (before React re-renders) can drop session continuity.
99
+ const conversationIdRef = useRef(null);
100
+
101
+ useEffect(() => {
102
+ mountedRef.current = true;
103
+ return () => {
104
+ mountedRef.current = false;
105
+ abortRef.current?.abort();
106
+ if (flushTimerRef.current) {
107
+ clearTimeout(flushTimerRef.current);
108
+ flushTimerRef.current = null;
109
+ }
110
+ };
111
+ }, []);
112
+
113
+ // ── Input-mode registry: claim 'input' mode while focused so global
114
+ // single-char shortcuts (like '?' for help) don't steal keystrokes
115
+ // out of the message box. Restore 'nav' when navigating away.
116
+ useEffect(() => {
117
+ setInputMode?.(isActive ? 'input' : 'nav');
118
+ }, [isActive, setInputMode]);
119
+
120
+ // Auto-stick the viewport to the newest messages unless the user has
121
+ // manually scrolled up (PgUp) — mirrors terminal/IRC client behaviour.
122
+ useEffect(() => {
123
+ const len = messages.length;
124
+ const grew = len - prevMsgLenRef.current;
125
+ prevMsgLenRef.current = len;
126
+ if (grew <= 0) return;
127
+ if (stickRef.current) {
128
+ setScrollOffset(0);
129
+ } else {
130
+ setScrollOffset((o) => o + grew);
131
+ }
132
+ }, [messages.length]);
133
+
134
+ // Lazily fetch the org's agent roster the first time the picker opens.
135
+ useEffect(() => {
136
+ if (!pickerOpen || agentsLoaded) return;
137
+ let cancelled = false;
138
+ (async () => {
139
+ if (!orgId) {
140
+ if (!cancelled) { setAgents([]); setAgentsLoaded(true); }
141
+ return;
142
+ }
143
+ try {
144
+ const res = await client.get(resolveEndpoint('agents.list', { orgId }).path, { service: resolveEndpoint('agents.list', { orgId }).service });
145
+ const list = res?.agents || res?.items || [];
146
+ if (!cancelled) { setAgents(Array.isArray(list) ? list : []); setAgentsLoaded(true); }
147
+ } catch {
148
+ if (!cancelled) { setAgents([]); setAgentsLoaded(true); }
149
+ }
150
+ })();
151
+ return () => { cancelled = true; };
152
+ }, [pickerOpen, agentsLoaded, client, orgId]);
153
+
154
+ const scrollUp = useCallback(() => {
155
+ stickRef.current = false;
156
+ setScrollOffset((o) => {
157
+ const maxOffset = Math.max(0, messages.length - viewportSize);
158
+ return Math.min(maxOffset, o + viewportSize);
159
+ });
160
+ }, [messages.length, viewportSize]);
161
+
162
+ const scrollDown = useCallback(() => {
163
+ setScrollOffset((o) => {
164
+ const next = Math.max(0, o - viewportSize);
165
+ if (next === 0) stickRef.current = true;
166
+ return next;
167
+ });
168
+ }, [viewportSize]);
169
+
170
+ // ── Handle keyboard input for the message box ────────────────────
171
+ useInput((ch, key) => {
172
+ if (!isActive) return;
173
+
174
+ // Scrollback works even mid-stream so a long reply can be reviewed.
175
+ if (key.pageUp) { scrollUp(); return; }
176
+ if (key.pageDown) { scrollDown(); return; }
177
+ if (key.ctrl && ch === 'u') { scrollUp(); return; }
178
+ if (key.ctrl && ch === 'd') { scrollDown(); return; }
179
+
180
+ if (isStreaming) return;
181
+
182
+ // ── Agent picker owns the keyboard while open ────────────────────
183
+ if (pickerOpen) {
184
+ if (key.tab || key.downArrow) {
185
+ setPickerIndex((i) => (agents.length ? (i + 1) % agents.length : 0));
186
+ return;
187
+ }
188
+ if (key.upArrow) {
189
+ setPickerIndex((i) => (agents.length ? (i - 1 + agents.length) % agents.length : 0));
190
+ return;
191
+ }
192
+ if (key.return) {
193
+ const chosen = agents[pickerIndex];
194
+ if (chosen) setAgent(typeof chosen === 'string' ? chosen : (chosen.id || chosen.name));
195
+ setPickerOpen(false);
196
+ return;
197
+ }
198
+ if (key.escape) {
199
+ setPickerOpen(false);
200
+ return;
201
+ }
202
+ return;
203
+ }
204
+
205
+ if (key.return) {
206
+ if (input.trim()) sendMessage();
207
+ return;
208
+ }
209
+
210
+ // Tab (with an empty box) opens the agent picker. Free otherwise.
211
+ if (key.tab) {
212
+ if (input.trim() === '') {
213
+ setPickerOpen(true);
214
+ setPickerIndex(0);
215
+ }
216
+ return;
217
+ }
218
+
219
+ // ── History recall ─────────────────────────────────────────────
220
+ if (key.upArrow) {
221
+ if (history.length === 0) return;
222
+ if (historyIndex === null) draftRef.current = input;
223
+ const newIdx = historyIndex === null ? history.length - 1 : Math.max(0, historyIndex - 1);
224
+ setHistoryIndex(newIdx);
225
+ setInput(history[newIdx]);
226
+ setCursor(history[newIdx].length);
227
+ return;
228
+ }
229
+ if (key.downArrow) {
230
+ if (historyIndex === null) return;
231
+ const newIdx = historyIndex + 1;
232
+ if (newIdx >= history.length) {
233
+ setHistoryIndex(null);
234
+ setInput(draftRef.current);
235
+ setCursor(draftRef.current.length);
236
+ } else {
237
+ setHistoryIndex(newIdx);
238
+ setInput(history[newIdx]);
239
+ setCursor(history[newIdx].length);
240
+ }
241
+ return;
242
+ }
243
+
244
+ // ── Cursor movement ────────────────────────────────────────────
245
+ if (key.leftArrow) { setCursor((c) => Math.max(0, c - 1)); return; }
246
+ if (key.rightArrow) { setCursor((c) => Math.min(input.length, c + 1)); return; }
247
+ if (key.home || (key.ctrl && ch === 'a')) { setCursor(0); return; }
248
+ if (key.end || (key.ctrl && ch === 'e')) { setCursor(input.length); return; }
249
+
250
+ // ── Edit at cursor ─────────────────────────────────────────────
251
+ if (key.backspace) {
252
+ if (cursor === 0) return;
253
+ setInput((prev) => prev.slice(0, cursor - 1) + prev.slice(cursor));
254
+ setCursor((c) => c - 1);
255
+ setHistoryIndex(null);
256
+ return;
257
+ }
258
+ if (key.delete) {
259
+ setInput((prev) => (cursor >= prev.length ? prev : prev.slice(0, cursor) + prev.slice(cursor + 1)));
260
+ setHistoryIndex(null);
261
+ return;
262
+ }
263
+
264
+ // Don't capture escape (handled by parent for navigation)
265
+ if (key.escape) return;
266
+
267
+ if (ch && !key.ctrl && !key.meta && !key.tab && !key.return) {
268
+ setInput((prev) => prev.slice(0, cursor) + ch + prev.slice(cursor));
269
+ setCursor((c) => c + ch.length);
270
+ setHistoryIndex(null);
271
+ }
272
+ }, { isActive });
273
+
274
+ // ── Throttled flush of the token buffer into React state ──────────
275
+ const scheduleFlush = useCallback(() => {
276
+ if (flushTimerRef.current) return;
277
+ flushTimerRef.current = setTimeout(() => {
278
+ flushTimerRef.current = null;
279
+ if (!mountedRef.current) return;
280
+ setStreamText(fullTextRef.current);
281
+ }, FLUSH_INTERVAL_MS);
282
+ }, []);
283
+
284
+ const cancelFlush = useCallback(() => {
285
+ if (flushTimerRef.current) {
286
+ clearTimeout(flushTimerRef.current);
287
+ flushTimerRef.current = null;
288
+ }
289
+ }, []);
290
+
291
+ // ── Send message ──────────────────────────────────────────────────
292
+ const sendMessage = useCallback(async () => {
293
+ const raw = input.trim();
294
+ if (!raw) return;
295
+
296
+ // `@name the rest of the message` routes just this send to `name`.
297
+ const atMatch = raw.match(/^@(\S+)\s+([\s\S]+)$/);
298
+ const routedAgent = atMatch ? atMatch[1] : null;
299
+ const promptBody = atMatch ? atMatch[2] : raw;
300
+ const effectiveAgent = routedAgent || agent || 'quox';
301
+
302
+ setHistory((prev) => [...prev, raw]);
303
+ setHistoryIndex(null);
304
+ draftRef.current = '';
305
+
306
+ setMessages((prev) => [...prev, { role: 'user', text: raw }]);
307
+ setInput('');
308
+ setCursor(0);
309
+
310
+ fullTextRef.current = '';
311
+ setIsStreaming(true);
312
+ setStreamText('');
313
+ setStreamStatus('');
314
+ setStreamLabel('');
315
+
316
+ const controller = new AbortController();
317
+ abortRef.current = controller;
318
+
319
+ const queryId = `CLI_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
320
+ const body = {
321
+ query_id: queryId,
322
+ prompt: promptBody,
323
+ assistant: effectiveAgent,
324
+ };
325
+ if (conversationIdRef.current) body.session_id = conversationIdRef.current;
326
+
327
+ let sawChunk = false;
328
+ let resultSessionId = conversationIdRef.current;
329
+ let agentUsed = null;
330
+
331
+ try {
332
+ for await (const event of client.stream(resolveEndpoint('chat.stream').path, {
333
+ service: resolveEndpoint('chat.stream').service,
334
+ body,
335
+ signal: controller.signal,
336
+ })) {
337
+ if (!mountedRef.current || controller.signal.aborted) return;
338
+
339
+ if (event.agent_used) {
340
+ agentUsed = event.agent_used;
341
+ setStreamLabel(agentUsed);
342
+ }
343
+
344
+ switch (event.type) {
345
+ case 'connected':
346
+ break;
347
+
348
+ case 'thinking': {
349
+ const stage = event.stage || '';
350
+ if (stage === 'tool_call' || stage.includes('tool')) {
351
+ setStreamStatus(`⚙ using tool: ${event.message || ''}`);
352
+ } else if (event.message) {
353
+ setStreamStatus(`… ${event.message}`);
354
+ }
355
+ break;
356
+ }
357
+
358
+ case 'chunk':
359
+ sawChunk = true;
360
+ fullTextRef.current += event.content || '';
361
+ scheduleFlush();
362
+ break;
363
+
364
+ case 'done':
365
+ if (!sawChunk && event.full_response) {
366
+ fullTextRef.current = event.full_response;
367
+ }
368
+ if (event.session_id) resultSessionId = event.session_id;
369
+ break;
370
+
371
+ case 'error':
372
+ throw new Error(event.error || 'Stream error');
373
+
374
+ default:
375
+ break;
376
+ }
377
+ }
378
+
379
+ if (!mountedRef.current || controller.signal.aborted) return;
380
+
381
+ cancelFlush();
382
+ if (resultSessionId) {
383
+ conversationIdRef.current = resultSessionId;
384
+ setConversationId(resultSessionId);
385
+ }
386
+ setMessages((prev) => [...prev, { role: 'assistant', text: fullTextRef.current, label: agentUsed }]);
387
+ } catch (err) {
388
+ if (!mountedRef.current || controller.signal.aborted) return;
389
+ cancelFlush();
390
+ setMessages((prev) => [...prev, { role: 'error', text: err.message }]);
391
+ } finally {
392
+ if (mountedRef.current) {
393
+ setIsStreaming(false);
394
+ setStreamText('');
395
+ setStreamStatus('');
396
+ setStreamLabel('');
397
+ }
398
+ if (abortRef.current === controller) abortRef.current = null;
399
+ }
400
+ }, [input, client, agent, scheduleFlush, cancelFlush]);
401
+
402
+ // ── Viewport window over the message list ──────────────────────────
403
+ const total = messages.length;
404
+ const windowEnd = Math.max(0, total - scrollOffset);
405
+ const windowStart = Math.max(0, windowEnd - viewportSize);
406
+ const visibleMessages = messages.slice(windowStart, windowEnd);
407
+ const hiddenAbove = windowStart;
408
+ const hiddenBelow = total - windowEnd;
409
+
410
+ const activeAgent = agent || 'quox';
411
+ const footer = `Enter: send ↑/↓: history PgUp/PgDn: scroll Tab: agent Esc: back [agent: ${activeAgent}]`;
412
+
413
+ // ── Render ─────────────────────────────────────────────────────────
414
+ return (
415
+ <FullLayout title="Chat" subtitle="CommanderQ" footer={footer}>
416
+ {/* Message history */}
417
+ <Box flexDirection="column" flexGrow={1} overflow="hidden">
418
+ {messages.length === 0 && !isStreaming && (
419
+ <Text color={colors.dim}>Type a message and press Enter to chat with CommanderQ</Text>
420
+ )}
421
+ {hiddenAbove > 0 && (
422
+ <Text color={colors.dim}>{`↑ ${hiddenAbove} earlier message${hiddenAbove === 1 ? '' : 's'} (PgUp)`}</Text>
423
+ )}
424
+ {visibleMessages.map((msg, i) => (
425
+ <Box key={windowStart + i} marginBottom={1}>
426
+ <Text
427
+ color={msg.role === 'user' ? colors.cyberBlue : msg.role === 'error' ? colors.error : colors.accent}
428
+ bold
429
+ >
430
+ {msg.role === 'user' ? 'You: ' : msg.role === 'error' ? 'Error: ' : `${msg.label || 'CommanderQ'}: `}
431
+ </Text>
432
+ <Text color={msg.role === 'error' ? colors.error : colors.text} wrap="wrap">
433
+ {msg.text}
434
+ </Text>
435
+ </Box>
436
+ ))}
437
+ {hiddenBelow > 0 && (
438
+ <Text color={colors.dim}>{`↓ ${hiddenBelow} newer message${hiddenBelow === 1 ? '' : 's'} (PgDn)`}</Text>
439
+ )}
440
+ {isStreaming && (
441
+ <Box marginBottom={streamStatus ? 0 : 1}>
442
+ <Text color={colors.accent} bold>{`${streamLabel || 'CommanderQ'}: `}</Text>
443
+ {streamText ? (
444
+ <Text color={colors.text} wrap="wrap">{streamText}</Text>
445
+ ) : (
446
+ <Text color={colors.warning}>is thinking...</Text>
447
+ )}
448
+ </Box>
449
+ )}
450
+ {isStreaming && streamStatus && (
451
+ <Box marginBottom={1}>
452
+ <Text color={colors.dim}>{streamStatus}</Text>
453
+ </Box>
454
+ )}
455
+ </Box>
456
+
457
+ {/* Input + agent picker */}
458
+ <ChatInput
459
+ input={input}
460
+ cursor={cursor}
461
+ disabled={isStreaming}
462
+ agents={agents}
463
+ pickerOpen={pickerOpen}
464
+ pickerIndex={pickerIndex}
465
+ />
466
+ </FullLayout>
467
+ );
468
+ }
@@ -0,0 +1,218 @@
1
+ /**
2
+ * FilesView — File management view
3
+ *
4
+ * Left panel: DataTable of files (name, size, type, created)
5
+ * Right panel: DetailPanel with file detail
6
+ *
7
+ * Features:
8
+ * - `d` key deletes selected file (with y/n confirmation)
9
+ * - `r` key refreshes file list
10
+ *
11
+ * API:
12
+ * GET /list (service: files) -> data.files
13
+ */
14
+
15
+ import React, { useState, useCallback } from 'react';
16
+ import { Box, Text, useInput } from 'ink';
17
+ import { Layout } from '../components/Layout.jsx';
18
+ import { DataTable } from '../components/DataTable.jsx';
19
+ import { DetailPanel } from '../components/DetailPanel.jsx';
20
+ import { Confirm } from '../components/Confirm.jsx';
21
+ import { useApi } from '../hooks/useApi.js';
22
+ import { useTui } from '../app.jsx';
23
+ import { matchKey } from '../keys.js';
24
+ import { colors } from '../theme.js';
25
+ import { resolveEndpoint } from '../../api/endpoints.js';
26
+
27
+ // ── Helpers ───────────────────────────────────────────────────────────
28
+
29
+ /**
30
+ * Format bytes into a human-readable file size.
31
+ */
32
+ function formatFileSize(bytes) {
33
+ if (bytes == null || isNaN(bytes)) return '--';
34
+ const num = Number(bytes);
35
+ if (num === 0) return '0 B';
36
+ const units = ['B', 'KB', 'MB', 'GB', 'TB'];
37
+ const i = Math.floor(Math.log(num) / Math.log(1024));
38
+ const size = (num / Math.pow(1024, i)).toFixed(i > 0 ? 1 : 0);
39
+ return `${size} ${units[i]}`;
40
+ }
41
+
42
+ /**
43
+ * Format a date string for display.
44
+ */
45
+ function formatDate(iso) {
46
+ if (!iso) return '--';
47
+ try {
48
+ const d = new Date(iso);
49
+ return d.toISOString().slice(0, 10);
50
+ } catch {
51
+ return String(iso).slice(0, 10);
52
+ }
53
+ }
54
+
55
+ // ── Column definitions ────────────────────────────────────────────────
56
+ const COLUMNS = [
57
+ { key: 'name', label: 'Name', width: 24 },
58
+ { key: 'size', label: 'Size', width: 10 },
59
+ { key: 'type', label: 'Type', width: 12 },
60
+ { key: 'created', label: 'Created', width: 14 },
61
+ ];
62
+
63
+ /**
64
+ * Format raw file data into table rows.
65
+ */
66
+ function formatRows(files) {
67
+ if (!Array.isArray(files)) return [];
68
+ return files.map((f) => ({
69
+ name: f.name || f.filename || f.id,
70
+ size: formatFileSize(f.size || f.file_size),
71
+ type: f.type || f.mime_type || f.content_type || '--',
72
+ created: formatDate(f.created_at || f.uploaded_at),
73
+ _raw: f,
74
+ }));
75
+ }
76
+
77
+ /**
78
+ * Build a detail object for the right panel.
79
+ */
80
+ function buildDetail(raw) {
81
+ if (!raw) return null;
82
+ return {
83
+ 'Name': raw.name || raw.filename,
84
+ 'ID': raw.id,
85
+ 'Size': formatFileSize(raw.size || raw.file_size),
86
+ 'Type': raw.type || raw.mime_type || raw.content_type,
87
+ 'Path': raw.path || raw.file_path || '--',
88
+ 'Created': raw.created_at || raw.uploaded_at,
89
+ 'Modified': raw.updated_at || raw.modified_at || '--',
90
+ 'Owner': raw.owner || raw.uploaded_by || '--',
91
+ 'Tags': Array.isArray(raw.tags) ? raw.tags.join(', ') : '--',
92
+ };
93
+ }
94
+
95
+ // ── Component ─────────────────────────────────────────────────────────
96
+ export function FilesView() {
97
+ const ctx = useTui();
98
+ const { client, screen, orgVersion } = ctx;
99
+ const isActive = screen === 'files';
100
+
101
+ const [selected, setSelected] = useState(0);
102
+ const [actionMsg, setActionMsg] = useState(null);
103
+ const [confirming, setConfirming] = useState(false);
104
+
105
+ // ── Data fetching (refetches when the active org changes) ───────────
106
+ const { data, loading, error, refresh } = useApi(
107
+ async () => {
108
+ const res = await client.get(resolveEndpoint('files.list').path, { service: resolveEndpoint('files.list').service });
109
+ return res?.files || [];
110
+ },
111
+ [client, orgVersion]
112
+ );
113
+
114
+ const rows = formatRows(data);
115
+ const selectedRow = rows[selected];
116
+ const detail = selectedRow ? buildDetail(selectedRow._raw) : null;
117
+
118
+ // ── Delete file ─────────────────────────────────────────────────────
119
+ const deleteFile = useCallback(async () => {
120
+ if (!selectedRow) return;
121
+ const raw = selectedRow._raw;
122
+ const fileId = raw.id;
123
+
124
+ try {
125
+ setActionMsg('Deleting...');
126
+ await client.delete(resolveEndpoint('file.delete', { fileId }).path, { service: resolveEndpoint('file.delete', { fileId }).service });
127
+ setActionMsg(`Deleted "${raw.name || raw.filename || fileId}"`);
128
+ refresh();
129
+ } catch (err) {
130
+ setActionMsg(`Delete failed: ${err.message}`);
131
+ }
132
+
133
+ setTimeout(() => setActionMsg(null), 3000);
134
+ }, [selectedRow, client, refresh]);
135
+
136
+ // ── Keyboard handling ──────────────────────────────────────────────
137
+ useInput((input, key) => {
138
+ if (!isActive || confirming) return;
139
+
140
+ // Manual refresh
141
+ if (matchKey('refresh', input, key)) {
142
+ refresh();
143
+ return;
144
+ }
145
+
146
+ // Delete file
147
+ if (matchKey('delete', input, key) && selectedRow) {
148
+ setConfirming(true);
149
+ return;
150
+ }
151
+ }, { isActive: isActive && !confirming });
152
+
153
+ // ── Confirmation handlers ─────────────────────────────────────────
154
+ const handleConfirm = useCallback(() => {
155
+ setConfirming(false);
156
+ deleteFile();
157
+ }, [deleteFile]);
158
+
159
+ const handleCancel = useCallback(() => {
160
+ setConfirming(false);
161
+ }, []);
162
+
163
+ // ── Footer hint ────────────────────────────────────────────────────
164
+ const footer = [
165
+ '\u2191/k \u2193/j Navigate',
166
+ 'd Delete',
167
+ 'r Refresh',
168
+ 'Esc Back',
169
+ ].join(' ');
170
+
171
+ // ── Render ─────────────────────────────────────────────────────────
172
+ return (
173
+ <Layout
174
+ title="Files"
175
+ subtitle={`${rows.length} files`}
176
+ footer={footer}
177
+ left={
178
+ <Box flexDirection="column">
179
+ {error && (
180
+ <Box marginBottom={1}>
181
+ <Text color={colors.error}>Error: {error.message}</Text>
182
+ </Box>
183
+ )}
184
+ {actionMsg && (
185
+ <Box marginBottom={1}>
186
+ <Text color={colors.info}>{actionMsg}</Text>
187
+ </Box>
188
+ )}
189
+ {confirming && (
190
+ <Box marginBottom={1}>
191
+ <Confirm
192
+ message={`Delete "${selectedRow?._raw?.name || selectedRow?._raw?.filename || 'file'}"?`}
193
+ onConfirm={handleConfirm}
194
+ onCancel={handleCancel}
195
+ active={confirming}
196
+ />
197
+ </Box>
198
+ )}
199
+ <DataTable
200
+ columns={COLUMNS}
201
+ rows={rows}
202
+ selected={selected}
203
+ onSelectionChange={setSelected}
204
+ loading={loading}
205
+ emptyMessage="No files — upload via `quox file upload <path>`"
206
+ active={isActive && !confirming}
207
+ />
208
+ </Box>
209
+ }
210
+ right={
211
+ <DetailPanel
212
+ title={selectedRow ? (selectedRow._raw.name || selectedRow._raw.filename || 'File') : undefined}
213
+ data={detail}
214
+ />
215
+ }
216
+ />
217
+ );
218
+ }