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,295 @@
1
+ /**
2
+ * Chat commands: send, stream, status
3
+ */
4
+
5
+ import chalk from 'chalk';
6
+ import { formatDetail } from '../core/output.js';
7
+ import { resolveEndpoint } from '../api/endpoints.js';
8
+
9
+ /**
10
+ * Build the POST body for /chat/stream (quox#782). The prompt and context
11
+ * travel in the JSON body, never in the URL. The name is kept for callers;
12
+ * the collector reads `assistant` (not `selected_agent`, the POST /chat key).
13
+ */
14
+ export function buildStreamQuery({ queryId, message, agent, sessionId, context }) {
15
+ const body = {
16
+ query_id: queryId,
17
+ prompt: message,
18
+ assistant: agent || 'quox',
19
+ };
20
+ if (sessionId) body.session_id = sessionId;
21
+ try {
22
+ const tz = Intl.DateTimeFormat().resolvedOptions().timeZone;
23
+ if (tz) body.timezone = tz;
24
+ } catch { /* best-effort */ }
25
+ if (context) body.context = context;
26
+ return body;
27
+ }
28
+
29
+ /**
30
+ * TUI-DIVIDER: `quox chat --trace` prints the turn's protocol events as they arrive, so the
31
+ * per-layer AOCL record (`aocl.layer`: id, name, result, ms) is visible in the CLI before any
32
+ * UI animates it. Returns { text, tone } or null for an event --trace does not show.
33
+ * tone: ok | warn | fail | accent (no grey: every tone is a real colour).
34
+ */
35
+ const RESULT_TONE = { pass: 'ok', gated: 'warn', blocked: 'fail', bypass: 'accent' };
36
+ const fmtTraceMs = (ms) => {
37
+ const n = Number(ms);
38
+ if (!Number.isFinite(n)) return '';
39
+ return n < 10 ? `${Math.round(n * 10) / 10} ms` : `${Math.round(n)} ms`;
40
+ };
41
+ export function formatTraceEvent(ev) {
42
+ if (!ev || typeof ev !== 'object') return null;
43
+ switch (ev.type) {
44
+ case 'turn.started':
45
+ return { text: `▸ turn.started ${[ev.provider, ev.model].filter(Boolean).join(' ')}`, tone: 'accent' };
46
+ case 'aocl.layer': {
47
+ const result = String(ev.result || 'pass');
48
+ const line = `▤ aocl.layer ${String(ev.id || '?').padEnd(4)}${String(ev.name || '').padEnd(10)}${result.padEnd(8)}${fmtTraceMs(ev.ms).padStart(8)} ${ev.phase || ''}${ev.reason ? ` ${ev.reason}` : ''}`;
49
+ return { text: line, tone: RESULT_TONE[result] || 'accent' };
50
+ }
51
+ case 'aocl.summary':
52
+ return { text: `▤ aocl.summary ${ev.accounted ?? '?'}/${ev.total ?? '?'} accounted · ${ev.passed ?? 0} passed · ${ev.bypassed ?? 0} bypassed · ${ev.rejected ?? 0} rejected${ev.ms != null ? ` · ${fmtTraceMs(ev.ms)}` : ''}`, tone: ev.rejected ? 'fail' : 'ok' };
53
+ case 'aocl.verdict':
54
+ return { text: `▤ aocl.verdict ${ev.layer || 'L8'} ${ev.verdict}${ev.reason ? `: ${ev.reason}` : ''}`, tone: ev.verdict === 'blocked' ? 'fail' : 'warn' };
55
+ case 'trace':
56
+ return { text: `· trace ${ev.protocol || ''} ${ev.label || ''}${ev.detail ? ` ${ev.detail}` : ''}`, tone: 'accent' };
57
+ case 'turn.finished':
58
+ return { text: `▸ turn.finished ${ev.status || ''}${ev.usage?.elapsed_ms != null ? ` · ${ev.usage.elapsed_ms} ms` : ''}`, tone: ev.status === 'completed' ? 'ok' : 'fail' };
59
+ default:
60
+ return null;
61
+ }
62
+ }
63
+ const TONE_PAINT = { ok: chalk.green, warn: chalk.yellow, fail: chalk.red, accent: chalk.cyan };
64
+ function printTrace(ev) {
65
+ const f = formatTraceEvent(ev);
66
+ if (f) process.stderr.write((TONE_PAINT[f.tone] || chalk.cyan)(f.text) + '\n');
67
+ }
68
+
69
+ function generateQueryId() {
70
+ return `CLI_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
71
+ }
72
+
73
+ /**
74
+ * Consume a chat SSE stream, printing chunks as they arrive.
75
+ * Returns { text, sessionId, agentUsed } once the stream completes.
76
+ */
77
+ export async function consumeStream(client, { message, agent, sessionId, context }, { onAgentLabel, trace = false } = {}) {
78
+ const queryId = generateQueryId();
79
+ const body = buildStreamQuery({ queryId, message, agent, sessionId, context });
80
+
81
+ let text = '';
82
+ let resultSessionId = sessionId;
83
+ let agentUsed = agent;
84
+ let labelPrinted = false;
85
+ let sawChunk = false;
86
+
87
+ const printLabel = () => {
88
+ if (labelPrinted) return;
89
+ labelPrinted = true;
90
+ onAgentLabel?.(agentUsed);
91
+ };
92
+
93
+ const iter = client.stream(resolveEndpoint('chat.stream').path, { service: resolveEndpoint('chat.stream').service, body, untilClose: Boolean(trace) })[Symbol.asyncIterator]();
94
+ while (true) {
95
+ let step;
96
+ try {
97
+ step = await iter.next();
98
+ } catch (err) {
99
+ // A refusal before the stream opened carries the layers it really evaluated.
100
+ if (trace && Array.isArray(err?.body?.aocl_layers)) for (const l of err.body.aocl_layers) printTrace({ type: 'aocl.layer', ...l });
101
+ throw err;
102
+ }
103
+ if (step.done) break;
104
+ const event = step.value;
105
+ if (trace) printTrace(event);
106
+ switch (event.type) {
107
+ case 'connected':
108
+ break;
109
+
110
+ case 'thinking': {
111
+ const stage = event.stage || '';
112
+ if (stage === 'tool_call' || stage.includes('tool')) {
113
+ console.log(chalk.dim(` ⚙ using tool: ${event.message}`));
114
+ } else if (process.argv.includes('--verbose') || process.argv.includes('-v')) {
115
+ console.log(chalk.dim(` … ${event.message}`));
116
+ }
117
+ break;
118
+ }
119
+
120
+ case 'chunk':
121
+ printLabel();
122
+ sawChunk = true;
123
+ process.stdout.write(event.content || '');
124
+ text += event.content || '';
125
+ break;
126
+
127
+ case 'done':
128
+ if (!sawChunk && event.full_response) {
129
+ printLabel();
130
+ process.stdout.write(event.full_response);
131
+ text = event.full_response;
132
+ }
133
+ if (event.session_id) resultSessionId = event.session_id;
134
+ if (event.agent_used) agentUsed = event.agent_used;
135
+ console.log();
136
+ break;
137
+
138
+ case 'error':
139
+ throw new Error(event.error || 'Stream error');
140
+
141
+ default:
142
+ break;
143
+ }
144
+ }
145
+
146
+ return { text, sessionId: resultSessionId, agentUsed };
147
+ }
148
+
149
+ /** One-shot (non-streaming) chat via POST /chat/claude. */
150
+ async function sendOneShot(client, { message, agent, sessionId }) {
151
+ const body = { prompt: message };
152
+ if (agent) body.selected_agent = agent;
153
+ if (sessionId) body.session_id = sessionId;
154
+
155
+ const data = await client.post(resolveEndpoint('chat.claude').path, {
156
+ service: resolveEndpoint('chat.claude').service,
157
+ body,
158
+ timeout: 120000,
159
+ });
160
+
161
+ const response = data.result || data.response || data.text || JSON.stringify(data);
162
+ return { data, response, sessionId: data.session_id || sessionId };
163
+ }
164
+
165
+ export function registerChatCommands(program, ctx) {
166
+ const { client, auth } = ctx;
167
+
168
+ const chat = program
169
+ .command('chat')
170
+ .description('Chat with CommanderQ or any agent, streaming by default')
171
+ .argument('[message]', 'message to send (omit for interactive mode)')
172
+ .option('--agent <name>', 'route to a specific agent (e.g. sentinel, cipher, nova)')
173
+ .option('--no-stream', 'disable streaming output (one-shot request/response)')
174
+ .option('--conversation <id>', 'continue a conversation (session id)')
175
+ .option('--trace', 'print the turn\'s protocol events (per-layer AOCL, traces, summary) to stderr as they arrive')
176
+ .action(async (message, options) => {
177
+ auth.requireAuth();
178
+ const streaming = options.stream !== false;
179
+
180
+ // Interactive mode if no message
181
+ if (!message) {
182
+ const { default: inquirer } = await import('inquirer');
183
+ let currentAgent = options.agent || 'quox';
184
+ let sessionId = options.conversation;
185
+
186
+ console.log(chalk.bold(currentAgent.toUpperCase()) + chalk.dim(' | Type /exit to quit, /agent <name> to switch agent\n'));
187
+
188
+ while (true) {
189
+ const ans = await inquirer.prompt([{
190
+ type: 'input',
191
+ name: 'message',
192
+ message: chalk.cyan('You:'),
193
+ }]);
194
+
195
+ const input = (ans.message || '').trim();
196
+ if (!input || input === '/exit') break;
197
+
198
+ if (input.startsWith('/agent')) {
199
+ const next = input.slice('/agent'.length).trim();
200
+ if (next) {
201
+ currentAgent = next.toLowerCase();
202
+ console.log(chalk.dim(`Switched to agent: ${currentAgent}\n`));
203
+ } else {
204
+ console.log(chalk.dim(`Current agent: ${currentAgent}\n`));
205
+ }
206
+ continue;
207
+ }
208
+
209
+ try {
210
+ if (streaming) {
211
+ const result = await consumeStream(client, {
212
+ message: input,
213
+ agent: currentAgent,
214
+ sessionId,
215
+ }, {
216
+ onAgentLabel: (agentUsed) => process.stdout.write(chalk.green(`${(agentUsed || currentAgent).toUpperCase()}: `)),
217
+ trace: Boolean(options.trace),
218
+ });
219
+ if (result.sessionId) sessionId = result.sessionId;
220
+ console.log();
221
+ } else {
222
+ const { response, sessionId: newSessionId } = await sendOneShot(client, {
223
+ message: input,
224
+ agent: currentAgent,
225
+ sessionId,
226
+ });
227
+ if (newSessionId) sessionId = newSessionId;
228
+ console.log(chalk.green(`${currentAgent.toUpperCase()}:`), response);
229
+ console.log();
230
+ }
231
+ } catch (err) {
232
+ console.error(chalk.red(`Error: ${err.message}`));
233
+ }
234
+ }
235
+ return;
236
+ }
237
+
238
+ // Single message mode
239
+ if (streaming) {
240
+ try {
241
+ await consumeStream(client, {
242
+ message,
243
+ agent: options.agent,
244
+ sessionId: options.conversation,
245
+ }, {
246
+ onAgentLabel: () => {}, // no label prefix in single-shot streaming; just print tokens
247
+ trace: Boolean(options.trace),
248
+ });
249
+ } catch (err) {
250
+ console.error(chalk.red(`Error: ${err.message}`));
251
+ process.exitCode = 1;
252
+ }
253
+ return;
254
+ }
255
+
256
+ const ora = (await import('ora')).default;
257
+ const spinner = ora('Thinking...').start();
258
+
259
+ try {
260
+ const { data, response } = await sendOneShot(client, {
261
+ message,
262
+ agent: options.agent,
263
+ sessionId: options.conversation,
264
+ });
265
+ spinner.stop();
266
+
267
+ if (program.opts().output === 'json') {
268
+ console.log(JSON.stringify(data, null, 2));
269
+ } else {
270
+ console.log(response);
271
+
272
+ if (data.tools_used?.length) {
273
+ console.log(chalk.dim(`\nTools used: ${data.tools_used.join(', ')}`));
274
+ }
275
+ }
276
+ } catch (err) {
277
+ spinner.fail('Failed');
278
+ throw err;
279
+ }
280
+ });
281
+
282
+ // quox chat status
283
+ program
284
+ .command('chat-status')
285
+ .description('Check chat service status')
286
+ .action(async () => {
287
+ // Token attached when logged in: the collector auth gate 401s this
288
+ // route without a JWT (noAuth previously made it fail even when logged in).
289
+ const data = await client.get(resolveEndpoint('chat.status.list').path, { service: resolveEndpoint('chat.status.list').service });
290
+ formatDetail(data, {
291
+ format: program.opts().output,
292
+ title: 'Chat Status',
293
+ });
294
+ });
295
+ }
@@ -0,0 +1,380 @@
1
+ /**
2
+ * quox claude / codex / gemini / run / sessions: governed tmux sessions. The runner
3
+ * lives in core/governedSession.js; this file holds argument parsing and the
4
+ * commander wiring. argv arrays only; user input never reaches a shell string.
5
+ */
6
+ import { markForwardsRawArgs } from '../core/global-flags.js';
7
+ import * as gs from '../core/governedSession.js';
8
+ import { validateName, PROGRAMS } from '../core/governedSession.js';
9
+ import { runClaudeLs } from '../core/claudeLs.js';
10
+ import { gatherReport } from '../core/liveSessionsReport.js';
11
+ import { resolveEndpoint } from '../api/endpoints.js';
12
+ import { formatOutput } from '../core/output.js';
13
+ import { resolveOrgId } from './helpers.js';
14
+ import { hostname as osHostname } from 'node:os';
15
+ import { runSessionsOverview } from '../core/sessionsOverview.js';
16
+ import {
17
+ buildBeat, probeTmux, runHeartbeatLoop, pidLock, fileLogger, DEFAULT_INTERVAL_S,
18
+ } from '../core/sessionHeartbeat.js';
19
+
20
+ export {
21
+ validateName, autoName, planLaunch, parseSessions, renderIntro, runKill, runLs, runAttach,
22
+ } from '../core/governedSession.js';
23
+
24
+ /**
25
+ * Split raw args after `quox claude`: strip quox's own --no-tmux, --as <agent>
26
+ * and --slot <name> (also --as=x / --slot=x; consumed only before a bare `--`),
27
+ * find --resume <name> (else -n/--name). Claude's own --agent is NOT ours and
28
+ * passes through verbatim, as does everything else, in order.
29
+ */
30
+ export function parseClaudeArgs(raw) {
31
+ let noTmux = false;
32
+ let as;
33
+ let slot;
34
+ const args = [];
35
+ let past = false;
36
+ for (let i = 0; i < raw.length; i++) {
37
+ const a = raw[i];
38
+ if (past) { args.push(a); continue; }
39
+ if (a === '--') { past = true; args.push(a); continue; }
40
+ if (a === '--no-tmux') noTmux = true;
41
+ else if ((a === '--as' || a === '--slot') && raw[i + 1] && !raw[i + 1].startsWith('-')) {
42
+ if (a === '--as') as = raw[i + 1]; else slot = raw[i + 1];
43
+ i++;
44
+ } else if (a.startsWith('--as=') && a.length > 5) as = a.slice(5);
45
+ else if (a.startsWith('--slot=') && a.length > 7) slot = a.slice(7);
46
+ else args.push(a);
47
+ }
48
+ let name;
49
+ let resume = false;
50
+ for (let i = 0; i < args.length; i++) {
51
+ const a = args[i];
52
+ if (a === '--') break;
53
+ if (a === '--resume' || a === '-r') {
54
+ resume = true;
55
+ if (args[i + 1] && !args[i + 1].startsWith('-')) name = args[i + 1];
56
+ break;
57
+ }
58
+ if (a.startsWith('--resume=')) {
59
+ resume = true;
60
+ name = a.slice('--resume='.length) || undefined;
61
+ break;
62
+ }
63
+ }
64
+ // Claude's own -n/--name also names the tmux session, so a session started
65
+ // as `quox claude -n VULCAN` comes back with `quox claude --resume VULCAN`.
66
+ if (!resume) {
67
+ for (let i = 0; i < args.length; i++) {
68
+ const a = args[i];
69
+ if (a === '--') break;
70
+ if ((a === '-n' || a === '--name') && args[i + 1] && !args[i + 1].startsWith('-')) { name = args[i + 1]; break; }
71
+ if (a.startsWith('--name=')) { name = a.slice('--name='.length) || undefined; break; }
72
+ }
73
+ }
74
+ if (name !== undefined && !validateName(name)) name = undefined;
75
+ return { args, name, resume, noTmux, as, slot };
76
+ }
77
+
78
+ /**
79
+ * quox codex <args>: verbatim to `codex`. Codex has no --resume flag; it
80
+ * resumes with the subcommand `codex resume [SESSION_ID|NAME]`, so
81
+ * `quox codex resume NAME` names the tmux session after NAME.
82
+ */
83
+ export function parseCodexArgs(raw) {
84
+ let noTmux = false;
85
+ const args = [];
86
+ for (const a of raw) {
87
+ if (a === '--no-tmux') noTmux = true;
88
+ else args.push(a);
89
+ }
90
+ let name;
91
+ let resume = false;
92
+ if (args[0] === 'resume') {
93
+ resume = true;
94
+ if (args[1] && !args[1].startsWith('-') && validateName(args[1])) name = args[1];
95
+ }
96
+ return { args, name, resume, noTmux };
97
+ }
98
+
99
+ /** `--as` / `--slot` become the preattach request that runGoverned exports as QUOX_PREATTACH_*. */
100
+ export const runClaude = ({ as, slot, ...opts } = {}, over) => gs.runGoverned({
101
+ ...opts,
102
+ program: 'claude',
103
+ ...(as || slot ? { preattach: { agent: as, slot, session: opts.name } } : {}),
104
+ }, over);
105
+ /**
106
+ * quox gemini <args>: verbatim to `gemini`. Gemini resumes by index or
107
+ * "latest" (`--resume latest`, `-r 5`), not by name, so the tmux session is
108
+ * auto-named; reattach with `quox sessions attach NAME`.
109
+ */
110
+ export function parseGeminiArgs(raw) {
111
+ let noTmux = false;
112
+ const args = [];
113
+ for (const a of raw) {
114
+ if (a === '--no-tmux') noTmux = true;
115
+ else args.push(a);
116
+ }
117
+ const resume = args.some((a) => a === '--resume' || a === '-r' || a.startsWith('--resume='));
118
+ return { args, name: undefined, resume, noTmux };
119
+ }
120
+
121
+ /**
122
+ * quox wrap <program> [args...]: wrap ANY command. Known programs use their
123
+ * registry entry (so `quox wrap codex` == `quox codex`); unknown ones get the
124
+ * generic tag and attach-based resume hint. Args are passed verbatim.
125
+ */
126
+ export function parseRunArgs(raw) {
127
+ let noTmux = false;
128
+ const rest = [];
129
+ for (const a of raw) {
130
+ if (a === '--no-tmux' && rest.length === 0) noTmux = true;
131
+ else rest.push(a);
132
+ }
133
+ const [bin, ...args] = rest;
134
+ return { bin, args, noTmux };
135
+ }
136
+
137
+ export function runRun({ bin, args = [], noTmux = false } = {}, over) {
138
+ const known = ['claude', 'codex', 'gemini'].find((k) => PROGRAMS[k].bin === bin);
139
+ if (known) return gs.runGoverned({ program: known, args, noTmux }, over);
140
+ return gs.runGoverned({ program: 'run', bin, args, noTmux }, over);
141
+ }
142
+
143
+ export const runGemini = (opts, over) => gs.runGoverned({ ...opts, program: 'gemini' }, over);
144
+ export const runCodex = (opts, over) => gs.runGoverned({ ...opts, program: 'codex' }, over);
145
+ export const runTui = (opts, over) => gs.runGoverned({ ...opts, program: 'tui' }, over);
146
+ export const runHelp = gs.runHelp;
147
+
148
+ /** `quox tui --governed [screen] [--name N]`: the inner command is plain `quox tui [screen]`. */
149
+ export function runTuiGoverned({ screen, name, noTmux = false } = {}, over) {
150
+ return runTui({ args: screen ? [screen] : [], name, resume: !!name, noTmux }, over);
151
+ }
152
+
153
+ /** True when --help/-h appears before a bare `--` (after it, flags belong to claude). */
154
+ export function wantsWrapperHelp(args) {
155
+ for (const a of args) {
156
+ if (a === '--') return false;
157
+ if (a === '--help' || a === '-h') return true;
158
+ }
159
+ return false;
160
+ }
161
+
162
+ export const CLAUDE_WRAPPER_HELP = `Usage: quox claude [options] [-- claude-args...]
163
+
164
+ Run Claude Code in a governed tmux session that survives sleep and drops.
165
+ All other arguments are passed to claude exactly as given.
166
+
167
+ quox's own flags (consumed here, not passed to claude):
168
+ --as <agent> start already attached to a Quox agent
169
+ --slot <name> start already holding a dev slot
170
+ --no-tmux run claude directly, without tmux
171
+ -n, --name <n> name the session (also names the tmux session; claude's own flag)
172
+ --resume <n> resume the named session (claude's own flag)
173
+ -h, --help show this help
174
+
175
+ To pass --help (or any flag) through to claude itself:
176
+ quox claude -- --help`;
177
+
178
+ export function registerClaudeCommands(program, ctx, over) {
179
+ // `quox claude <args>` behaves exactly like `claude <args>`: every arg is
180
+ // forwarded verbatim. Only --no-tmux is quox's own. Management lives in
181
+ // `quox sessions` so it can never collide with claude's own arguments.
182
+ markForwardsRawArgs(program
183
+ .command('claude'), 'forwards argv after the verb verbatim')
184
+ .description('Run Claude Code (same arguments as claude) in a tmux session that survives sleep and drops')
185
+ .argument('[args...]', 'passed to claude exactly as given (quox adds only --no-tmux, --as, --slot)')
186
+ .addHelpText('after', `
187
+ quox's own flags (consumed here, not passed to claude):
188
+ --as <agent> start already attached to a Quox agent (quox agent attach <agent> at session start)
189
+ --slot <name> start already holding a dev slot (talk to it from Discord)
190
+ --no-tmux run claude directly, without tmux
191
+ Subcommand: quox claude ls [--json] lists running quox-* tmux sessions.
192
+ Claude's own --agent is untouched and passes through to claude.`)
193
+ .helpOption(false)
194
+ .allowUnknownOption()
195
+ .allowExcessArguments()
196
+ .action((_a, _o, cmd) => {
197
+ const raw = (cmd.parent && cmd.parent.rawArgs) || process.argv;
198
+ const i = raw.indexOf('claude', 2);
199
+ const rest = i >= 0 ? raw.slice(i + 1) : [];
200
+ if (wantsWrapperHelp(rest)) { console.log(CLAUDE_WRAPPER_HELP); process.exitCode = 0; return; }
201
+ // `quox claude ls [--json]` lists sessions instead of launching claude.
202
+ if (rest[0] === 'ls' && rest.slice(1).every((a) => a === '--json')) {
203
+ process.exitCode = runClaudeLs({ json: rest.includes('--json') }, over);
204
+ return;
205
+ }
206
+ const parsed = parseClaudeArgs(rest);
207
+ process.exitCode = runClaude(parsed, over);
208
+ });
209
+ markForwardsRawArgs(program
210
+ .command('codex'), 'forwards argv after the verb verbatim')
211
+ .description('Run Codex (same arguments as codex) in a tmux session that survives sleep and drops')
212
+ .argument('[args...]', 'passed to codex exactly as given (quox adds only --no-tmux)')
213
+ .helpOption(false)
214
+ .allowUnknownOption()
215
+ .allowExcessArguments()
216
+ .action((_a, _o, cmd) => {
217
+ const raw = (cmd.parent && cmd.parent.rawArgs) || process.argv;
218
+ const i = raw.indexOf('codex', 2);
219
+ const parsed = parseCodexArgs(i >= 0 ? raw.slice(i + 1) : []);
220
+ process.exitCode = runCodex(parsed, over);
221
+ });
222
+ markForwardsRawArgs(program
223
+ .command('gemini'), 'forwards argv after the verb verbatim')
224
+ .description('Run Gemini CLI (same arguments as gemini) in a tmux session that survives sleep and drops')
225
+ .argument('[args...]', 'passed to gemini exactly as given (quox adds only --no-tmux)')
226
+ .helpOption(false)
227
+ .allowUnknownOption()
228
+ .allowExcessArguments()
229
+ .action((_a, _o, cmd) => {
230
+ const raw = (cmd.parent && cmd.parent.rawArgs) || process.argv;
231
+ const i = raw.indexOf('gemini', 2);
232
+ process.exitCode = runGemini(parseGeminiArgs(i >= 0 ? raw.slice(i + 1) : []), over);
233
+ });
234
+ markForwardsRawArgs(program
235
+ .command('wrap'), 'forwards argv after the verb verbatim')
236
+ .description('Run any program in a governed tmux session: quox wrap <program> [args...]')
237
+ .argument('<program>', 'command name on PATH')
238
+ .argument('[args...]', 'passed to the program exactly as given')
239
+ .helpOption(false)
240
+ .allowUnknownOption()
241
+ .allowExcessArguments()
242
+ .action((_prog, _args, _opts, cmd) => {
243
+ // Two declared arguments => commander passes (program, args, opts, command).
244
+ const raw = (cmd && cmd.parent && cmd.parent.rawArgs) || process.argv;
245
+ const i = raw.indexOf('wrap', 2);
246
+ const rest = i >= 0 ? raw.slice(i + 1) : [];
247
+ // `quox wrap --help` / `-h` (program position only) shows usage instead
248
+ // of being refused as a program name.
249
+ if (rest.length === 0 || rest[0] === '--help' || rest[0] === '-h') {
250
+ cmd.outputHelp();
251
+ return;
252
+ }
253
+ process.exitCode = runRun(parseRunArgs(rest), over);
254
+ });
255
+ const orgOrNull = (auth) => { try { return resolveOrgId(auth, program) || null; } catch { return null; } };
256
+ // Bare `quox sessions`: the org-wide live index (QUOXON J2). Subcommands keep working.
257
+ const sessions = program.command('sessions')
258
+ .description('Everything live in your org, grouped by agent (bare); ls, attach, kill, report manage tmux sessions')
259
+ .option('--json', 'print the raw index as JSON')
260
+ .option('--watch', 'refresh every 2 s until Ctrl-C')
261
+ .option('--all', 'show every conversation (default: the 5 most recent plus any working or waiting)')
262
+ .action(async (o) => {
263
+ const so = (over && over.sessionsOverview) || {};
264
+ const fetchIndex = so.fetchIndex || (async () => {
265
+ const { client, auth } = ctx;
266
+ auth.requireAuth();
267
+ const ep = resolveEndpoint('v1.sessions.index');
268
+ const org = orgOrNull(auth);
269
+ return client.get(ep.path, { service: ep.service, retries: 0, ...(org ? { query: { org_id: org } } : {}) });
270
+ });
271
+ const json = !!o.json || program.opts().output === 'json';
272
+ process.exitCode = await runSessionsOverview({ json, watch: !!o.watch, all: !!o.all }, { ...so, fetchIndex });
273
+ });
274
+ // `quox active [sessions|slots|agents]`: one short summary of who is doing what (QUOXON-1208).
275
+ program.command('active [filter]')
276
+ .description('Who is doing what: one line per active worker, grouped working / waiting on you / idle; filter: sessions, slots, agents')
277
+ .option('--json', 'print the summary as JSON')
278
+ .option('--all', 'show every worker (default: top 10 per group)')
279
+ .option('--lines', 'the older one-line-per-worker layout with state and age columns')
280
+ .action(async (filter, o) => {
281
+ const so = (over && over.sessionsOverview) || {};
282
+ const fetchIndex = so.fetchIndex || (async () => {
283
+ const { client, auth } = ctx;
284
+ auth.requireAuth();
285
+ const ep = resolveEndpoint('v1.sessions.index');
286
+ const org = orgOrNull(auth);
287
+ return client.get(ep.path, { service: ep.service, retries: 0, ...(org ? { query: { org_id: org } } : {}) });
288
+ });
289
+ const json = !!o.json || program.opts().output === 'json';
290
+ const { runActive } = await import('../core/activeSummary.js');
291
+ const fetchSlots = so.fetchSlots || (async () => {
292
+ const { client, auth } = ctx;
293
+ const ep = resolveEndpoint('v1.slots.list');
294
+ const r = await client.get(ep.path, { service: ep.service, retries: 0 });
295
+ return Array.isArray(r) ? r : (r?.slots || r?.data || []);
296
+ });
297
+ process.exitCode = await runActive({ filter: filter || null, json, all: !!o.all, lines: !!o.lines }, { ...so, fetchIndex, fetchSlots });
298
+ });
299
+ sessions.command('heartbeat <tmuxSession>', { hidden: true })
300
+ .description('Heartbeat one wrapped tmux session to the org session index (started by quox claude)')
301
+ .option('--loop', 'keep beating until the tmux session ends')
302
+ .option('--backend <program>', 'claude, codex, gemini, ...')
303
+ .option('--agent <agent>', 'agent the session started attached to (--as)')
304
+ .option('--slot <slot>', 'slot the session started holding (--slot)')
305
+ .action(async (name, o) => {
306
+ const { client, auth } = ctx;
307
+ auth.requireAuth();
308
+ const org = orgOrNull(auth);
309
+ const host = osHostname();
310
+ const hb = resolveEndpoint('v1.sessions.heartbeat');
311
+ const en = resolveEndpoint('v1.sessions.end');
312
+ const withOrg = (b) => (org ? { ...b, org_id: org } : b);
313
+ const post = (session) => client.post(hb.path, { service: hb.service, retries: 0, body: withOrg({ host, session }) });
314
+ const end = () => client.post(en.path, { service: en.service, retries: 0, body: withOrg({ host, name }) });
315
+ if (!o.loop) {
316
+ const p = probeTmux(name);
317
+ if (!p) { process.stderr.write(`No tmux session named ${name}.\n`); process.exitCode = 1; return; }
318
+ const r = await post(buildBeat({ probe: p, backend: o.backend, agent: o.agent, slot: o.slot }));
319
+ process.stdout.write(`Registered ${name} (expires after ${r && r.expires_after_s ? r.expires_after_s : 3 * DEFAULT_INTERVAL_S}s without a beat).\n`);
320
+ return;
321
+ }
322
+ const r = await runHeartbeatLoop({
323
+ tmuxName: name, backend: o.backend || null, agent: o.agent || null, slot: o.slot || null,
324
+ post, end, log: fileLogger(name), lock: pidLock(name),
325
+ });
326
+ process.exitCode = r.exit === 'retired' ? 1 : 0;
327
+ });
328
+ sessions.command('help').description('Show how governed sessions work (also Ctrl-b then h)')
329
+ .option('--wait', 'wait for a key before exiting (used by the popup)')
330
+ .action((o) => {
331
+ process.exitCode = runHelp({ wait: !!o.wait }, over);
332
+ });
333
+ sessions.command('ls').description('List Quox sessions (--all: the org-wide live register)')
334
+ .option('--all', 'list the org-wide register of live sessions from the collector')
335
+ .action(async (o) => {
336
+ // The bare overview also has --all, and commander hands `sessions ls --all` to the parent;
337
+ // either spelling means the org-wide register here.
338
+ if (!o.all && !sessions.opts().all) {
339
+ process.exitCode = gs.runLs(over);
340
+ return;
341
+ }
342
+ const { client, auth } = ctx;
343
+ auth.requireAuth();
344
+ const ep = resolveEndpoint('v1.liveSessions.list');
345
+ const data = await client.get(ep.path, { service: ep.service, query: { org_id: resolveOrgId(auth, program) } });
346
+ const rows = (data.sessions || []).map((s) => ({
347
+ NAME: s.name, HOST: s.host, PROGRAM: s.program || '-', TMUX: s.tmux ? 'yes' : 'no',
348
+ SLOT: s.slot || '-', AGENT: s.agent || '-', STREAM: s.stream || '-',
349
+ 'LAST-SEEN': s.last_seen_at, LIVE: s.live ? 'yes' : 'no',
350
+ }));
351
+ formatOutput(rows, {
352
+ format: program.opts().output,
353
+ columns: ['NAME', 'HOST', 'PROGRAM', 'TMUX', 'SLOT', 'AGENT', 'STREAM', 'LAST-SEEN', 'LIVE'],
354
+ emptyMessage: 'No sessions registered. Run `quox sessions report` on a dev host.',
355
+ raw: data.sessions || [],
356
+ });
357
+ });
358
+ sessions.command('report').description('Report this host\'s tmux sessions to the org live-session register').action(async () => {
359
+ const { client, auth } = ctx;
360
+ auth.requireAuth();
361
+ const payload = gatherReport();
362
+ if (!payload) {
363
+ process.stderr.write('tmux is not installed; nothing to report.\n');
364
+ process.exitCode = 1;
365
+ return;
366
+ }
367
+ const ep = resolveEndpoint('v1.liveSessions.report');
368
+ const data = await client.post(ep.path, {
369
+ service: ep.service,
370
+ body: { ...payload, org_id: resolveOrgId(auth, program) },
371
+ });
372
+ process.stdout.write(`Reported ${payload.sessions.length} session(s) from ${payload.host} (ended ${data.ended ?? 0}).\n`);
373
+ });
374
+ sessions.command('attach <name>').description('Reattach to a running Quox session').action((name) => {
375
+ process.exitCode = gs.runAttach(name, over);
376
+ });
377
+ sessions.command('kill <name>').description('Kill a Quox session').action((name) => {
378
+ process.exitCode = gs.runKill(name, over);
379
+ });
380
+ }