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,119 @@
1
+ /**
2
+ * Approvals commands: result (quox#791), grants list|create|revoke (fleet standing grants, 2026-10-13)
3
+ *
4
+ * After a human approves a held tool call (e.g. a gated ssh_exec) the collector
5
+ * runs it and stores the outcome. `quox approvals result <id>` reads it back.
6
+ */
7
+
8
+ import { resolveEndpoint } from '../api/endpoints.js';
9
+
10
+ import { attachWalkthrough } from './walkthrough.js';
11
+
12
+ export function registerApprovalsCommands(program, ctx) {
13
+ const { client, auth } = ctx;
14
+
15
+ const approvals = program
16
+ .command('approvals')
17
+ .description('Tool approvals (held actions awaiting or past a human decision)');
18
+ attachWalkthrough(approvals, ctx, program);
19
+
20
+ approvals
21
+ .command('result <approvalId>')
22
+ .description('Show the status and stored output of an approved tool call')
23
+ .option('--org <id>', 'org ID (service-key automation callers; defaults to active org / QUOX_ORG_ID)')
24
+ .action(async (approvalId, options) => {
25
+ auth.requireAuth();
26
+ const ep = resolveEndpoint('v1.approvals.result', { id: approvalId });
27
+ const orgId = auth.getOrgId(options.org || process.env.QUOX_ORG_ID);
28
+ const query = orgId ? { org_id: orgId } : undefined;
29
+ const data = await client.get(ep.path, { service: ep.service, ...(query ? { query } : {}) });
30
+
31
+ if (program.opts().output === 'json') {
32
+ console.log(JSON.stringify(data, null, 2));
33
+ return;
34
+ }
35
+ console.log(`Approval ${data.approval_id} tool: ${data.tool} status: ${data.status}`
36
+ + (data.executed_at ? ` executed: ${data.executed_at}` : ''));
37
+ if (data.result === null || data.result === undefined) {
38
+ if (data.status === 'pending') console.log('Still pending: a human has not decided yet.');
39
+ else if (data.status === 'resuming') console.log('Approved, executing. Re-run shortly.');
40
+ else console.log('No stored output.');
41
+ return;
42
+ }
43
+ const r = data.result;
44
+ if (typeof r === 'string') { console.log(r); return; }
45
+ if (r.success === false) console.log(`Failed: ${r.error || 'unknown error'}`);
46
+ const out = r.output ?? r.stdout ?? r.result;
47
+ if (out !== undefined) console.log(typeof out === 'string' ? out : JSON.stringify(out, null, 2));
48
+ else console.log(JSON.stringify(r, null, 2));
49
+ });
50
+
51
+ // Fleet standing grants: an org admin pre-approves ONE host + an anchored command
52
+ // shape + a VMID range until an expiry, for ssh_exec. Every use still lands in
53
+ // approvals history with an AEE envelope; anything outside the grant files HITL.
54
+ const grants = approvals
55
+ .command('grants')
56
+ .description('Standing grants: org-admin pre-approved fleet command lanes (ssh_exec)');
57
+
58
+ grants
59
+ .command('list')
60
+ .description('List active standing grants (--all includes revoked and expired)')
61
+ .option('--all', 'include revoked and expired grants')
62
+ .action(async (options) => {
63
+ auth.requireAuth();
64
+ const ep = resolveEndpoint('v1.approvals.grants.list');
65
+ const data = await client.get(ep.path, { service: ep.service, ...(options.all ? { query: { all: '1' } } : {}) });
66
+ if (program.opts().output === 'json') { console.log(JSON.stringify(data, null, 2)); return; }
67
+ const rows = data.grants || [];
68
+ if (!rows.length) { console.log('No standing grants.'); return; }
69
+ for (const g of rows) {
70
+ const state = g.revoked_at ? `revoked ${g.revoked_at}` : `expires ${g.expires_at}`;
71
+ const range = g.vmid_min != null ? ` vmids ${g.vmid_min}-${g.vmid_max}` : '';
72
+ console.log(`${g.grant_id} ${g.tool}@${g.host}${range} ${g.preset || `${g.patterns.length} patterns`} uses ${g.use_count} ${state}`);
73
+ console.log(` reason: ${g.reason} (by ${g.created_by})`);
74
+ }
75
+ });
76
+
77
+ grants
78
+ .command('create')
79
+ .description('Create a standing grant (human org admin only)')
80
+ .requiredOption('--host <hostId>', 'the ONE host the grant covers')
81
+ .requiredOption('--reason <text>', 'why (shown in history and evidence)')
82
+ .option('--preset <name>', 'proxmox-test-vm-lane (clone/power/destroy/guest-exec in a VMID range)')
83
+ .option('--template <vmid>', 'template VMID the lane clones from (preset)')
84
+ .option('--vmid-range <min-max>', 'VMID range, e.g. 9100-9199')
85
+ .option('--name-prefix <prefix>', 'VM name prefix the lane may create (preset)', 'z2h')
86
+ .option('--pattern <regex>', 'custom anchored command regex (repeatable; instead of --preset)', (v, a) => (a || []).concat([v]))
87
+ .option('--days <n>', 'expiry in days (max 30)', '14')
88
+ .action(async (options) => {
89
+ auth.requireAuth();
90
+ const body = { tool: 'ssh_exec', host: options.host, reason: options.reason, expires_in_days: Number(options.days) };
91
+ if (options.vmidRange) {
92
+ const m = /^(\d+)-(\d+)$/.exec(options.vmidRange);
93
+ if (!m) { console.error('--vmid-range must look like 9100-9199'); process.exitCode = 1; return; }
94
+ body.vmid_min = Number(m[1]); body.vmid_max = Number(m[2]);
95
+ }
96
+ if (options.preset) {
97
+ body.preset = options.preset; body.template_vmid = Number(options.template); body.name_prefix = options.namePrefix;
98
+ } else {
99
+ body.patterns = options.pattern || [];
100
+ }
101
+ const ep = resolveEndpoint('v1.approvals.grants.create');
102
+ const data = await client.post(ep.path, { service: ep.service, body });
103
+ if (program.opts().output === 'json') { console.log(JSON.stringify(data, null, 2)); return; }
104
+ const g = data.grant || {};
105
+ console.log(`Created ${g.grant_id}: ${g.tool}@${g.host}${g.vmid_min != null ? ` vmids ${g.vmid_min}-${g.vmid_max}` : ''}, expires ${g.expires_at}`);
106
+ console.log(`Revoke any time: quox approvals grants revoke ${g.grant_id}`);
107
+ });
108
+
109
+ grants
110
+ .command('revoke <grantId>')
111
+ .description('Revoke a standing grant now (human org admin only)')
112
+ .action(async (grantId) => {
113
+ auth.requireAuth();
114
+ const ep = resolveEndpoint('v1.approvals.grants.revoke', { id: grantId });
115
+ const data = await client.post(ep.path, { service: ep.service, body: {} });
116
+ if (program.opts().output === 'json') { console.log(JSON.stringify(data, null, 2)); return; }
117
+ console.log(`Revoked ${data.grant?.grant_id || grantId} at ${data.grant?.revoked_at || 'now'}.`);
118
+ });
119
+ }
@@ -0,0 +1,24 @@
1
+ /**
2
+ * quox aside "<question>"
3
+ *
4
+ * A read-only side question: the model gets no tools and no conversation, so nothing it says can change
5
+ * anything or land in a conversation's history. The TUI's /aside is the same call with the recent
6
+ * exchanges passed as read-only context.
7
+ */
8
+ import { askAside } from '../core/aside.js';
9
+
10
+ export function registerAsideCommand(program, ctx) {
11
+ const { client, auth } = ctx;
12
+ program
13
+ .command('aside')
14
+ .description('Ask a read-only side question: no tools, not saved to any conversation')
15
+ .argument('<question...>', 'the question')
16
+ .option('--agent <id>', 'who answers (default quox)')
17
+ .action(async (words, opts) => {
18
+ auth.requireAuth();
19
+ const r = await askAside(client, { question: words.join(' '), agent: opts.agent });
20
+ if (program.opts().output === 'json') { console.log(JSON.stringify({ answer: r.text, model: r.model, provider: r.provider, tools_used: r.tools, read_only: true }, null, 2)); return; }
21
+ console.log(r.text || '(no answer)');
22
+ console.log(`· aside, read only: no tools, not saved${r.model ? ` · ${r.provider ? `${r.provider}/` : ''}${r.model}` : ''}`);
23
+ });
24
+ }
@@ -0,0 +1,144 @@
1
+ /**
2
+ * `quox ask`: a session puts a fork in front of a human through the Approvals inbox (one inbox item, kind decision).
3
+ * Who is asking, what, why, the options, the recommendation and the expiry travel with it, so ONE HITL session
4
+ * can answer for twenty terminals. Not an approval of an action: no step-up PIN unless --high-risk.
5
+ */
6
+ import { readFileSync, existsSync } from 'node:fs';
7
+ import { execFileSync } from 'node:child_process';
8
+ import { homedir } from 'node:os';
9
+ import { join } from 'node:path';
10
+ import { resolveEndpoint } from '../api/endpoints.js';
11
+ import { resolveOrgId } from './helpers.js';
12
+ import { readPresence, approvalPresenceFields } from './presence.js';
13
+ import { toRepoRelative, LOOSENING_HINT } from '../core/repoPath.js';
14
+ import { parseOptions, parseDuration, YN_OPTIONS, waitForDecision, EXIT_NO_ANSWER } from '../core/askDecision.js';
15
+
16
+ function heldSlotFor(session) {
17
+ try {
18
+ const all = JSON.parse(readFileSync(join(homedir(), '.quox', 'held-slots.json'), 'utf8'));
19
+ const want = String(session || '').toLowerCase();
20
+ return Object.keys(all).find((k) => String(all[k]?.session || '').toLowerCase() === want) || null;
21
+ } catch { return null; }
22
+ }
23
+
24
+ export function registerAskCommands(program, { client, auth }) {
25
+ const err = (s) => process.stderr.write(`${s}\n`);
26
+
27
+ async function waitAndPrint(orgId, id, { timeoutSec = null } = {}) {
28
+ const r = await waitForDecision({
29
+ poll: (w) => { const ep = resolveEndpoint('inbox.decision.get', { orgId, id }); return client.get(ep.path, { service: ep.service, query: { wait: w }, timeout: (w + 15) * 1000, retries: 0 }); },
30
+ log: err,
31
+ maxWaitMs: timeoutSec != null ? timeoutSec * 1000 : null,
32
+ });
33
+ if (r.stdout) console.log(r.stdout);
34
+ process.exitCode = r.code;
35
+ return r;
36
+ }
37
+
38
+ const ask = program
39
+ .command('ask')
40
+ .description('Ask a human a question through the Approvals inbox: who asks, what, why, the options. Use this instead of asking in your own terminal')
41
+ .option('--session <name>', 'which session is asking (default: $QUOX_SESSION)')
42
+ .option('--title <text>', 'what you are asking, one line')
43
+ .option('--why <text>', 'a simple why: what the human needs to know to decide')
44
+ .option('--justify <text>', 'for a loosening (a check made easier to pass): why it is safe, in plain words; the card shows it on its JUSTIFY line and defaults to No without one')
45
+ .option('--options <list>', 'the choices: "a: Ship now|b: Wait for review|c: Drop it"')
46
+ .option('--yn', 'shorthand for a yes/no question (options y and n)')
47
+ .option('--default <key>', 'the option you would take if nobody answers (shown, never applied for you)')
48
+ .option('--recommend <key>', 'the option you recommend')
49
+ .option('--expires <dur>', 'how long it stays open: 30m, 2h, 1d (default 24h, max 30d)')
50
+ .option('--slot <name>', 'your slot, so the answer is also posted there (default: found from held slots)')
51
+ .option('--agent <name>', 'the agent asking, when it is an agent rather than a session')
52
+ .option('--high-risk', 'the answer needs the human step-up PIN')
53
+ .option('--wait', 'block until answered; prints the chosen option key (and any note) on stdout, exits 2 on expiry or deny')
54
+ .option('--timeout <dur>', 'with --wait: stop waiting after this long (the question stays open)')
55
+ .action((options) => fileAsk(options));
56
+
57
+ async function fileAsk(options) {
58
+ auth.requireAuth();
59
+ const orgId = resolveOrgId(auth, program);
60
+ const session = options.session || process.env.QUOX_SESSION;
61
+ if (!session) throw new Error('say which session is asking: --session <NAME>');
62
+ if (!options.title) throw new Error('say what you are asking: --title "<what>"');
63
+ if (options.yn && options.options) throw new Error('use --yn or --options, not both');
64
+ if (!options.yn && !options.options) throw new Error('give the choices: --options "a: Ship now|b: Wait" (or --yn)');
65
+ // QUOXON 2026-10-17: a high-risk ask (a loosening, anything the owner must PIN) carries a plain justification
66
+ // 2026-10-19: three PIN approvals were wasted on loosening asks filed without --high-risk or with unusable paths
67
+ if (!options.highRisk && /^\s*approve\s+(?:loosening|test)/i.test(options.title)) { err(`A test-edit approval must go through the loosening verb, which sets --high-risk and repo-relative paths for you:\n ${LOOSENING_HINT}`); process.exitCode = 2; return; }
68
+ if (options.highRisk && !String(options.justify || '').trim()) { err('High-risk asks need --justify "<2-3 plain lines the owner can judge>"'); process.exitCode = 2; return; }
69
+ const opts = options.yn ? YN_OPTIONS : parseOptions(options.options);
70
+ const body = {
71
+ session, title: options.title, why: options.why, options: opts,
72
+ ...(options.justify ? { justification: options.justify } : {}),
73
+ default: options.default, recommend: options.recommend,
74
+ ...(options.expires ? { expires_in_seconds: parseDuration(options.expires) } : {}),
75
+ high_risk: Boolean(options.highRisk),
76
+ slot: options.slot || heldSlotFor(session) || undefined,
77
+ profile: program.opts().profile || process.env.QUOX_PROFILE || undefined,
78
+ agent: options.agent,
79
+ };
80
+ const ep = resolveEndpoint('inbox.decision.create', { orgId });
81
+ const data = await client.post(ep.path, { service: ep.service, body });
82
+ // PRESENCE (owner 2026-10-16): say now whether the human is away, so this session can work on
83
+ // something else instead of waiting. The question is filed and queued exactly as before.
84
+ const presence = approvalPresenceFields(await readPresence(client, orgId));
85
+ const d = { ...data.decision, ...presence };
86
+ if (program.opts().output === 'json' && !options.wait) { console.log(JSON.stringify(d, null, 2)); return; }
87
+ err(`asked: ${d.id} (${session}: ${d.title}); it shows in /approvals${d.expires_at ? `, open until ${d.expires_at}` : ''}`);
88
+ if (presence.owner_away) err(`${presence.owner_away_notice}. Expect a wait: work on something else meanwhile.`);
89
+ if (!options.wait) { console.log(d.id); return; }
90
+ await waitAndPrint(orgId, d.id, { timeoutSec: options.timeout ? parseDuration(options.timeout) : null });
91
+ }
92
+
93
+ ask
94
+ .command('loosening')
95
+ .description('Ask a human to approve edits to test files (a check made easier to pass). Files a yes/no, high-risk (PIN) ask with repo-relative paths')
96
+ .option('--paths <files...>', 'every test file the commit edits (absolute, worktree or repo-relative: all are normalised)')
97
+ .option('--justify <text>', 'why it is safe, in plain words (required)')
98
+ .option('--why <text>', 'detail: the findings, before and after lines')
99
+ .option('--session <name>', 'which session is asking (default: $QUOX_SESSION)')
100
+ .option('--slot <name>', 'your slot')
101
+ .option('--expires <dur>', 'how long it stays open')
102
+ .option('--wait', 'block until answered')
103
+ .option('--timeout <dur>', 'with --wait: stop waiting after this long')
104
+ .action(async (subOptions) => {
105
+ // commander lets the parent `ask` swallow flags it shares with this verb (--justify, --why, --session...), so merge both
106
+ const options = { ...ask.opts(), ...Object.fromEntries(Object.entries(subOptions).filter(([, v]) => v !== undefined)) };
107
+ if (!String(options.justify || '').trim()) { err('say why it is safe: --justify "<plain words>"'); process.exitCode = 2; return; }
108
+ const raw = [].concat(options.paths || []).flatMap((x) => String(x).split(',')).map((x) => x.trim()).filter(Boolean);
109
+ let root;
110
+ try { root = execFileSync('git', ['rev-parse', '--show-toplevel'], { encoding: 'utf8' }).trim(); } catch { root = process.cwd(); }
111
+ const paths = [...new Set(raw.map(toRepoRelative))];
112
+ const missing = paths.filter((p) => !p || !existsSync(join(root, p)));
113
+ if (!paths.length || missing.length) { err(`not found in this repo (${root}): ${missing.join(', ') || '(no paths)'}. Run from the worktree and name files that exist.`); process.exitCode = 2; return; }
114
+ // 2026-10-19: the server truncates long titles, and the attestation names only paths found in title+body,
115
+ // so a 7-file ask covered 3. Every path also goes in the body.
116
+ const files = `Files (${paths.length}):\n${paths.map((p) => `- ${p}`).join('\n')}`;
117
+ await fileAsk({ ...options, title: `Approve test edits: ${paths.join(' ')}`, why: options.why ? `${files}\n\n${options.why}` : files, yn: true, highRisk: true, justify: options.justify });
118
+ });
119
+
120
+ ask
121
+ .command('status')
122
+ .description('Show where a question stands: pending, answered, denied or expired, with the answer')
123
+ .argument('<id>', 'the id `quox ask` printed')
124
+ .action(async (id) => {
125
+ auth.requireAuth();
126
+ const orgId = resolveOrgId(auth, program);
127
+ const ep = resolveEndpoint('inbox.decision.get', { orgId, id });
128
+ const d = (await client.get(ep.path, { service: ep.service })).decision;
129
+ if (program.opts().output === 'json') { console.log(JSON.stringify(d, null, 2)); return; }
130
+ console.log(`${d.state}${d.answer?.option ? ` ${d.answer.option}` : ''}${d.answer?.note ? ` (${d.answer.note})` : ''}`);
131
+ if (d.state === 'expired' || d.state === 'denied') process.exitCode = EXIT_NO_ANSWER;
132
+ });
133
+
134
+ ask
135
+ .command('wait')
136
+ .description('Block until a question is answered; prints the chosen option key (and note), exits 2 on expiry or deny')
137
+ .argument('<id>', 'the id `quox ask` printed')
138
+ .option('--timeout <dur>', 'stop waiting after this long (the question stays open)')
139
+ .action(async (id, options) => {
140
+ auth.requireAuth();
141
+ const orgId = resolveOrgId(auth, program);
142
+ await waitAndPrint(orgId, id, { timeoutSec: options.timeout ? parseDuration(options.timeout) : null });
143
+ });
144
+ }
@@ -0,0 +1,169 @@
1
+ /**
2
+ * Assistant commands: CRUD, deploy, fork
3
+ */
4
+
5
+ import { formatOutput, formatDetail, printSuccess } from '../core/output.js';
6
+ import { resolveOrgId } from './helpers.js';
7
+ import { resolveEndpoint } from '../api/endpoints.js';
8
+ import { QuoxError } from '../core/errors.js';
9
+
10
+ // #1049: auth routes/assistants.js DEPLOYMENT_MODES (the server is the authority).
11
+ const DEPLOY_MODES = ['private', 'shared', 'public'];
12
+
13
+ export function registerAssistantCommands(program, ctx) {
14
+ const { client, auth } = ctx;
15
+
16
+ const assistant = program
17
+ .command('assistant')
18
+ .description('Manage assistants');
19
+
20
+ assistant
21
+ .command('list')
22
+ .description('List assistants')
23
+ .action(async () => {
24
+ auth.requireAuth();
25
+ const orgId = resolveOrgId(auth, program);
26
+ const data = await client.get(resolveEndpoint('assistants.list', { orgId }).path, { service: resolveEndpoint('assistants.list', { orgId }).service });
27
+ formatOutput({
28
+ // fleet #392: route returns active_deployments, not deployed.
29
+ columns: ['id', 'name', 'status', 'active_deployments', 'created_at'],
30
+ headers: ['ID', 'Name', 'Status', 'Deployed', 'Created'],
31
+ rows: data.items || data.assistants || data,
32
+ }, { format: program.opts().output });
33
+ });
34
+
35
+ assistant
36
+ .command('get')
37
+ .description('Get assistant details')
38
+ .argument('<assistantId>', 'assistant ID')
39
+ .action(async (assistantId) => {
40
+ auth.requireAuth();
41
+ const orgId = resolveOrgId(auth, program);
42
+ const data = await client.get(resolveEndpoint('assistants.get', { orgId, assistantId }).path, { service: resolveEndpoint('assistants.get', { orgId, assistantId }).service });
43
+ formatDetail(data.assistant || data, { format: program.opts().output, title: data.assistant?.name || data.name });
44
+ });
45
+
46
+ assistant
47
+ .command('create')
48
+ .description('Create an assistant')
49
+ .requiredOption('--name <name>', 'assistant name')
50
+ .option('--persona <text>', 'persona/system prompt')
51
+ .option('--description <desc>', 'description')
52
+ .action(async (options) => {
53
+ auth.requireAuth();
54
+ const orgId = resolveOrgId(auth, program);
55
+ const body = { name: options.name };
56
+ if (options.persona) body.persona = options.persona;
57
+ if (options.description) body.description = options.description;
58
+ await client.post(resolveEndpoint('assistants.create', { orgId }).path, { service: resolveEndpoint('assistants.create', { orgId }).service, body });
59
+ printSuccess(`Assistant "${options.name}" created.`);
60
+ });
61
+
62
+ assistant
63
+ .command('update')
64
+ .description('Update an assistant')
65
+ .argument('<assistantId>', 'assistant ID')
66
+ .option('--name <name>', 'new name')
67
+ .option('--persona <text>', 'new persona')
68
+ .option('--description <desc>', 'new description')
69
+ .action(async (assistantId, options) => {
70
+ auth.requireAuth();
71
+ const orgId = resolveOrgId(auth, program);
72
+ const body = {};
73
+ if (options.name) body.name = options.name;
74
+ if (options.persona) body.persona = options.persona;
75
+ if (options.description) body.description = options.description;
76
+ await client.patch(resolveEndpoint('assistants.update', { orgId, assistantId }).path, { service: resolveEndpoint('assistants.update', { orgId, assistantId }).service, body });
77
+ printSuccess('Assistant updated.');
78
+ });
79
+
80
+ assistant
81
+ .command('delete')
82
+ .description('Delete an assistant')
83
+ .argument('<assistantId>', 'assistant ID')
84
+ .action(async (assistantId) => {
85
+ auth.requireAuth();
86
+ const orgId = resolveOrgId(auth, program);
87
+ await client.delete(resolveEndpoint('assistants.delete', { orgId, assistantId }).path, { service: resolveEndpoint('assistants.delete', { orgId, assistantId }).service });
88
+ printSuccess('Assistant deleted.');
89
+ });
90
+
91
+ assistant
92
+ .command('publish')
93
+ .description('Publish a draft assistant (draft to active), so it can be deployed')
94
+ .argument('<assistantId>', 'assistant ID')
95
+ .action(async (assistantId) => {
96
+ auth.requireAuth();
97
+ const orgId = resolveOrgId(auth, program);
98
+ // #1028: create makes a draft and deploy refuses anything not active; this is the step between.
99
+ const ep = resolveEndpoint('assistants.publish', { orgId, assistantId });
100
+ await client.post(ep.path, { service: ep.service });
101
+ printSuccess('Assistant published.');
102
+ });
103
+
104
+ assistant
105
+ .command('deploy')
106
+ .description('Deploy an active assistant to a scope (scope ids: quox org divisions list, quox department list, quox team list)')
107
+ .argument('<assistantId>', 'assistant ID')
108
+ .option('--scope <scopeId>', 'scope ID to deploy to (required)')
109
+ .option('--target <scopeId>', 'alias for --scope')
110
+ .option('--mode <mode>', `${DEPLOY_MODES.join(', ')} (default shared)`)
111
+ .action(async (assistantId, options) => {
112
+ auth.requireAuth();
113
+ const orgId = resolveOrgId(auth, program);
114
+ // #998: the auth route requires scope_id; the CLI used to send { target }.
115
+ const scopeId = options.scope || options.target;
116
+ if (!scopeId) throw new QuoxError('assistant deploy needs --scope <scopeId>.', 1);
117
+ // #1049: the server's modes (auth routes/assistants.js DEPLOYMENT_MODES); refuse anything else here.
118
+ if (options.mode && !DEPLOY_MODES.includes(options.mode)) {
119
+ throw new QuoxError(`--mode must be one of: ${DEPLOY_MODES.join(', ')} (got "${options.mode}").`, 1);
120
+ }
121
+ const body = { scope_id: scopeId };
122
+ if (options.mode) body.mode = options.mode;
123
+ await client.post(resolveEndpoint('assistants.deploy', { orgId, assistantId }).path, { service: resolveEndpoint('assistants.deploy', { orgId, assistantId }).service, body });
124
+ printSuccess('Assistant deployed.');
125
+ });
126
+
127
+ assistant
128
+ .command('undeploy')
129
+ .description('Remove a deployment of an assistant (by --deployment id, or the active one at --scope)')
130
+ .argument('<assistantId>', 'assistant ID')
131
+ .option('--deployment <deploymentId>', 'deployment ID to remove (see quox assistant get)')
132
+ .option('--scope <scopeId>', 'remove the active deployment at this scope')
133
+ .action(async (assistantId, options) => {
134
+ auth.requireAuth();
135
+ const orgId = resolveOrgId(auth, program);
136
+ // #1049: a deployed assistant could not be removed from the CLI.
137
+ let deploymentId = options.deployment;
138
+ if (!deploymentId) {
139
+ if (!options.scope) throw new QuoxError('assistant undeploy needs --deployment <id> or --scope <scopeId>.', 1);
140
+ const g = resolveEndpoint('assistants.get', { orgId, assistantId });
141
+ const data = await client.get(g.path, { service: g.service });
142
+ const deps = (data && data.assistant && data.assistant.deployments) || (data && data.deployments) || [];
143
+ const live = deps.filter((d) => d.status === 'active');
144
+ const hit = live.find((d) => d.scope_id === options.scope);
145
+ if (!hit) {
146
+ const where = live.length ? live.map((d) => `${d.scope_id} (${d.id})`).join(', ') : 'nowhere';
147
+ throw new QuoxError(`No active deployment of ${assistantId} at scope ${options.scope}. It is deployed at: ${where}.`, 1);
148
+ }
149
+ deploymentId = hit.id;
150
+ }
151
+ const ep = resolveEndpoint('assistants.undeploy', { orgId, assistantId, deploymentId });
152
+ await client.delete(ep.path, { service: ep.service });
153
+ printSuccess(`Deployment ${deploymentId} removed.`);
154
+ });
155
+
156
+ assistant
157
+ .command('fork')
158
+ .description('Fork an assistant')
159
+ .argument('<assistantId>', 'assistant ID to fork')
160
+ .option('--name <name>', 'name for the fork')
161
+ .action(async (assistantId, options) => {
162
+ auth.requireAuth();
163
+ const orgId = resolveOrgId(auth, program);
164
+ const body = {};
165
+ if (options.name) body.name = options.name;
166
+ await client.post(resolveEndpoint('assistants.fork', { orgId, assistantId }).path, { service: resolveEndpoint('assistants.fork', { orgId, assistantId }).service, body });
167
+ printSuccess('Assistant forked.');
168
+ });
169
+ }