quoxcli 0.3.1 → 0.5.0

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 (306) hide show
  1. package/CHANGELOG.md +61 -0
  2. package/README.md +2 -2
  3. package/bin/quox.js +19 -1
  4. package/bin/quoxon.js +6 -1
  5. package/lib/api/endpoints/actions.js +15 -0
  6. package/lib/api/endpoints/admin.js +27 -0
  7. package/lib/api/endpoints/agent-attach.js +7 -0
  8. package/lib/api/endpoints/blog.js +16 -0
  9. package/lib/api/endpoints/chat.js +7 -0
  10. package/lib/api/endpoints/compliance.js +25 -0
  11. package/lib/api/endpoints/contactsq.js +4 -0
  12. package/lib/api/endpoints/devServerRegistry.js +25 -0
  13. package/lib/api/endpoints/engagement.js +26 -0
  14. package/lib/api/endpoints/evidence.js +20 -0
  15. package/lib/api/endpoints/hat.js +14 -0
  16. package/lib/api/endpoints/inbox.js +6 -0
  17. package/lib/api/endpoints/inboxq.js +19 -0
  18. package/lib/api/endpoints/index.js +14 -0
  19. package/lib/api/endpoints/loops.js +26 -0
  20. package/lib/api/endpoints/mon.js +295 -0
  21. package/lib/api/endpoints/objectives.js +6 -0
  22. package/lib/api/endpoints/quoxseo.js +6 -0
  23. package/lib/api/endpoints/server.js +21 -0
  24. package/lib/api/endpoints/setup.js +6 -0
  25. package/lib/api/endpoints/tools.js +13 -0
  26. package/lib/api/endpoints/v1.js +47 -0
  27. package/lib/commands/actions.js +81 -11
  28. package/lib/commands/admin.js +35 -0
  29. package/lib/commands/agent.js +11 -4
  30. package/lib/commands/agentAttach.js +61 -7
  31. package/lib/commands/approvals.js +198 -3
  32. package/lib/commands/ask.js +4 -2
  33. package/lib/commands/auth.js +64 -11
  34. package/lib/commands/backup.js +11 -4
  35. package/lib/commands/blog.js +110 -0
  36. package/lib/commands/capabilities.js +3 -2
  37. package/lib/commands/chat.js +142 -28
  38. package/lib/commands/chatCompanion.js +27 -0
  39. package/lib/commands/chatState.js +45 -0
  40. package/lib/commands/claude.js +7 -33
  41. package/lib/commands/compliance.js +109 -0
  42. package/lib/commands/connect.js +69 -0
  43. package/lib/commands/contacts.js +85 -4
  44. package/lib/commands/contactsSendAt.js +21 -0
  45. package/lib/commands/dev.js +6 -8
  46. package/lib/commands/doctor.js +22 -3
  47. package/lib/commands/engagement.js +90 -0
  48. package/lib/commands/evidence.js +155 -0
  49. package/lib/commands/ext.js +23 -0
  50. package/lib/commands/fleet.js +25 -0
  51. package/lib/commands/gripe.js +24 -13
  52. package/lib/commands/hat.js +76 -0
  53. package/lib/commands/image.js +68 -0
  54. package/lib/commands/inbox.js +37 -3
  55. package/lib/commands/inboxq.js +147 -0
  56. package/lib/commands/kuma.js +1123 -0
  57. package/lib/commands/kumaSla.js +174 -0
  58. package/lib/commands/licence.js +39 -1
  59. package/lib/commands/licenceLinkView.js +311 -0
  60. package/lib/commands/linkedin.js +19 -0
  61. package/lib/commands/loop.js +318 -0
  62. package/lib/commands/lucid.js +1 -0
  63. package/lib/commands/mail.js +161 -20
  64. package/lib/commands/memory.js +68 -4
  65. package/lib/commands/memorySync.js +158 -0
  66. package/lib/commands/mon.js +55 -144
  67. package/lib/commands/notes.js +29 -7
  68. package/lib/commands/notesSeal.js +259 -0
  69. package/lib/commands/objective.js +53 -3
  70. package/lib/commands/offload.js +2 -3
  71. package/lib/commands/org.js +21 -4
  72. package/lib/commands/plan.js +17 -0
  73. package/lib/commands/provider.js +87 -8
  74. package/lib/commands/qlarity.js +32 -1
  75. package/lib/commands/quoxseo.js +31 -0
  76. package/lib/commands/research.js +79 -0
  77. package/lib/commands/rows.js +9 -0
  78. package/lib/commands/run.js +20 -2
  79. package/lib/commands/scope.js +2 -2
  80. package/lib/commands/server.js +150 -0
  81. package/lib/commands/setup.js +127 -75
  82. package/lib/commands/shortcut.js +41 -0
  83. package/lib/commands/skills.js +24 -5
  84. package/lib/commands/slot.js +49 -9
  85. package/lib/commands/status.js +92 -44
  86. package/lib/commands/tool.js +30 -0
  87. package/lib/commands/vault.js +6 -3
  88. package/lib/commands/vm.js +2 -2
  89. package/lib/commands/walkthrough.js +14 -2
  90. package/lib/commands/watch.js +11 -2
  91. package/lib/commands/wazuh.js +824 -0
  92. package/lib/commands/wazuhIntake.js +317 -0
  93. package/lib/commands/wazuhReport.js +192 -0
  94. package/lib/commands/workflow.js +47 -4
  95. package/lib/commands/x.js +50 -0
  96. package/lib/commands/youtube.js +172 -0
  97. package/lib/core/actionItems.js +115 -0
  98. package/lib/core/agentAlias.js +2 -0
  99. package/lib/core/agentFamilies.js +7 -0
  100. package/lib/core/announce.js +86 -0
  101. package/lib/core/auth.js +20 -2
  102. package/lib/core/callMe.js +118 -0
  103. package/lib/core/client.js +37 -3
  104. package/lib/core/commandRegistrars.js +17 -0
  105. package/lib/core/config.js +29 -3
  106. package/lib/core/confirm.js +68 -7
  107. package/lib/core/crossOrgApprovals.js +69 -0
  108. package/lib/core/errors.js +52 -1
  109. package/lib/core/findingReconcile.js +90 -0
  110. package/lib/core/global-flags.js +1 -1
  111. package/lib/core/governedSession.js +136 -8
  112. package/lib/core/inboxResolution.js +3 -2
  113. package/lib/core/liveSessionsReport.js +1 -1
  114. package/lib/core/loginGuard.js +73 -0
  115. package/lib/core/loopGlyph.js +97 -0
  116. package/lib/core/offload.js +73 -7
  117. package/lib/core/org-override.js +5 -1
  118. package/lib/core/output.js +8 -8
  119. package/lib/core/profileTrust.js +182 -0
  120. package/lib/core/quoxglyph.js +22 -1
  121. package/lib/core/router.js +14 -0
  122. package/lib/core/sessionHeartbeat.js +12 -8
  123. package/lib/core/shortcut.js +83 -0
  124. package/lib/core/stepUpPrompt.js +99 -0
  125. package/lib/core/version.js +1 -1
  126. package/lib/core/vm.js +5 -0
  127. package/lib/core/walkthrough.js +9 -5
  128. package/lib/dragon/companionView.js +34 -0
  129. package/lib/dragon/frames.js +118 -0
  130. package/lib/dragon/jobs.js +123 -0
  131. package/lib/dragon/renderWorker.js +15 -0
  132. package/lib/dragon/select.js +72 -0
  133. package/lib/evidence/bundleExport.js +47 -0
  134. package/lib/evidence/bundleVerify.js +77 -0
  135. package/lib/quoxon/EXTENSIONS.md +146 -0
  136. package/lib/quoxon/api.js +364 -27
  137. package/lib/quoxon/app.js +1629 -183
  138. package/lib/quoxon/approvalBatch.js +117 -0
  139. package/lib/quoxon/approvalFacts.js +64 -8
  140. package/lib/quoxon/approvalSentence.js +48 -0
  141. package/lib/quoxon/approvalsView.js +124 -7
  142. package/lib/quoxon/autoOpen.js +94 -0
  143. package/lib/quoxon/backgroundWork.js +59 -0
  144. package/lib/quoxon/bang.js +1 -1
  145. package/lib/quoxon/capabilities.js +7 -2
  146. package/lib/quoxon/commandShort.js +22 -3
  147. package/lib/quoxon/commands.js +110 -15
  148. package/lib/quoxon/connect.js +5 -3
  149. package/lib/quoxon/countdownLine.js +10 -1
  150. package/lib/quoxon/deck.js +30 -0
  151. package/lib/quoxon/deckLazy.js +58 -0
  152. package/lib/quoxon/demo.autoplay.js +1 -1
  153. package/lib/quoxon/demo.js +3 -1
  154. package/lib/quoxon/destructive.js +35 -0
  155. package/lib/quoxon/dividerAocl.js +4 -3
  156. package/lib/quoxon/dividerRule.js +3 -3
  157. package/lib/quoxon/dnd.js +71 -0
  158. package/lib/quoxon/dragonCompanion.js +285 -0
  159. package/lib/quoxon/dragonModes.js +1 -0
  160. package/lib/quoxon/dragonMoments.js +160 -0
  161. package/lib/quoxon/dragonReads.js +68 -0
  162. package/lib/quoxon/dragonView.js +2 -2
  163. package/lib/quoxon/echo.js +1 -0
  164. package/lib/quoxon/events.js +67 -10
  165. package/lib/quoxon/extensions.js +636 -0
  166. package/lib/quoxon/gripeQueue.js +135 -0
  167. package/lib/quoxon/inboxView.js +182 -0
  168. package/lib/quoxon/installCli.js +79 -0
  169. package/lib/quoxon/keys.js +4 -4
  170. package/lib/quoxon/loopCard.js +460 -0
  171. package/lib/quoxon/loopCards.js +189 -0
  172. package/lib/quoxon/loopStream.js +98 -0
  173. package/lib/quoxon/mailView.js +71 -0
  174. package/lib/quoxon/main.js +29 -5
  175. package/lib/quoxon/markdown.js +1 -1
  176. package/lib/quoxon/model.js +15 -0
  177. package/lib/quoxon/mouse.js +12 -1
  178. package/lib/quoxon/neverAnswered.js +20 -0
  179. package/lib/quoxon/objectiveOffer.js +82 -0
  180. package/lib/quoxon/objects/away.js +43 -5
  181. package/lib/quoxon/objects/index.js +22 -4
  182. package/lib/quoxon/objects/model.js +33 -0
  183. package/lib/quoxon/objects/proof.js +12 -4
  184. package/lib/quoxon/onboarding/connectServer.js +162 -0
  185. package/lib/quoxon/onboarding/copy.js +6 -0
  186. package/lib/quoxon/onboarding/index.js +5 -43
  187. package/lib/quoxon/onboarding/probe.js +20 -1
  188. package/lib/quoxon/onboarding/shortcutOffer.js +28 -0
  189. package/lib/quoxon/onboarding/view.js +16 -3
  190. package/lib/quoxon/orgSwitch.js +49 -1
  191. package/lib/quoxon/planSteps.js +51 -0
  192. package/lib/quoxon/print.js +8 -3
  193. package/lib/quoxon/profileSwitch.js +7 -0
  194. package/lib/quoxon/promptHistory.js +3 -1
  195. package/lib/quoxon/qdragonFly.js +7 -6
  196. package/lib/quoxon/qmotion.js +17 -0
  197. package/lib/quoxon/render.js +187 -41
  198. package/lib/quoxon/roster.js +36 -17
  199. package/lib/quoxon/rosterSessions.js +44 -0
  200. package/lib/quoxon/rows.js +244 -1
  201. package/lib/quoxon/screenContext.js +1 -1
  202. package/lib/quoxon/secretShape.js +86 -0
  203. package/lib/quoxon/serverChip.js +42 -0
  204. package/lib/quoxon/session.js +10 -0
  205. package/lib/quoxon/slash/agents.js +2 -1
  206. package/lib/quoxon/slash/argSources.js +9 -2
  207. package/lib/quoxon/slash/args.js +4 -2
  208. package/lib/quoxon/slash/broadcast.js +18 -5
  209. package/lib/quoxon/slash/broadcastRun.js +13 -2
  210. package/lib/quoxon/slash/cliCommand.js +42 -1
  211. package/lib/quoxon/slash/cliLeaves.json +139 -2
  212. package/lib/quoxon/slash/evidenceCmd.js +34 -0
  213. package/lib/quoxon/slash/hatWalk.js +1 -1
  214. package/lib/quoxon/slash/palette.js +23 -2
  215. package/lib/quoxon/slash/paletteController.js +10 -4
  216. package/lib/quoxon/slash/qpeCmd.js +35 -0
  217. package/lib/quoxon/slash/restart.js +31 -4
  218. package/lib/quoxon/slash/resume.js +18 -1
  219. package/lib/quoxon/slash/stepUp.js +5 -5
  220. package/lib/quoxon/slash/stepUpCmds.js +74 -1
  221. package/lib/quoxon/slash/todoCmd.js +122 -0
  222. package/lib/quoxon/slashSpinner.js +35 -0
  223. package/lib/quoxon/slotAttach.js +8 -0
  224. package/lib/quoxon/slotChat.js +17 -0
  225. package/lib/quoxon/slotFormat.js +1 -1
  226. package/lib/quoxon/slotOutbox.js +113 -0
  227. package/lib/quoxon/suggestCommand.js +34 -3
  228. package/lib/quoxon/term.js +25 -1
  229. package/lib/quoxon/toolCards.js +30 -0
  230. package/lib/quoxon/transcript.js +2 -1
  231. package/lib/quoxon/welcome.js +1 -1
  232. package/lib/quoxon/whatsnew.js +1 -1
  233. package/lib/quoxon/whatsnew.jsonl +81 -0
  234. package/lib/quoxon/windowOrg.js +11 -1
  235. package/lib/server/devServers.js +137 -0
  236. package/lib/server/installFlow.js +168 -0
  237. package/lib/server/status.js +15 -1
  238. package/lib/toolOutputShape.js +55 -0
  239. package/package.json +4 -2
  240. package/vendor/dragonlab/SOURCE +4 -0
  241. package/vendor/dragonlab/design/cipher/v1/cipher-master.svg +46 -0
  242. package/vendor/dragonlab/design/cipher/v2/character.mjs +49 -0
  243. package/vendor/dragonlab/design/cipher/v2/review.mjs +33 -0
  244. package/vendor/dragonlab/design/cipher/v2/watch.mjs +56 -0
  245. package/vendor/dragonlab/design/drago/v1/character.mjs +19 -0
  246. package/vendor/dragonlab/design/drago/v1/drago-master.svg +56 -0
  247. package/vendor/dragonlab/design/drago/v2/character.mjs +87 -0
  248. package/vendor/dragonlab/design/drago/v4/character.mjs +67 -0
  249. package/vendor/dragonlab/design/drago/v4/profile.mjs +35 -0
  250. package/vendor/dragonlab/design/drago/v4/review.mjs +33 -0
  251. package/vendor/dragonlab/design/drago/v4/watch.mjs +56 -0
  252. package/vendor/dragonlab/design/hyperion/v1/hyperion-master.svg +56 -0
  253. package/vendor/dragonlab/design/hyperion/v2/character.mjs +79 -0
  254. package/vendor/dragonlab/design/hyperion/v2/review.mjs +33 -0
  255. package/vendor/dragonlab/design/hyperion/v2/watch.mjs +56 -0
  256. package/vendor/dragonlab/design/lucid/recovery/arrival.mjs +22 -0
  257. package/vendor/dragonlab/design/lucid/recovery/character.mjs +106 -0
  258. package/vendor/dragonlab/design/lucid/recovery/layout.mjs +50 -0
  259. package/vendor/dragonlab/design/lucid/recovery/lucid-master.svg +78 -0
  260. package/vendor/dragonlab/design/lucid/recovery/motion.mjs +42 -0
  261. package/vendor/dragonlab/design/lucid/recovery/render.mjs +121 -0
  262. package/vendor/dragonlab/design/lucid/recovery/review.mjs +68 -0
  263. package/vendor/dragonlab/design/lucid/recovery/verify.mjs +84 -0
  264. package/vendor/dragonlab/design/lucid/recovery/watch.mjs +56 -0
  265. package/vendor/dragonlab/design/quoxperticus/v2/quoxperticus-master.svg +59 -0
  266. package/vendor/dragonlab/design/quoxperticus/v3/character.mjs +43 -0
  267. package/vendor/dragonlab/design/quoxperticus/v4/character.mjs +57 -0
  268. package/vendor/dragonlab/design/quoxperticus/v4/review.mjs +35 -0
  269. package/vendor/dragonlab/design/quoxperticus/v4/watch.mjs +56 -0
  270. package/vendor/dragonlab/design/seer/v1/seer-master.svg +53 -0
  271. package/vendor/dragonlab/design/seer/v2/character.mjs +88 -0
  272. package/vendor/dragonlab/design/seer/v3/character.mjs +33 -0
  273. package/vendor/dragonlab/design/seer/v4/character.mjs +66 -0
  274. package/vendor/dragonlab/design/seer/v4/review.mjs +33 -0
  275. package/vendor/dragonlab/design/seer/v4/watch.mjs +56 -0
  276. package/vendor/dragonlab/design/stage3/companion-review.mjs +28 -0
  277. package/vendor/dragonlab/design/stage3/sentinel-art.js +39 -0
  278. package/vendor/dragonlab/design/stage3/sentinel-braille.js +216 -0
  279. package/vendor/dragonlab/design/stage3/sentinel-character.js +257 -0
  280. package/vendor/dragonlab/design/stage3/sentinel-icon.js +103 -0
  281. package/vendor/dragonlab/design/stage3/sentinel-warden-eyes.js +95 -0
  282. package/vendor/dragonlab/design/stage3/svg-coverage.js +148 -0
  283. package/vendor/dragonlab/design/vulcan/v1/character.mjs +34 -0
  284. package/vendor/dragonlab/design/vulcan/v1/vulcan-master.svg +57 -0
  285. package/vendor/dragonlab/design/vulcan/v2/character.mjs +39 -0
  286. package/vendor/dragonlab/design/vulcan/v3/character.mjs +41 -0
  287. package/vendor/dragonlab/design/vulcan/v3/review.mjs +35 -0
  288. package/vendor/dragonlab/design/vulcan/v3/watch.mjs +56 -0
  289. package/vendor/dragonlab/factory/svg-rig-contour.mjs +64 -0
  290. package/vendor/dragonlab/factory/svg-rig.mjs +63 -0
  291. package/vendor/dragonlab/integration/companions-v1/characters.mjs +108 -0
  292. package/vendor/dragonlab/integration/companions-v1/cipher.mjs +2 -0
  293. package/vendor/dragonlab/integration/companions-v1/companion.mjs +63 -0
  294. package/vendor/dragonlab/integration/companions-v1/drago.mjs +2 -0
  295. package/vendor/dragonlab/integration/companions-v1/hyperion.mjs +2 -0
  296. package/vendor/dragonlab/integration/companions-v1/lucid.mjs +2 -0
  297. package/vendor/dragonlab/integration/companions-v1/quoxperticus.mjs +2 -0
  298. package/vendor/dragonlab/integration/companions-v1/seer.mjs +2 -0
  299. package/vendor/dragonlab/integration/companions-v1/sentinel.mjs +2 -0
  300. package/vendor/dragonlab/integration/companions-v1/view.mjs +28 -0
  301. package/vendor/dragonlab/integration/companions-v1/vulcan.mjs +2 -0
  302. package/vendor/dragonlab/integration/hyperion-v3/activity.mjs +76 -0
  303. package/vendor/dragonlab/lib/power-effects.js +294 -0
  304. package/vendor/dragonlab/lib/power-registry.js +74 -0
  305. package/vendor/dragonlab/vendor/quox-dragon/qart.js +348 -0
  306. package/vendor/dragonlab/vendor/quox-dragon/qeyes.js +213 -0
