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,45 @@
1
+ /**
2
+ * Invitation commands (GRIPE-712): list and accept the caller's own pending
3
+ * invitations without needing the emailed token.
4
+ */
5
+ import { formatOutput, printSuccess } from '../core/output.js';
6
+ import { resolveEndpoint } from '../api/endpoints.js';
7
+
8
+ export function registerInvitesCommands(program, ctx) {
9
+ const { client, auth } = ctx;
10
+
11
+ const invites = program.command('invites').description('Your pending organization invitations');
12
+
13
+ invites
14
+ .command('list')
15
+ .description('List pending invitations addressed to your verified email')
16
+ .action(async () => {
17
+ auth.requireAuth();
18
+ const ep = resolveEndpoint('invites.mine.list');
19
+ const data = await client.get(ep.path, { service: ep.service });
20
+ const rows = (data.invites || []).map(i => ({
21
+ id: i.id,
22
+ organization: i.organization?.name || i.organization?.slug || '',
23
+ role: i.role,
24
+ invited_by: i.invited_by || '',
25
+ expires_at: i.expires_at || '',
26
+ }));
27
+ formatOutput({
28
+ columns: ['id', 'organization', 'role', 'invited_by', 'expires_at'],
29
+ headers: ['ID', 'Organization', 'Role', 'Invited by', 'Expires'],
30
+ rows,
31
+ }, { format: program.opts().output });
32
+ });
33
+
34
+ invites
35
+ .command('accept')
36
+ .description('Accept a pending invitation by id (no emailed token needed)')
37
+ .argument('<id>', 'invitation id from `quox invites list`')
38
+ .action(async (id) => {
39
+ auth.requireAuth();
40
+ const ep = resolveEndpoint('invites.mine.accept', { inviteId: id });
41
+ const data = await client.post(ep.path, { service: ep.service, body: {} });
42
+ const org = data.organization;
43
+ printSuccess(`${data.message || 'Invite accepted'}${org?.name ? `: ${org.name}` : ''}. Run \`quox org switch ${org?.id || '<orgId>'}\` to use it.`);
44
+ });
45
+ }
@@ -0,0 +1,139 @@
1
+ /**
2
+ * `quox licence` (alias `license`), GRIPE-715: governed, audited licence
3
+ * operations from the terminal.
4
+ *
5
+ * Phase 1 (instance-local): status reads the lease (never the key), refresh
6
+ * runs the renewal, seats lists/cleans band holders (dry run default).
7
+ *
8
+ * Phase 2 (owner-only vendor tooling for the quox.ai website) lives in
9
+ * lib/vendor/licenceOwner.js and is registered only when that file is present.
10
+ * lib/vendor/ is excluded from the npm package (quox#1134): the public build
11
+ * never carries it.
12
+ */
13
+
14
+ import { formatOutput, formatDetail, printSuccess, printInfo, printWarning } from '../core/output.js';
15
+ import { resolveEndpoint } from '../api/endpoints.js';
16
+ import { QuoxValidationError } from '../core/errors.js';
17
+
18
+ // quox#1134: the owner-only website verbs are vendor tooling, kept out of the published package (package.json
19
+ // "files" excludes lib/vendor/). Present in the dev tree, absent for every npm user.
20
+ let VENDOR_OWNER = null;
21
+ try {
22
+ VENDOR_OWNER = await import('../vendor/licenceOwner.js');
23
+ } catch (e) {
24
+ if (!(e?.code === 'ERR_MODULE_NOT_FOUND' && String(e?.message || '').includes('licenceOwner'))) throw e;
25
+ }
26
+
27
+ export function registerLicenceCommands(program, ctx, { owner = VENDOR_OWNER } = {}) {
28
+ const { client, auth } = ctx;
29
+ const fetchImpl = ctx.websiteFetch || globalThis.fetch;
30
+ const json = () => program.opts().output === 'json';
31
+
32
+ const licence = program
33
+ .command('licence')
34
+ .alias('license')
35
+ .description('Instance licence status, lease refresh and seat bands')
36
+ .action(() => { licence.help(); });
37
+ if (owner) licence.addHelpText('after', owner.OWNER_HELP);
38
+
39
+ licence
40
+ .command('status')
41
+ .description('Licence id, plan, lease timestamps, governed count, entitled list with seat usage')
42
+ .option('--plugin <id>', 'limit to one plugin')
43
+ .action(async (opts) => {
44
+ auth.requireAuth();
45
+ const ep = resolveEndpoint('setup.licensing.status');
46
+ const d = await client.get(ep.path, { service: ep.service });
47
+ const bands = d.org_bands || {};
48
+ const pick = (id) => !opts.plugin || id === opts.plugin;
49
+ const entitled = (d.entitlements || []).filter(pick).map((id) => {
50
+ const b = bands[id];
51
+ return { plugin: id, seats: b ? `${b.assigned_count}/${b.allowance}` : 'whole install' };
52
+ });
53
+ const out = {
54
+ licenses: (d.licenses || []).map((l) => ({
55
+ license_id: l.license_id,
56
+ plans: l.plans || [],
57
+ lease_issued_at: l.issued_at,
58
+ lease_expires_at: l.lease_expires_at,
59
+ licence_expires_at: l.expires_at,
60
+ })),
61
+ governed_count: Array.isArray(d.governed) ? d.governed.length : 0,
62
+ org_id: d.org_id || null,
63
+ entitled,
64
+ entitlement_errors: d.entitlement_errors || [],
65
+ renewal_health: d.renewal_health || null,
66
+ };
67
+ if (opts.plugin) out.governed = (d.governed || []).includes(opts.plugin);
68
+ if (json()) { console.log(JSON.stringify(out, null, 2)); return; }
69
+ formatDetail({
70
+ licence_id: out.licenses.map((l) => l.license_id).join(', ') || '(none)',
71
+ plan: out.licenses.flatMap((l) => l.plans).join(', ') || '(none)',
72
+ lease_issued: out.licenses.map((l) => l.lease_issued_at || '?').join(', ') || '(none)',
73
+ lease_expires: out.licenses.map((l) => l.lease_expires_at).join(', ') || '(none)',
74
+ governed: String(out.governed_count),
75
+ org_id: out.org_id || '(instance scoped)',
76
+ entitlement_errors: out.entitlement_errors.length
77
+ ? out.entitlement_errors.map((e) => (e.entitlement ? `${e.entitlement}: ${e.error}` : JSON.stringify(e))).join('; ')
78
+ : '(none)',
79
+ }, { title: 'Licence status' });
80
+ formatOutput({
81
+ columns: ['plugin', 'seats'],
82
+ headers: ['Entitled plugin', 'Seats (used/cap)'],
83
+ rows: entitled,
84
+ }, { format: program.opts().output, emptyMessage: 'No entitlements.' });
85
+ });
86
+
87
+ licence
88
+ .command('refresh')
89
+ .description('Renew the licence lease now; prints old to new lease timestamps and entitlement diff')
90
+ .action(async () => {
91
+ auth.requireAuth();
92
+ const ep = resolveEndpoint('setup.licensing.refresh');
93
+ const d = await client.post(ep.path, { service: ep.service, body: {} });
94
+ if (json()) { console.log(JSON.stringify(d, null, 2)); return; }
95
+ const byId = new Map((d.before || []).map((l) => [l.license_id, l]));
96
+ for (const l of d.after || []) {
97
+ const old = byId.get(l.license_id);
98
+ printInfo(`${l.license_id}: lease expires ${old ? old.lease_expires_at : '(new)'} -> ${l.lease_expires_at}`);
99
+ }
100
+ for (const r of d.results || []) printInfo(`${r.license_id}: ${r.action}${r.reason ? ` (${r.reason})` : ''}`);
101
+ const diff = d.entitlement_diff || { added: [], removed: [] };
102
+ printInfo(`entitlements added: ${diff.added.join(', ') || '(none)'}`);
103
+ printInfo(`entitlements removed: ${diff.removed.join(', ') || '(none)'}`);
104
+ printSuccess('Lease refresh complete.');
105
+ });
106
+
107
+ licence
108
+ .command('seats')
109
+ .description('List a plugin band holders; --release-dead frees non-live holders (dry run unless --yes)')
110
+ .argument('<pluginId>', 'plugin id, e.g. notesq')
111
+ .option('--release-dead', 'release holders that are not live orgs (deleted orgs, user: ids)')
112
+ .option('--yes', 'actually release (otherwise dry run)')
113
+ .action(async (pluginId, opts) => {
114
+ auth.requireAuth();
115
+ const lep = resolveEndpoint('setup.licensing.seats.list', { pluginId });
116
+ const list = await client.get(lep.path, { service: lep.service });
117
+ let rel = null;
118
+ if (opts.releaseDead) {
119
+ const rep = resolveEndpoint('setup.licensing.seats.releaseDead', { pluginId });
120
+ rel = await client.post(rep.path, { service: rep.service, body: { dry_run: !opts.yes } });
121
+ }
122
+ if (json()) { console.log(JSON.stringify({ ...list, release: rel }, null, 2)); return; }
123
+ printInfo(`${pluginId}: ${list.holders.length} holder(s), cap ${list.allowance ?? '(no band)'}`);
124
+ formatOutput({
125
+ columns: ['id', 'name', 'status'],
126
+ headers: ['Holder', 'Org name', 'Status'],
127
+ rows: list.holders.map((h) => ({ id: h.id, name: h.name || '-', status: h.status })),
128
+ }, { format: program.opts().output, emptyMessage: 'No holders.' });
129
+ if (rel) {
130
+ if (rel.dry_run) {
131
+ printInfo(`DRY RUN: would release ${rel.dead.length} non-live holder(s): ${rel.dead.map((d) => d.id).join(', ') || '(none)'}. Re-run with --yes to release.`);
132
+ } else {
133
+ printSuccess(`Released ${rel.released.length} non-live holder(s): ${rel.released.join(', ') || '(none)'}`);
134
+ }
135
+ }
136
+ });
137
+
138
+ if (owner) owner.registerLicenceOwnerCommands(licence, { json, fetchImpl });
139
+ }
@@ -0,0 +1,178 @@
1
+ /**
2
+ * `quox linkedin` — LinkedIn plugin verbs, LI-OVERHAUL P9 (X CLI parity).
3
+ *
4
+ * quox linkedin post "<text>" --as <author_urn> [--visibility PUBLIC|CONNECTIONS] [--link <url>] [--image-url <https url>]
5
+ * quox linkedin comment <post_urn> "<text>" --as <actor_urn>
6
+ * quox linkedin posts <author_urn> [--count <n>]
7
+ * quox linkedin org <org_id>
8
+ *
9
+ * Both write verbs execute the linkedin connector tools through the governed
10
+ * collector endpoint (POST /api/v1/tools/execute -> connector bridge). The
11
+ * bridge gates them on their requiresApproval flag: each files an owner
12
+ * approval card and returns immediately with
13
+ * { pending:true, status:'awaiting_approval', approvalId, inbox_item_id }.
14
+ * The actual LinkedIn API write only happens once the owner approves via the
15
+ * dashboard inbox or `quox inbox respond <id> --action approve`. Reads
16
+ * (posts, org) execute directly; LinkedIn reads carry no per-call dollar
17
+ * cost (unlike X), only LinkedIn's own daily program quotas.
18
+ *
19
+ * URNs are explicit by design: LinkedIn addresses everything by URN
20
+ * (urn:li:person:xxx member, urn:li:organization:12345 org page) and the
21
+ * CLI has no org-scoped plugin-config lookup yet, so --as is required on
22
+ * writes rather than silently guessed.
23
+ */
24
+
25
+ import { formatDetail, printSuccess, printInfo } from '../core/output.js';
26
+ import { resolveEndpoint } from '../api/endpoints.js';
27
+ import { resolveOrgId } from './helpers.js';
28
+
29
+ const MAX_POST_CHARS = 3000;
30
+
31
+ /**
32
+ * Execute one linkedin connector tool via the governed collector endpoint.
33
+ * A pending-approval response is a SUCCESS shape here (the card was filed);
34
+ * only a non-pending success:false is an error.
35
+ */
36
+ async function executeLinkedInTool({ client, auth, program }, toolName, input) {
37
+ auth.requireAuth();
38
+ const orgId = resolveOrgId(auth, program);
39
+ const ep = resolveEndpoint('v1.tools.execute');
40
+ const body = { tool_name: toolName, input, org_id: orgId };
41
+ const data = await client.post(ep.path, { service: ep.service, body });
42
+ if (data && data.success === false && !data.pending) {
43
+ throw new Error(`${toolName} via POST ${ep.path} returned success:false: ${data.error || 'unknown error'}`);
44
+ }
45
+ return data;
46
+ }
47
+
48
+ function printAwaitingApproval(action, data) {
49
+ const itemRef = data.inbox_item_id || data.approvalId || 'unknown';
50
+ printSuccess(`${action} filed for owner approval — inbox item ${itemRef} (awaiting approval). Nothing publishes until an approver says yes.`);
51
+ if (data.inbox_item_id) {
52
+ printInfo(`Review and approve: quox inbox get ${data.inbox_item_id} (or: quox inbox respond ${data.inbox_item_id} --action approve)`);
53
+ }
54
+ }
55
+
56
+ export function registerLinkedInCommands(program, ctx) {
57
+ const { client, auth } = ctx;
58
+
59
+ const linkedin = program
60
+ .command('linkedin')
61
+ .description('LinkedIn publishing: governed, HITL-approved via HITL Inbox');
62
+
63
+ // ── linkedin post ────────────────────────────────────────────────────────
64
+
65
+ linkedin
66
+ .command('post')
67
+ .description('Draft a LinkedIn post. Files an owner approval card and returns immediately; never posts directly.')
68
+ .argument('<text>', `post text, max ${MAX_POST_CHARS} characters`)
69
+ .requiredOption('--as <author_urn>', 'author URN (urn:li:person:xxx or urn:li:organization:12345)')
70
+ .option('--visibility <visibility>', 'PUBLIC or CONNECTIONS', 'PUBLIC')
71
+ .option('--link <url>', 'attach a link/article URL')
72
+ .option('--image-url <url>', 'attach an image from an https URL (max 10MB); uploaded to LinkedIn server-side before the card is filed, so the approver sees the finished attachment')
73
+ .action(async (text, options) => {
74
+ if (text.length > MAX_POST_CHARS) {
75
+ throw new Error(`Text is ${text.length} characters, over the ${MAX_POST_CHARS} character limit.`);
76
+ }
77
+ if (!['PUBLIC', 'CONNECTIONS'].includes(options.visibility)) {
78
+ throw new Error(`--visibility must be PUBLIC or CONNECTIONS, got ${options.visibility}`);
79
+ }
80
+
81
+ const input = { author: options.as, text, visibility: options.visibility };
82
+ if (options.link) input.link_url = options.link;
83
+
84
+ if (options.imageUrl) {
85
+ const media = await executeLinkedInTool({ client, auth, program }, 'linkedin_upload_media', {
86
+ owner: options.as,
87
+ image_url: options.imageUrl,
88
+ });
89
+ const urn = media?.result?.image_urn;
90
+ if (!urn) {
91
+ throw new Error(`Image upload did not return an image URN: ${JSON.stringify(media).slice(0, 200)}`);
92
+ }
93
+ printInfo(`Image uploaded (${media.result.bytes} bytes) — ${urn}`);
94
+ input.media_id = urn;
95
+ }
96
+
97
+ const data = await executeLinkedInTool({ client, auth, program }, 'linkedin_publish_post', input);
98
+
99
+ if (program.opts().output === 'json') {
100
+ formatDetail(data, { format: 'json' });
101
+ return;
102
+ }
103
+ printAwaitingApproval('Post', data);
104
+ });
105
+
106
+ // ── linkedin comment ─────────────────────────────────────────────────────
107
+
108
+ linkedin
109
+ .command('comment')
110
+ .description('Draft a comment on a LinkedIn post. Files an owner approval card and returns immediately; never comments directly.')
111
+ .argument('<post_urn>', 'URN of the post to comment on (e.g. urn:li:share:12345)')
112
+ .argument('<text>', 'comment text')
113
+ .requiredOption('--as <actor_urn>', 'actor URN posting the comment (person or organisation)')
114
+ .action(async (postUrn, text, options) => {
115
+ const data = await executeLinkedInTool({ client, auth, program }, 'linkedin_create_comment', {
116
+ post_urn: postUrn,
117
+ actor: options.as,
118
+ text,
119
+ });
120
+
121
+ if (program.opts().output === 'json') {
122
+ formatDetail(data, { format: 'json' });
123
+ return;
124
+ }
125
+ printAwaitingApproval('Comment', data);
126
+ });
127
+
128
+ // ── linkedin posts (read) ────────────────────────────────────────────────
129
+
130
+ linkedin
131
+ .command('posts')
132
+ .description('List recent posts for a member or organisation (read-only, no approval needed).')
133
+ .argument('<author_urn>', 'author URN (person or organisation)')
134
+ .option('--count <n>', 'number of posts (max 50)', '20')
135
+ .action(async (authorUrn, options) => {
136
+ const count = Math.min(parseInt(options.count, 10) || 20, 50);
137
+ const data = await executeLinkedInTool({ client, auth, program }, 'linkedin_get_posts', {
138
+ author: authorUrn,
139
+ count,
140
+ });
141
+
142
+ if (program.opts().output === 'json') {
143
+ formatDetail(data, { format: 'json' });
144
+ return;
145
+ }
146
+ const posts = data.result || [];
147
+ if (posts.length === 0) {
148
+ printInfo('No posts returned.');
149
+ return;
150
+ }
151
+ for (const p of posts) {
152
+ console.log(`${p.id} ${p.created_at || ''} ${p.lifecycle_state || ''}`);
153
+ console.log(` ${String(p.text || '').replace(/\n/g, '\n ')}`);
154
+ }
155
+ });
156
+
157
+ // ── linkedin org (read) ──────────────────────────────────────────────────
158
+
159
+ linkedin
160
+ .command('org')
161
+ .description('Show a LinkedIn organisation page: name, follower count, website (read-only). Also the cheapest live credential check.')
162
+ .argument('<org_id>', 'numeric organisation id (e.g. 12345)')
163
+ .action(async (orgId) => {
164
+ const data = await executeLinkedInTool({ client, auth, program }, 'linkedin_get_org_info', { org_id: orgId });
165
+
166
+ if (program.opts().output === 'json') {
167
+ formatDetail(data, { format: 'json' });
168
+ return;
169
+ }
170
+ const org = data.result || {};
171
+ printSuccess(`${org.name || 'Unknown'} (urn:li:organization:${org.id})`);
172
+ if (org.vanity_name) printInfo(`linkedin.com/company/${org.vanity_name}`);
173
+ // followers can be null when networkSizes is unavailable — say unknown,
174
+ // never a fake 0.
175
+ printInfo(`Followers: ${org.followers == null ? 'unknown' : org.followers.toLocaleString()}`);
176
+ if (org.website) printInfo(`Website: ${org.website}`);
177
+ });
178
+ }
@@ -0,0 +1,117 @@
1
+ /**
2
+ * LLM routing policy commands: view/set/dry-run-test the org's execution
3
+ * policy (which providers/models agents are allowed to route to).
4
+ *
5
+ * quox llm-policy get|set|test
6
+ *
7
+ * Backend: services/auth/routes/llm-routing-policies.js, mounted at plain
8
+ * `/api` (org-scoped in the URL): GET/PUT `/api/orgs/:orgId/llm-routing-policy`,
9
+ * POST `/api/orgs/:orgId/llm-routing-policy/test`. See
10
+ * cli/lib/api/endpoints/llm-policy.js for the full verified response shapes.
11
+ */
12
+
13
+ import { readFileSync } from 'node:fs';
14
+ import { formatDetail, printSuccess, printWarning } from '../core/output.js';
15
+ import { resolveOrgId, parseJSON } from './helpers.js';
16
+ import { resolveEndpoint } from '../api/endpoints.js';
17
+
18
+ /**
19
+ * Resolve a policy object from --file or --policy. Throws if neither given
20
+ * or the input isn't a JSON object.
21
+ */
22
+ function resolvePolicy(options) {
23
+ let raw;
24
+ if (options.file) {
25
+ try {
26
+ raw = readFileSync(options.file, 'utf-8');
27
+ } catch (err) {
28
+ throw new Error(`Could not read ${options.file}: ${err.message}`);
29
+ }
30
+ } else if (options.policy !== undefined) {
31
+ raw = options.policy;
32
+ } else {
33
+ throw new Error('Policy input is required. Use --file <path> or --policy <json>.');
34
+ }
35
+
36
+ const policy = parseJSON(raw, options.file ? '--file contents' : '--policy');
37
+ if (!policy || typeof policy !== 'object' || Array.isArray(policy)) {
38
+ throw new Error('Policy must be a JSON object.');
39
+ }
40
+ return policy;
41
+ }
42
+
43
+ export function registerLlmPolicyCommands(program, ctx) {
44
+ const { client, auth } = ctx;
45
+
46
+ const llmPolicy = program
47
+ .command('llm-policy')
48
+ .description('View, set, and dry-run-validate the org LLM routing policy');
49
+
50
+ // ── llm-policy get ──────────────────────────────────────────────────────────
51
+
52
+ llmPolicy
53
+ .command('get')
54
+ .description('Show the effective LLM routing policy for the active org')
55
+ .action(async () => {
56
+ auth.requireAuth();
57
+ const orgId = resolveOrgId(auth, program);
58
+ const data = await client.get(resolveEndpoint('llm-policy.get', { orgId }).path, {
59
+ service: resolveEndpoint('llm-policy.get', { orgId }).service,
60
+ });
61
+
62
+ if (data.source === 'seed') {
63
+ printWarning('No org-specific policy saved — showing the built-in seed policy.');
64
+ }
65
+
66
+ formatDetail(data.policy, {
67
+ format: program.opts().output,
68
+ title: `LLM Routing Policy (source: ${data.source})`,
69
+ });
70
+ });
71
+
72
+ // ── llm-policy set ──────────────────────────────────────────────────────────
73
+
74
+ llmPolicy
75
+ .command('set')
76
+ .description('Save a new LLM routing policy for the active org (requires ORG_MANAGE_SETTINGS)')
77
+ .option('--file <path>', 'path to a JSON file containing the policy object')
78
+ .option('--policy <json>', 'inline JSON policy object')
79
+ .action(async (options) => {
80
+ auth.requireAuth();
81
+ const orgId = resolveOrgId(auth, program);
82
+ const policy = resolvePolicy(options);
83
+
84
+ const data = await client.put(resolveEndpoint('llm-policy.set', { orgId }).path, {
85
+ service: resolveEndpoint('llm-policy.set', { orgId }).service,
86
+ body: { policy },
87
+ });
88
+
89
+ printSuccess('LLM routing policy saved.');
90
+ formatDetail(data.policy, { format: program.opts().output });
91
+ });
92
+
93
+ // ── llm-policy test ─────────────────────────────────────────────────────────
94
+
95
+ llmPolicy
96
+ .command('test')
97
+ .description('Dry-run validate a policy without saving it')
98
+ .option('--file <path>', 'path to a JSON file containing the policy object')
99
+ .option('--policy <json>', 'inline JSON policy object')
100
+ .action(async (options) => {
101
+ auth.requireAuth();
102
+ const orgId = resolveOrgId(auth, program);
103
+ const policy = resolvePolicy(options);
104
+
105
+ const data = await client.post(resolveEndpoint('llm-policy.test', { orgId }).path, {
106
+ service: resolveEndpoint('llm-policy.test', { orgId }).service,
107
+ body: { policy },
108
+ });
109
+
110
+ if (data.valid) {
111
+ printSuccess('Policy is valid.');
112
+ } else {
113
+ printWarning(`Policy is invalid (${(data.errors || []).length} error(s)).`);
114
+ }
115
+ formatDetail(data, { format: program.opts().output });
116
+ });
117
+ }
@@ -0,0 +1,45 @@
1
+ /**
2
+ * LLM commands: provider status incl. degraded state and the failover target.
3
+ *
4
+ * quox llm status
5
+ *
6
+ * Backend: collector `GET /chat/status` (same endpoint as `quox chat-status`,
7
+ * key 'chat.status.list'). This is the curated LLM view of it: it surfaces the
8
+ * failover fields shipped with the LLM failover chain work (`degraded`,
9
+ * `degraded_reason`, `degraded_until`, `fallback_hint`) and warns loudly when
10
+ * the primary provider is in a failover cooldown. Routing policy itself lives
11
+ * under `quox llm-policy`.
12
+ */
13
+
14
+ import { formatDetail, printWarning } from '../core/output.js';
15
+ import { resolveEndpoint } from '../api/endpoints.js';
16
+
17
+ export function registerLlmCommands(program, ctx) {
18
+ const { client } = ctx;
19
+
20
+ const llm = program
21
+ .command('llm')
22
+ .description('LLM provider status and failover');
23
+
24
+ llm
25
+ .command('status')
26
+ .description('Show LLM provider status, degraded state, and the failover target')
27
+ .action(async () => {
28
+ // No requireAuth: the route is public on collectors that allowlist it,
29
+ // but the token is attached when logged in (the dev gate requires a JWT).
30
+ const data = await client.get(resolveEndpoint('chat.status.list').path, { service: resolveEndpoint('chat.status.list').service });
31
+
32
+ if (data.degraded) {
33
+ const reason = data.degraded_reason ? ` (${data.degraded_reason})` : '';
34
+ const fallback = data.fallback_hint
35
+ ? ` Failing over to ${data.fallback_hint.provider}:${data.fallback_hint.model}.`
36
+ : '';
37
+ printWarning(`Primary provider degraded${reason}.${fallback}`);
38
+ }
39
+
40
+ formatDetail(data, {
41
+ format: program.opts().output,
42
+ title: 'LLM Status',
43
+ });
44
+ });
45
+ }