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,270 @@
1
+ /**
2
+ * QuoxBox commands: status, workflows, tasks, and HITL approvals for the
3
+ * governed Mac-mini agent gateway, proxied through the collector
4
+ * (services/collector/routes/quoxbox-proxy.js, mounted at /api/quoxbox).
5
+ *
6
+ * quox quoxbox <subcommand> [options]
7
+ */
8
+
9
+ import chalk from 'chalk';
10
+ import { formatOutput, formatDetail, printSuccess, printWarning } from '../core/output.js';
11
+ import { resolveEndpoint } from '../api/endpoints.js';
12
+
13
+ const VALID_MODES = ['readonly', 'propose', 'actuate'];
14
+
15
+ /** Commander collector for repeatable --param key=value flags -> { key: value, ... }. */
16
+ function collectParam(input, previous) {
17
+ const idx = input.indexOf('=');
18
+ if (idx === -1) {
19
+ throw new Error(`Invalid --param value "${input}". Expected key=value.`);
20
+ }
21
+ const key = input.slice(0, idx).trim();
22
+ const value = input.slice(idx + 1);
23
+ if (!key) {
24
+ throw new Error(`Invalid --param value "${input}". Key cannot be empty.`);
25
+ }
26
+ return { ...previous, [key]: value };
27
+ }
28
+
29
+ function statusDot(ok) {
30
+ return ok ? chalk.green('●') : chalk.red('●');
31
+ }
32
+
33
+ function renderStatus(data) {
34
+ const pending = data.pending || [];
35
+ const tasks = data.tasks || [];
36
+ const lines = [];
37
+
38
+ lines.push('');
39
+ lines.push(chalk.bold(' QUOXBOX STATUS') + chalk.dim(` mode: ${data.mode}`));
40
+ lines.push(chalk.dim(' ' + '─'.repeat(60)));
41
+ lines.push(` ${statusDot(!data.halt)} Halt ${data.halt ? chalk.red('yes') : chalk.green('no')}`);
42
+ lines.push(` ${statusDot(data.screenLocked === false)} Screen Locked ${data.screenLocked ? chalk.yellow('yes') : chalk.green('no')}`);
43
+ lines.push(` ${statusDot(!data.breakerTripped)} Breaker Tripped ${data.breakerTripped ? chalk.red('yes') : chalk.green('no')}`);
44
+ lines.push(` ${statusDot(true)} Pending Approvals ${pending.length > 0 ? chalk.yellow(pending.length) : pending.length}`);
45
+ lines.push(` ${statusDot(true)} Actuations/hr ${data.actuationsLastHour ?? 0}`);
46
+
47
+ if (tasks.length > 0) {
48
+ lines.push('');
49
+ lines.push(chalk.bold(' Recent Tasks'));
50
+ for (const t of tasks) {
51
+ lines.push(` ${chalk.cyan(t.id)} ${t.workflow} ${t.status}`);
52
+ }
53
+ }
54
+
55
+ lines.push('');
56
+ return lines.join('\n');
57
+ }
58
+
59
+ function renderTask(task) {
60
+ const lines = [];
61
+ lines.push('');
62
+ lines.push(chalk.bold(` Task: ${task.id}`));
63
+ lines.push(chalk.dim(' ' + '─'.repeat(60)));
64
+ lines.push(` Workflow ${task.workflow}`);
65
+ if (task.desc) lines.push(` Desc ${task.desc}`);
66
+ lines.push(` Status ${task.status}`);
67
+ lines.push(` Progress ${task.cursor}/${task.total}`);
68
+ lines.push(` Started ${task.startedAt || '-'}`);
69
+ lines.push(` Finished ${task.finishedAt || '-'}`);
70
+
71
+ const steps = task.steps || [];
72
+ if (steps.length > 0) {
73
+ lines.push('');
74
+ lines.push(chalk.bold(' Steps'));
75
+ steps.forEach((step, i) => {
76
+ if (!step) {
77
+ lines.push(` ${i + 1}. ${chalk.dim('(pending)')}`);
78
+ return;
79
+ }
80
+ const label = step.label || step.tool || `step ${i + 1}`;
81
+ lines.push(` ${i + 1}. ${label} ${chalk.dim(step.status || '-')}`);
82
+ if (step.status === 'awaiting_approval' && (step.pendingId || task.pendingId)) {
83
+ const approvalId = step.pendingId || task.pendingId;
84
+ lines.push(` ${chalk.yellow.bold(`⚠ HELD — approval required: ${approvalId}`)}`);
85
+ lines.push(` ${chalk.dim(`Run \`quox quoxbox approve ${approvalId}\` or \`quox quoxbox deny ${approvalId}\``)}`);
86
+ }
87
+ if (step.detail) lines.push(` ${chalk.dim(step.detail)}`);
88
+ });
89
+ }
90
+
91
+ lines.push('');
92
+ return lines.join('\n');
93
+ }
94
+
95
+ export function registerQuoxboxCommands(program, ctx) {
96
+ const { client, auth } = ctx;
97
+
98
+ const quoxbox = program
99
+ .command('quoxbox')
100
+ .description('QuoxBox governed Mac-mini agent — status, workflows, tasks, HITL approvals');
101
+
102
+ // ── status ───────────────────────────────────────────────────────────────
103
+
104
+ quoxbox
105
+ .command('status')
106
+ .description('Show QuoxBox live status: mode, halt, breaker, pending approvals, recent tasks')
107
+ .action(async () => {
108
+ auth.requireAuth();
109
+ const ep = resolveEndpoint('quoxbox.live');
110
+ const data = await client.get(ep.path, { service: ep.service });
111
+
112
+ const format = program.opts().output;
113
+ if (format === 'json') {
114
+ console.log(JSON.stringify(data, null, 2));
115
+ return;
116
+ }
117
+ if (format === 'quiet') {
118
+ console.log(data.mode || '');
119
+ return;
120
+ }
121
+ console.log(renderStatus(data));
122
+ });
123
+
124
+ // ── workflows ────────────────────────────────────────────────────────────
125
+
126
+ quoxbox
127
+ .command('workflows')
128
+ .description('List available governed workflows')
129
+ .action(async () => {
130
+ auth.requireAuth();
131
+ const ep = resolveEndpoint('quoxbox.workflows.list');
132
+ const data = await client.get(ep.path, { service: ep.service });
133
+ formatOutput({
134
+ columns: ['id', 'desc', 'params', 'steps'],
135
+ headers: ['ID', 'Description', 'Params', 'Steps'],
136
+ rows: (data.workflows || []).map((w) => ({
137
+ ...w,
138
+ params: (w.params || []).map((p) => p.name || p).join(', '),
139
+ })),
140
+ }, { format: program.opts().output, emptyMessage: 'No workflows registered.' });
141
+ });
142
+
143
+ // ── run ──────────────────────────────────────────────────────────────────
144
+
145
+ quoxbox
146
+ .command('run')
147
+ .description('Start a governed workflow task')
148
+ .argument('<workflow>', 'workflow ID')
149
+ .option('--param <key=value>', 'workflow param (repeatable)', collectParam, {})
150
+ .option('--mode <mode>', 'override gateway mode for this call (readonly|propose|actuate)')
151
+ .action(async (workflow, options) => {
152
+ auth.requireAuth();
153
+ if (options.mode && !VALID_MODES.includes(options.mode)) {
154
+ throw new Error(`--mode must be one of: ${VALID_MODES.join(', ')}`);
155
+ }
156
+
157
+ const body = { workflow, params: options.param || {} };
158
+ if (options.mode) body.mode = options.mode;
159
+
160
+ const ep = resolveEndpoint('quoxbox.task.run');
161
+ const data = await client.post(ep.path, { service: ep.service, body });
162
+ const task = data.task || data;
163
+
164
+ if (program.opts().output === 'json') {
165
+ console.log(JSON.stringify(data, null, 2));
166
+ return;
167
+ }
168
+ printSuccess(`Task started: ${task.id} (workflow: ${task.workflow}, status: ${task.status})`);
169
+ });
170
+
171
+ // ── task ─────────────────────────────────────────────────────────────────
172
+
173
+ quoxbox
174
+ .command('task')
175
+ .description('Show full task detail, including step states')
176
+ .argument('<taskId>', 'task ID')
177
+ .action(async (taskId) => {
178
+ auth.requireAuth();
179
+ const ep = resolveEndpoint('quoxbox.task.get', { taskId });
180
+ const data = await client.get(ep.path, { service: ep.service });
181
+ const task = data.task || data;
182
+
183
+ const format = program.opts().output;
184
+ if (format === 'json') {
185
+ console.log(JSON.stringify(data, null, 2));
186
+ return;
187
+ }
188
+ if (format === 'quiet') {
189
+ console.log(task.id || '');
190
+ return;
191
+ }
192
+ console.log(renderTask(task));
193
+ });
194
+
195
+ // ── tasks ────────────────────────────────────────────────────────────────
196
+
197
+ quoxbox
198
+ .command('tasks')
199
+ .description('List recent tasks (from live status)')
200
+ .action(async () => {
201
+ auth.requireAuth();
202
+ const ep = resolveEndpoint('quoxbox.live');
203
+ const data = await client.get(ep.path, { service: ep.service });
204
+ formatOutput({
205
+ columns: ['id', 'workflow', 'status', 'startedAt'],
206
+ headers: ['Task ID', 'Workflow', 'Status', 'Started'],
207
+ rows: data.tasks || [],
208
+ }, { format: program.opts().output, emptyMessage: 'No recent tasks.' });
209
+ });
210
+
211
+ // ── approve / deny ───────────────────────────────────────────────────────
212
+
213
+ quoxbox
214
+ .command('approve')
215
+ .description('Approve a pending HITL action')
216
+ .argument('<approvalId>', 'pending approval ID')
217
+ .action(async (approvalId) => {
218
+ auth.requireAuth();
219
+ const ep = resolveEndpoint('quoxbox.approve', { approvalId });
220
+ const data = await client.post(ep.path, { service: ep.service, body: {} });
221
+
222
+ if (program.opts().output === 'json') {
223
+ console.log(JSON.stringify(data, null, 2));
224
+ return;
225
+ }
226
+ formatDetail(data, { format: program.opts().output, title: `Approved: ${approvalId}` });
227
+ });
228
+
229
+ quoxbox
230
+ .command('deny')
231
+ .description('Deny a pending HITL action')
232
+ .argument('<approvalId>', 'pending approval ID')
233
+ .action(async (approvalId) => {
234
+ auth.requireAuth();
235
+ const ep = resolveEndpoint('quoxbox.deny', { approvalId });
236
+ const data = await client.post(ep.path, { service: ep.service, body: {} });
237
+
238
+ if (program.opts().output === 'json') {
239
+ console.log(JSON.stringify(data, null, 2));
240
+ return;
241
+ }
242
+ formatDetail(data, { format: program.opts().output, title: `Denied: ${approvalId}` });
243
+ });
244
+
245
+ // ── mode ─────────────────────────────────────────────────────────────────
246
+
247
+ quoxbox
248
+ .command('mode')
249
+ .description('Set the QuoxBox gateway mode (readonly|propose|actuate)')
250
+ .argument('<mode>', 'readonly | propose | actuate')
251
+ .action(async (mode) => {
252
+ auth.requireAuth();
253
+ if (!VALID_MODES.includes(mode)) {
254
+ throw new Error(`mode must be one of: ${VALID_MODES.join(', ')}`);
255
+ }
256
+
257
+ if (mode === 'actuate') {
258
+ printWarning('WARNING: actuate mode allows QuoxBox to execute governed actions on approval/policy pass, without further confirmation from this CLI.');
259
+ }
260
+
261
+ const ep = resolveEndpoint('quoxbox.mode.set');
262
+ const data = await client.post(ep.path, { service: ep.service, body: { mode } });
263
+
264
+ if (program.opts().output === 'json') {
265
+ console.log(JSON.stringify(data, null, 2));
266
+ return;
267
+ }
268
+ printSuccess(`QuoxBox mode set to: ${data.mode || mode}`);
269
+ });
270
+ }
@@ -0,0 +1,275 @@
1
+ /**
2
+ * QuoxChat commands: website-widget list + operator availability + live-support
3
+ * desk parity (QuoxChat Pro).
4
+ *
5
+ * quox quoxchat widgets
6
+ * quox quoxchat availability <widgetId> [--online|--offline]
7
+ * quox quoxchat conversations <widgetId> [--status <status>] [--waiting]
8
+ * quox quoxchat transcript <widgetId> <conversationId>
9
+ * quox quoxchat reply <widgetId> <conversationId> <message...>
10
+ *
11
+ * Backend: services/auth/routes/widgets.js (mounted at plain `/api`,
12
+ * requireOrgMembership): GET/PATCH `/api/orgs/:orgId/widgets[/:widgetId]`,
13
+ * GET `/api/orgs/:orgId/widgets/:widgetId/conversations[/:conversationId/messages]`.
14
+ * `operator_online` and `office_hours_json` are the QuoxChat Pro availability
15
+ * fields; plan-gated PATCH fields return 402 `plan_upgrade_required`.
16
+ *
17
+ * Operator reply is a separate org-authed router: POST
18
+ * `/api/orgs/:orgId/widgets/:widgetId/conversations/:conversationId/operator-reply`
19
+ * in services/auth/routes/internal-widget-matrix.js (widgetConversationOrgRouter).
20
+ * It derives the sender name server-side and returns 409 when the
21
+ * conversation is not `handed_off`.
22
+ *
23
+ * Desk status label + visitor display precedence mirror
24
+ * src/pages/views/LiveSupportView.jsx (convDeskStatus / visitorDisplay) so the
25
+ * CLI shows the same picture as the dashboard live-support desk.
26
+ */
27
+
28
+ import { formatOutput, formatDetail, printSuccess } from '../core/output.js';
29
+ import { resolveOrgId } from './helpers.js';
30
+ import { resolveEndpoint } from '../api/endpoints.js';
31
+
32
+ /** Reduce a full widget row to the availability-relevant fields. */
33
+ function availabilityView(widget) {
34
+ return {
35
+ id: widget.id,
36
+ name: widget.name,
37
+ status: widget.status,
38
+ operator_online: Boolean(widget.operator_online),
39
+ office_hours: widget.office_hours_json ?? null,
40
+ };
41
+ }
42
+
43
+ // Desk status, mirrors convDeskStatus() in LiveSupportView.jsx. A handed-off
44
+ // conversation that no operator has joined yet is WAITING whoever spoke last
45
+ // (the AI's handoff ack is the last turn right after a handoff, so keying off
46
+ // the last turn alone showed every fresh handoff as "AI active"). Otherwise
47
+ // the last turn decides: the visitor spoke last means waiting on a human, an
48
+ // operator spoke last means answered, anything else means the AI holds it.
49
+ function deskStatus(row) {
50
+ if (row?.status === 'handed_off') {
51
+ if (!row?.operator_joined_at && row?.last_message_role !== 'operator') return 'waiting';
52
+ return row?.last_message_role === 'user' ? 'waiting' : 'answered';
53
+ }
54
+ if (row?.last_message_role === 'user') return 'waiting';
55
+ if (row?.last_message_role === 'operator') return 'answered';
56
+ return 'ai';
57
+ }
58
+
59
+ const DESK_STATUS_LABEL = { waiting: 'Waiting', answered: 'Answered', ai: 'AI active' };
60
+
61
+ // Handed-off rows say so, so the desk never reads a human-owned chat as AI.
62
+ function deskStatusLabel(row) {
63
+ const base = DESK_STATUS_LABEL[deskStatus(row)];
64
+ return row?.status === 'handed_off' ? `${base} (handed off)` : base;
65
+ }
66
+
67
+ // Visitor display precedence mirrors visitorDisplay() in LiveSupportView.jsx:
68
+ // pre-handoff form name, then identify() attrs, then email, then a short
69
+ // readable visitor id. Never crops a name mid-word.
70
+ function visitorLabel(row) {
71
+ if (!row || typeof row !== 'object') return 'Visitor';
72
+ if (row.visitor_name && String(row.visitor_name).trim()) return String(row.visitor_name).trim();
73
+ let attrs = {};
74
+ if (row.visitor_identified_attrs_json) {
75
+ try {
76
+ const parsed = JSON.parse(row.visitor_identified_attrs_json);
77
+ if (parsed && typeof parsed === 'object') attrs = parsed;
78
+ } catch {
79
+ // malformed attrs, fall through to the other precedence levels
80
+ }
81
+ }
82
+ const name = attrs.name || [attrs.first_name, attrs.last_name].filter(Boolean).join(' ');
83
+ if (name) return name;
84
+ if (row.visitor_email) return String(row.visitor_email);
85
+ if (attrs.email) return String(attrs.email);
86
+ const raw = String(row.visitor_id || '').replace(/^(visitor[-_]?|qc[-_]?)/i, '');
87
+ return raw ? `Visitor ${raw.slice(0, 8)}` : 'Visitor';
88
+ }
89
+
90
+ // Transcript rows mix SQLite "YYYY-MM-DD HH:MM:SS" (UTC, no marker) and ISO
91
+ // strings depending on which service wrote them; render both as one local
92
+ // "YYYY-MM-DD HH:MM" format.
93
+ function formatMessageTime(value) {
94
+ if (!value) return '-';
95
+ const raw = String(value);
96
+ const normalised = /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/.test(raw)
97
+ ? `${raw.replace(' ', 'T')}Z`
98
+ : raw;
99
+ const d = new Date(normalised);
100
+ if (Number.isNaN(d.getTime())) return raw;
101
+ const pad = (n) => String(n).padStart(2, '0');
102
+ return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}`;
103
+ }
104
+
105
+ /** Epoch ms for a created_at that may be SQLite 'YYYY-MM-DD HH:MM:SS' (UTC) or ISO. */
106
+ function messageEpoch(value) {
107
+ if (!value) return Number.POSITIVE_INFINITY;
108
+ const raw = String(value);
109
+ const t = Date.parse(/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}(\.\d+)?$/.test(raw) ? `${raw.replace(' ', 'T')}Z` : raw);
110
+ return Number.isNaN(t) ? Number.POSITIVE_INFINITY : t;
111
+ }
112
+
113
+ /** Strictly chronological by created_at; ties keep arrival order. */
114
+ export function sortByCreatedAt(messages) {
115
+ return messages
116
+ .map((m, i) => ({ m, i, t: messageEpoch(m.created_at) }))
117
+ .sort((a, b) => (a.t - b.t) || (a.i - b.i))
118
+ .map((x) => x.m);
119
+ }
120
+
121
+ export function registerQuoxchatCommands(program, ctx) {
122
+ const { client, auth } = ctx;
123
+
124
+ const quoxchat = program
125
+ .command('quoxchat')
126
+ .description('Manage QuoxChat website widgets');
127
+
128
+ quoxchat
129
+ .command('widgets')
130
+ .description('List QuoxChat widgets for the active org')
131
+ .action(async () => {
132
+ auth.requireAuth();
133
+ const orgId = resolveOrgId(auth, program);
134
+ // QC-BRUTALOOP-W15: the route pages at 20; listing only page 1 silently
135
+ // under-reported the org's widgets (20 of 34). Walk every page.
136
+ const ep = resolveEndpoint('quoxchat.widgets.list', { orgId });
137
+ const rows = [];
138
+ for (let page = 1; page <= 50; page++) {
139
+ const data = await client.get(page === 1 ? ep.path : `${ep.path}?page=${page}`, { service: ep.service });
140
+ rows.push(...(Array.isArray(data) ? data : (data.items || [])));
141
+ if (Array.isArray(data) || !data.pagination?.has_more) break;
142
+ }
143
+ formatOutput({
144
+ columns: ['id', 'name', 'assistant_name', 'status', 'operator_online', 'created_at'],
145
+ headers: ['ID', 'Name', 'Assistant', 'Status', 'Operator online', 'Created'],
146
+ rows,
147
+ }, { format: program.opts().output, emptyMessage: 'No widgets found.' });
148
+ });
149
+
150
+ quoxchat
151
+ .command('availability')
152
+ .description('Show or set operator availability for a widget (QuoxChat Pro)')
153
+ .argument('<widgetId>', 'widget ID')
154
+ .option('--online', 'mark the human operator online')
155
+ .option('--offline', 'mark the human operator offline')
156
+ .action(async (widgetId, options) => {
157
+ auth.requireAuth();
158
+ const orgId = resolveOrgId(auth, program);
159
+
160
+ if (options.online && options.offline) {
161
+ throw new Error('Use either --online or --offline, not both.');
162
+ }
163
+
164
+ let widget;
165
+ if (options.online || options.offline) {
166
+ const data = await client.patch(resolveEndpoint('quoxchat.widgets.update', { orgId, widgetId }).path, {
167
+ service: resolveEndpoint('quoxchat.widgets.update', { orgId, widgetId }).service,
168
+ body: { operator_online: Boolean(options.online) },
169
+ });
170
+ widget = data.widget || data;
171
+ printSuccess(`Operator marked ${options.online ? 'online' : 'offline'}.`);
172
+ } else {
173
+ const data = await client.get(resolveEndpoint('quoxchat.widgets.get', { orgId, widgetId }).path, { service: resolveEndpoint('quoxchat.widgets.get', { orgId, widgetId }).service });
174
+ widget = data.widget || data;
175
+ }
176
+
177
+ formatDetail(availabilityView(widget), {
178
+ format: program.opts().output,
179
+ title: 'QuoxChat Availability',
180
+ });
181
+ });
182
+
183
+ quoxchat
184
+ .command('conversations')
185
+ .description('List conversations for a QuoxChat widget (live-support desk)')
186
+ .argument('<widgetId>', 'widget ID')
187
+ .option('--status <status>', 'filter by conversation status (active, handed_off, closed)')
188
+ .option('--waiting', 'show only conversations waiting on a human reply')
189
+ .option('--include-test', 'also list simulation (sim_*) and test conversations')
190
+ .action(async (widgetId, options) => {
191
+ auth.requireAuth();
192
+ const orgId = resolveOrgId(auth, program);
193
+
194
+ const query = options.includeTest ? {} : { exclude_test: '1' };
195
+ if (options.status) query.status = options.status;
196
+
197
+ const ep = resolveEndpoint('quoxchat.conversations.list', { orgId, widgetId });
198
+ const data = await client.get(ep.path, { service: ep.service, query });
199
+ let rows = data.items || data.conversations || data || [];
200
+ if (options.waiting) rows = rows.filter((row) => deskStatus(row) === 'waiting');
201
+
202
+ formatOutput({
203
+ columns: ['id', 'visitor', 'status', 'last_message_at', 'message_count'],
204
+ headers: ['ID', 'Visitor', 'Status', 'Last message', 'Messages'],
205
+ rows: rows.map((row) => ({
206
+ id: row.id,
207
+ visitor: visitorLabel(row),
208
+ status: deskStatusLabel(row),
209
+ last_message_at: row.last_message_at || row.started_at || '-',
210
+ message_count: row.message_count ?? 0,
211
+ })),
212
+ }, { format: program.opts().output, emptyMessage: 'No conversations found.' });
213
+ });
214
+
215
+ quoxchat
216
+ .command('transcript')
217
+ .description('Print a conversation transcript in chronological order')
218
+ .argument('<widgetId>', 'widget ID')
219
+ .argument('<conversationId>', 'conversation ID')
220
+ .option('--full', 'do not truncate long messages in table output (JSON output is never truncated)')
221
+ .action(async (widgetId, conversationId, cmdOpts = {}) => {
222
+ auth.requireAuth();
223
+ const orgId = resolveOrgId(auth, program);
224
+
225
+ // Look up the visitor's display name from the conversation list (the
226
+ // messages endpoint itself carries no visitor identity, only role +
227
+ // sender_name for operator turns), mirroring LiveSupportView.jsx.
228
+ const listEp = resolveEndpoint('quoxchat.conversations.list', { orgId, widgetId });
229
+ const listData = await client.get(listEp.path, { service: listEp.service, query: { limit: 100 } });
230
+ const listRows = listData.items || listData.conversations || listData || [];
231
+ const conv = listRows.find((row) => row.id === conversationId);
232
+ const visitorName = conv ? visitorLabel(conv) : 'Visitor';
233
+
234
+ const msgEp = resolveEndpoint('quoxchat.conversations.messages.list', { orgId, widgetId, conversationId });
235
+ const data = await client.get(msgEp.path, { service: msgEp.service });
236
+ const messages = sortByCreatedAt(data.messages || data || []);
237
+
238
+ formatOutput({
239
+ columns: ['created_at', 'from', 'content'],
240
+ headers: ['Time', 'From', 'Message'],
241
+ rows: messages.map((m) => ({
242
+ // Rows mix SQLite datetime('now') and ISO strings depending on the
243
+ // writer; normalise to one readable local format.
244
+ created_at: formatMessageTime(m.created_at),
245
+ from: m.role === 'user' ? visitorName : m.role === 'operator' ? (m.sender_name || 'Operator') : 'AI assistant',
246
+ content: m.content || '',
247
+ })),
248
+ }, { format: program.opts().output, full: cmdOpts.full === true, emptyMessage: 'No messages in this conversation yet.' });
249
+ });
250
+
251
+ quoxchat
252
+ .command('reply')
253
+ .description('Send an operator reply in a handed-off QuoxChat conversation')
254
+ .argument('<widgetId>', 'widget ID')
255
+ .argument('<conversationId>', 'conversation ID')
256
+ .argument('<message...>', 'reply text')
257
+ .action(async (widgetId, conversationId, messageParts) => {
258
+ auth.requireAuth();
259
+ const orgId = resolveOrgId(auth, program);
260
+ const body = { body: messageParts.join(' ') };
261
+
262
+ const ep = resolveEndpoint('quoxchat.conversations.reply.create', { orgId, widgetId, conversationId });
263
+ try {
264
+ const data = await client.post(ep.path, { service: ep.service, body });
265
+ printSuccess(`Reply sent as ${data.sender_name || 'operator'}.`);
266
+ } catch (err) {
267
+ if (err.status === 409) {
268
+ throw new Error(
269
+ 'This conversation is not handed off to a human operator yet. The visitor needs to request a human, or the AI needs to hand off, before a reply can be sent.'
270
+ );
271
+ }
272
+ throw err;
273
+ }
274
+ });
275
+ }