@@ -127,6 +127,185 @@ export const mon = {
127
127
  path: () => `/docker/system-df`,
128
128
  tags: ['live-safe'],
129
129
  },
130
+ 'mon.kuma.monitors.list': {
131
+ method: 'GET',
132
+ service: 'collector',
133
+ path: ({ id } = {}) => `/api/v1/kuma/monitors`,
134
+ tags: ['live-safe'],
135
+ },
136
+ 'mon.kuma.monitors.get': {
137
+ method: 'GET',
138
+ service: 'collector',
139
+ path: ({ id } = {}) => `/api/v1/kuma/monitors/${encodeURIComponent(id)}`,
140
+ tags: ['live-safe'],
141
+ },
142
+ 'mon.kuma.monitors.create': {
143
+ method: 'POST',
144
+ service: 'collector',
145
+ path: ({ id } = {}) => `/api/v1/kuma/monitors`,
146
+ tags: ['live-write'],
147
+ },
148
+ 'mon.kuma.monitors.update': {
149
+ method: 'PATCH',
150
+ service: 'collector',
151
+ path: ({ id } = {}) => `/api/v1/kuma/monitors/${encodeURIComponent(id)}`,
152
+ tags: ['live-write'],
153
+ },
154
+ 'mon.kuma.monitors.pause': {
155
+ method: 'POST',
156
+ service: 'collector',
157
+ path: ({ id } = {}) => `/api/v1/kuma/monitors/${encodeURIComponent(id)}/pause`,
158
+ tags: ['live-write'],
159
+ },
160
+ 'mon.kuma.monitors.resume': {
161
+ method: 'POST',
162
+ service: 'collector',
163
+ path: ({ id } = {}) => `/api/v1/kuma/monitors/${encodeURIComponent(id)}/resume`,
164
+ tags: ['live-write'],
165
+ },
166
+ 'mon.kuma.monitors.wire-alerts': {
167
+ method: 'POST',
168
+ service: 'collector',
169
+ path: ({ id } = {}) => `/api/v1/kuma/monitors/${encodeURIComponent(id)}/wire-alerts`,
170
+ tags: ['live-write'],
171
+ },
172
+ 'mon.kuma.monitors.delete': {
173
+ method: 'DELETE',
174
+ service: 'collector',
175
+ path: ({ id } = {}) => `/api/v1/kuma/monitors/${encodeURIComponent(id)}`,
176
+ tags: ['live-write'],
177
+ },
178
+ 'mon.kuma.incidents.list': {
179
+ method: 'GET',
180
+ service: 'collector',
181
+ path: ({ open, limit } = {}) => {
182
+ const q = [];
183
+ if (open) q.push('open=1');
184
+ if (limit) q.push(`limit=${encodeURIComponent(limit)}`);
185
+ return `/api/v1/kuma/incidents${q.length ? `?${q.join('&')}` : ''}`;
186
+ },
187
+ tags: ['live-safe'],
188
+ },
189
+ 'mon.kuma.incidents.get': {
190
+ method: 'GET',
191
+ service: 'collector',
192
+ path: ({ id } = {}) => `/api/v1/kuma/incidents/${encodeURIComponent(id)}`,
193
+ tags: ['live-safe'],
194
+ },
195
+ 'mon.kuma.coverage.get': {
196
+ method: 'GET',
197
+ service: 'collector',
198
+ path: () => `/api/v1/kuma/coverage`,
199
+ tags: ['live-safe'],
200
+ },
201
+ 'mon.kuma.coverage.propose': {
202
+ method: 'POST',
203
+ service: 'collector',
204
+ path: () => `/api/v1/kuma/coverage/propose`,
205
+ tags: ['live-safe'],
206
+ },
207
+ 'mon.kuma.maintenance.list': {
208
+ method: 'GET',
209
+ service: 'collector',
210
+ path: () => `/api/v1/kuma/maintenance`,
211
+ tags: ['live-safe'],
212
+ },
213
+ 'mon.kuma.maintenance.open': {
214
+ method: 'POST',
215
+ service: 'collector',
216
+ path: () => `/api/v1/kuma/maintenance`,
217
+ tags: ['live-write'],
218
+ },
219
+ 'mon.kuma.maintenance.end': {
220
+ method: 'POST',
221
+ service: 'collector',
222
+ path: ({ id } = {}) => `/api/v1/kuma/maintenance/${encodeURIComponent(id)}/end`,
223
+ tags: ['live-write'],
224
+ },
225
+ 'mon.kuma.statusIncident.draft': {
226
+ method: 'GET',
227
+ service: 'collector',
228
+ path: ({ id } = {}) => `/api/v1/kuma/status-incidents/${encodeURIComponent(id)}/draft`,
229
+ tags: ['live-safe'],
230
+ },
231
+ 'mon.kuma.statusIncident.publish': {
232
+ method: 'POST',
233
+ service: 'collector',
234
+ path: ({ id } = {}) => `/api/v1/kuma/status-incidents/${encodeURIComponent(id)}/publish`,
235
+ tags: ['live-write'],
236
+ },
237
+ 'mon.kuma.statusIncident.resolve': {
238
+ method: 'POST',
239
+ service: 'collector',
240
+ path: () => `/api/v1/kuma/status-incidents/resolve`,
241
+ tags: ['live-write'],
242
+ },
243
+ 'mon.kuma.diagnose.create': {
244
+ method: 'POST',
245
+ service: 'collector',
246
+ path: () => `/api/v1/kuma/diagnose`,
247
+ tags: ['live-safe'],
248
+ },
249
+ 'mon.kuma.sla.create': {
250
+ method: 'POST',
251
+ service: 'collector',
252
+ path: () => `/api/v1/kuma/sla`,
253
+ tags: ['live-safe'],
254
+ },
255
+ 'mon.kuma.sla.list': {
256
+ method: 'GET',
257
+ service: 'collector',
258
+ path: () => `/api/v1/kuma/sla`,
259
+ tags: ['live-safe'],
260
+ },
261
+ 'mon.kuma.sla.get': {
262
+ method: 'GET',
263
+ service: 'collector',
264
+ path: ({ id } = {}) => `/api/v1/kuma/sla/${encodeURIComponent(id)}`,
265
+ tags: ['live-safe'],
266
+ },
267
+ 'mon.kuma.sla.verify': {
268
+ method: 'GET',
269
+ service: 'collector',
270
+ path: ({ id } = {}) => `/api/v1/kuma/sla/${encodeURIComponent(id)}/verify`,
271
+ tags: ['live-safe'],
272
+ },
273
+ 'mon.kuma.hooks.list': {
274
+ method: 'GET',
275
+ service: 'collector',
276
+ path: () => `/api/v1/kuma/hooks`,
277
+ tags: ['live-safe'],
278
+ },
279
+ 'mon.kuma.hooks.create': {
280
+ method: 'POST',
281
+ service: 'collector',
282
+ path: () => `/api/v1/kuma/hooks`,
283
+ tags: ['live-write'],
284
+ },
285
+ 'mon.kuma.hooks.delete': {
286
+ method: 'DELETE',
287
+ service: 'collector',
288
+ path: ({ id } = {}) => `/api/v1/kuma/hooks/${encodeURIComponent(id)}`,
289
+ tags: ['live-write'],
290
+ },
291
+ 'mon.kuma.refresh.create': {
292
+ method: 'POST',
293
+ service: 'collector',
294
+ path: () => `/api/v1/monitoring/uptime-kuma/refresh`,
295
+ tags: ['live-write'],
296
+ },
297
+ 'mon.kuma.live.get': {
298
+ method: 'GET',
299
+ service: 'collector',
300
+ path: ({ fresh } = {}) => `/api/v1/kuma/status${fresh ? '?fresh=1' : ''}`,
301
+ tags: ['live-safe'],
302
+ },
303
+ 'mon.kuma.status.get': {
304
+ method: 'GET',
305
+ service: 'collector',
306
+ path: ({ slug }) => `/api/v1/monitoring/uptime-kuma/status/${encodeURIComponent(slug)}`,
307
+ tags: ['live-safe'],
308
+ },
130
309
  'mon.metrics.get': {
131
310
  method: 'GET',
132
311
  service: 'collector',
@@ -145,12 +324,36 @@ export const mon = {
145
324
  path: () => `/api/v1/wazuh/agents`,
146
325
  tags: ['live-safe'],
147
326
  },
327
+ 'mon.wazuh.read': {
328
+ method: 'GET',
329
+ service: 'collector',
330
+ path: ({ tool }) => `/api/v1/wazuh/read/${tool}`,
331
+ tags: ['live-safe'],
332
+ },
148
333
  'mon.wazuh.alerts.list': {
149
334
  method: 'GET',
150
335
  service: 'collector',
151
336
  path: () => `/api/v1/wazuh/alerts`,
152
337
  tags: ['live-safe'],
153
338
  },
339
+ 'mon.wazuh.alerts.triage': {
340
+ method: 'GET',
341
+ service: 'collector',
342
+ path: () => `/api/v1/wazuh/alerts/triage`,
343
+ tags: ['live-safe'],
344
+ },
345
+ 'mon.wazuh.coverage': {
346
+ method: 'GET',
347
+ service: 'collector',
348
+ path: () => `/api/v1/wazuh/coverage`,
349
+ tags: ['live-safe'],
350
+ },
351
+ 'mon.wazuh.credential.import-instance-env': {
352
+ method: 'POST',
353
+ service: 'collector',
354
+ path: () => `/api/v1/wazuh/credential/import-instance-env`,
355
+ tags: ['live-write'],
356
+ },
154
357
  'mon.wazuh.deploy-agent': {
155
358
  method: 'POST',
156
359
  service: 'collector',
@@ -175,6 +378,98 @@ export const mon = {
175
378
  path: () => `/api/v1/wazuh/manager/status`,
176
379
  tags: ['live-safe'],
177
380
  },
381
+ 'mon.wazuh.reports.create': {
382
+ method: 'POST',
383
+ service: 'collector',
384
+ path: () => `/api/v1/wazuh/reports`,
385
+ tags: ['live-safe'],
386
+ },
387
+ 'mon.wazuh.reports.list': {
388
+ method: 'GET',
389
+ service: 'collector',
390
+ path: () => `/api/v1/wazuh/reports`,
391
+ tags: ['live-safe'],
392
+ },
393
+ 'mon.wazuh.reports.get': {
394
+ method: 'GET',
395
+ service: 'collector',
396
+ path: ({ id } = {}) => `/api/v1/wazuh/reports/${encodeURIComponent(id)}`,
397
+ tags: ['live-safe'],
398
+ },
399
+ 'mon.wazuh.reports.verify': {
400
+ method: 'GET',
401
+ service: 'collector',
402
+ path: ({ id } = {}) => `/api/v1/wazuh/reports/${encodeURIComponent(id)}/verify`,
403
+ tags: ['live-safe'],
404
+ },
405
+ // WAZ P6: Wazuh integratord alert hooks (org admin) and the incidents they open.
406
+ 'mon.wazuh.hooks.list': {
407
+ method: 'GET',
408
+ service: 'collector',
409
+ path: () => `/api/v1/wazuh/hooks`,
410
+ tags: ['live-safe'],
411
+ },
412
+ 'mon.wazuh.hooks.create': {
413
+ method: 'POST',
414
+ service: 'collector',
415
+ path: () => `/api/v1/wazuh/hooks`,
416
+ tags: ['live-write'],
417
+ },
418
+ 'mon.wazuh.hooks.rotate': {
419
+ method: 'POST',
420
+ service: 'collector',
421
+ path: ({ id } = {}) => `/api/v1/wazuh/hooks/${encodeURIComponent(id)}/rotate`,
422
+ tags: ['live-write'],
423
+ },
424
+ 'mon.wazuh.hooks.delete': {
425
+ method: 'DELETE',
426
+ service: 'collector',
427
+ path: ({ id } = {}) => `/api/v1/wazuh/hooks/${encodeURIComponent(id)}`,
428
+ tags: ['live-write'],
429
+ },
430
+ 'mon.wazuh.incidents.list': {
431
+ method: 'GET',
432
+ service: 'collector',
433
+ path: ({ open, since, limit } = {}) => {
434
+ const q = [];
435
+ if (open) q.push('open=1');
436
+ if (since) q.push(`since=${encodeURIComponent(since)}`);
437
+ if (limit) q.push(`limit=${encodeURIComponent(limit)}`);
438
+ return `/api/v1/wazuh/incidents${q.length ? `?${q.join('&')}` : ''}`;
439
+ },
440
+ tags: ['live-safe'],
441
+ },
442
+ 'mon.wazuh.incidents.get': {
443
+ method: 'GET',
444
+ service: 'collector',
445
+ path: ({ id } = {}) => `/api/v1/wazuh/incidents/${encodeURIComponent(id)}`,
446
+ tags: ['live-safe'],
447
+ },
448
+ 'mon.wazuh.incidents.close': {
449
+ method: 'POST',
450
+ service: 'collector',
451
+ path: ({ id } = {}) => `/api/v1/wazuh/incidents/${encodeURIComponent(id)}/close`,
452
+ tags: ['live-write'],
453
+ },
454
+ // WAZ P7: read-only host diagnosis (off-list reads are held by the ssh_exec approval gate) and hand-off to QuoxSecurity.
455
+ 'mon.wazuh.incidents.diagnose': {
456
+ method: 'POST',
457
+ service: 'collector',
458
+ path: ({ id } = {}) => `/api/v1/wazuh/incidents/${encodeURIComponent(id)}/diagnose`,
459
+ tags: ['live-write'],
460
+ },
461
+ 'mon.wazuh.incidents.escalate': {
462
+ method: 'POST',
463
+ service: 'collector',
464
+ path: ({ id } = {}) => `/api/v1/wazuh/incidents/${encodeURIComponent(id)}/escalate`,
465
+ tags: ['live-write'],
466
+ },
467
+ 'mon.wazuh.vulnerabilities.priority': {
468
+ method: 'GET',
469
+ service: 'collector',
470
+ path: () => `/api/v1/wazuh/vulnerabilities/priority`,
471
+ tags: ['live-safe'],
472
+ },
178
473
  'mon.wazuh.vulnerabilities.list': {
179
474
  method: 'GET',
180
475
  service: 'collector',
@@ -11,6 +11,12 @@ export const objectives = {
11
11
  path: ({ id }) => `/api/objectives/${id}/approve-plan`,
12
12
  tags: ['live-write'],
13
13
  },
14
+ 'objectives.retry': {
15
+ method: 'POST',
16
+ service: 'tasks',
17
+ path: ({ id }) => `/api/objectives/${id}/retry`,
18
+ tags: ['live-write'],
19
+ },
14
20
  'objectives.cancel': {
15
21
  method: 'DELETE',
16
22
  service: 'tasks',
@@ -59,6 +59,12 @@ export const quoxseo = {
59
59
  path: ({ query = '' }) => `/api/v1/quoxseo/trends${query}`,
60
60
  tags: ['live-safe'],
61
61
  },
62
+ 'quoxseo.queries.rows': {
63
+ method: 'GET',
64
+ service: 'collector',
65
+ path: ({ query = '' }) => `/api/v1/quoxseo/queries/rows${query}`,
66
+ tags: ['live-safe'],
67
+ },
62
68
  'quoxseo.inspection': {
63
69
  method: 'GET',
64
70
  service: 'collector',
@@ -0,0 +1,21 @@
1
+ /**
2
+ * 'server.*' endpoints: moved out of admin.js so each key carries its fragment's own domain prefix.
3
+ * See cli/lib/api/endpoints/index.js for aggregation + the fragment convention.
4
+ */
5
+
6
+ export const server = {
7
+ // DEVFLEET CX-2: server roles registry (role -> url, read before env by resolveServiceUrl). Collector routes;
8
+ // list is instance-admin readable, set/unset/test are instance-OWNER only (see services/collector/server.js).
9
+ 'server.roles.list': {
10
+ method: 'GET', service: 'collector', path: () => '/api/v1/server/roles', tags: ['live-safe'],
11
+ },
12
+ 'server.roles.set': {
13
+ method: 'PUT', service: 'collector', path: ({ role }) => `/api/v1/server/roles/${encodeURIComponent(role)}`, tags: ['admin-write'],
14
+ },
15
+ 'server.roles.unset': {
16
+ method: 'DELETE', service: 'collector', path: ({ role }) => `/api/v1/server/roles/${encodeURIComponent(role)}`, tags: ['admin-write'],
17
+ },
18
+ 'server.roles.test': {
19
+ method: 'POST', service: 'collector', path: ({ role }) => `/api/v1/server/roles/${encodeURIComponent(role)}/test`, tags: ['admin-write'],
20
+ },
21
+ };
@@ -81,6 +81,12 @@ export const setup = {
81
81
  path: ({ pluginId }) => `/api/setup/licensing/seats/${encodeURIComponent(pluginId)}/release-dead`,
82
82
  tags: ['live-write'],
83
83
  },
84
+ 'setup.licensing.seats.release': {
85
+ method: 'POST',
86
+ service: 'auth',
87
+ path: ({ pluginId }) => `/api/setup/licensing/seats/${encodeURIComponent(pluginId)}/release`,
88
+ tags: ['live-write'],
89
+ },
84
90
  'setup.status.list': {
85
91
  method: 'GET',
86
92
  service: 'auth',
@@ -29,6 +29,19 @@ export const tools = {
29
29
  path: () => `/api/tools/install-to-scope`,
30
30
  tags: ['live-write'],
31
31
  },
32
+ // CLI-COV 2026-11-05: read and undo what `tool install` wrote (tool_installations, not the org's tool definitions)
33
+ 'tools.installed': {
34
+ method: 'GET',
35
+ service: 'auth',
36
+ path: () => `/api/tools/installed`,
37
+ tags: ['live-safe'],
38
+ },
39
+ 'tools.uninstall-from-scope': {
40
+ method: 'DELETE',
41
+ service: 'auth',
42
+ path: ({ toolId }) => `/api/tools/install-to-scope/${encodeURIComponent(toolId)}`,
43
+ tags: ['live-write'],
44
+ },
32
45
  'tools.list': {
33
46
  method: 'GET',
34
47
  service: 'auth',
@@ -59,6 +59,14 @@ export const v1 = {
59
59
  path: () => `/api/v1/fleet/hosts`,
60
60
  tags: ['live-safe'],
61
61
  },
62
+ // quoxbastion#34 — `quox fleet ping [host]`: governed Bastion host-state
63
+ // refresh (org admin; emits a quox.fleet.ping evidence envelope).
64
+ 'v1.fleet.ping': {
65
+ method: 'POST',
66
+ service: 'collector',
67
+ path: () => `/api/v1/fleet/ping`,
68
+ tags: ['admin-write'],
69
+ },
62
70
  // DEVSUITE-HUB Phase 2 — `quox dev enable` (see lib/commands/dev.js).
63
71
  // Constructs + signs + delivers a quoxagent dev.CapabilityProfile onto a
64
72
  // target host via Bastion. See services/collector/server.js's
@@ -290,6 +298,32 @@ export const v1 = {
290
298
  path: () => `/api/v1/policies/validate`,
291
299
  tags: ['live-write'],
292
300
  },
301
+ // LAZY-AI-CLI: vendor CLIs (Claude Code, Codex) the user's own server installs from npm. Status is any
302
+ // signed-in caller; plan + install need a human instance admin (the binary is instance-wide).
303
+ 'v1.providers.cli.status': {
304
+ method: 'GET',
305
+ service: 'collector',
306
+ path: () => `/api/v1/providers/cli`,
307
+ tags: ['live-safe'],
308
+ },
309
+ 'v1.providers.cli.plan': {
310
+ method: 'GET',
311
+ service: 'collector',
312
+ path: ({ tool }) => `/api/v1/providers/cli/${encodeURIComponent(tool)}/plan`,
313
+ tags: ['live-safe'],
314
+ },
315
+ 'v1.providers.cli.install': {
316
+ method: 'POST',
317
+ service: 'collector',
318
+ path: ({ tool }) => `/api/v1/providers/cli/${encodeURIComponent(tool)}/install`,
319
+ tags: ['live-write'],
320
+ },
321
+ 'v1.providers.cli.job': {
322
+ method: 'GET',
323
+ service: 'collector',
324
+ path: ({ id }) => `/api/v1/providers/cli/jobs/${encodeURIComponent(id)}`,
325
+ tags: ['live-safe'],
326
+ },
293
327
  'v1.tools.execute': {
294
328
  method: 'POST',
295
329
  service: 'collector',
@@ -331,6 +365,19 @@ export const v1 = {
331
365
  path: ({ id }) => `/api/v1/approvals/grants/${encodeURIComponent(id)}/revoke`,
332
366
  tags: ['live-write'],
333
367
  },
368
+ // ApprovalsQ call-me policy (2026-11-03): human org admin only; flips the stale-approval phone watcher.
369
+ 'v1.approvals.call-me.get': {
370
+ method: 'GET',
371
+ service: 'collector',
372
+ path: () => `/api/v1/approvalsq/call-me`,
373
+ tags: ['live-safe'],
374
+ },
375
+ 'v1.approvals.call-me.put': {
376
+ method: 'PUT',
377
+ service: 'collector',
378
+ path: () => `/api/v1/approvalsq/call-me`,
379
+ tags: ['live-write'],
380
+ },
334
381
  'v1.tools.list': {
335
382
  method: 'GET',
336
383
  service: 'collector',
@@ -5,39 +5,52 @@
5
5
  * Tracker answers could not be checked against CLI truth. These verbs call the
6
6
  * SAME governed tool the Action Tracker UI and the agent use (POST
7
7
  * /api/v1/tools/execute, tool_name action_list), so chat, UI and CLI read one
8
- * source. Writes (add/move/update/delete) stay in chat and the UI for now.
8
+ * source. `add` and `done` write through the collector route the dashboard
9
+ * uses (POST/PATCH /api/v1/actions) as the logged-in user, via core/actionItems.js,
10
+ * the same core the Quox TUI /todo uses. Move/update/delete stay in chat and the UI.
9
11
  */
10
12
 
11
- import { formatOutput, formatDetail } from '../core/output.js';
13
+ import { formatOutput, formatDetail, printSuccess } from '../core/output.js';
12
14
  import { QuoxError } from '../core/errors.js';
15
+ import { confirmDestructive } from '../core/confirm.js';
13
16
  import { executeGovernedTool } from './tool.js';
17
+ import { addActionItem, completeActionItem, moveActionItem, deleteActionItem, STATUS_COLUMNS, PRIORITIES } from '../core/actionItems.js';
14
18
 
15
19
  const STATUSES = ['todo', 'doing', 'done', 'all'];
20
+ const MAX_PAGES = 50;
16
21
 
17
22
  async function listItems(ctx, { status = 'all', limit = 100, scope } = {}) {
18
23
  if (!STATUSES.includes(status)) {
19
24
  throw new QuoxError(`--status must be one of ${STATUSES.join(', ')}`);
20
25
  }
21
- const input = { status, limit: Math.min(Math.max(Number(limit) || 20, 1), 100) };
22
- if (scope) input.scope_id = scope;
23
- const data = await executeGovernedTool(ctx, 'action_list', input);
24
- const result = data && data.result !== undefined ? data.result : data;
25
- if (!result || result.success === false) {
26
- throw new QuoxError(`action_list failed: ${(result && (result.error || result.message)) || 'no result'}`);
26
+ const pageSize = Math.min(Math.max(Number(limit) || 20, 1), 100);
27
+ // Page through everything: a silent cap at one page hid 4 of 24 items (owner, 2026-10-20).
28
+ const all = [];
29
+ for (let page = 1; page <= MAX_PAGES; page++) {
30
+ const input = { status, limit: pageSize };
31
+ if (scope) input.scope_id = scope;
32
+ if (page > 1) input.page = page;
33
+ const data = await executeGovernedTool(ctx, 'action_list', input);
34
+ const result = data && data.result !== undefined ? data.result : data;
35
+ if (!result || result.success === false) {
36
+ throw new QuoxError(`action_list failed: ${(result && (result.error || result.message)) || 'no result'}`);
37
+ }
38
+ all.push(...(Array.isArray(result.items) ? result.items : []));
39
+ if (!result.hasMore) return all;
27
40
  }
28
- return Array.isArray(result.items) ? result.items : [];
41
+ throw new QuoxError(`More than ${MAX_PAGES * pageSize} items; narrow with --status or --scope.`);
29
42
  }
30
43
 
31
44
  export function registerActionsCommands(program, ctx) {
32
45
  const actions = program
33
46
  .command('actions')
34
- .description('Action Tracker items (read-only; add and move items in chat or the dashboard)');
47
+ .description('Action Tracker items: list, get, add, done, move, delete (edit in chat or the dashboard)');
35
48
 
36
49
  actions
37
50
  .command('list')
38
51
  .description('List action items')
39
52
  .option('--status <status>', 'todo, doing, done or all', 'all')
40
- .option('--limit <n>', 'max items (1-100)', '100')
53
+ .option('--limit <n>', 'page size (1-100); every page is listed', '100')
41
54
  .option('--scope <scopeId>', 'only items in this team/department/division scope')
42
55
  .action(async (options) => {
43
56
  const items = await listItems({ ...ctx, program }, options);
@@ -58,4 +71,61 @@ export function registerActionsCommands(program, ctx) {
58
71
  if (!item) throw new QuoxError(`No action item ${id} among the latest 100 items.`);
59
72
  formatDetail(item);
60
73
  });
74
+
75
+ actions
76
+ .command('add')
77
+ .description('Add an Action Tracker item (todo) as the logged-in user')
78
+ .argument('<text...>', 'what needs doing')
79
+ .option('--due <date>', 'YYYY-MM-DD, today or tomorrow')
80
+ .option('--priority <priority>', `one of ${PRIORITIES.join(', ')}`)
81
+ .option('--description <text>', 'longer notes')
82
+ .action(async (words, options) => {
83
+ ctx.auth.requireAuth();
84
+ const item = await addActionItem(ctx.client, { title: words, due: options.due, priority: options.priority, description: options.description });
85
+ if (program.opts().output === 'json') return formatDetail(item);
86
+ printSuccess(`Added action item ${item.id}: ${item.title}${item.due_date ? ` (due ${String(item.due_date).slice(0, 10)})` : ''}`);
87
+ return undefined;
88
+ });
89
+
90
+ actions
91
+ .command('done')
92
+ .description('Mark an Action Tracker item done')
93
+ .argument('<id>', 'action item id (from `quox actions list`)')
94
+ .action(async (id) => {
95
+ ctx.auth.requireAuth();
96
+ const item = await completeActionItem(ctx.client, id);
97
+ if (program.opts().output === 'json') return formatDetail(item);
98
+ printSuccess(`Marked done ${item.id}: ${item.title}`);
99
+ return undefined;
100
+ });
101
+
102
+ actions
103
+ .command('move')
104
+ .description('Move an Action Tracker item to todo, doing or done')
105
+ .argument('<id>', 'action item id (from `quox actions list`)')
106
+ .argument('<status>', STATUS_COLUMNS.join(', '))
107
+ .action(async (id, status) => {
108
+ ctx.auth.requireAuth();
109
+ const item = await moveActionItem(ctx.client, id, status);
110
+ if (program.opts().output === 'json') return formatDetail(item);
111
+ printSuccess(`Moved ${item.id} to ${item.status}: ${item.title}`);
112
+ return undefined;
113
+ });
114
+
115
+ actions
116
+ .command('delete')
117
+ .description('Delete one of your Action Tracker items (asks first; --yes skips, required without a terminal)')
118
+ .argument('<id>', 'action item id (from `quox actions list`)')
119
+ .option('-y, --yes', 'do not ask')
120
+ .action(async (id, options) => {
121
+ ctx.auth.requireAuth();
122
+ if (!(await confirmDestructive(program, { force: options.yes === true }, `Delete action item ${id}?`))) {
123
+ console.log('Not deleted.');
124
+ return undefined;
125
+ }
126
+ const r = await deleteActionItem(ctx.client, id);
127
+ if (program.opts().output === 'json') return formatDetail(r);
128
+ printSuccess(`Deleted ${r.id}${r.title ? `: ${r.title}` : ''}`);
129
+ return undefined;
130
+ });
61
131
  }
@@ -4,6 +4,9 @@
4
4
 
5
5
  import { formatOutput, formatDetail, printSuccess } from '../core/output.js';
6
6
  import { resolveEndpoint } from '../api/endpoints.js';
7
+ import { withStepUp } from '../core/stepUpPrompt.js';
8
+ import { announce, announceFailure } from '../core/announce.js';
9
+ import { resolveOrgId } from './helpers.js';
7
10
 
8
11
  export function registerAdminCommands(program, ctx) {
9
12
  const { client, auth } = ctx;
@@ -154,6 +157,38 @@ export function registerAdminCommands(program, ctx) {
154
157
  console.log(data.token);
155
158
  });
156
159
 
160
+ // ADMIN-VERIFY-EMAIL: accounts with no real mailbox (test/service accounts) can never click the
161
+ // emailed link, so they never see org invites. Instance-admin, human, step-up PIN (hidden prompt).
162
+ const users = admin
163
+ .command('users')
164
+ .description('Instance user administration');
165
+
166
+ users
167
+ .command('verify-email')
168
+ .description('Mark a user email verified (instance admin; asks for your step-up PIN; audited)')
169
+ .argument('<email>', 'the email address to mark verified')
170
+ .requiredOption('--reason <text>', 'why this address is verified without a mailbox (recorded in the audit log)')
171
+ .option('--user-id <id>', 'refuse unless the email belongs to this user id')
172
+ .action(async (email, opts) => {
173
+ auth.requireAuth();
174
+ const reason = String(opts.reason || '').trim();
175
+ if (!reason) throw new Error('--reason must not be empty');
176
+ const orgId = resolveOrgId(auth, program);
177
+ const ep = resolveEndpoint('admin.users.verify_email');
178
+ let data;
179
+ try {
180
+ data = await withStepUp(
181
+ (headers) => client.post(ep.path, { service: ep.service, headers, body: { email, reason, ...(opts.userId ? { user_id: opts.userId } : {}) } }),
182
+ { client, orgId, scope: 'override', io: ctx.stepUpIO, what: 'Verifying an email address' },
183
+ );
184
+ } catch (err) {
185
+ announceFailure('quox', `admin verify-email ${email}`, err);
186
+ throw err;
187
+ }
188
+ announce('quox', `admin verify-email ${email}`, { result: `verified · user ${data.user_id}` });
189
+ printSuccess(`Email ${data.email} is now verified. Reason recorded in the audit log.`);
190
+ });
191
+
157
192
  // Email / SMTP (QCPRO-SMTP): instance email onboarding parity
158
193
  const email = admin
159
194
  .command('email')