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,687 @@
1
+ /**
2
+ * Skills commands.
3
+ *
4
+ * `list`/`show` are read-only queries against the quoxflow QSKL
5
+ * (procedural-knowledge Skills / Crystals) library, via the collector's
6
+ * quoxflow proxy — see the comment above each subcommand for the exact
7
+ * route it calls.
8
+ *
9
+ * `run`, `review`, `library`, and the Crystal-lifecycle writes
10
+ * (`from-execution`/`promote-draft`/`rollback-to-version`) added in WP2.3
11
+ * go DIRECT to quoxflow (service: 'quoxflow', port 3200) — the collector
12
+ * does NOT proxy these routes (only the three read-only proxy paths used
13
+ * by `list`/`show` plus evidence/observations are hand-mounted; see
14
+ * cli/lib/api/endpoints/skills.js header for the full route provenance).
15
+ * `library` is the one exception: it's the auth service's per-user saved
16
+ * workflow library (services/auth/routes/user-library.js), not quoxflow.
17
+ *
18
+ * NOTE (deviations from the upstream field names, see quoxflow
19
+ * src/store/quox-skills-store.ts):
20
+ * - The real status field on a skill is `edition`, with values
21
+ * experimental | stable | deprecated | archived (there is no
22
+ * "canonical" value). `--edition` filters on this field directly.
23
+ * - There is no server-side full-text `search` query param on
24
+ * GET /api/quox-skills. `--search` is applied client-side (substring
25
+ * match against name + description) after fetching the (filtered)
26
+ * list from the proxy.
27
+ */
28
+
29
+ import { existsSync, readFileSync, statSync } from 'node:fs';
30
+ import path from 'node:path';
31
+ import { formatOutput, formatDetail, printSuccess, printWarning, printInfo } from '../core/output.js';
32
+ import { resolveOrgId, parseJSON } from './helpers.js';
33
+ import { resolveEndpoint } from '../api/endpoints.js';
34
+ import { shortLicenceLabel } from './skillRightsFormat.js';
35
+ import { loadOrBuildManifest, readSkillFrontmatter } from './skillManifest.js';
36
+
37
+ export function registerSkillsCommands(program, ctx) {
38
+ const { client, auth } = ctx;
39
+
40
+ const skills = program
41
+ .command('skills')
42
+ .description('Manage the quoxflow skill library (QSKL Crystals): query, run, review, promote, and your saved library');
43
+
44
+ // ── skills list ──────────────────────────────────────────────────────────
45
+ // GET /quoxflow/skills — collector proxy to quoxflow GET /api/quox-skills
46
+
47
+ skills
48
+ .command('list')
49
+ .description('List skills in the library')
50
+ .option('--edition <edition>', 'filter by edition (experimental|stable|deprecated|archived)')
51
+ .option('--category <category>', 'filter by category')
52
+ .option('--agent <agentId>', 'filter to skills best-suited for an agent')
53
+ .option('--tag <tag>', 'filter by tag')
54
+ .option('--search <q>', 'client-side filter: substring match on name/description')
55
+ .option('--limit <n>', 'max results')
56
+ .option('--order-by <field>', 'sort field (last_used_at|created_at)')
57
+ .option('--order <dir>', 'sort direction (asc|desc)')
58
+ .option('--org <id>', 'org ID (overrides active org)')
59
+ .action(async (options) => {
60
+ auth.requireAuth();
61
+ const query = {};
62
+ query.orgId = options.org || resolveOrgId(auth, program);
63
+ if (options.edition) query.edition = options.edition;
64
+ if (options.category) query.category = options.category;
65
+ if (options.agent) query.agentId = options.agent;
66
+ if (options.tag) query.tag = options.tag;
67
+ if (options.limit) query.limit = options.limit;
68
+ if (options.orderBy) query.orderBy = options.orderBy;
69
+ if (options.order) query.order = options.order;
70
+
71
+ const data = await client.get(resolveEndpoint('quoxflow.skills.list').path, { service: resolveEndpoint('quoxflow.skills.list').service, query });
72
+ let rows = data.data || data.records || data;
73
+ if (!Array.isArray(rows)) rows = [];
74
+ rows = rows.map((r) => ({ ...r, store: 'library' }));
75
+
76
+ // 4.2.4 skills/t3-skill-view: a library skill with an active quox#748 review row (pending or rejected) cannot
77
+ // run, and skill_view refuses it. Say so per skill. A queue read failure leaves runnable unknown, never true.
78
+ try {
79
+ const rq = resolveEndpoint('skills.reviewQueue.list');
80
+ const active = new Map();
81
+ for (const status of ['pending', 'rejected']) {
82
+ const r = await client.get(rq.path, { service: rq.service, query: { status, orgId: query.orgId } });
83
+ const items = r && (r.data || r.records);
84
+ for (const it of Array.isArray(items) ? items : []) if (it && it.skill_id) active.set(it.skill_id, it.status || status);
85
+ }
86
+ rows = rows.map((r) => ({ ...r, review_status: active.get(r.id) || null, runnable: !active.has(r.id) }));
87
+ } catch (err) {
88
+ printWarning(`Skill review queue could not be read, so which skills can run is unknown: ${err.message}`);
89
+ }
90
+
91
+ // #1006: crystals (`skills from-execution`) live in quoxflow's crystal store, not this library. Merge them
92
+ // unless a library-only filter is set (crystals have no edition/category/agent fit). A failure there warns,
93
+ // it never sinks the library listing.
94
+ if (!options.edition && !options.category && !options.agent) {
95
+ try {
96
+ const ep = resolveEndpoint('skills.crystals.list');
97
+ const c = await client.get(ep.path, { service: ep.service, query: { orgId: query.orgId } });
98
+ let crystals = c.data || c.skills || c;
99
+ if (!Array.isArray(crystals)) crystals = [];
100
+ if (options.tag) crystals = crystals.filter((r) => Array.isArray(r.tags) && r.tags.includes(options.tag));
101
+ rows = rows.concat(crystals.map((r) => ({ ...r, store: 'crystal' })));
102
+ } catch (err) {
103
+ printWarning(`Crystal store (skills from-execution) could not be read, showing the library only: ${err.message}`);
104
+ }
105
+ }
106
+
107
+ if (options.search) {
108
+ const needle = options.search.toLowerCase();
109
+ rows = rows.filter((r) =>
110
+ (r.name || '').toLowerCase().includes(needle) ||
111
+ (r.description || '').toLowerCase().includes(needle)
112
+ );
113
+ }
114
+
115
+ // SKILLRIGHTS-8: declarations travel with the skill; a missing one is
116
+ // shown as undeclared, never defaulted to a licence.
117
+ rows = rows.map((r) => ({ ...r, licence: shortLicenceLabel(r.license) }));
118
+ formatOutput({
119
+ columns: ['id', 'store', 'name', 'category', 'edition', 'version', 'licence', 'decayState', 'createdAt'],
120
+ headers: ['ID', 'Store', 'Name', 'Category', 'Edition', 'Version', 'Licence', 'Decay', 'Created'],
121
+ rows,
122
+ }, { format: program.opts().output, emptyMessage: 'No skills found.' });
123
+ });
124
+
125
+ // ── skills show ──────────────────────────────────────────────────────────
126
+ // GET /quoxflow/skills/:id — collector proxy to quoxflow GET /api/quox-skills/:id
127
+
128
+ skills
129
+ .command('show')
130
+ .description('Show skill details')
131
+ .argument('<id>', 'skill ID')
132
+ .option('--org <id>', 'org ID (overrides active org)')
133
+ .action(async (id, options) => {
134
+ auth.requireAuth();
135
+ const query = { orgId: options.org || resolveOrgId(auth, program) };
136
+ let data, store = 'library';
137
+ try {
138
+ data = await client.get(resolveEndpoint('quoxflow.skills.get', { id }).path, { service: resolveEndpoint('quoxflow.skills.get', { id }).service, query });
139
+ } catch (err) {
140
+ if (err.status !== 404) throw err;
141
+ // #1006: not in the library; a crystal from `skills from-execution` lives in the crystal store
142
+ const ep = resolveEndpoint('skills.crystals.get', { id });
143
+ try { data = await client.get(ep.path, { service: ep.service, query }); } catch (err2) { if (err2.status === 404) throw err; throw err2; }
144
+ store = 'crystal';
145
+ }
146
+ formatDetail({ ...(data.data || data), store }, { format: program.opts().output, title: `Skill: ${id}` });
147
+ });
148
+
149
+ // ── skills run ───────────────────────────────────────────────────────────
150
+ // POST /api/workflows/:id/execute — quoxflow DIRECT (executions.ts:206).
151
+ // Crystals ARE workflows: this runs a skill/crystal by its (source)
152
+ // workflow id. Sync by default (waits for the result); --async fires and
153
+ // returns immediately with an executionId.
154
+
155
+ skills
156
+ .command('run')
157
+ .description('Execute a skill/crystal (its underlying workflow)')
158
+ .argument('<id>', 'workflow ID (the skill\'s sourceWorkflowId)')
159
+ .option('--data <json>', 'trigger data, as a JSON object string')
160
+ .option('--async', 'fire-and-forget: return immediately with an executionId instead of waiting for the result')
161
+ .option('--org <id>', 'org ID (overrides active org)')
162
+ .action(async (id, options) => {
163
+ auth.requireAuth();
164
+ const orgId = options.org || resolveOrgId(auth, program);
165
+ const body = { orgId };
166
+ if (options.data) body.triggerData = parseJSON(options.data, 'trigger data');
167
+ if (options.async) body.async = true;
168
+
169
+ const ep = resolveEndpoint('skills.run', { id });
170
+ const data = await client.post(ep.path, { service: ep.service, body });
171
+ const result = data.data || data;
172
+
173
+ if (options.async) {
174
+ printSuccess(`Execution started (${result.executionId}).`);
175
+ } else if (result.success === false) {
176
+ printWarning('Execution finished with errors.');
177
+ } else {
178
+ printSuccess('Execution complete.');
179
+ }
180
+ formatDetail(result, { format: program.opts().output });
181
+ });
182
+
183
+ // ── skills review ────────────────────────────────────────────────────────
184
+ // QSKL-SAFETY.F review queue — quox-skills.ts:392-553, quoxflow DIRECT.
185
+ // Org-scoped server-side (JWT-primary orgId, 403 on cross-org row access).
186
+
187
+ const review = skills
188
+ .command('review')
189
+ .description('Manage the QSKL-SAFETY skill review queue');
190
+
191
+ review
192
+ .command('list')
193
+ .description('List review queue items (default: pending)')
194
+ .option('--status <status>', 'pending|approved|rejected', 'pending')
195
+ .action(async (options) => {
196
+ auth.requireAuth();
197
+ const orgId = resolveOrgId(auth, program);
198
+ const ep = resolveEndpoint('skills.reviewQueue.list');
199
+ const data = await client.get(ep.path, {
200
+ service: ep.service,
201
+ query: { status: options.status, orgId },
202
+ });
203
+ const rows = data.data || data.records || [];
204
+
205
+ formatOutput({
206
+ // fleet #392: review queue rows carry queued_at.
207
+ columns: ['id', 'skill_id', 'skill_name', 'status', 'reviewer_id', 'queued_at'],
208
+ headers: ['ID', 'Skill ID', 'Skill Name', 'Status', 'Reviewer', 'Created'],
209
+ rows: Array.isArray(rows) ? rows : [],
210
+ }, { format: program.opts().output, emptyMessage: `No ${options.status} review queue items.` });
211
+ });
212
+
213
+ review
214
+ .command('show')
215
+ .description('Show a review queue item (with skill snapshot + latest firewall log)')
216
+ .argument('<qid>', 'review queue item ID')
217
+ .action(async (qid) => {
218
+ auth.requireAuth();
219
+ const ep = resolveEndpoint('skills.reviewQueue.get', { qid });
220
+ const data = await client.get(ep.path, { service: ep.service });
221
+ formatDetail(data.data || data, { format: program.opts().output, title: `Review Queue Item: ${qid}` });
222
+ });
223
+
224
+ review
225
+ .command('approve')
226
+ .description('Approve a review queue item')
227
+ .argument('<qid>', 'review queue item ID')
228
+ .option('--comment <text>', 'optional reviewer comment')
229
+ .action(async (qid, options) => {
230
+ auth.requireAuth();
231
+ const body = {};
232
+ if (options.comment) body.comment = options.comment;
233
+ const ep = resolveEndpoint('skills.reviewQueue.approve', { qid });
234
+ const data = await client.post(ep.path, { service: ep.service, body });
235
+ printSuccess(`Review queue item ${qid} approved.`);
236
+ formatDetail(data.data || data, { format: program.opts().output });
237
+ });
238
+
239
+ review
240
+ .command('reject')
241
+ .description('Reject a review queue item')
242
+ .argument('<qid>', 'review queue item ID')
243
+ .option('--comment <text>', 'optional reviewer comment')
244
+ .action(async (qid, options) => {
245
+ auth.requireAuth();
246
+ const body = {};
247
+ if (options.comment) body.comment = options.comment;
248
+ const ep = resolveEndpoint('skills.reviewQueue.reject', { qid });
249
+ const data = await client.post(ep.path, { service: ep.service, body });
250
+ printSuccess(`Review queue item ${qid} rejected.`);
251
+ formatDetail(data.data || data, { format: program.opts().output });
252
+ });
253
+
254
+ // ── skills library ───────────────────────────────────────────────────────
255
+ // Per-org/per-user saved workflow library — auth service (NOT quoxflow),
256
+ // services/auth/routes/user-library.js. Always scoped to the caller
257
+ // (org_id + user_id); another user in the same org cannot see/delete
258
+ // these entries.
259
+
260
+ const library = skills
261
+ .command('library')
262
+ .description('Manage your saved workflow library');
263
+
264
+ library
265
+ .command('list')
266
+ .description('List your saved library entries')
267
+ .option('--source <source>', 'filter by source: curated|n8n-imported|mine')
268
+ .action(async (options) => {
269
+ auth.requireAuth();
270
+ const orgId = resolveOrgId(auth, program);
271
+ const query = {};
272
+ if (options.source) query.source = options.source;
273
+ const ep = resolveEndpoint('user-library.list', { orgId });
274
+ const data = await client.get(ep.path, { service: ep.service, query });
275
+ const entries = data.entries || data || [];
276
+
277
+ formatOutput({
278
+ columns: ['id', 'name', 'source', 'source_workflow_id', 'updated_at'],
279
+ headers: ['ID', 'Name', 'Source', 'Source Workflow', 'Updated'],
280
+ rows: Array.isArray(entries) ? entries : [],
281
+ }, { format: program.opts().output, emptyMessage: 'No saved library entries.' });
282
+ });
283
+
284
+ library
285
+ .command('add')
286
+ .description('Save a workflow definition to your library')
287
+ .requiredOption('--name <name>', 'entry name')
288
+ .option('--definition <json>', 'workflow definition, as a JSON object string')
289
+ .option('--file <path>', 'read the workflow definition from a JSON file (overrides --definition)')
290
+ .option('--description <text>', 'description')
291
+ .option('--source <source>', 'curated|n8n-imported|mine', 'mine')
292
+ .option('--source-workflow-id <id>', 'originating workflow ID')
293
+ .option('--tags <tags>', 'comma-separated tags')
294
+ .action(async (options) => {
295
+ auth.requireAuth();
296
+ const orgId = resolveOrgId(auth, program);
297
+
298
+ let definitionJson;
299
+ if (options.file) {
300
+ definitionJson = parseJSON(readFileSync(options.file, 'utf-8'), 'workflow definition file');
301
+ } else if (options.definition) {
302
+ definitionJson = parseJSON(options.definition, 'workflow definition');
303
+ } else {
304
+ throw new Error('Workflow definition is required. Use --definition <json> or --file <path>.');
305
+ }
306
+
307
+ const body = { name: options.name, definition_json: definitionJson, source: options.source };
308
+ if (options.description) body.description = options.description;
309
+ if (options.sourceWorkflowId) body.source_workflow_id = options.sourceWorkflowId;
310
+ if (options.tags) body.tags = options.tags.split(',').map(t => t.trim()).filter(Boolean);
311
+
312
+ const ep = resolveEndpoint('user-library.create', { orgId });
313
+ const data = await client.post(ep.path, { service: ep.service, body });
314
+ printSuccess(`Library entry "${options.name}" saved.`);
315
+ formatDetail(data.entry || data, { format: program.opts().output });
316
+ });
317
+
318
+ library
319
+ .command('remove')
320
+ .description('Remove a saved library entry')
321
+ .argument('<id>', 'library entry ID')
322
+ .option('--force', 'skip confirmation')
323
+ .action(async (id, options) => {
324
+ auth.requireAuth();
325
+ const orgId = resolveOrgId(auth, program);
326
+
327
+ if (!options.force && !program.opts().yes) {
328
+ const { default: inquirer } = await import('inquirer');
329
+ const ans = await inquirer.prompt([{
330
+ type: 'confirm',
331
+ name: 'confirm',
332
+ message: `Remove library entry ${id}? This cannot be undone.`,
333
+ default: false,
334
+ }]);
335
+ if (!ans.confirm) {
336
+ printInfo('Cancelled.');
337
+ return;
338
+ }
339
+ }
340
+
341
+ const ep = resolveEndpoint('user-library.delete', { orgId, id });
342
+ await client.delete(ep.path, { service: ep.service });
343
+ printSuccess('Library entry removed.');
344
+ });
345
+
346
+ // ── skills from-execution / promote-draft / rollback-to-version ────────
347
+ // Crystal Skill Library lifecycle writes — quoxflow DIRECT
348
+ // (skills.ts, mounted at /api/skills, distinct from the QSKL
349
+ // /api/quox-skills store used by `skills list`/`show`).
350
+
351
+ skills
352
+ .command('from-execution')
353
+ .description('Crystallise a workflow into a skill (idempotent — returns the existing skill if one already exists)')
354
+ .argument('<workflowId>', 'workflow ID to crystallise')
355
+ .option('--name <name>', 'workflow display name (used for the generated skill name)')
356
+ .action(async (workflowId, options) => {
357
+ auth.requireAuth();
358
+ const orgId = resolveOrgId(auth, program);
359
+ const body = { workflowId };
360
+ if (options.name) body.workflowName = options.name;
361
+
362
+ const ep = resolveEndpoint('skills.fromExecution');
363
+ const data = await client.post(ep.path, { service: ep.service, body, query: { orgId } });
364
+ const record = data.data || data;
365
+ printSuccess(`Skill "${record.name || workflowId}" crystallised.`);
366
+ formatDetail(record, { format: program.opts().output });
367
+ });
368
+
369
+ skills
370
+ .command('promote-draft')
371
+ .description('Promote an in-flight task-time draft Crystal to the skill library (requires tier_b)')
372
+ .argument('<executionId>', 'execution ID with an in-flight draft')
373
+ .option('--tier <tier>', 'org tier: tier_a|tier_b (tier_b required to promote)', 'tier_a')
374
+ .action(async (executionId, options) => {
375
+ auth.requireAuth();
376
+ const body = { executionId, orgTier: options.tier };
377
+
378
+ const ep = resolveEndpoint('skills.promoteDraft');
379
+ const data = await client.post(ep.path, { service: ep.service, body });
380
+ const record = data.data || data;
381
+ printSuccess(`Draft for execution ${executionId} promoted.`);
382
+ formatDetail(record, { format: program.opts().output });
383
+ });
384
+
385
+ skills
386
+ .command('rollback-to-version')
387
+ .description('Roll a skill back to a prior version (writes a NEW version copying the target\'s content)')
388
+ .argument('<sourceWorkflowId>', 'source workflow ID')
389
+ .argument('<targetVersion>', 'version number to roll back to', (v) => parseInt(v, 10))
390
+ .action(async (sourceWorkflowId, targetVersion) => {
391
+ auth.requireAuth();
392
+ const orgId = resolveOrgId(auth, program);
393
+ const body = { sourceWorkflowId, targetVersion };
394
+
395
+ const ep = resolveEndpoint('skills.rollbackToVersion');
396
+ const data = await client.post(ep.path, { service: ep.service, body, query: { orgId } });
397
+ const record = data.data || data;
398
+ // #1006: rolling back to the version that is already current is a server-side no-op (it returns that row)
399
+ if (record && Number(record.version) === targetVersion) printInfo(`Already at version ${targetVersion}: nothing was written.`);
400
+ else printSuccess(`Skill rolled back to version ${targetVersion} (written as version ${record?.version ?? '?'}).`);
401
+ formatDetail(record, { format: program.opts().output });
402
+ });
403
+
404
+ // ── skills protect ───────────────────────────────────────────────────────
405
+ // SKILLRIGHTS #478 Phase 10. POST /api/v1/skills/protect (collector).
406
+ //
407
+ // Hashes the skill LOCALLY (or reuses the manifest the open `skillrights`
408
+ // CLI already wrote) and sends only that manifest. The collector has the
409
+ // org sign a domain-separated digest, registers the hash in the open
410
+ // SkillRights registry, verifies the receipt, and witnesses the whole
411
+ // thing into the org's evidence chain.
412
+ //
413
+ // What it proves: this exact artefact existed by this time, and this org's
414
+ // key claimed and signed it. NOT legal ownership.
415
+ skills
416
+ .command('protect')
417
+ .description('Sign a skill with the org identity, register it in the open SkillRights registry, and keep the receipt in the org evidence chain')
418
+ .argument('[dir]', 'skill directory', '.')
419
+ .option('--public', 'list the skill publicly (sends name/description to the registry directory)')
420
+ .option('--supersedes <sha256>', 'claimed earlier version this replaces')
421
+ .option('--repository <url>', 'repository URL (public mode only)')
422
+ .action(async (dir, options) => {
423
+ auth.requireAuth();
424
+ const resolvedDir = path.resolve(dir);
425
+ const { manifest, source } = loadOrBuildManifest(resolvedDir);
426
+ const front = readSkillFrontmatter(resolvedDir);
427
+
428
+ const body = { manifest, mode: options.public ? 'public' : 'private' };
429
+ if (options.supersedes) body.supersedes = options.supersedes;
430
+ if (options.public) {
431
+ const meta = {};
432
+ if (front.name) meta.name = front.name;
433
+ if (front.description) meta.description = front.description;
434
+ if (options.repository) meta.repository = options.repository;
435
+ if (Object.keys(meta).length) body.meta = meta;
436
+ }
437
+
438
+ if (!manifest.identifier) {
439
+ printWarning('This skill declares no SkillRights licence (no `license:` in SKILL.md frontmatter). Protecting it anyway; the registration will record no licence.');
440
+ }
441
+ printInfo(`Manifest ${source === 'existing' ? 'read from' : 'computed for'} ${resolvedDir} (${Object.keys(manifest.files).length} files). File contents never leave this machine; the manifest sent carries relative file names and per-file hashes.`);
442
+
443
+ const ep = resolveEndpoint('skills.protect');
444
+ const data = await client.post(ep.path, { service: ep.service, body });
445
+ const p = data.protection || data;
446
+ if (data.created === false) {
447
+ printInfo(`Already protected (identical content): ${p.srid}`);
448
+ } else {
449
+ printSuccess(`Protected. SRID ${p.srid}`);
450
+ }
451
+ printInfo('Proves the artefact existed by the registered time and that your org key claimed and signed it. It does not prove legal ownership.');
452
+ formatDetail({
453
+ srid: p.srid,
454
+ manifest_sha256: p.manifestSha256,
455
+ licence: p.license || '(none declared)',
456
+ mode: p.mode,
457
+ org_key_id: p.orgKeyId,
458
+ registry: p.registryUrl,
459
+ evidence_envelope: p.aeeEnvelopeId || '(not recorded)',
460
+ registered_at: p.receipt?.receipt?.record?.ts,
461
+ }, { format: program.opts().output });
462
+ });
463
+
464
+ // ── skills disclosures ───────────────────────────────────────────────────
465
+ // SKILLRIGHTS #478 Phase 12. GET /api/v1/skills/rights-ledger (collector).
466
+ // The org's rights disclosure ledger: what was distributed and protected,
467
+ // under which declared rights, with the policy in force and evidence
468
+ // counts. Read-only. `-o json` is the export format for handing the
469
+ // disclosure to an auditor. What it does NOT claim: execution/usage
470
+ // events (that ledger does not exist yet) or verified signatures.
471
+ skills
472
+ .command('disclosures')
473
+ .description('Org rights disclosure ledger: distributions + protections under declared rights, policy in force, evidence counts')
474
+ .action(async () => {
475
+ auth.requireAuth();
476
+ const ep = resolveEndpoint('skills.rightsLedger');
477
+ const ledger = await client.get(ep.path, { service: ep.service });
478
+
479
+ if (program.opts().output === 'json') {
480
+ formatDetail(ledger, { format: 'json' });
481
+ return;
482
+ }
483
+
484
+ const s = ledger.summary || {};
485
+ printInfo(`Rights disclosure for org ${ledger.orgId} (generated ${ledger.generatedAt}). Policy in force: ${ledger.policy || 'unknown'}${ledger.policyError ? ` (policy lookup failed: ${ledger.policyError})` : ''}.`);
486
+ printInfo(`${s.hosts ?? 0} host(s), ${s.skillsDistributed ?? 0} skill(s) distributed (${s.skillsDeclared ?? 0} declared, ${s.skillsUndeclared ?? 0} undeclared), ${s.protections ?? 0} protection(s). Evidence: ${ledger.evidence?.syncEnvelopes ?? 0} sync + ${ledger.evidence?.protectEnvelopes ?? 0} protect envelope(s).`);
487
+
488
+ formatOutput({
489
+ columns: ['hostId', 'installedVersion', 'status', 'rightsSummary'],
490
+ headers: ['Host', 'Pack ver', 'Status', 'Rights'],
491
+ rows: (ledger.distributions || []).map((d) => ({
492
+ hostId: d.hostId,
493
+ installedVersion: d.installedVersion || '?',
494
+ status: d.status,
495
+ rightsSummary: d.rights
496
+ ? `${d.rights.declared}/${d.rights.total} declared`
497
+ : (d.rightsUnreadable ? 'UNREADABLE record' : 'no rights record'),
498
+ })),
499
+ }, { format: program.opts().output, emptyMessage: 'No distributions recorded.' });
500
+
501
+ formatOutput({
502
+ columns: ['srid', 'skillName', 'licence', 'mode', 'evidence'],
503
+ headers: ['SRID', 'Skill', 'Licence', 'Mode', 'Evidence'],
504
+ rows: (ledger.protections || []).map((p) => ({
505
+ srid: p.srid,
506
+ skillName: p.skillName || '',
507
+ licence: shortLicenceLabel(p.license),
508
+ mode: p.mode,
509
+ evidence: p.aeeEnvelopeId || '',
510
+ })),
511
+ }, { format: program.opts().output, emptyMessage: 'No protections recorded.' });
512
+ });
513
+
514
+ // ── skills protections ───────────────────────────────────────────────────
515
+ // GET /api/v1/skills/protections (collector).
516
+ skills
517
+ .command('protections')
518
+ .description('List this org\'s protected skills (SRID, licence, org key, evidence envelope)')
519
+ .action(async () => {
520
+ auth.requireAuth();
521
+ const ep = resolveEndpoint('skills.protections');
522
+ const data = await client.get(ep.path, { service: ep.service });
523
+ const rows = (data.protections || []).map((p) => ({
524
+ srid: p.srid,
525
+ name: p.skillName || '',
526
+ licence: p.license || '',
527
+ mode: p.mode,
528
+ registered: p.receipt?.receipt?.record?.ts || p.createdAt,
529
+ evidence: p.aeeEnvelopeId || '',
530
+ }));
531
+ formatOutput(rows, {
532
+ format: program.opts().output,
533
+ columns: ['srid', 'name', 'licence', 'mode', 'registered', 'evidence'],
534
+ });
535
+ });
536
+
537
+ // ── skills sealed ────────────────────────────────────────────────────────
538
+ // SKILLRIGHTS #478 Phase 14, sealed execution pilot. Collector routes
539
+ // (server.js /api/v1/skills/sealed[...]). See
540
+ // docs/SEALED_EXECUTION_PILOT_DESIGN.md for the full design and the
541
+ // binding claims language below (section G, verbatim).
542
+ //
543
+ // What sealed execution IS: the model invokes a capability (tool call);
544
+ // the methodology runs on infrastructure the org controls; the caller
545
+ // gets only inputs and outputs, never the skill text. The manifest read
546
+ // back by list/show never contains the sealed content, only its hash.
547
+ //
548
+ // What it is NOT: a guarantee against cloning-by-behaviour, and NOT a
549
+ // reliable filter on invocation output (the executor's overlap check is
550
+ // partial at best). Every surface below says so; do not soften it.
551
+ const sealed = skills
552
+ .command('sealed')
553
+ .description('Manage sealed-execution skills: methodology runs on org infrastructure, callers get inputs/outputs only (pilot)');
554
+
555
+ // The binding sentence, verbatim. Printed on every `sealed add` success
556
+ // (docs/SEALED_EXECUTION_PILOT_DESIGN.md).
557
+ //
558
+ // SUPERSEDED 2026-09-11 (external audit): the original section G wording
559
+ // claimed the text stays out of "every model's context and every provider's
560
+ // training pipeline". The executor sends the plaintext to the executing
561
+ // model, so that half was contradicted on every successful invocation.
562
+ const SEALED_SECTION_G_SENTENCE = "Sealed execution keeps the text of your methodology out of the calling model's context; the executing model and its provider do see it, under that provider's data terms, and nothing here prevents someone who can call the capability from learning what it does.";
563
+
564
+ sealed
565
+ .command('list')
566
+ .description('List sealed skill manifests for this org (manifest only, never the sealed content)')
567
+ .action(async () => {
568
+ auth.requireAuth();
569
+ const ep = resolveEndpoint('skills.sealed.list');
570
+ const data = await client.get(ep.path, { service: ep.service });
571
+ const rows = data.sealed ?? data;
572
+
573
+ formatOutput({
574
+ columns: ['sealedId', 'name', 'contentSha256', 'createdAt'],
575
+ headers: ['Sealed ID', 'Name', 'Content SHA256', 'Created'],
576
+ rows: (Array.isArray(rows) ? rows : []).map((r) => ({
577
+ sealedId: r.sealedId,
578
+ name: r.name,
579
+ contentSha256: (r.contentSha256 || '').slice(0, 12),
580
+ createdAt: r.createdAt,
581
+ })),
582
+ }, { format: program.opts().output, emptyMessage: 'No sealed skills found.' });
583
+ });
584
+
585
+ sealed
586
+ .command('show')
587
+ .description('Show a sealed skill\'s manifest (name, description, input contract, content hash). Manifest only.')
588
+ .argument('<sealedId>', 'sealed skill ID')
589
+ .action(async (sealedId) => {
590
+ auth.requireAuth();
591
+ const ep = resolveEndpoint('skills.sealed.get', { sealedId });
592
+ const data = await client.get(ep.path, { service: ep.service });
593
+ printInfo('Manifest only. The sealed content is never returned by the API.');
594
+ formatDetail(data, { format: program.opts().output, title: `Sealed skill: ${sealedId}` });
595
+ });
596
+
597
+ sealed
598
+ .command('add')
599
+ .description('Seal a local skill: its content is uploaded once, executed on org infrastructure thereafter, and never returned to a caller')
600
+ .argument('<path>', 'skill directory (its SKILL.md is read) or a single file')
601
+ .requiredOption('--name <name>', 'sealed skill name')
602
+ .option('--description <text>', 'description')
603
+ .option('--contract <file>', 'JSON file describing the expected input contract')
604
+ .action(async (target, options) => {
605
+ auth.requireAuth();
606
+ const resolved = path.resolve(target);
607
+ if (!existsSync(resolved)) {
608
+ throw new Error(`No such file or directory: ${resolved}`);
609
+ }
610
+ const isDir = statSync(resolved).isDirectory();
611
+ const contentPath = isDir ? path.join(resolved, 'SKILL.md') : resolved;
612
+ if (!existsSync(contentPath)) {
613
+ throw new Error(`No SKILL.md found in ${resolved}.`);
614
+ }
615
+ const content = readFileSync(contentPath, 'utf8');
616
+
617
+ let inputContract = {};
618
+ if (options.contract) {
619
+ inputContract = parseJSON(readFileSync(options.contract, 'utf8'), 'input contract file');
620
+ }
621
+
622
+ const body = { name: options.name, inputContract, content };
623
+ if (options.description) body.description = options.description;
624
+
625
+ try {
626
+ const ep = resolveEndpoint('skills.sealed.create');
627
+ const data = await client.post(ep.path, { service: ep.service, body });
628
+ printSuccess(`Sealed. sealedId ${data.sealedId}`);
629
+ formatDetail(data, { format: program.opts().output, title: 'Sealed skill' });
630
+ printInfo(SEALED_SECTION_G_SENTENCE);
631
+ } catch (err) {
632
+ if (err.status === 503 && err.code === 'sealed_unavailable') {
633
+ throw new Error(
634
+ 'sealed_unavailable: this server has no sealed-content encryption key configured. '
635
+ + 'An org admin must register one before any skill can be sealed.'
636
+ );
637
+ }
638
+ throw err;
639
+ }
640
+ });
641
+
642
+ sealed
643
+ .command('invoke')
644
+ .description('Invoke a sealed skill: the model gets only the output, never the methodology text. Output filtering is partial, not guaranteed; the caller\'s input still transits the executing provider.')
645
+ .argument('<sealedId>', 'sealed skill ID')
646
+ .option('--input <text>', 'input text')
647
+ .option('--input-file <path>', 'read the input from a file (overrides --input)')
648
+ .action(async (sealedId, options) => {
649
+ auth.requireAuth();
650
+ let input;
651
+ if (options.inputFile) {
652
+ input = readFileSync(options.inputFile, 'utf8');
653
+ } else if (options.input) {
654
+ input = options.input;
655
+ } else {
656
+ throw new Error('Input is required. Use --input <text> or --input-file <path>.');
657
+ }
658
+
659
+ try {
660
+ const ep = resolveEndpoint('skills.sealed.invoke', { sealedId });
661
+ // A sealed invocation is a full LLM run: the collector allows the
662
+ // executor 120s, so the default 30s client timeout hangs up on runs
663
+ // that then complete (and are witnessed) server-side with nobody to
664
+ // receive the output. Proven live on the first pilot drive 2026-09-11
665
+ // (73s run, orphaned output). 150s = executor deadline + margin.
666
+ const data = await client.post(ep.path, { service: ep.service, body: { input }, timeout: 150000 });
667
+
668
+ if (data.refused) {
669
+ printWarning(
670
+ `Output withheld by the disclosure check (${data.error || 'sealed_output_withheld'}). `
671
+ + `Evidence envelope: ${data.evidence?.envelopeId || '(none)'}.`
672
+ );
673
+ formatDetail(data.evidence || {}, { format: program.opts().output, title: 'Evidence' });
674
+ return;
675
+ }
676
+
677
+ printSuccess('Invocation complete.');
678
+ console.log(data.output);
679
+ formatDetail(data.evidence || {}, { format: program.opts().output, title: 'Evidence' });
680
+ } catch (err) {
681
+ if (err.status === 429 || err.status === 502) {
682
+ throw new Error(`Sealed invocation failed: ${err.code}`);
683
+ }
684
+ throw err;
685
+ }
686
+ });
687
+ }