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,581 @@
1
+ /**
2
+ * Monitoring commands: Docker fleet, Wazuh security monitoring, AGH-chain
3
+ * agent honesty leaderboard, Prometheus metrics, and monitoring config.
4
+ *
5
+ * quox mon docker fleet|containers|container|inspect|logs|stats|stacks|df|action
6
+ * quox mon wazuh status|agents|alerts|vulns|deploy-history|deploy-agent|deploy-bulk|active-response
7
+ * quox mon agh-chain leaderboard|agent|events
8
+ * quox mon metrics
9
+ * quox mon config get|cache|grafana
10
+ *
11
+ * Backend: services/collector/server.js. See endpoints/mon.js's header for
12
+ * the full auth/org-scoping verification per route family (WP4.3,
13
+ * STREAM_CLI_PARITY_PLAN.md §2.3 #10) — summary:
14
+ * - `/docker/*` — NO auth middleware, no org filter (fleet-wide).
15
+ * - `/api/v1/wazuh/*` — requireServiceOrUserAuth(); not org-filtered by
16
+ * the Wazuh API itself; deploy-agent/deploy-bulk/active-response are
17
+ * HITL-gated (queue an HITL Inbox approval, return 202, do not execute
18
+ * immediately).
19
+ * - `/api/v1/agh-chain/*` — requireServiceOrUserAuth() AND genuinely
20
+ * org-scoped (403s without req.user.org_id).
21
+ * - `/metrics` — NO auth middleware, plain text (Prometheus exposition
22
+ * format), not JSON.
23
+ * - `/api/v1/monitoring/config` — optional auth; `/api/v1/monitoring/
24
+ * cache/:service` and `/api/v1/grafana/config` — requireServiceOrUserAuth().
25
+ * None of the three are org-scoped (single shared config/cache).
26
+ */
27
+
28
+ import { formatOutput, formatDetail, printSuccess, printWarning, printInfo } from '../core/output.js';
29
+ import { parseJSON } from './helpers.js';
30
+ import { resolveEndpoint } from '../api/endpoints.js';
31
+
32
+ async function confirmOrSkip(program, options, message) {
33
+ if (options.force || program.opts().yes) return true;
34
+ const { default: inquirer } = await import('inquirer');
35
+ const ans = await inquirer.prompt([{ type: 'confirm', name: 'confirm', message, default: false }]);
36
+ return ans.confirm;
37
+ }
38
+
39
+
40
+ /** One readable line per fact from the inspect health block (null when the container has no healthcheck). */
41
+ function healthRows(h) {
42
+ if (!h) return null;
43
+ const rows = [];
44
+ const streak = h.failing_streak ? ` (failing ${h.failing_streak} times)` : '';
45
+ rows.push(`health: ${h.status || 'unknown'}${streak}`);
46
+ if (h.test) {
47
+ const parts = [h.interval && `every ${h.interval}`, h.timeout && `timeout ${h.timeout}`, h.retries != null && `retries ${h.retries}`].filter(Boolean);
48
+ rows.push(`probe: ${h.test}${parts.length ? ' ' + parts.join(', ') : ''}`);
49
+ }
50
+ for (const p of h.last_probes || []) {
51
+ const o = String(p.output || '').replace(/\s+/g, ' ').trim();
52
+ rows.push(`last: exit ${p.exit_code}${o ? ` '${o}'` : ''}${p.end ? ` at ${p.end}` : ''}`);
53
+ }
54
+ return rows;
55
+ }
56
+
57
+ /**
58
+ * DEVFLEET-DOCKER: an error body is not data. If the collector reports a refused/failed Docker
59
+ * read, say so (stderr) and set a non-zero exit instead of printing an empty list. Partial fleets
60
+ * print the failed hosts as warnings. Returns true when the whole read failed (caller stops).
61
+ */
62
+ function reportDockerReadFailures(data) {
63
+ if (!data) return false;
64
+ const failedHosts = Array.isArray(data.hosts_failed) ? data.hosts_failed
65
+ : (data.success === false && Array.isArray(data.hosts) ? data.hosts.filter((h) => h && h.ok === false) : []);
66
+ if (data.success === false) {
67
+ const tag = data.refused ? ' (refused, error_code ' + (data.error_code || 'approval_required') + ')' : '';
68
+ console.error('Docker read failed' + tag + ': ' + (data.error || 'unknown error'));
69
+ for (const h of failedHosts) console.error(' ' + h.host + ': ' + (h.error || 'failed'));
70
+ process.exitCode = 1;
71
+ return true;
72
+ }
73
+ if (data.partial) {
74
+ console.error('Partial result: ' + failedHosts.length + ' host(s) could not be read; the list below is incomplete.');
75
+ for (const h of failedHosts) console.error(' ' + h.host + ': ' + (h.error || 'failed'));
76
+ }
77
+ return false;
78
+ }
79
+
80
+ export function registerMonCommands(program, ctx) {
81
+ const { client, auth } = ctx;
82
+
83
+ const mon = program
84
+ .command('mon')
85
+ .description('Monitoring: Docker fleet, Wazuh security, AGH-chain leaderboard, metrics');
86
+
87
+ // ══════════════════════════════════════════════════════════════════════
88
+ // docker
89
+ // ══════════════════════════════════════════════════════════════════════
90
+
91
+ const docker = mon
92
+ .command('docker')
93
+ .description('Docker fleet: hosts, containers, stacks, disk usage');
94
+
95
+ docker
96
+ .command('fleet')
97
+ .description('Discover Docker hosts across the fleet')
98
+ .option('--refresh', 'force a live scan instead of returning the cache')
99
+ .action(async (options) => {
100
+ auth.requireAuth();
101
+ const ep = resolveEndpoint('mon.docker.fleet.list');
102
+ const data = await client.get(ep.path, { service: ep.service, query: options.refresh ? { refresh: 'true' } : undefined });
103
+ if (reportDockerReadFailures(data)) return;
104
+ const hosts = data.hosts || [];
105
+ formatOutput({
106
+ // fleet #392: docker fleet rows are id/containers_total/docker_version; ip and status don't exist.
107
+ columns: ['id', 'containers_total', 'containers_running', 'docker_version'],
108
+ headers: ['Host', 'Containers', 'Running', 'Docker'],
109
+ rows: hosts,
110
+ }, { format: program.opts().output, emptyMessage: 'No Docker hosts found.' });
111
+ });
112
+
113
+ docker
114
+ .command('containers')
115
+ .description('List containers across the fleet (or a single host)')
116
+ .option('--host <hostId>', 'filter to a single host')
117
+ .option('--no-all', 'only running containers (default includes stopped)')
118
+ .option('--refresh', 'force a live fetch instead of returning the cache')
119
+ .action(async (options) => {
120
+ auth.requireAuth();
121
+ const ep = resolveEndpoint('mon.docker.containers.list');
122
+ const query = {};
123
+ if (options.host) query.host = options.host;
124
+ if (options.all === false) query.all = 'false';
125
+ if (options.refresh) query.refresh = 'true';
126
+ const data = await client.get(ep.path, { service: ep.service, query });
127
+ if (reportDockerReadFailures(data)) return;
128
+ formatOutput({
129
+ columns: ['host_id', 'id', 'name', 'image', 'state', 'status'],
130
+ headers: ['Host', 'ID', 'Name', 'Image', 'State', 'Status'],
131
+ rows: data.containers || [],
132
+ }, { format: program.opts().output, emptyMessage: 'No containers found.' });
133
+ });
134
+
135
+ docker
136
+ .command('container')
137
+ .description('Show container detail (stats + recent logs)')
138
+ .argument('<id>', 'container ID')
139
+ .requiredOption('--host <hostId>', 'host the container lives on')
140
+ .action(async (id, options) => {
141
+ auth.requireAuth();
142
+ const ep = resolveEndpoint('mon.docker.containers.get', { id });
143
+ const data = await client.get(ep.path, { service: ep.service, query: { host: options.host } });
144
+ // quox#1001: a 200 with success:false (e.g. "Bastion not configured") is a failure, not an
145
+ // empty container. Surface the error on stderr + exit non-zero instead of rendering a blank card.
146
+ if (reportDockerReadFailures(data)) return;
147
+ formatDetail(data, {
148
+ format: program.opts().output,
149
+ title: `Container: ${id} (${options.host})`,
150
+ fields: ['host', 'container', 'stats', 'logs'],
151
+ labels: { host: 'Host', container: 'Container', stats: 'Stats', logs: 'Logs' },
152
+ });
153
+ });
154
+
155
+ docker
156
+ .command('inspect')
157
+ .description('Show container state and health (failing probe command and last results)')
158
+ .argument('<id>', 'container ID')
159
+ .requiredOption('--host <hostId>', 'host the container lives on')
160
+ .action(async (id, options) => {
161
+ auth.requireAuth();
162
+ const ep = resolveEndpoint('mon.docker.containers.inspect', { id });
163
+ const data = await client.get(ep.path, { service: ep.service, query: { host: options.host } });
164
+ if (reportDockerReadFailures(data)) return;
165
+ if (program.opts().output === 'json') { console.log(JSON.stringify(data, null, 2)); return; }
166
+ const d = data.details || {};
167
+ console.log(`Container: ${id} (${options.host})`);
168
+ console.log(`state: ${d.status || 'unknown'} · image: ${d.image || 'unknown'}`);
169
+ const rows = healthRows(d.health);
170
+ console.log(rows ? rows.join('\n') : 'health: no healthcheck configured');
171
+ });
172
+
173
+ docker
174
+ .command('logs')
175
+ .description('Show container logs')
176
+ .argument('<id>', 'container ID')
177
+ .requiredOption('--host <hostId>', 'host the container lives on')
178
+ .option('--tail <n>', 'number of lines', '100')
179
+ .action(async (id, options) => {
180
+ auth.requireAuth();
181
+ const ep = resolveEndpoint('mon.docker.containers.logs', { id });
182
+ const data = await client.get(ep.path, { service: ep.service, query: { host: options.host, tail: options.tail } });
183
+ if (program.opts().output === 'json') {
184
+ console.log(JSON.stringify(data, null, 2));
185
+ } else {
186
+ console.log(data.logs || '');
187
+ }
188
+ });
189
+
190
+ docker
191
+ .command('stats')
192
+ .description('Show container resource stats')
193
+ .argument('<id>', 'container ID')
194
+ .requiredOption('--host <hostId>', 'host the container lives on')
195
+ .action(async (id, options) => {
196
+ auth.requireAuth();
197
+ const ep = resolveEndpoint('mon.docker.containers.stats', { id });
198
+ const data = await client.get(ep.path, { service: ep.service, query: { host: options.host } });
199
+ formatDetail(data.stats || data, { format: program.opts().output, title: `Stats: ${id} (${options.host})` });
200
+ });
201
+
202
+ docker
203
+ .command('stacks')
204
+ .description('List Docker Compose stacks')
205
+ .option('--host <hostId>', 'filter to a single host')
206
+ .action(async (options) => {
207
+ auth.requireAuth();
208
+ const ep = resolveEndpoint('mon.docker.stacks.list');
209
+ const data = await client.get(ep.path, { service: ep.service, query: options.host ? { host: options.host } : undefined });
210
+ if (reportDockerReadFailures(data)) return;
211
+ formatOutput({
212
+ columns: ['host_id', 'name', 'status', 'services'],
213
+ headers: ['Host', 'Stack', 'Status', 'Services'],
214
+ rows: data.stacks || [],
215
+ }, { format: program.opts().output, emptyMessage: 'No stacks found.' });
216
+ });
217
+
218
+ docker
219
+ .command('df')
220
+ .description('Show Docker disk usage on a host')
221
+ .requiredOption('--host <hostId>', 'host to query')
222
+ .action(async (options) => {
223
+ auth.requireAuth();
224
+ const ep = resolveEndpoint('mon.docker.system-df.get');
225
+ const data = await client.get(ep.path, { service: ep.service, query: { host: options.host } });
226
+ formatDetail(data, { format: program.opts().output, title: `Docker disk usage: ${options.host}` });
227
+ });
228
+
229
+ docker
230
+ .command('action')
231
+ .description('Start/stop/restart a container (destructive)')
232
+ .argument('<id>', 'container ID')
233
+ .argument('<action>', 'start|stop|restart')
234
+ .requiredOption('--host <hostId>', 'host the container lives on')
235
+ .option('--force', 'skip confirmation')
236
+ .action(async (id, action, options) => {
237
+ auth.requireAuth();
238
+ if (!['start', 'stop', 'restart'].includes(action)) {
239
+ throw new Error(`Invalid action: ${action}. Must be one of: start, stop, restart.`);
240
+ }
241
+ const confirmed = await confirmOrSkip(program, options, `${action} container ${id} on ${options.host}?`);
242
+ if (!confirmed) {
243
+ printInfo('Cancelled.');
244
+ return;
245
+ }
246
+ const ep = resolveEndpoint('mon.docker.containers.action', { id, action });
247
+ const data = await client.post(ep.path, { service: ep.service, body: { host: options.host } });
248
+ if (data.success === false) {
249
+ // quox#1001: surface the real server error and exit non-zero (was exit 0 = success on failure).
250
+ printWarning(`Action failed: ${data.error || data.message || 'unknown error'}`);
251
+ process.exitCode = 1;
252
+ return;
253
+ }
254
+ printSuccess(`Container ${id}: ${action} succeeded.`);
255
+ });
256
+
257
+ // ══════════════════════════════════════════════════════════════════════
258
+ // wazuh
259
+ // ══════════════════════════════════════════════════════════════════════
260
+
261
+ const wazuh = mon
262
+ .command('wazuh')
263
+ .description('Wazuh security monitoring: manager status, agents, alerts, vulnerabilities');
264
+
265
+ wazuh
266
+ .command('status')
267
+ .description('Show Wazuh manager status')
268
+ .action(async () => {
269
+ auth.requireAuth();
270
+ const ep = resolveEndpoint('mon.wazuh.manager-status.get');
271
+ const data = await client.get(ep.path, { service: ep.service });
272
+ formatDetail(data.data || data, { format: program.opts().output, title: 'Wazuh Manager Status' });
273
+ });
274
+
275
+ wazuh
276
+ .command('agents')
277
+ .description('List Wazuh agents')
278
+ .option('--status <status>', 'filter by agent status')
279
+ .option('--limit <n>', 'max results')
280
+ .option('--offset <n>', 'result offset')
281
+ .option('--q <query>', 'query string passed through to the Wazuh API')
282
+ .action(async (options) => {
283
+ auth.requireAuth();
284
+ const ep = resolveEndpoint('mon.wazuh.agents.list');
285
+ const query = {};
286
+ if (options.status) query.status = options.status;
287
+ if (options.limit) query.limit = options.limit;
288
+ if (options.offset) query.offset = options.offset;
289
+ if (options.q) query.q = options.q;
290
+ const data = await client.get(ep.path, { service: ep.service, query });
291
+ const agents = data.data?.data?.affected_items || data.data?.affected_items || data.data || [];
292
+ formatOutput({
293
+ columns: ['id', 'name', 'ip', 'status', 'version'],
294
+ headers: ['ID', 'Name', 'IP', 'Status', 'Version'],
295
+ rows: Array.isArray(agents) ? agents : [],
296
+ }, { format: program.opts().output, emptyMessage: 'No Wazuh agents found.' });
297
+ });
298
+
299
+ wazuh
300
+ .command('alerts')
301
+ .description('Query recent Wazuh alerts')
302
+ .option('--q <query>', 'search text (rule description / agent name / rule groups)')
303
+ .option('--limit <n>', 'max results (default 50, capped at 500)')
304
+ .action(async (options) => {
305
+ auth.requireAuth();
306
+ const ep = resolveEndpoint('mon.wazuh.alerts.list');
307
+ const query = {};
308
+ if (options.q) query.q = options.q;
309
+ if (options.limit) query.limit = options.limit;
310
+ const data = await client.get(ep.path, { service: ep.service, query });
311
+ formatOutput({
312
+ columns: ['timestamp', 'rule', 'agent', 'level'],
313
+ headers: ['Time', 'Rule', 'Agent', 'Level'],
314
+ rows: (data.data || []).map(a => ({
315
+ timestamp: a.timestamp,
316
+ rule: a.rule?.description || '',
317
+ agent: a.agent?.name || '',
318
+ level: a.rule?.level ?? '',
319
+ })),
320
+ }, { format: program.opts().output, emptyMessage: 'No alerts found.' });
321
+ });
322
+
323
+ wazuh
324
+ .command('vulns')
325
+ .description('Query current vulnerability states')
326
+ .option('--agent-id <id>', 'filter by agent ID')
327
+ .option('--agent-name <name>', 'filter by agent name')
328
+ .option('--severity <severity>', 'filter by severity')
329
+ .option('--limit <n>', 'max results (default 100, capped at 1000)')
330
+ .action(async (options) => {
331
+ auth.requireAuth();
332
+ const ep = resolveEndpoint('mon.wazuh.vulnerabilities.list');
333
+ const query = {};
334
+ if (options.agentId) query.agent_id = options.agentId;
335
+ if (options.agentName) query.agent_name = options.agentName;
336
+ if (options.severity) query.severity = options.severity;
337
+ if (options.limit) query.limit = options.limit;
338
+ const data = await client.get(ep.path, { service: ep.service, query });
339
+ formatOutput({
340
+ columns: ['agent', 'cve', 'severity', 'score'],
341
+ headers: ['Agent', 'CVE', 'Severity', 'Score'],
342
+ rows: (data.data || []).map(v => ({
343
+ agent: v.agent?.name || '',
344
+ cve: v.vulnerability?.id || '',
345
+ severity: v.vulnerability?.severity || '',
346
+ score: v.vulnerability?.score?.base ?? '',
347
+ })),
348
+ }, { format: program.opts().output, emptyMessage: 'No vulnerabilities found.' });
349
+ });
350
+
351
+ wazuh
352
+ .command('deploy-history')
353
+ .description('Show Wazuh agent deploy history')
354
+ .option('--mode <mode>', 'latest|all', 'latest')
355
+ .option('--limit <n>', 'max results (mode=all only)', '200')
356
+ .action(async (options) => {
357
+ auth.requireAuth();
358
+ const ep = resolveEndpoint('mon.wazuh.deploy-history.list');
359
+ const data = await client.get(ep.path, { service: ep.service, query: { mode: options.mode, limit: options.limit } });
360
+ formatOutput({
361
+ // fleet #385 class sweep: the route returns
362
+ // { hostname, ip, ssh_user, success, message, deployed_at }, but this
363
+ // declared hostIp/status/deployedAt — three of four columns rendered
364
+ // as dashes with no error. `success` is a boolean, so it's mapped to
365
+ // a readable status rather than printed raw.
366
+ columns: ['hostname', 'ip', 'status', 'deployed_at'],
367
+ headers: ['Host', 'IP', 'Status', 'Deployed'],
368
+ rows: (data.deploys || []).map(d => ({
369
+ ...d,
370
+ status: d.success ? 'ok' : (d.message ? `failed: ${String(d.message).slice(0, 40)}` : 'failed'),
371
+ })),
372
+ }, { format: program.opts().output, emptyMessage: 'No deploy history found.' });
373
+ });
374
+
375
+ wazuh
376
+ .command('deploy-agent')
377
+ .description('Queue a Wazuh agent deploy for one host (HITL-gated — requires HITL Inbox approval)')
378
+ .requiredOption('--hostname <hostname>', 'target hostname')
379
+ .requiredOption('--host-ip <ip>', 'target host IP')
380
+ .option('--wazuh-server <ip>', 'Wazuh manager IP (defaults to server config)')
381
+ .option('--bastion-host <ip>', 'bastion host for the SSH hop')
382
+ .option('--ssh-user <user>', 'SSH user', 'control')
383
+ .option('--ssh-port <n>', 'SSH port', '22')
384
+ .option('--force', 'skip confirmation')
385
+ .action(async (options) => {
386
+ auth.requireAuth();
387
+ const confirmed = await confirmOrSkip(program, options, `Queue Wazuh agent deploy to ${options.hostname} (${options.hostIp})? This will require HITL Inbox approval before it runs.`);
388
+ if (!confirmed) {
389
+ printInfo('Cancelled.');
390
+ return;
391
+ }
392
+ const body = { hostname: options.hostname, hostIp: options.hostIp, sshUser: options.sshUser, sshPort: options.sshPort };
393
+ if (options.wazuhServer) body.wazuhServer = options.wazuhServer;
394
+ if (options.bastionHost) body.bastionHost = options.bastionHost;
395
+ const ep = resolveEndpoint('mon.wazuh.deploy-agent');
396
+ const data = await client.post(ep.path, { service: ep.service, body });
397
+ printSuccess(`Deploy queued — inbox item ${data.inbox_item_id} (awaiting approval).`);
398
+ });
399
+
400
+ wazuh
401
+ .command('deploy-bulk')
402
+ .description('Queue a Wazuh agent deploy for multiple hosts (HITL-gated — requires HITL Inbox approval)')
403
+ .requiredOption('--hosts <json>', 'JSON array of {hostname, ip} objects')
404
+ .option('--wazuh-server <ip>', 'Wazuh manager IP (defaults to server config)')
405
+ .option('--bastion-host <ip>', 'bastion host for the SSH hop')
406
+ .option('--force', 'skip confirmation')
407
+ .action(async (options) => {
408
+ auth.requireAuth();
409
+ const hosts = parseJSON(options.hosts, '--hosts');
410
+ if (!Array.isArray(hosts) || hosts.length === 0) {
411
+ throw new Error('--hosts must be a non-empty JSON array of {hostname, ip} objects.');
412
+ }
413
+ const confirmed = await confirmOrSkip(program, options, `Queue Wazuh agent deploy to ${hosts.length} host(s)? This will require HITL Inbox approval before it runs.`);
414
+ if (!confirmed) {
415
+ printInfo('Cancelled.');
416
+ return;
417
+ }
418
+ const body = { hosts };
419
+ if (options.wazuhServer) body.wazuhServer = options.wazuhServer;
420
+ if (options.bastionHost) body.bastionHost = options.bastionHost;
421
+ const ep = resolveEndpoint('mon.wazuh.deploy-bulk');
422
+ const data = await client.post(ep.path, { service: ep.service, body });
423
+ printSuccess(`Bulk deploy queued for ${data.host_count ?? hosts.length} host(s) — inbox item ${data.inbox_item_id} (awaiting approval).`);
424
+ });
425
+
426
+ wazuh
427
+ .command('active-response')
428
+ .description('Trigger a Wazuh active response (HITL-gated — requires HITL Inbox approval)')
429
+ .requiredOption('--command <command>', 'firewall-block|host-isolate|restart-wazuh-agent')
430
+ .requiredOption('--agents <ids>', 'comma-separated Wazuh agent IDs')
431
+ .requiredOption('--reason <text>', 'justification (min 10 characters)')
432
+ .option('--args <args>', 'comma-separated command arguments')
433
+ .option('--force', 'skip confirmation')
434
+ .action(async (options) => {
435
+ auth.requireAuth();
436
+ const agentList = options.agents.split(',').map(a => a.trim()).filter(Boolean);
437
+ const args = options.args ? options.args.split(',').map(a => a.trim()).filter(Boolean) : [];
438
+ const confirmed = await confirmOrSkip(program, options, `Trigger active response "${options.command}" on ${agentList.length} agent(s)? This will require HITL Inbox approval before it executes.`);
439
+ if (!confirmed) {
440
+ printInfo('Cancelled.');
441
+ return;
442
+ }
443
+ const ep = resolveEndpoint('mon.wazuh.active-response');
444
+ const data = await client.post(ep.path, { service: ep.service, body: { command: options.command, agentList, args, reason: options.reason } });
445
+ printSuccess(`Active response queued — inbox item ${data.inbox_item_id} (awaiting approval).`);
446
+ });
447
+
448
+ // ══════════════════════════════════════════════════════════════════════
449
+ // agh-chain
450
+ // ══════════════════════════════════════════════════════════════════════
451
+
452
+ const aghChain = mon
453
+ .command('agh-chain')
454
+ .description('AGH-chain: per-agent honesty leaderboard (org-scoped)');
455
+
456
+ aghChain
457
+ .command('leaderboard')
458
+ .description('Show the org honesty leaderboard')
459
+ .option('--window <window>', '24h|7d|30d', '24h')
460
+ .action(async (options) => {
461
+ auth.requireAuth();
462
+ const ep = resolveEndpoint('mon.agh-chain.leaderboard.list');
463
+ const data = await client.get(ep.path, { service: ep.service, query: { window: options.window } });
464
+ formatOutput({
465
+ columns: ['agent_id', 'claims_made', 'claims_verified', 'claims_stripped', 'unfulfilled_promises', 'honesty_rate'],
466
+ headers: ['Agent', 'Claims Made', 'Verified', 'Stripped', 'Unfulfilled', 'Honesty Rate'],
467
+ rows: data.agents || [],
468
+ }, { format: program.opts().output, emptyMessage: 'No leaderboard data found.' });
469
+ });
470
+
471
+ aghChain
472
+ .command('agent')
473
+ .description('Show honesty metrics for a single agent')
474
+ .argument('<agentId>', 'agent ID')
475
+ .option('--window <window>', '24h|7d|30d', '24h')
476
+ .action(async (agentId, options) => {
477
+ auth.requireAuth();
478
+ const ep = resolveEndpoint('mon.agh-chain.leaderboard.get', { agentId });
479
+ const data = await client.get(ep.path, { service: ep.service, query: { window: options.window } });
480
+ formatDetail(data, { format: program.opts().output, title: `Honesty metrics: ${agentId}` });
481
+ });
482
+
483
+ aghChain
484
+ .command('events')
485
+ .description('Show drill-through events for a guard kind')
486
+ .argument('<agentId>', 'agent ID')
487
+ .option('--window <window>', '24h|7d|30d', '24h')
488
+ .option('--guard <kind>', 'guard kind', 'claims_stripped')
489
+ .action(async (agentId, options) => {
490
+ auth.requireAuth();
491
+ const ep = resolveEndpoint('mon.agh-chain.leaderboard.events.list', { agentId });
492
+ const data = await client.get(ep.path, { service: ep.service, query: { window: options.window, guard: options.guard } });
493
+ formatOutput({
494
+ columns: ['event_id', 'run_id', 'ts', 'payload_preview'],
495
+ headers: ['Event', 'Run', 'Time', 'Preview'],
496
+ rows: data.events || [],
497
+ }, { format: program.opts().output, emptyMessage: 'No drill-through events found.' });
498
+ });
499
+
500
+ // ══════════════════════════════════════════════════════════════════════
501
+ // metrics
502
+ // ══════════════════════════════════════════════════════════════════════
503
+
504
+ mon
505
+ .command('metrics')
506
+ .description('Show Prometheus scrape metrics (collector fleet gauges)')
507
+ .option('--raw', 'print the raw Prometheus exposition text')
508
+ .action(async (options) => {
509
+ auth.requireAuth();
510
+ const ep = resolveEndpoint('mon.metrics.get');
511
+ const data = await client.get(ep.path, { service: ep.service });
512
+ const text = data.text || '';
513
+
514
+ if (options.raw || program.opts().output === 'json') {
515
+ if (program.opts().output === 'json') {
516
+ console.log(JSON.stringify({ text }, null, 2));
517
+ } else {
518
+ console.log(text);
519
+ }
520
+ return;
521
+ }
522
+
523
+ const rows = text
524
+ .split('\n')
525
+ .filter(line => line && !line.startsWith('#'))
526
+ .map(line => {
527
+ const idx = line.lastIndexOf(' ');
528
+ if (idx === -1) return null;
529
+ return { metric: line.slice(0, idx), value: line.slice(idx + 1) };
530
+ })
531
+ .filter(Boolean);
532
+
533
+ formatOutput({
534
+ columns: ['metric', 'value'],
535
+ headers: ['Metric', 'Value'],
536
+ rows,
537
+ }, { format: program.opts().output, emptyMessage: 'No metrics returned.' });
538
+ });
539
+
540
+ // ══════════════════════════════════════════════════════════════════════
541
+ // config
542
+ // ══════════════════════════════════════════════════════════════════════
543
+
544
+ const config = mon
545
+ .command('config')
546
+ .description('Monitoring service config (Prometheus/Uptime Kuma/Proxmox/Grafana)');
547
+
548
+ config
549
+ .command('get')
550
+ .description('Show configured monitoring service URLs')
551
+ .action(async () => {
552
+ const ep = resolveEndpoint('mon.config.get');
553
+ const data = await client.get(ep.path, { service: ep.service });
554
+ formatDetail(data.services || data, { format: program.opts().output, title: 'Monitoring Config' });
555
+ });
556
+
557
+ config
558
+ .command('cache')
559
+ .description('Show the last cached scan for a monitoring service')
560
+ .argument('<service>', 'service name, e.g. prometheus|uptime-kuma|proxmox')
561
+ .action(async (service) => {
562
+ auth.requireAuth();
563
+ const ep = resolveEndpoint('mon.config.cache.get', { service });
564
+ const data = await client.get(ep.path, { service: ep.service });
565
+ if (data.cached === false) {
566
+ printInfo(`No cached data for ${service}.`);
567
+ return;
568
+ }
569
+ formatDetail(data, { format: program.opts().output, title: `Monitoring cache: ${service}` });
570
+ });
571
+
572
+ config
573
+ .command('grafana')
574
+ .description('Show the configured Grafana base URL')
575
+ .action(async () => {
576
+ auth.requireAuth();
577
+ const ep = resolveEndpoint('mon.config.grafana.get');
578
+ const data = await client.get(ep.path, { service: ep.service });
579
+ formatDetail(data, { format: program.opts().output, title: 'Grafana Config' });
580
+ });
581
+ }
@@ -0,0 +1,86 @@
1
+ /**
2
+ * Monitoring commands: platform health and governance incidents.
3
+ *
4
+ * `quox status` (lib/commands/status.js) and `quox service health`
5
+ * (lib/commands/service.js) already cover aggregate platform health and
6
+ * per-service reachability — this group focuses on the gap: governance
7
+ * incidents, which had no CLI surface at all.
8
+ *
9
+ * Endpoints wired (services/collector/server.js):
10
+ * GET /api/v1/health/aggregate — same endpoint `quox status` uses
11
+ * GET /governance/incidents — list
12
+ * GET /governance/incidents/:id — detail + linked AEE envelopes
13
+ */
14
+
15
+ import { formatOutput, formatDetail } from '../core/output.js';
16
+ import { resolveEndpoint } from '../api/endpoints.js';
17
+
18
+ export function registerMonitoringCommands(program, ctx) {
19
+ const { client, auth } = ctx;
20
+
21
+ const monitoring = program
22
+ .command('monitoring')
23
+ .description('Platform health and governance incidents');
24
+
25
+ // GET /api/v1/health/aggregate — see `quox status` for the human-readable
26
+ // pulse view; this subcommand exists for scripting/discoverability under
27
+ // the monitoring namespace.
28
+ monitoring
29
+ .command('health')
30
+ .description('Show aggregate platform health (services, fleet, sessions)')
31
+ .action(async () => {
32
+ // fleet #602: dropped noAuth: true, which suppressed the Authorization
33
+ // header and 401'd on an authenticated collector (the same bug fixed in
34
+ // `quox status`). Logged-out still works (client sends no header when
35
+ // nothing is stored); logged-in now actually sends the token.
36
+ const data = await client.get(resolveEndpoint('v1.health.aggregate.list').path, {
37
+ service: resolveEndpoint('v1.health.aggregate.list').service,
38
+ timeout: 15000, // #930: aggregate fan-out, 5s too tight under load
39
+ });
40
+ formatDetail(data, { format: program.opts().output, title: 'Platform Health' });
41
+ });
42
+
43
+ const incidents = monitoring
44
+ .command('incidents')
45
+ .description('Governance incidents');
46
+
47
+ incidents
48
+ .command('list')
49
+ .description('List governance incidents')
50
+ .option('--severity <severity>', 'filter by severity')
51
+ .option('--status <status>', 'filter by status')
52
+ .option('--type <type>', 'filter by incident type')
53
+ .option('--agent <id>', 'filter by agent ID')
54
+ .option('--corr <id>', 'filter by correlation ID')
55
+ .option('--since <date>', 'start date (ISO)')
56
+ .option('--until <date>', 'end date (ISO)')
57
+ .option('--limit <n>', 'max results', '100')
58
+ .action(async (options) => {
59
+ auth.requireAuth();
60
+ const query = { limit: options.limit };
61
+ if (options.severity) query.severity = options.severity;
62
+ if (options.status) query.status = options.status;
63
+ if (options.type) query.incident_type = options.type;
64
+ if (options.agent) query.agent_id = options.agent;
65
+ if (options.corr) query.corr = options.corr;
66
+ if (options.since) query.since = options.since;
67
+ if (options.until) query.until = options.until;
68
+
69
+ const data = await client.get(resolveEndpoint('governance.incidents.list').path, { service: resolveEndpoint('governance.incidents.list').service, query });
70
+ formatOutput({
71
+ columns: ['id', 'severity', 'status', 'incident_type', 'agent_id', 'created_at'],
72
+ headers: ['ID', 'Severity', 'Status', 'Type', 'Agent', 'Created'],
73
+ rows: data.data || data.incidents || data,
74
+ }, { format: program.opts().output, emptyMessage: 'No incidents found.' });
75
+ });
76
+
77
+ incidents
78
+ .command('get')
79
+ .description('Show incident details and linked AEE envelopes')
80
+ .argument('<id>', 'incident ID')
81
+ .action(async (id) => {
82
+ auth.requireAuth();
83
+ const data = await client.get(resolveEndpoint('governance.incidents.get', { id }).path, { service: resolveEndpoint('governance.incidents.get', { id }).service });
84
+ formatDetail(data.incident || data, { format: program.opts().output, title: `Incident: ${id}` });
85
+ });
86
+ }