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,649 @@
1
+ /**
2
+ * Plugin commands: org-scoped plugin install registry (PD-1..PD-8)
3
+ *
4
+ * quox plugin list|get|install|update|uninstall|mine
5
+ * quox plugin enable <id> (PLUGIN-IMG #1012: prebuilt private image, licence first)
6
+ * quox plugin data list|get|set|delete
7
+ * quox plugin secrets list|set|reveal|delete
8
+ * quox plugin assign list|add|remove
9
+ * quox plugin trusted-keys list|add|remove
10
+ * quox plugin revocations list|add|remove
11
+ *
12
+ * Backend: services/auth/routes/plugins.js, mounted org-scoped at
13
+ * `/api/orgs/:orgId/...` (server.js). Install/update/uninstall and all
14
+ * secrets writes are admin-only per the PD stream's locked "admin-only
15
+ * install model" decision; read endpoints require org membership only.
16
+ */
17
+
18
+ import { registerPluginDoctor } from './plugin-doctor.js';
19
+ import { readFileSync } from 'node:fs';
20
+ import { formatOutput, formatDetail, printSuccess, printWarning, printInfo } from '../core/output.js';
21
+ import { resolveOrgId, parseJSON } from './helpers.js';
22
+ import { resolveEndpoint } from '../api/endpoints.js';
23
+ import { enablePlugin, entitlementFrom } from '../server/pluginEnable.js';
24
+ import { resolveInstall, readEnvKeys } from '../server/install.js';
25
+ import { createSys } from '../server/sys.js';
26
+
27
+ /** Read + JSON.parse a file, wrapping errors with the file path for context. */
28
+ function readJsonFile(filePath, label) {
29
+ let raw;
30
+ try {
31
+ raw = readFileSync(filePath, 'utf-8');
32
+ } catch (err) {
33
+ throw new Error(`Could not read ${label} file "${filePath}": ${err.message}`);
34
+ }
35
+ return parseJSON(raw, label);
36
+ }
37
+
38
+ /** Read a file and base64-encode its bytes (bundle_b64 / css_b64 shape). */
39
+ function readBase64File(filePath, label) {
40
+ try {
41
+ return readFileSync(filePath).toString('base64');
42
+ } catch (err) {
43
+ throw new Error(`Could not read ${label} file "${filePath}": ${err.message}`);
44
+ }
45
+ }
46
+
47
+ /** Best-effort JSON parse for a data value; falls back to the raw string. */
48
+ function coerceDataValue(raw) {
49
+ try {
50
+ return JSON.parse(raw);
51
+ } catch {
52
+ return raw;
53
+ }
54
+ }
55
+
56
+ async function confirmOrSkip(program, message) {
57
+ const { default: inquirer } = await import('inquirer');
58
+ const ans = await inquirer.prompt([{ type: 'confirm', name: 'confirm', message, default: false }]);
59
+ return ans.confirm;
60
+ }
61
+
62
+ export function registerPluginCommands(program, ctx) {
63
+ const { client, auth } = ctx;
64
+
65
+ const plugin = program
66
+ .command('plugin')
67
+ .description('Manage org-installed plugins');
68
+
69
+ registerPluginDoctor(plugin);
70
+
71
+ // ── plugin licence ──────────────────────────────────────────────────────────
72
+
73
+ plugin
74
+ .command('licence')
75
+ .alias('license')
76
+ .description('Show whether a plugin is licence governed and entitled for this org (band, org id, entitlement errors)')
77
+ .argument('<pluginId>', 'plugin id, e.g. notesq')
78
+ .action(async (pluginId) => {
79
+ auth.requireAuth();
80
+ const ep = resolveEndpoint('setup.licensing.entitlements.list');
81
+ const data = await client.get(ep.path, { service: ep.service });
82
+ const entitlements = Array.isArray(data.entitlements) ? data.entitlements : [];
83
+ const governed = (Array.isArray(data.governed) ? data.governed : []).includes(pluginId);
84
+ const match = entitlements.find((e) => e === pluginId || String(e).startsWith(`${pluginId}@`)) || null;
85
+ // `entitlements` is the resolved (band-stripped) list; the band string lives on the licence itself.
86
+ const licenceEnts = (Array.isArray(data.licenses) ? data.licenses : []).flatMap((l) => (Array.isArray(l.entitlements) ? l.entitlements : []));
87
+ const banded = licenceEnts.find((e) => String(e).startsWith(`${pluginId}@`)) || null;
88
+ const bandInfo = (data.org_bands && data.org_bands[pluginId]) || null;
89
+ // A plugin outside the governed set is never licence gated (same rule as the server).
90
+ const entitled = governed ? match !== null : true;
91
+ const summary = {
92
+ plugin: pluginId,
93
+ governed,
94
+ entitled,
95
+ band: banded || (match && match.includes('@') ? match : null),
96
+ seats_used: bandInfo && typeof bandInfo.assigned_count === 'number' ? bandInfo.assigned_count : null,
97
+ seats_allowed: bandInfo && typeof bandInfo.allowance === 'number' ? bandInfo.allowance : null,
98
+ seat_holders: bandInfo && Array.isArray(bandInfo.assigned_orgs) ? bandInfo.assigned_orgs : [],
99
+ org_id: data.org_id || null,
100
+ org_licensed: bandInfo ? bandInfo.org_licensed ?? null : null,
101
+ entitlement_errors: Array.isArray(data.entitlement_errors) ? data.entitlement_errors : [],
102
+ };
103
+ if (program.opts().output === 'json') {
104
+ console.log(JSON.stringify(summary, null, 2));
105
+ return;
106
+ }
107
+ formatDetail({
108
+ plugin: summary.plugin,
109
+ governed: summary.governed ? 'yes' : 'no',
110
+ entitled: summary.entitled ? 'yes' : 'no',
111
+ band: summary.band || '(none)',
112
+ org_seats: summary.seats_allowed === null ? '(no band)' : `${summary.seats_used} of ${summary.seats_allowed} used`,
113
+ org_id: summary.org_id || '(instance scoped)',
114
+ org_licensed: summary.org_licensed === null ? '(unknown)' : summary.org_licensed ? 'yes' : 'no',
115
+ entitlement_errors: summary.entitlement_errors.length
116
+ ? summary.entitlement_errors.map((e) => (typeof e === 'string' ? e : JSON.stringify(e))).join('; ')
117
+ : '(none)',
118
+ }, { title: `Licence: ${pluginId}` });
119
+ });
120
+
121
+ // ── plugin enable (PLUGIN-IMG #1012) ────────────────────────────────────────
122
+ // Starts a licensed plugin from its prebuilt private image on this
123
+ // self-hosted install. Licence first: unlicensed means nothing runs.
124
+
125
+ plugin
126
+ .command('enable')
127
+ .description('Start a licensed plugin from its prebuilt image on this self-hosted install (QuoxPlan for now). Unlicensed: refused, nothing pulled.')
128
+ .argument('<pluginId>', 'plugin id, e.g. quoxplan')
129
+ .option('--dir <path>', 'the install directory (default: the one Getting started recorded)')
130
+ .action(async (pluginId, opts) => {
131
+ auth.requireAuth();
132
+ const deps = ctx.serverDeps || {};
133
+ const env = deps.env || process.env;
134
+ const sys = deps.sys || createSys();
135
+ const checkEntitlement = async (id) => {
136
+ const ep = resolveEndpoint('setup.licensing.entitlements.list');
137
+ const data = await client.get(ep.path, { service: ep.service });
138
+ return entitlementFrom(data, id);
139
+ };
140
+ // Licence before anything that touches the box: an unlicensed enable must not even look for the install.
141
+ let ent;
142
+ try { ent = await checkEntitlement(pluginId); } catch (err) { ent = err; }
143
+ const resolveFirst = !(ent instanceof Error) && ent && ent.entitled;
144
+ let install = null;
145
+ if (resolveFirst) {
146
+ const i = await resolveInstall({ dir: opts.dir, env, sys, journey: deps.journey });
147
+ if (i.error) { const e = new Error(i.error); e.exitCode = 2; throw e; }
148
+ install = i;
149
+ }
150
+ const tag = install ? (env.QUOX_IMAGE_TAG || readEnvKeys(install.repoDir, ['QUOX_IMAGE_TAG']).QUOX_IMAGE_TAG || '') : '';
151
+ const result = await enablePlugin({
152
+ pluginId,
153
+ checkEntitlement: async () => { if (ent instanceof Error) throw ent; return ent; },
154
+ install: install || { repoDir: '' },
155
+ sys,
156
+ tag,
157
+ ...(deps.getPullCredential ? { getPullCredential: deps.getPullCredential } : {}),
158
+ ...(deps.sleep ? { sleep: deps.sleep } : {}),
159
+ log: (l) => printInfo(l),
160
+ });
161
+ if (program.opts().output === 'json') {
162
+ console.log(JSON.stringify({ plugin: pluginId, ok: result.ok, stage: result.stage, message: result.message }, null, 2));
163
+ } else if (result.ok) {
164
+ printSuccess(result.message);
165
+ } else {
166
+ printWarning(result.message);
167
+ }
168
+ if (!result.ok) process.exitCode = result.stage === 'licence' ? 3 : 1;
169
+ });
170
+
171
+ // ── plugin list ─────────────────────────────────────────────────────────────
172
+
173
+ plugin
174
+ .command('list')
175
+ .description('List installed plugins for the active org')
176
+ .action(async () => {
177
+ auth.requireAuth();
178
+ const orgId = resolveOrgId(auth, program);
179
+ const ep = resolveEndpoint('plugins.list', { orgId });
180
+ const data = await client.get(ep.path, { service: ep.service });
181
+ const plugins = data.plugins || data || [];
182
+ formatOutput({
183
+ columns: ['plugin_id', 'version', 'is_enabled', 'installed_by', 'installed_at', 'upgraded_at'],
184
+ headers: ['Plugin ID', 'Version', 'Enabled', 'Installed By', 'Installed', 'Upgraded'],
185
+ rows: plugins,
186
+ }, { format: program.opts().output, emptyMessage: 'No plugins installed.' });
187
+ });
188
+
189
+ // ── plugin get ──────────────────────────────────────────────────────────────
190
+
191
+ plugin
192
+ .command('get')
193
+ .description('Show plugin install details')
194
+ .argument('<pluginId>', 'plugin ID (slug) or install-record id')
195
+ .action(async (pluginId) => {
196
+ auth.requireAuth();
197
+ const orgId = resolveOrgId(auth, program);
198
+ const getFor = (id) => {
199
+ const ep = resolveEndpoint('plugins.get', { orgId, pluginId: id });
200
+ return client.get(ep.path, { service: ep.service });
201
+ };
202
+ let resolvedId = pluginId;
203
+ let data;
204
+ try {
205
+ data = await getFor(resolvedId);
206
+ } catch (err) {
207
+ // quox-plugin-sdk#2(B): `plugin list --json` emits the install-record
208
+ // ULID as `id`, but get resolves by plugin_id (slug) and 404s on the
209
+ // ULID — so `plugin list --json | jq .id | xargs quox plugin get` broke.
210
+ // On a 404, treat the arg as an install id and map it to its plugin_id
211
+ // via the list, so BOTH identifiers round-trip. Slugs stay the fast path.
212
+ if (err && err.status === 404) {
213
+ const listEp = resolveEndpoint('plugins.list', { orgId });
214
+ const listData = await client.get(listEp.path, { service: listEp.service });
215
+ const rows = listData.plugins || listData || [];
216
+ const match = rows.find(p => p.id === pluginId || p.install_id === pluginId);
217
+ if (match && match.plugin_id && match.plugin_id !== pluginId) {
218
+ resolvedId = match.plugin_id;
219
+ data = await getFor(resolvedId);
220
+ } else {
221
+ throw err;
222
+ }
223
+ } else {
224
+ throw err;
225
+ }
226
+ }
227
+ formatDetail(data.plugin || data, {
228
+ format: program.opts().output,
229
+ title: `Plugin: ${resolvedId}`,
230
+ fields: ['id', 'plugin_id', 'version', 'is_enabled', 'bundle_sha256', 'installed_by', 'installed_at', 'upgraded_at', 'manifest', 'signature'],
231
+ labels: {
232
+ id: 'Install ID', plugin_id: 'Plugin ID', version: 'Version', is_enabled: 'Enabled',
233
+ bundle_sha256: 'Bundle SHA256', installed_by: 'Installed By', installed_at: 'Installed',
234
+ upgraded_at: 'Upgraded', manifest: 'Manifest', signature: 'Signature',
235
+ },
236
+ });
237
+ });
238
+
239
+ // ── plugin install ──────────────────────────────────────────────────────────
240
+
241
+ plugin
242
+ .command('install')
243
+ .description('Install a plugin (admin only)')
244
+ .requiredOption('--manifest <file>', 'path to a manifest JSON file (must include id, name, version)')
245
+ .requiredOption('--bundle <file>', 'path to the plugin bundle JS file')
246
+ .option('--css <file>', 'path to a CSS file for the plugin')
247
+ .option('--signature <file>', 'path to a signature JSON file (required if the org has trusted keys)')
248
+ .action(async (options) => {
249
+ auth.requireAuth();
250
+ const orgId = resolveOrgId(auth, program);
251
+
252
+ const manifest = readJsonFile(options.manifest, '--manifest');
253
+ const body = { manifest, bundle_b64: readBase64File(options.bundle, '--bundle') };
254
+ if (options.css) body.css_b64 = readBase64File(options.css, '--css');
255
+ if (options.signature) body.signature = readJsonFile(options.signature, '--signature');
256
+
257
+ const ep = resolveEndpoint('plugins.install', { orgId });
258
+ const data = await client.post(ep.path, { service: ep.service, body });
259
+ printSuccess(`Plugin "${manifest.id}" installed.`);
260
+ formatDetail(data.plugin || data, { format: program.opts().output });
261
+ });
262
+
263
+ // ── plugin update ───────────────────────────────────────────────────────────
264
+
265
+ plugin
266
+ .command('update')
267
+ .description('Upgrade a plugin bundle and/or toggle its enabled state (admin only)')
268
+ .argument('<pluginId>', 'plugin ID')
269
+ .option('--enable', 'enable the plugin')
270
+ .option('--disable', 'disable the plugin')
271
+ .option('--manifest <file>', 'path to a new manifest JSON file (required together with --bundle)')
272
+ .option('--bundle <file>', 'path to a new bundle JS file (required together with --manifest)')
273
+ .option('--css <file>', 'path to a new CSS file')
274
+ .option('--signature <file>', 'path to a new signature JSON file')
275
+ .action(async (pluginId, options) => {
276
+ auth.requireAuth();
277
+ const orgId = resolveOrgId(auth, program);
278
+
279
+ if (options.enable && options.disable) {
280
+ throw new Error('Specify only one of --enable or --disable.');
281
+ }
282
+
283
+ const body = {};
284
+ if (options.enable) body.is_enabled = true;
285
+ if (options.disable) body.is_enabled = false;
286
+
287
+ if (options.manifest || options.bundle) {
288
+ if (!options.manifest || !options.bundle) {
289
+ throw new Error('--manifest and --bundle must be provided together for an upgrade.');
290
+ }
291
+ body.manifest = readJsonFile(options.manifest, '--manifest');
292
+ body.bundle_b64 = readBase64File(options.bundle, '--bundle');
293
+ if (options.css) body.css_b64 = readBase64File(options.css, '--css');
294
+ if (options.signature) body.signature = readJsonFile(options.signature, '--signature');
295
+ }
296
+
297
+ if (Object.keys(body).length === 0) {
298
+ throw new Error('Specify --enable, --disable, or --manifest/--bundle to upgrade.');
299
+ }
300
+
301
+ const ep = resolveEndpoint('plugins.update', { orgId, pluginId });
302
+ const data = await client.patch(ep.path, { service: ep.service, body });
303
+ printSuccess('Plugin updated.');
304
+ formatDetail(data.plugin || data, { format: program.opts().output });
305
+ });
306
+
307
+ // ── plugin uninstall ────────────────────────────────────────────────────────
308
+
309
+ plugin
310
+ .command('uninstall')
311
+ .description('Uninstall a plugin (admin only)')
312
+ .argument('<pluginId>', 'plugin ID')
313
+ .option('--force', 'skip confirmation')
314
+ .action(async (pluginId, options) => {
315
+ auth.requireAuth();
316
+ const orgId = resolveOrgId(auth, program);
317
+
318
+ if (!options.force && !program.opts().yes) {
319
+ const ok = await confirmOrSkip(program, `Uninstall plugin ${pluginId}? This cannot be undone.`);
320
+ if (!ok) { printInfo('Cancelled.'); return; }
321
+ }
322
+
323
+ const ep = resolveEndpoint('plugins.uninstall', { orgId, pluginId });
324
+ await client.delete(ep.path, { service: ep.service });
325
+ printSuccess('Plugin uninstalled.');
326
+ });
327
+
328
+ // ── plugin mine ─────────────────────────────────────────────────────────────
329
+
330
+ plugin
331
+ .command('mine')
332
+ .description('List plugins visible to the current user (respects assignments)')
333
+ .action(async () => {
334
+ auth.requireAuth();
335
+ const orgId = resolveOrgId(auth, program);
336
+ const ep = resolveEndpoint('plugins.mine.list', { orgId });
337
+ const data = await client.get(ep.path, { service: ep.service });
338
+ const plugins = data.plugins || data || [];
339
+ formatOutput({
340
+ columns: ['plugin_id', 'version', 'is_enabled', 'installed_at'],
341
+ headers: ['Plugin ID', 'Version', 'Enabled', 'Installed'],
342
+ rows: plugins,
343
+ }, { format: program.opts().output, emptyMessage: 'No plugins visible to you in this org.' });
344
+ });
345
+
346
+ // ── plugin data ─────────────────────────────────────────────────────────────
347
+
348
+ const data = plugin
349
+ .command('data')
350
+ .description('Manage plugin-scoped durable data (KV)');
351
+
352
+ data
353
+ .command('list')
354
+ .description('List data keys for a plugin')
355
+ .argument('<pluginId>', 'plugin ID')
356
+ .option('--scope <scope>', 'org|user', 'org')
357
+ .action(async (pluginId, options) => {
358
+ auth.requireAuth();
359
+ const orgId = resolveOrgId(auth, program);
360
+ const ep = resolveEndpoint('plugins.data.list', { orgId, pluginId });
361
+ const result = await client.get(ep.path, { service: ep.service, query: { scope: options.scope } });
362
+ const keys = result.keys || [];
363
+ if (keys.length === 0) {
364
+ printInfo('No data keys found.');
365
+ return;
366
+ }
367
+ formatOutput({ columns: ['key'], headers: ['Key'], rows: keys.map(key => ({ key })) }, { format: program.opts().output });
368
+ });
369
+
370
+ data
371
+ .command('get')
372
+ .description('Get a plugin data value')
373
+ .argument('<pluginId>', 'plugin ID')
374
+ .argument('<key>', 'data key')
375
+ .option('--scope <scope>', 'org|user', 'org')
376
+ .action(async (pluginId, key, options) => {
377
+ auth.requireAuth();
378
+ const orgId = resolveOrgId(auth, program);
379
+ const ep = resolveEndpoint('plugins.data.get', { orgId, pluginId, key });
380
+ const row = await client.get(ep.path, { service: ep.service, query: { scope: options.scope } });
381
+ formatDetail(row, { format: program.opts().output });
382
+ });
383
+
384
+ data
385
+ .command('set')
386
+ .description('Set a plugin data value')
387
+ .argument('<pluginId>', 'plugin ID')
388
+ .argument('<key>', 'data key')
389
+ .requiredOption('--value <value>', 'value to store (JSON is parsed automatically; otherwise stored as a string)')
390
+ .option('--scope <scope>', 'org|user', 'org')
391
+ .action(async (pluginId, key, options) => {
392
+ auth.requireAuth();
393
+ const orgId = resolveOrgId(auth, program);
394
+ const ep = resolveEndpoint('plugins.data.set', { orgId, pluginId, key });
395
+ const row = await client.put(ep.path, {
396
+ service: ep.service,
397
+ query: { scope: options.scope },
398
+ body: { value: coerceDataValue(options.value) },
399
+ });
400
+ printSuccess(`Data key "${key}" set.`);
401
+ formatDetail(row, { format: program.opts().output });
402
+ });
403
+
404
+ data
405
+ .command('delete')
406
+ .description('Delete a plugin data value')
407
+ .argument('<pluginId>', 'plugin ID')
408
+ .argument('<key>', 'data key')
409
+ .option('--scope <scope>', 'org|user', 'org')
410
+ .action(async (pluginId, key, options) => {
411
+ auth.requireAuth();
412
+ const orgId = resolveOrgId(auth, program);
413
+ const ep = resolveEndpoint('plugins.data.delete', { orgId, pluginId, key });
414
+ await client.delete(ep.path, { service: ep.service, query: { scope: options.scope } });
415
+ printSuccess('Data key deleted.');
416
+ });
417
+
418
+ // ── plugin secrets ──────────────────────────────────────────────────────────
419
+
420
+ const secrets = plugin
421
+ .command('secrets')
422
+ .description('Manage plugin-scoped encrypted secrets');
423
+
424
+ secrets
425
+ .command('list')
426
+ .description('List secret metadata for a plugin (no plaintext)')
427
+ .argument('<pluginId>', 'plugin ID')
428
+ .action(async (pluginId) => {
429
+ auth.requireAuth();
430
+ const orgId = resolveOrgId(auth, program);
431
+ const ep = resolveEndpoint('plugins.secrets.list', { orgId, pluginId });
432
+ const result = await client.get(ep.path, { service: ep.service });
433
+ const rows = result.secrets || result || [];
434
+ formatOutput({
435
+ columns: ['name', 'description', 'created_by', 'created_at', 'rotated_at'],
436
+ headers: ['Name', 'Description', 'Created By', 'Created', 'Rotated'],
437
+ rows,
438
+ }, { format: program.opts().output, emptyMessage: 'No secrets set for this plugin.' });
439
+ });
440
+
441
+ secrets
442
+ .command('set')
443
+ .description('Set (or rotate) a plugin secret (admin only)')
444
+ .argument('<pluginId>', 'plugin ID')
445
+ .argument('<name>', 'secret name')
446
+ .requiredOption('--value <text>', 'secret value')
447
+ .option('--description <text>', 'secret description')
448
+ .action(async (pluginId, name, options) => {
449
+ auth.requireAuth();
450
+ const orgId = resolveOrgId(auth, program);
451
+ const body = { value: options.value };
452
+ if (options.description) body.description = options.description;
453
+ const ep = resolveEndpoint('plugins.secrets.set', { orgId, pluginId, name });
454
+ const result = await client.put(ep.path, { service: ep.service, body });
455
+ printSuccess(`Secret "${name}" set.`);
456
+ formatDetail(result.secret || result, { format: program.opts().output });
457
+ });
458
+
459
+ secrets
460
+ .command('reveal')
461
+ .description('Reveal a plugin secret\'s plaintext value (audited)')
462
+ .argument('<pluginId>', 'plugin ID')
463
+ .argument('<name>', 'secret name')
464
+ .action(async (pluginId, name) => {
465
+ auth.requireAuth();
466
+ const orgId = resolveOrgId(auth, program);
467
+ printWarning('This reveals a plaintext secret and is recorded in the audit log.');
468
+ const ep = resolveEndpoint('plugins.secrets.reveal', { orgId, pluginId, name });
469
+ const result = await client.post(ep.path, { service: ep.service });
470
+ formatDetail(result, { format: program.opts().output });
471
+ });
472
+
473
+ secrets
474
+ .command('delete')
475
+ .description('Delete a plugin secret (admin only)')
476
+ .argument('<pluginId>', 'plugin ID')
477
+ .argument('<name>', 'secret name')
478
+ .action(async (pluginId, name) => {
479
+ auth.requireAuth();
480
+ const orgId = resolveOrgId(auth, program);
481
+ const ep = resolveEndpoint('plugins.secrets.delete', { orgId, pluginId, name });
482
+ await client.delete(ep.path, { service: ep.service });
483
+ printSuccess('Secret deleted.');
484
+ });
485
+
486
+ // ── plugin assign ───────────────────────────────────────────────────────────
487
+
488
+ const assign = plugin
489
+ .command('assign')
490
+ .description('Manage plugin visibility assignments (admin only)');
491
+
492
+ assign
493
+ .command('list')
494
+ .description('List assignments for a plugin')
495
+ .argument('<pluginId>', 'plugin ID')
496
+ .action(async (pluginId) => {
497
+ auth.requireAuth();
498
+ const orgId = resolveOrgId(auth, program);
499
+ const ep = resolveEndpoint('plugins.assignments.list', { orgId, pluginId });
500
+ const result = await client.get(ep.path, { service: ep.service });
501
+ const rows = result.assignments || result || [];
502
+ formatOutput({
503
+ columns: ['assignee_type', 'assignee_id', 'assigned_by', 'assigned_at'],
504
+ headers: ['Type', 'Assignee', 'Assigned By', 'Assigned'],
505
+ rows,
506
+ }, { format: program.opts().output, emptyMessage: 'No assignments set (plugin uses default visibility).' });
507
+ });
508
+
509
+ assign
510
+ .command('add')
511
+ .description('Assign a plugin to all org members, a user, or a team')
512
+ .argument('<pluginId>', 'plugin ID')
513
+ .requiredOption('--type <assigneeType>', 'all_org_members|user|team')
514
+ .option('--id <assigneeId>', 'assignee ID (user or team ID; omit for all_org_members)')
515
+ .action(async (pluginId, options) => {
516
+ auth.requireAuth();
517
+ const orgId = resolveOrgId(auth, program);
518
+ const body = { assignee_type: options.type };
519
+ if (options.id) body.assignee_id = options.id;
520
+ const ep = resolveEndpoint('plugins.assignments.create', { orgId, pluginId });
521
+ const result = await client.post(ep.path, { service: ep.service, body });
522
+ printSuccess('Assignment added.');
523
+ formatDetail(result.assignment || result, { format: program.opts().output });
524
+ });
525
+
526
+ assign
527
+ .command('remove')
528
+ .description('Remove a plugin assignment')
529
+ .argument('<pluginId>', 'plugin ID')
530
+ .argument('<assigneeType>', 'all_org_members|user|team')
531
+ .argument('[assigneeId]', 'assignee ID (omit for all_org_members)')
532
+ .action(async (pluginId, assigneeType, assigneeId) => {
533
+ auth.requireAuth();
534
+ const orgId = resolveOrgId(auth, program);
535
+ const ep = resolveEndpoint('plugins.assignments.delete', { orgId, pluginId, assigneeType, assigneeId });
536
+ await client.delete(ep.path, { service: ep.service });
537
+ printSuccess('Assignment removed.');
538
+ });
539
+
540
+ // ── plugin trusted-keys ─────────────────────────────────────────────────────
541
+
542
+ const trustedKeys = plugin
543
+ .command('trusted-keys')
544
+ .description('Manage per-org trusted Ed25519 signing keys (admin only)');
545
+
546
+ trustedKeys
547
+ .command('list')
548
+ .description('List trusted keys')
549
+ .action(async () => {
550
+ auth.requireAuth();
551
+ const orgId = resolveOrgId(auth, program);
552
+ const ep = resolveEndpoint('plugins.trusted-keys.list', { orgId });
553
+ const result = await client.get(ep.path, { service: ep.service });
554
+ const rows = result.trusted_keys || result || [];
555
+ formatOutput({
556
+ columns: ['id', 'label', 'public_key_hex', 'added_by', 'added_at'],
557
+ headers: ['ID', 'Label', 'Public Key', 'Added By', 'Added'],
558
+ rows,
559
+ }, { format: program.opts().output, emptyMessage: 'No trusted keys configured (unsigned installs are accepted).' });
560
+ });
561
+
562
+ trustedKeys
563
+ .command('add')
564
+ .description('Add a trusted signing key')
565
+ .requiredOption('--label <label>', 'key label')
566
+ .requiredOption('--public-key <hex>', 'Ed25519 public key, hex-encoded')
567
+ .action(async (options) => {
568
+ auth.requireAuth();
569
+ const orgId = resolveOrgId(auth, program);
570
+ const body = { label: options.label, public_key_hex: options.publicKey };
571
+ const ep = resolveEndpoint('plugins.trusted-keys.create', { orgId });
572
+ const result = await client.post(ep.path, { service: ep.service, body });
573
+ printSuccess('Trusted key added.');
574
+ formatDetail(result.trusted_key || result, { format: program.opts().output });
575
+ });
576
+
577
+ trustedKeys
578
+ .command('remove')
579
+ .description('Remove a trusted signing key')
580
+ .argument('<keyId>', 'trusted key ID')
581
+ .option('--confirm-unsigned', 'WARNING: required to remove the LAST trusted key; the org will then accept UNSIGNED plugin bundles')
582
+ .action(async (keyId, opts) => {
583
+ auth.requireAuth();
584
+ const orgId = resolveOrgId(auth, program);
585
+ const ep = resolveEndpoint('plugins.trusted-keys.delete', { orgId, keyId });
586
+ const reqOpts = { service: ep.service };
587
+ if (opts && opts.confirmUnsigned) {
588
+ console.error('WARNING: confirming downgrade. This org will accept UNSIGNED plugin bundles after this key is removed.');
589
+ reqOpts.query = { confirm_unsigned: '1' };
590
+ }
591
+ await client.delete(ep.path, reqOpts);
592
+ printSuccess('Trusted key removed.');
593
+ });
594
+
595
+ // ── plugin revocations (SDK-TEAM W5) ────────────────────────────────────────
596
+
597
+ const revocations = plugin
598
+ .command('revocations')
599
+ .description('Revoke a plugin signer key or one bundle digest for this org (admin only). A revoked plugin cannot be installed and stops loading on the next page load.');
600
+
601
+ revocations
602
+ .command('list')
603
+ .description('List revocations')
604
+ .action(async () => {
605
+ auth.requireAuth();
606
+ const orgId = resolveOrgId(auth, program);
607
+ const ep = resolveEndpoint('plugins.revocations.list', { orgId });
608
+ const result = await client.get(ep.path, { service: ep.service });
609
+ const rows = result.revocations || result || [];
610
+ formatOutput({
611
+ columns: ['id', 'kind', 'value', 'reason', 'revoked_by', 'revoked_at'],
612
+ headers: ['ID', 'Kind', 'Value', 'Reason', 'Revoked By', 'Revoked'],
613
+ rows,
614
+ }, { format: program.opts().output, emptyMessage: 'No revocations.' });
615
+ });
616
+
617
+ revocations
618
+ .command('add')
619
+ .description('Revoke a signer key or a bundle digest')
620
+ .option('--signer-key <hex>', 'raw Ed25519 public key (64 hex), as in signature.json public_key_hex')
621
+ .option('--bundle-digest <hex>', 'sha256 of plugin.esm.js (64 hex), as shown by quox plugin list')
622
+ .option('--reason <text>', 'why (kept in the audit trail)')
623
+ .action(async (options) => {
624
+ auth.requireAuth();
625
+ if (!!options.signerKey === !!options.bundleDigest) {
626
+ throw new Error('Specify exactly one of --signer-key or --bundle-digest.');
627
+ }
628
+ const orgId = resolveOrgId(auth, program);
629
+ const body = options.signerKey
630
+ ? { kind: 'signer_key', value: options.signerKey, reason: options.reason }
631
+ : { kind: 'bundle_digest', value: options.bundleDigest, reason: options.reason };
632
+ const ep = resolveEndpoint('plugins.revocations.create', { orgId });
633
+ const result = await client.post(ep.path, { service: ep.service, body });
634
+ printSuccess('Revoked.');
635
+ formatDetail(result.revocation || result, { format: program.opts().output });
636
+ });
637
+
638
+ revocations
639
+ .command('remove')
640
+ .description('Lift a revocation')
641
+ .argument('<revocationId>', 'revocation ID')
642
+ .action(async (revocationId) => {
643
+ auth.requireAuth();
644
+ const orgId = resolveOrgId(auth, program);
645
+ const ep = resolveEndpoint('plugins.revocations.delete', { orgId, revocationId });
646
+ await client.delete(ep.path, { service: ep.service });
647
+ printSuccess('Revocation lifted.');
648
+ });
649
+ }