quoxcli 0.2.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (442) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +2 -0
  3. package/bin/quox.js +99 -126
  4. package/lib/api/endpoints/actions.js +15 -0
  5. package/lib/api/endpoints/admin.js +46 -0
  6. package/lib/api/endpoints/agent-schedules.js +26 -0
  7. package/lib/api/endpoints/agents.js +7 -0
  8. package/lib/api/endpoints/assistants.js +12 -0
  9. package/lib/api/endpoints/away.js +15 -0
  10. package/lib/api/endpoints/blog.js +16 -0
  11. package/lib/api/endpoints/chat.js +14 -0
  12. package/lib/api/endpoints/contactsq.js +6 -0
  13. package/lib/api/endpoints/conversations.js +14 -0
  14. package/lib/api/endpoints/devServerRegistry.js +25 -0
  15. package/lib/api/endpoints/engagement.js +26 -0
  16. package/lib/api/endpoints/evidence.js +20 -0
  17. package/lib/api/endpoints/executions.js +13 -0
  18. package/lib/api/endpoints/fetchAllowlist.js +27 -0
  19. package/lib/api/endpoints/files.js +14 -0
  20. package/lib/api/endpoints/hat.js +44 -0
  21. package/lib/api/endpoints/inbox.js +20 -0
  22. package/lib/api/endpoints/index.js +26 -0
  23. package/lib/api/endpoints/loops.js +26 -0
  24. package/lib/api/endpoints/memory.js +19 -0
  25. package/lib/api/endpoints/mind.js +13 -0
  26. package/lib/api/endpoints/mon.js +179 -0
  27. package/lib/api/endpoints/objectives.js +12 -0
  28. package/lib/api/endpoints/plugins.js +18 -0
  29. package/lib/api/endpoints/presence.js +33 -0
  30. package/lib/api/endpoints/quoxplan.js +7 -0
  31. package/lib/api/endpoints/quoxseo.js +12 -0
  32. package/lib/api/endpoints/router.js +17 -0
  33. package/lib/api/endpoints/safety.js +7 -0
  34. package/lib/api/endpoints/server.js +21 -0
  35. package/lib/api/endpoints/setup.js +6 -0
  36. package/lib/api/endpoints/skills.js +20 -0
  37. package/lib/api/endpoints/stepup.js +20 -0
  38. package/lib/api/endpoints/teams.js +2 -2
  39. package/lib/api/endpoints/triggers.js +26 -0
  40. package/lib/api/endpoints/v1.js +120 -0
  41. package/lib/api/endpoints/ward.js +7 -0
  42. package/lib/api/endpoints/workflows.js +7 -0
  43. package/lib/api/endpoints/x.js +8 -0
  44. package/lib/commands/actions.js +131 -0
  45. package/lib/commands/admin.js +16 -0
  46. package/lib/commands/agent.js +170 -27
  47. package/lib/commands/agentAttach.js +140 -13
  48. package/lib/commands/approvals.js +78 -1
  49. package/lib/commands/aside.js +24 -0
  50. package/lib/commands/ask.js +146 -0
  51. package/lib/commands/assistant.js +59 -4
  52. package/lib/commands/auth.js +8 -2
  53. package/lib/commands/backup.js +8 -4
  54. package/lib/commands/blog.js +110 -0
  55. package/lib/commands/brain.js +105 -14
  56. package/lib/commands/build.js +19 -5
  57. package/lib/commands/chat.js +180 -26
  58. package/lib/commands/chatCompanion.js +27 -0
  59. package/lib/commands/chatState.js +45 -0
  60. package/lib/commands/claude.js +35 -38
  61. package/lib/commands/contacts.js +134 -4
  62. package/lib/commands/contactsSendAt.js +21 -0
  63. package/lib/commands/conversation.js +35 -4
  64. package/lib/commands/dashboard.js +43 -0
  65. package/lib/commands/department.js +28 -7
  66. package/lib/commands/devResident.js +15 -3
  67. package/lib/commands/devSupervisor.js +13 -1
  68. package/lib/commands/discord.js +75 -39
  69. package/lib/commands/done.js +98 -28
  70. package/lib/commands/engagement.js +107 -6
  71. package/lib/commands/evidence.js +154 -0
  72. package/lib/commands/ext.js +23 -0
  73. package/lib/commands/fetchAllowlist.js +71 -0
  74. package/lib/commands/file.js +38 -1
  75. package/lib/commands/fleet.js +336 -4
  76. package/lib/commands/governance.js +12 -3
  77. package/lib/commands/gripe.js +44 -13
  78. package/lib/commands/hat.js +254 -9
  79. package/lib/commands/helpers.js +18 -1
  80. package/lib/commands/hyperion.js +58 -0
  81. package/lib/commands/image.js +68 -0
  82. package/lib/commands/inbox.js +74 -23
  83. package/lib/commands/kuma.js +1050 -0
  84. package/lib/commands/kumaSla.js +174 -0
  85. package/lib/commands/licence.js +52 -155
  86. package/lib/commands/loop.js +291 -0
  87. package/lib/commands/lucid.js +10 -4
  88. package/lib/commands/memory.js +85 -8
  89. package/lib/commands/mind.js +71 -0
  90. package/lib/commands/mon.js +69 -2
  91. package/lib/commands/monitoring.js +1 -1
  92. package/lib/commands/motion.js +2 -2
  93. package/lib/commands/nucleus.js +48 -17
  94. package/lib/commands/objective.js +59 -1
  95. package/lib/commands/offload.js +89 -0
  96. package/lib/commands/onboard.js +2 -1
  97. package/lib/commands/org.js +30 -3
  98. package/lib/commands/peek.js +28 -0
  99. package/lib/commands/plan.js +38 -0
  100. package/lib/commands/plugin.js +110 -0
  101. package/lib/commands/presence.js +89 -0
  102. package/lib/commands/provider.js +217 -0
  103. package/lib/commands/qlarity.js +19 -3
  104. package/lib/commands/quoxchat.js +13 -4
  105. package/lib/commands/quoxseo.js +69 -0
  106. package/lib/commands/reach.js +2 -1
  107. package/lib/commands/research.js +79 -0
  108. package/lib/commands/router.js +77 -0
  109. package/lib/commands/rows.js +367 -0
  110. package/lib/commands/run.js +82 -10
  111. package/lib/commands/scope.js +2 -2
  112. package/lib/commands/server.js +405 -0
  113. package/lib/commands/setup.js +33 -7
  114. package/lib/commands/shortcut.js +41 -0
  115. package/lib/commands/skills.js +68 -9
  116. package/lib/commands/slot.js +260 -7
  117. package/lib/commands/status.js +1 -1
  118. package/lib/commands/team.js +3 -1
  119. package/lib/commands/tips.js +23 -0
  120. package/lib/commands/tool.js +133 -45
  121. package/lib/commands/trace.js +12 -7
  122. package/lib/commands/trigger.js +95 -0
  123. package/lib/commands/update.js +46 -0
  124. package/lib/commands/vault.js +31 -8
  125. package/lib/commands/vm.js +237 -0
  126. package/lib/commands/voice.js +34 -3
  127. package/lib/commands/volt.js +45 -3
  128. package/lib/commands/walkthrough.js +32 -0
  129. package/lib/commands/watch.js +73 -21
  130. package/lib/commands/welcome.js +14 -0
  131. package/lib/commands/workflow.js +189 -32
  132. package/lib/commands/x.js +13 -4
  133. package/lib/commands/youtube.js +172 -0
  134. package/lib/core/actingAs.js +2 -2
  135. package/lib/core/actionItems.js +115 -0
  136. package/lib/core/activeSummary.js +186 -0
  137. package/lib/core/agentAlias.js +2 -0
  138. package/lib/core/agentFamilies.js +7 -0
  139. package/lib/core/aside.js +54 -0
  140. package/lib/core/askDecision.js +60 -0
  141. package/lib/core/auth.js +164 -13
  142. package/lib/core/callerSource.js +1 -1
  143. package/lib/core/cliBuild.js +62 -0
  144. package/lib/core/client.js +152 -35
  145. package/lib/core/commandRegistrars.js +130 -0
  146. package/lib/core/config.js +143 -25
  147. package/lib/core/customHats.js +168 -0
  148. package/lib/core/doneEngineFetch.js +8 -0
  149. package/lib/core/errors.js +329 -20
  150. package/lib/core/findingReconcile.js +90 -0
  151. package/lib/core/global-flags.js +105 -5
  152. package/lib/core/governedSession.js +1 -3
  153. package/lib/core/hyperion.js +102 -0
  154. package/lib/core/inboxResolution.js +65 -0
  155. package/lib/core/lazyCommands.js +4 -1
  156. package/lib/core/liveSessionsReport.js +1 -1
  157. package/lib/core/loopGlyph.js +97 -0
  158. package/lib/core/offload.js +533 -0
  159. package/lib/core/org-override.js +1 -1
  160. package/lib/core/orgResolve.js +70 -0
  161. package/lib/core/output.js +11 -11
  162. package/lib/core/peek.js +126 -0
  163. package/lib/core/profileUsers.js +51 -0
  164. package/lib/core/promptCancel.js +18 -0
  165. package/lib/core/repoPath.js +11 -0
  166. package/lib/core/residentSeed.js +3 -1
  167. package/lib/core/rootOptions.js +39 -0
  168. package/lib/core/router.js +168 -0
  169. package/lib/core/selfUpdate.js +188 -0
  170. package/lib/core/sessionHeartbeat.js +12 -8
  171. package/lib/core/sessionsOverview.js +64 -0
  172. package/lib/core/shortcut.js +83 -0
  173. package/lib/core/slotKeeper.js +248 -3
  174. package/lib/core/slotWake.js +120 -0
  175. package/lib/core/supervisorEngine.js +71 -2
  176. package/lib/core/version.js +1 -1
  177. package/lib/core/vm.js +366 -0
  178. package/lib/core/vmTui.js +86 -0
  179. package/lib/core/walkthrough.js +35 -0
  180. package/lib/dragon/companionView.js +34 -0
  181. package/lib/dragon/frames.js +118 -0
  182. package/lib/dragon/jobs.js +123 -0
  183. package/lib/dragon/renderWorker.js +15 -0
  184. package/lib/dragon/select.js +72 -0
  185. package/lib/evidence/bundleExport.js +47 -0
  186. package/lib/evidence/bundleVerify.js +77 -0
  187. package/lib/hyperion/deck.js +29 -0
  188. package/lib/lucid/LucidCard.jsx +68 -0
  189. package/lib/lucid/LucidIntro.jsx +45 -58
  190. package/lib/lucid/cards.js +86 -0
  191. package/lib/lucid/markdown.js +81 -0
  192. package/lib/lucid/motion.js +56 -0
  193. package/lib/quoxon/EXTENSIONS.md +23 -0
  194. package/lib/quoxon/activity.js +14 -2
  195. package/lib/quoxon/aocl.js +117 -0
  196. package/lib/quoxon/api.js +690 -25
  197. package/lib/quoxon/app.js +3586 -250
  198. package/lib/quoxon/approvalFacts.js +96 -0
  199. package/lib/quoxon/approvalSentence.js +44 -0
  200. package/lib/quoxon/approvalsView.js +384 -0
  201. package/lib/quoxon/asideView.js +40 -0
  202. package/lib/quoxon/ask.js +121 -0
  203. package/lib/quoxon/away.js +52 -0
  204. package/lib/quoxon/bang.js +224 -0
  205. package/lib/quoxon/bulkRisk.js +17 -0
  206. package/lib/quoxon/capabilities.js +13 -6
  207. package/lib/quoxon/cells.js +53 -0
  208. package/lib/quoxon/commandShort.js +124 -0
  209. package/lib/quoxon/commands.js +429 -39
  210. package/lib/quoxon/connect.js +210 -23
  211. package/lib/quoxon/connectCard.js +19 -2
  212. package/lib/quoxon/consent.js +86 -0
  213. package/lib/quoxon/copy.js +4 -3
  214. package/lib/quoxon/countdownLine.js +20 -0
  215. package/lib/quoxon/deck.js +30 -0
  216. package/lib/quoxon/demo.autoplay.js +29 -0
  217. package/lib/quoxon/demo.fixtures.js +1 -1
  218. package/lib/quoxon/demo.js +46 -3
  219. package/lib/quoxon/devObserver.js +20 -0
  220. package/lib/quoxon/dividerAocl.js +192 -0
  221. package/lib/quoxon/dividerRule.js +57 -0
  222. package/lib/quoxon/dragonCompanion.js +255 -0
  223. package/lib/quoxon/dragonModes.js +151 -0
  224. package/lib/quoxon/dragonMoments.js +82 -0
  225. package/lib/quoxon/dragonReads.js +68 -0
  226. package/lib/quoxon/dragonView.js +41 -0
  227. package/lib/quoxon/earlyInput.js +40 -0
  228. package/lib/quoxon/echo.js +15 -0
  229. package/lib/quoxon/egg.js +2 -2
  230. package/lib/quoxon/events.js +266 -26
  231. package/lib/quoxon/extensions.js +276 -0
  232. package/lib/quoxon/feedback.js +50 -0
  233. package/lib/quoxon/gallery.js +21 -7
  234. package/lib/quoxon/handoffOffer.js +78 -0
  235. package/lib/quoxon/hatSwitch.js +37 -0
  236. package/lib/quoxon/headless.js +161 -0
  237. package/lib/quoxon/hostUrls.js +41 -0
  238. package/lib/quoxon/inboxView.js +79 -0
  239. package/lib/quoxon/indicator.js +6 -2
  240. package/lib/quoxon/installCli.js +79 -0
  241. package/lib/quoxon/intent.js +12 -1
  242. package/lib/quoxon/keys.js +51 -8
  243. package/lib/quoxon/launcher.js +103 -0
  244. package/lib/quoxon/loopCard.js +456 -0
  245. package/lib/quoxon/loopCards.js +180 -0
  246. package/lib/quoxon/loopStream.js +87 -0
  247. package/lib/quoxon/main.js +101 -160
  248. package/lib/quoxon/markdown.js +45 -21
  249. package/lib/quoxon/markdownSettle.js +19 -0
  250. package/lib/quoxon/matrixDomains.json +46 -0
  251. package/lib/quoxon/mentions.js +90 -0
  252. package/lib/quoxon/mind.js +103 -0
  253. package/lib/quoxon/mode.js +46 -0
  254. package/lib/quoxon/model.js +132 -26
  255. package/lib/quoxon/modelPrefs.js +345 -0
  256. package/lib/quoxon/motion/clock.js +3 -2
  257. package/lib/quoxon/motion/level.js +91 -0
  258. package/lib/quoxon/mouse.js +222 -0
  259. package/lib/quoxon/noai.js +57 -0
  260. package/lib/quoxon/objectiveOffer.js +82 -0
  261. package/lib/quoxon/objects/away.js +72 -0
  262. package/lib/quoxon/objects/fetch.js +17 -5
  263. package/lib/quoxon/objects/fleet.js +149 -0
  264. package/lib/quoxon/objects/health.js +186 -0
  265. package/lib/quoxon/objects/index.js +46 -7
  266. package/lib/quoxon/objects/mirror.js +137 -0
  267. package/lib/quoxon/objects/model.js +33 -0
  268. package/lib/quoxon/objects/peek.js +17 -0
  269. package/lib/quoxon/objects/proof.js +12 -4
  270. package/lib/quoxon/objects/prove.js +130 -0
  271. package/lib/quoxon/objects/replay.js +125 -0
  272. package/lib/quoxon/objects/sitrep.js +58 -0
  273. package/lib/quoxon/objects/view.js +11 -0
  274. package/lib/quoxon/onboarding/copy.js +32 -4
  275. package/lib/quoxon/onboarding/credential.js +17 -4
  276. package/lib/quoxon/onboarding/dockerOffer.js +45 -0
  277. package/lib/quoxon/onboarding/failureCause.js +33 -0
  278. package/lib/quoxon/onboarding/finish.js +15 -0
  279. package/lib/quoxon/onboarding/index.js +34 -7
  280. package/lib/quoxon/onboarding/installRunner.js +64 -5
  281. package/lib/quoxon/onboarding/preflight.js +17 -3
  282. package/lib/quoxon/onboarding/probe.js +65 -0
  283. package/lib/quoxon/onboarding/shortcutOffer.js +28 -0
  284. package/lib/quoxon/onboarding/view.js +76 -19
  285. package/lib/quoxon/orgLabel.js +10 -0
  286. package/lib/quoxon/orgSwitch.js +59 -0
  287. package/lib/quoxon/ownBroadcast.js +22 -0
  288. package/lib/quoxon/palette.js +43 -0
  289. package/lib/quoxon/planSteps.js +51 -0
  290. package/lib/quoxon/print.js +12 -5
  291. package/lib/quoxon/profileSwitch.js +53 -0
  292. package/lib/quoxon/promptHistory.js +41 -0
  293. package/lib/quoxon/providers.js +48 -0
  294. package/lib/quoxon/qart.js +20 -51
  295. package/lib/quoxon/qdragon.js +410 -0
  296. package/lib/quoxon/qdragonFly.js +62 -0
  297. package/lib/quoxon/qdragonScenes.js +282 -0
  298. package/lib/quoxon/qeyes.js +213 -0
  299. package/lib/quoxon/qmotion.js +75 -37
  300. package/lib/quoxon/render.js +740 -124
  301. package/lib/quoxon/resend.js +72 -0
  302. package/lib/quoxon/roster.js +117 -17
  303. package/lib/quoxon/route.js +6 -5
  304. package/lib/quoxon/rows.js +954 -0
  305. package/lib/quoxon/rowsStore.js +80 -0
  306. package/lib/quoxon/screenContext.js +150 -0
  307. package/lib/quoxon/screenFrames.js +254 -0
  308. package/lib/quoxon/serverChip.js +42 -0
  309. package/lib/quoxon/session.js +182 -2
  310. package/lib/quoxon/sessionDead.js +17 -0
  311. package/lib/quoxon/signin.js +125 -0
  312. package/lib/quoxon/slash/agents.js +112 -0
  313. package/lib/quoxon/slash/argSources.js +65 -0
  314. package/lib/quoxon/slash/args.js +65 -0
  315. package/lib/quoxon/slash/automate.js +89 -0
  316. package/lib/quoxon/slash/broadcast.js +140 -0
  317. package/lib/quoxon/slash/broadcastRun.js +108 -0
  318. package/lib/quoxon/slash/card.js +30 -0
  319. package/lib/quoxon/slash/challenge.js +114 -0
  320. package/lib/quoxon/slash/cliCommand.js +94 -0
  321. package/lib/quoxon/slash/cliLeaves.json +1023 -0
  322. package/lib/quoxon/slash/compact.js +1 -1
  323. package/lib/quoxon/slash/confirm.js +30 -0
  324. package/lib/quoxon/slash/crystallize.js +69 -0
  325. package/lib/quoxon/slash/dashboard.js +136 -0
  326. package/lib/quoxon/slash/draft.js +54 -0
  327. package/lib/quoxon/slash/evidenceCmd.js +34 -0
  328. package/lib/quoxon/slash/hatWalk.js +206 -0
  329. package/lib/quoxon/slash/inverses.js +77 -0
  330. package/lib/quoxon/slash/killer.js +24 -0
  331. package/lib/quoxon/slash/killerApi.js +16 -0
  332. package/lib/quoxon/slash/ledger.js +13 -8
  333. package/lib/quoxon/slash/listView.js +3 -1
  334. package/lib/quoxon/slash/modelCmd.js +261 -0
  335. package/lib/quoxon/slash/palette.js +22 -8
  336. package/lib/quoxon/slash/paletteController.js +117 -7
  337. package/lib/quoxon/slash/panels.js +21 -6
  338. package/lib/quoxon/slash/picker.js +20 -2
  339. package/lib/quoxon/slash/qpeCmd.js +35 -0
  340. package/lib/quoxon/slash/restart.js +95 -13
  341. package/lib/quoxon/slash/resume.js +18 -1
  342. package/lib/quoxon/slash/rowCmd.js +157 -0
  343. package/lib/quoxon/slash/rowWalk.js +175 -0
  344. package/lib/quoxon/slash/settings.js +16 -6
  345. package/lib/quoxon/slash/spawn.js +177 -0
  346. package/lib/quoxon/slash/stepUp.js +274 -0
  347. package/lib/quoxon/slash/stepUpCard.js +60 -0
  348. package/lib/quoxon/slash/stepUpCmds.js +78 -0
  349. package/lib/quoxon/slash/todoCmd.js +122 -0
  350. package/lib/quoxon/slash/undoApi.js +38 -0
  351. package/lib/quoxon/slash/undoCmd.js +49 -0
  352. package/lib/quoxon/slash/undoWish.js +15 -0
  353. package/lib/quoxon/slash/watch.js +164 -0
  354. package/lib/quoxon/slash/wish.js +23 -0
  355. package/lib/quoxon/slash/wishCmd.js +32 -0
  356. package/lib/quoxon/slotChat.js +300 -0
  357. package/lib/quoxon/slotFormat.js +195 -0
  358. package/lib/quoxon/slotRun.js +131 -0
  359. package/lib/quoxon/sound/mapping.js +2 -1
  360. package/lib/quoxon/stray.js +22 -0
  361. package/lib/quoxon/suggestCommand.js +90 -0
  362. package/lib/quoxon/term.js +46 -11
  363. package/lib/quoxon/textBuffer.js +176 -2
  364. package/lib/quoxon/theme.js +58 -25
  365. package/lib/quoxon/tips.js +433 -0
  366. package/lib/quoxon/toolCards.js +30 -0
  367. package/lib/quoxon/toolError.js +41 -0
  368. package/lib/quoxon/transcript.js +42 -4
  369. package/lib/quoxon/web/qface.js +18 -10
  370. package/lib/quoxon/welcome.js +1 -1
  371. package/lib/quoxon/whatsnew.js +136 -0
  372. package/lib/quoxon/whatsnew.jsonl +134 -0
  373. package/lib/quoxon/windowOrg.js +123 -0
  374. package/lib/server/devServers.js +137 -0
  375. package/lib/server/diag.js +129 -0
  376. package/lib/server/doctor.js +71 -0
  377. package/lib/server/install.js +149 -0
  378. package/lib/server/pluginEnable.js +161 -0
  379. package/lib/server/skew.js +56 -0
  380. package/lib/server/snapshot.js +131 -0
  381. package/lib/server/status.js +128 -0
  382. package/lib/server/sys.js +65 -0
  383. package/lib/server/uninstall.js +63 -0
  384. package/lib/server/update.js +234 -0
  385. package/lib/toolOutputShape.js +315 -0
  386. package/lib/tui/views/HyperionDeck.jsx +79 -0
  387. package/lib/tui/views/LucidDeck.jsx +209 -217
  388. package/package.json +5 -1
  389. package/vendor/dragonlab/SOURCE +4 -0
  390. package/vendor/dragonlab/design/cipher/v1/cipher-master.svg +46 -0
  391. package/vendor/dragonlab/design/cipher/v2/character.mjs +49 -0
  392. package/vendor/dragonlab/design/cipher/v2/review.mjs +33 -0
  393. package/vendor/dragonlab/design/cipher/v2/watch.mjs +56 -0
  394. package/vendor/dragonlab/design/drago/v1/character.mjs +19 -0
  395. package/vendor/dragonlab/design/drago/v1/drago-master.svg +56 -0
  396. package/vendor/dragonlab/design/drago/v2/character.mjs +87 -0
  397. package/vendor/dragonlab/design/drago/v4/character.mjs +67 -0
  398. package/vendor/dragonlab/design/drago/v4/profile.mjs +35 -0
  399. package/vendor/dragonlab/design/drago/v4/review.mjs +33 -0
  400. package/vendor/dragonlab/design/drago/v4/watch.mjs +56 -0
  401. package/vendor/dragonlab/design/hyperion/v1/hyperion-master.svg +56 -0
  402. package/vendor/dragonlab/design/hyperion/v2/character.mjs +79 -0
  403. package/vendor/dragonlab/design/hyperion/v2/review.mjs +33 -0
  404. package/vendor/dragonlab/design/hyperion/v2/watch.mjs +56 -0
  405. package/vendor/dragonlab/design/lucid/recovery/arrival.mjs +22 -0
  406. package/vendor/dragonlab/design/lucid/recovery/character.mjs +106 -0
  407. package/vendor/dragonlab/design/lucid/recovery/layout.mjs +50 -0
  408. package/vendor/dragonlab/design/lucid/recovery/lucid-master.svg +78 -0
  409. package/vendor/dragonlab/design/lucid/recovery/motion.mjs +42 -0
  410. package/vendor/dragonlab/design/lucid/recovery/render.mjs +121 -0
  411. package/vendor/dragonlab/design/lucid/recovery/review.mjs +68 -0
  412. package/vendor/dragonlab/design/lucid/recovery/verify.mjs +84 -0
  413. package/vendor/dragonlab/design/lucid/recovery/watch.mjs +56 -0
  414. package/vendor/dragonlab/design/seer/v1/seer-master.svg +53 -0
  415. package/vendor/dragonlab/design/seer/v2/character.mjs +88 -0
  416. package/vendor/dragonlab/design/seer/v3/character.mjs +33 -0
  417. package/vendor/dragonlab/design/seer/v4/character.mjs +66 -0
  418. package/vendor/dragonlab/design/seer/v4/review.mjs +33 -0
  419. package/vendor/dragonlab/design/seer/v4/watch.mjs +56 -0
  420. package/vendor/dragonlab/design/stage3/companion-review.mjs +28 -0
  421. package/vendor/dragonlab/design/stage3/sentinel-art.js +39 -0
  422. package/vendor/dragonlab/design/stage3/sentinel-braille.js +216 -0
  423. package/vendor/dragonlab/design/stage3/sentinel-character.js +257 -0
  424. package/vendor/dragonlab/design/stage3/sentinel-icon.js +103 -0
  425. package/vendor/dragonlab/design/stage3/sentinel-warden-eyes.js +95 -0
  426. package/vendor/dragonlab/design/stage3/svg-coverage.js +148 -0
  427. package/vendor/dragonlab/factory/svg-rig.mjs +63 -0
  428. package/vendor/dragonlab/integration/companions-v1/characters.mjs +88 -0
  429. package/vendor/dragonlab/integration/companions-v1/cipher.mjs +2 -0
  430. package/vendor/dragonlab/integration/companions-v1/companion.mjs +63 -0
  431. package/vendor/dragonlab/integration/companions-v1/drago.mjs +2 -0
  432. package/vendor/dragonlab/integration/companions-v1/hyperion.mjs +2 -0
  433. package/vendor/dragonlab/integration/companions-v1/lucid.mjs +2 -0
  434. package/vendor/dragonlab/integration/companions-v1/seer.mjs +2 -0
  435. package/vendor/dragonlab/integration/companions-v1/sentinel.mjs +2 -0
  436. package/vendor/dragonlab/integration/companions-v1/view.mjs +28 -0
  437. package/vendor/dragonlab/integration/hyperion-v3/activity.mjs +76 -0
  438. package/vendor/dragonlab/lib/power-effects.js +294 -0
  439. package/vendor/dragonlab/lib/power-registry.js +74 -0
  440. package/vendor/dragonlab/vendor/quox-dragon/qart.js +348 -0
  441. package/vendor/dragonlab/vendor/quox-dragon/qeyes.js +213 -0
  442. package/lib/core/websiteSession.js +0 -148
@@ -0,0 +1,130 @@
1
+ /**
2
+ * The CLI's command groups, in registration order (moved verbatim from bin/quox.js so
3
+ * one list feeds both the binary and cli/scripts/export-leaf-tree.mjs, which exports the
4
+ * machine-readable leaf tree the collector's quox_cli tool validates against).
5
+ * Paths are relative to THIS file; registerCommandGroups resolves them against the
6
+ * baseUrl it is given (COMMAND_REGISTRARS_BASE).
7
+ */
8
+ export const COMMAND_REGISTRARS = [
9
+ ['../commands/auth.js', 'registerAuthCommands'],
10
+ ['../commands/service.js', 'registerServiceCommands'],
11
+ ['../commands/status.js', 'registerStatusCommand'],
12
+ ['../commands/doctor.js', 'registerDoctorCommand'],
13
+ ['../commands/server.js', 'registerServerCommands'],
14
+ ['../commands/update.js', 'registerUpdateCommand'],
15
+ ['../commands/shortcut.js', 'registerShortcutCommand'],
16
+ ['../commands/open.js', 'registerOpenCommand'],
17
+ ['../commands/peek.js', 'registerPeekCommand'],
18
+ ['../commands/aside.js', 'registerAsideCommand'],
19
+ ['../commands/motion.js', 'registerMotionCommand'],
20
+ ['../commands/welcome.js', 'registerWelcomeCommand'],
21
+ ['../commands/config-cmd.js', 'registerConfigCommands'],
22
+ ['../commands/org.js', 'registerOrgCommands'],
23
+ ['../commands/invites.js', 'registerInvitesCommands'],
24
+ ['../commands/team.js', 'registerTeamCommands'],
25
+ ['../commands/department.js', 'registerDepartmentCommands'],
26
+ ['../commands/agent.js', 'registerAgentCommands'],
27
+ ['../commands/tool.js', 'registerToolCommands'],
28
+ ['../commands/workflow.js', 'registerWorkflowCommands'],
29
+ ['../commands/objective.js', 'registerObjectiveCommands'],
30
+ ['../commands/loop.js', 'registerLoopCommands'],
31
+ ['../commands/assistant.js', 'registerAssistantCommands'],
32
+ ['../commands/fleet.js', 'registerFleetCommands'],
33
+ ['../commands/chat.js', 'registerChatCommands'],
34
+ ['../commands/memory.js', 'registerMemoryCommands'],
35
+ ['../commands/actions.js', 'registerActionsCommands'],
36
+ ['../commands/brain.js', 'registerBrainCommands'],
37
+ ['../commands/entity.js', 'registerEntityCommands'],
38
+ ['../commands/backup.js', 'registerBackupCommands'],
39
+ ['../commands/inbox.js', 'registerInboxCommands'],
40
+ ['../commands/approvals.js', 'registerApprovalsCommands'],
41
+ ['../commands/vm.js', 'registerVmCommands'],
42
+ ['../commands/router.js', 'registerRouterCommands'],
43
+ ['../commands/mail.js', 'registerMailCommands'],
44
+ ['../commands/calendar.js', 'registerCalendarCommands'],
45
+ ['../commands/notes.js', 'registerNotesCommands'],
46
+ ['../commands/blog.js', 'registerBlogCommands'],
47
+ ['../commands/contacts.js', 'registerContactsCommands'],
48
+ ['../commands/licence.js', 'registerLicenceCommands'],
49
+ ['../commands/run.js', 'registerRunCommands'],
50
+ ['../commands/file.js', 'registerFileCommands'],
51
+ ['../commands/evidence.js', 'registerEvidenceCommands'],
52
+ ['../commands/admin.js', 'registerAdminCommands'],
53
+ ['../commands/aee.js', 'registerAeeCommands'],
54
+ ['../commands/integration.js', 'registerIntegrationCommands'],
55
+ ['../commands/consent.js', 'registerConsentCommands'],
56
+ ['../commands/setup.js', 'registerSetupCommands'],
57
+ ['../commands/watch.js', 'registerWatchCommands'],
58
+ ['../commands/tag.js', 'registerTagCommands'],
59
+ ['../commands/scope.js', 'registerScopeCommands'],
60
+ ['../commands/notification.js', 'registerNotificationCommands'],
61
+ ['../commands/prompt.js', 'registerPromptCommands'],
62
+ ['../commands/plugin.js', 'registerPluginCommands'],
63
+ ['../commands/powers.js', 'registerPowersCommands'],
64
+ ['../commands/conversation.js', 'registerConversationCommands'],
65
+ ['../commands/vault.js', 'registerVaultCommands'],
66
+ ['../commands/volt.js', 'registerVoltCommands'],
67
+ ['../commands/governance.js', 'registerGovernanceCommands'],
68
+ ['../commands/skills.js', 'registerSkillsCommands'],
69
+ ['../commands/claude.js', 'registerClaudeCommands'],
70
+ ['../commands/monitoring.js', 'registerMonitoringCommands'],
71
+ ['../commands/trigger.js', 'registerTriggerCommands'],
72
+ ['../commands/webhook.js', 'registerWebhookCommands'],
73
+ ['../commands/sso.js', 'registerSsoCommands'],
74
+ ['../commands/role.js', 'registerRoleCommands'],
75
+ ['../commands/domain.js', 'registerDomainCommands'],
76
+ ['../commands/security.js', 'registerSecurityCommands'],
77
+ ['../commands/safety.js', 'registerSafetyCommands'],
78
+ ['../commands/scim.js', 'registerScimCommands'],
79
+ ['../commands/llm-policy.js', 'registerLlmPolicyCommands'],
80
+ ['../commands/hat.js', 'registerHatCommands'],
81
+ ['../commands/rows.js', 'registerRowsCommands'],
82
+ ['../commands/settings.js', 'registerSettingsCommands'],
83
+ ['../commands/llm.js', 'registerLlmCommands'],
84
+ ['../commands/capabilities.js', 'registerCapabilitiesCommands'],
85
+ ['../commands/provider.js', 'registerProviderCommands'],
86
+ ['../commands/tips.js', 'registerTipsCommands'],
87
+ ['../commands/ext.js', 'registerExtCommands'],
88
+ ['../commands/quoxchat.js', 'registerQuoxchatCommands'],
89
+ ['../commands/budget.js', 'registerBudgetCommands'],
90
+ ['../commands/trace.js', 'registerTraceCommands'],
91
+ ['../commands/mon.js', 'registerMonCommands'],
92
+ ['../commands/kuma.js', 'registerKumaCommands'],
93
+ ['../commands/quoxbox.js', 'registerQuoxboxCommands'],
94
+ ['../commands/plan.js', 'registerPlanCommands'],
95
+ ['../commands/engagement.js', 'registerEngagementCommands'],
96
+ ['../commands/done.js', 'registerDoneCommands'],
97
+ ['../commands/discord.js', 'registerDiscordCommands'],
98
+ ['../commands/qlarity.js', 'registerQlarityCommands'],
99
+ ['../commands/fetchAllowlist.js', 'registerFetchAllowlistCommands'],
100
+ ['../commands/research.js', 'registerResearchCommands'],
101
+ ['../commands/reach.js', 'registerReachCommands'],
102
+ ['../commands/inventory.js', 'registerInventoryCommands'],
103
+ ['../commands/policy.js', 'registerPolicyCommands'],
104
+ ['../commands/quoxseo.js', 'registerQuoxseoCommands'],
105
+ ['../commands/voice.js', 'registerVoiceCommands'],
106
+ ['../commands/awareness.js', 'registerAwarenessCommands'],
107
+ ['../commands/mind.js', 'registerMindCommands'],
108
+ ['../commands/lucid.js', 'registerLucidCommands'],
109
+ ['../commands/hyperion.js', 'registerHyperionCommands'],
110
+ ['../commands/tg.js', 'registerTgCommands'],
111
+ ['../commands/dev.js', 'registerDevCommands'],
112
+ ['../commands/build.js', 'registerBuildCommands'],
113
+ ['../commands/slot.js', 'registerSlotCommands'],
114
+ ['../commands/gripe.js', 'registerGripeCommands'],
115
+ ['../commands/ask.js', 'registerAskCommands'],
116
+ ['../commands/presence.js', 'registerPresenceCommands'],
117
+ ['../commands/dashboard.js', 'registerDashboardCommands'],
118
+ ['../commands/nucleus.js', 'registerNucleusCommands'],
119
+ ['../commands/onboard.js', 'registerOnboardCommands'],
120
+ ['../commands/x.js', 'registerXCommands'],
121
+ ['../commands/linkedin.js', 'registerLinkedInCommands'],
122
+ ['../commands/facebook.js', 'registerFacebookCommands'],
123
+ ['../commands/instagram.js', 'registerInstagramCommands'],
124
+ ['../commands/tiktok.js', 'registerTikTokCommands'],
125
+ ['../commands/youtube.js', 'registerYouTubeCommands'],
126
+ ['../commands/image.js', 'registerImageCommands'],
127
+ ['../commands/offload.js', 'registerOffloadCommands'],
128
+ ];
129
+
130
+ export const COMMAND_REGISTRARS_BASE = import.meta.url;
@@ -7,7 +7,7 @@
7
7
 
8
8
  import { existsSync, mkdirSync, readFileSync, writeFileSync, chmodSync, renameSync, openSync, closeSync, statSync, unlinkSync, copyFileSync } from 'node:fs';
9
9
  import { join } from 'node:path';
10
- import { homedir } from 'node:os';
10
+ import { homedir, networkInterfaces, hostname as osHostname } from 'node:os';
11
11
 
12
12
  function getConfigDir() { return join(homedir(), '.config', 'quox'); }
13
13
  function getConfigFile() { return join(getConfigDir(), 'config.json'); }
@@ -94,35 +94,118 @@ function isPrivateHost(hostname) {
94
94
  return a === 10 || (a === 172 && b >= 16 && b <= 31) || (a === 192 && b === 168);
95
95
  }
96
96
 
97
- // Pure port-swap derivation, extracted so it is unit-testable without a
98
- // full config/profile fixture. Given a base URL (normally the ACTIVE
99
- // profile's own `url`, never a global default), swap in the target
100
- // service's port and return the origin. See getServiceUrl step 3 for the
101
- // loopback scheme-downgrade rule this also carries.
97
+ // QUOXON-Z2H lane R (2026-10-14): where the edge (nginx on the profile's base
98
+ // URL) serves each compose service. Mirrors nginx.conf: /api/auth, /api/setup,
99
+ // /api/orgs ... go to auth at the SAME path, so auth's prefix is empty.
100
+ export const EDGE_PATHS = {
101
+ auth: '',
102
+ collector: '/collector',
103
+ memory: '/api/memory',
104
+ tasks: '/tasks',
105
+ orchestrator: '/orchestrator',
106
+ quoxflow: '/quoxflow',
107
+ quoxbrain: '/api/quoxbrain',
108
+ files: '/files-api',
109
+ };
110
+
111
+ // The local edge's default port. A loopback base on this port is the stack on
112
+ // THIS box, whose services are reachable on their plain-http loopback binds.
113
+ // Any other loopback port is a tunnel (ssh -L 13105:vm:3000) to another box.
114
+ const LOCAL_EDGE_PORTS = new Set(['3000']);
115
+
116
+ function localIdentity(opts = {}) {
117
+ let localAddrs = opts.localAddrs;
118
+ if (!localAddrs) {
119
+ localAddrs = [];
120
+ try {
121
+ for (const list of Object.values(networkInterfaces())) {
122
+ for (const a of list || []) localAddrs.push(a.address);
123
+ }
124
+ } catch { /* no interfaces readable: treat nothing as local */ }
125
+ }
126
+ let host = opts.hostname;
127
+ if (host === undefined) { try { host = osHostname(); } catch { host = ''; } }
128
+ return { localAddrs: new Set(localAddrs), hostname: String(host || '').toLowerCase() };
129
+ }
130
+
131
+ function isThisMachine(hostname, id) {
132
+ const h = String(hostname || '').toLowerCase().replace(/^\[|\]$/g, '');
133
+ if (LOOPBACK_HOSTS.has(h) || LOOPBACK_HOSTS.has(`[${h}]`)) return true;
134
+ if (id.localAddrs.has(h)) return true;
135
+ return !!id.hostname && (h === id.hostname || h === `${id.hostname}.local`);
136
+ }
137
+
138
+ /**
139
+ * True when a service URL lands on THIS machine (loopback bind, or a base whose
140
+ * host is one of this box's own addresses) rather than another host or a tunnel
141
+ * to one. Used to keep this box's ambient QUOX_SERVICE_KEY from being offered
142
+ * to a remote instance.
143
+ */
144
+ export function isLocalServiceTarget(serviceUrl, opts = {}) {
145
+ try {
146
+ const u = new URL(serviceUrl);
147
+ const id = localIdentity(opts);
148
+ if (LOOPBACK_HOSTS.has(u.hostname)) {
149
+ // Loopback is this box when it is the local edge or a compose service
150
+ // bind; any other loopback port is a tunnel to another box.
151
+ const port = u.port || (u.protocol === 'https:' ? '443' : '80');
152
+ return LOCAL_EDGE_PORTS.has(port) || Object.values(SERVICE_PORTS).map(String).includes(port);
153
+ }
154
+ return isThisMachine(u.hostname, id);
155
+ } catch {
156
+ return false;
157
+ }
158
+ }
159
+
160
+ /** Join an absolute or relative path onto a service URL WITHOUT dropping its path prefix (new URL('/x', base) would). */
161
+ export function joinServiceUrl(serviceUrl, path) {
162
+ const base = new URL(serviceUrl);
163
+ const prefix = base.pathname.replace(/\/+$/, '');
164
+ const rel = new URL(String(path).replace(/^\/*/, '/'), 'http://x');
165
+ base.pathname = `${prefix}${rel.pathname}`;
166
+ base.search = rel.search;
167
+ base.hash = '';
168
+ return base;
169
+ }
170
+
171
+ // Derivation of a compose service's URL from a profile base URL (normally the
172
+ // ACTIVE profile's own `url`, never a global default).
102
173
  //
103
- // DEVSUITE-GRIPE-P7 / Bug A: this used to be computed from getBaseUrl(),
104
- // which honours the global QUOX_URL env override BEFORE the active
105
- // profile's own url. That meant `-p <profile>` picked which profile's
106
- // token/services were used, but a QUOX_URL left set in the shell silently
107
- // overrode which HOST every derived service URL (auth, memory, etc.)
108
- // pointed at — `quox -p vulcan-proof signup ...` derived the auth base
109
- // from whatever QUOX_URL said, not from vulcan-proof's own url. Deriving
110
- // directly from the profile url here means -p is authoritative for service
111
- // URL derivation the same way it already is for auth/services overrides.
112
- export function deriveServiceUrl(baseUrl, port) {
174
+ // QUOXON-Z2H lane R: the base URL is the single source of truth. Port guessing
175
+ // is ONLY for the stack on this very machine:
176
+ // - loopback base on the local edge port (:3000): plain-http loopback port
177
+ // swap (BRAIN2-AUDIT: compose services are plain HTTP);
178
+ // - private-LAN base whose host is one of THIS box's addresses: the
179
+ // loopback bind (#572/#623: services bind 127.0.0.1, only :3000 is on LAN).
180
+ // Everything else (another LAN host, a tunnel on a loopback port, a public
181
+ // host) goes through that base's edge at the service's nginx path. The old
182
+ // rule rewrote ANY RFC1918 base to 127.0.0.1:<port>, so `quox -p vm9110 login`
183
+ // against https://192.0.2.68:3000 was sent to this box's own auth service
184
+ // and got 401 invalid_credentials, and a tunnel profile hit local ports.
185
+ //
186
+ // DEVSUITE-GRIPE-P7 / Bug A: computed from the profile url, not getBaseUrl(),
187
+ // so a stale QUOX_URL cannot defeat -p.
188
+ export function deriveServiceUrl(baseUrl, port, service, opts = {}) {
113
189
  try {
114
190
  const url = new URL(baseUrl);
115
- url.port = String(port);
116
- if (LOOPBACK_HOSTS.has(url.hostname)) {
117
- // Loopback base: force http (compose services are plain HTTP); keep the
118
- // hostname as-is (localhost stays localhost — already reachable).
191
+ const id = localIdentity(opts);
192
+ const basePort = url.port || (url.protocol === 'https:' ? '443' : '80');
193
+ if (LOOPBACK_HOSTS.has(url.hostname) && LOCAL_EDGE_PORTS.has(basePort)) {
194
+ url.port = String(port);
119
195
  url.protocol = 'http:';
120
- } else if (isPrivateHost(url.hostname)) {
121
- // Private-LAN base: the service binds loopback, so point at the reachable
122
- // bind (#572/#623). Public/remote hosts fall through unchanged.
196
+ return url.origin;
197
+ }
198
+ if (!LOOPBACK_HOSTS.has(url.hostname) && isPrivateHost(url.hostname) && isThisMachine(url.hostname, id)) {
199
+ url.port = String(port);
123
200
  url.protocol = 'http:';
124
201
  url.hostname = '127.0.0.1';
202
+ return url.origin;
203
+ }
204
+ if (service && Object.prototype.hasOwnProperty.call(EDGE_PATHS, service)) {
205
+ return `${url.origin}${url.pathname.replace(/\/+$/, '')}${EDGE_PATHS[service]}`;
125
206
  }
207
+ // A port-mapped service with no edge route: the old port swap is the only guess left.
208
+ url.port = String(port);
126
209
  return url.origin;
127
210
  } catch {
128
211
  return baseUrl;
@@ -137,7 +220,7 @@ export function deriveServiceUrl(baseUrl, port) {
137
220
  // only correct source for the flag at ctx-build time.
138
221
  // Commands whose remaining argv belongs to another program (`quox claude -p
139
222
  // "prompt"` is claude's --print, not quox's --profile).
140
- const WRAPPED_PROGRAM_COMMANDS = new Set(['claude', 'codex', 'gemini', 'wrap']);
223
+ const WRAPPED_PROGRAM_COMMANDS = new Set(['claude', 'codex', 'wrap']);
141
224
 
142
225
  export function resolveProfileFlagFromArgv(argv) {
143
226
  for (let i = 0; i < argv.length; i++) {
@@ -227,6 +310,9 @@ export function loadConfig(profileOverride) {
227
310
  // The profile this invocation is using (persisted default, or the -p /
228
311
  // QUOX_PROFILE override for this process only). Never written to _data.
229
312
  _effectiveProfile: effectiveProfile,
313
+ // quox#805: a profile passed explicitly to loadConfig(profile) means "act as
314
+ // that profile's user", same as -p on the CLI (no implicit attach default).
315
+ _explicitProfile: Boolean(profileOverride),
230
316
 
231
317
  getActiveProfile() {
232
318
  const name = this._effectiveProfile;
@@ -325,6 +411,38 @@ export function loadConfig(profileOverride) {
325
411
  this.save();
326
412
  },
327
413
 
414
+ // Stale-sign-in fix: another window or `quox login` may have written fresher credentials for this
415
+ // profile since this process loaded. Re-read ONLY the active profile's auth from disk and adopt it in
416
+ // place (callers hold profile refs). Returns true when the auth changed. Never logs or returns a token.
417
+ reloadAuth() {
418
+ try {
419
+ const name = this._effectiveProfile;
420
+ const disk = JSON.parse(readFileSync(getConfigFile(), 'utf-8'));
421
+ const dAuth = disk?.profiles?.[name]?.auth ?? null;
422
+ const prof = this._data.profiles?.[name];
423
+ if (!prof || dAuth == null) return false;
424
+ if (J(prof.auth) === J(dAuth)) return false;
425
+ prof.auth = dAuth;
426
+ // The loaded snapshot now agrees with disk for auth, so save() does not treat it as our change.
427
+ try {
428
+ const snap = JSON.parse(this._loadedProfiles[name] || '{}');
429
+ snap.auth = dAuth;
430
+ this._loadedProfiles[name] = J(snap);
431
+ } catch { /* snapshot is advisory */ }
432
+ this._clearedAuth.delete(name);
433
+ this._refreshedAuth.delete(name);
434
+ return true;
435
+ } catch { return false; }
436
+ },
437
+
438
+ /** mtime (ms) of the credentials file, or 0. A cheap stat for "did anything sign in elsewhere". */
439
+ credentialsMtime() {
440
+ try { return statSync(getConfigFile()).mtimeMs; } catch { return 0; }
441
+ },
442
+
443
+ /** Cross-process refresh lock file, next to the credentials. */
444
+ refreshLockFile() { return `${getConfigFile()}.refresh.lock`; },
445
+
328
446
  setAuth(authData, opts = {}) {
329
447
  const profile = this.getActiveProfile();
330
448
  if (!profile) throw new Error('No active profile.');
@@ -400,7 +518,7 @@ export function loadConfig(profileOverride) {
400
518
  // and the shared services config (step 2) still say exactly what they
401
519
  // say, and a remote/non-loopback host keeps its scheme (a real
402
520
  // deployment may terminate TLS per port).
403
- return deriveServiceUrl(profileUrl, port);
521
+ return deriveServiceUrl(profileUrl, port, service);
404
522
  },
405
523
 
406
524
  get(key) {
@@ -0,0 +1,168 @@
1
+ /**
2
+ * CUSTOM-HATS (owner 2026-10-17): pure helpers that build and edit a custom hat definition.
3
+ * Shared by `quox hat create|edit` (cli/lib/commands/hat.js) and the quox window's /hat new|edit
4
+ * (cli/lib/quoxon). No I/O, no chalk: safe to import anywhere.
5
+ */
6
+
7
+ /** The two tools an orchestrator needs to reach the agents a hat lists. */
8
+ export const DELEGATION_TOOLS = ['delegate_to_agent', 'agent_directory'];
9
+ export const HAT_MODES = ['permissive', 'restrictive'];
10
+ export const HAT_OFFERS = ['members', 'authorized'];
11
+ const HARD_CAP = 128;
12
+
13
+ /** "a, b,,c" -> ['a','b','c'] (trimmed, lowercased, deduped, order kept). */
14
+ export function parseList(v) {
15
+ if (v === undefined || v === null || v === true) return [];
16
+ const out = [];
17
+ for (const raw of String(v).split(',')) {
18
+ const x = raw.trim().toLowerCase();
19
+ if (x && !out.includes(x)) out.push(x);
20
+ }
21
+ return out;
22
+ }
23
+
24
+ /** Every tool name a hat names: explicit, bundles, on-demand reads. */
25
+ export function memberTools(def) {
26
+ const t = def?.tools || {};
27
+ const names = [
28
+ ...(Array.isArray(t.explicit) ? t.explicit : []),
29
+ ...(Array.isArray(t.bundles) ? t.bundles.flatMap(b => (Array.isArray(b?.tools) ? b.tools : [])) : []),
30
+ ...(Array.isArray(t.on_demand_reads) ? t.on_demand_reads : []),
31
+ ];
32
+ return [...new Set(names)];
33
+ }
34
+
35
+ function emptyDefinition() {
36
+ return {
37
+ schema_version: 1,
38
+ purpose: '',
39
+ agents: { orchestrator: 'quox', specialists: [] },
40
+ tools: { explicit: [], bundles: [], connector_families: [] },
41
+ budgets: { initial_tool_target: 12, max_manifest: 32 },
42
+ transitions: { allowed: 'any', confirm: 'none', privileged: false },
43
+ };
44
+ }
45
+
46
+ function ensureDelegationTools(def) {
47
+ const specialists = def.agents?.specialists || [];
48
+ if (!specialists.length) return [];
49
+ const explicit = def.tools.explicit;
50
+ const added = DELEGATION_TOOLS.filter(t => !explicit.includes(t));
51
+ explicit.unshift(...added);
52
+ return added;
53
+ }
54
+
55
+ function fitBudgets(def) {
56
+ const b = def.budgets || (def.budgets = {});
57
+ const need = (def.tools.explicit || []).length;
58
+ if (!Number.isInteger(b.max_manifest) || b.max_manifest < need) b.max_manifest = Math.min(HARD_CAP, Math.max(32, need));
59
+ if (!Number.isInteger(b.initial_tool_target) || b.initial_tool_target < 1) b.initial_tool_target = Math.min(12, b.max_manifest);
60
+ if (b.initial_tool_target > b.max_manifest) b.initial_tool_target = b.max_manifest;
61
+ }
62
+
63
+ /**
64
+ * Restrictive = the hat AUTHORIZES only its members (+ the delegation pair); this binds every agent
65
+ * working under the hat, the hat's own agents included when delegated to. Permissive = the agent's
66
+ * own grant is the ceiling (the default). A deny list carried from --from is kept either way.
67
+ */
68
+ export function applyMode(def, mode) {
69
+ if (mode === undefined || mode === null) return;
70
+ if (!HAT_MODES.includes(mode)) throw new Error(`--mode must be ${HAT_MODES.join(' or ')} (got '${mode}')`);
71
+ const deny = Array.isArray(def.authz?.deny) ? def.authz.deny : null;
72
+ if (mode === 'permissive') {
73
+ if (deny) def.authz = { mode: 'permissive', deny };
74
+ else delete def.authz;
75
+ return;
76
+ }
77
+ def.authz = { mode: 'restrictive', allow: [...new Set([...memberTools(def), ...DELEGATION_TOOLS])], ...(deny ? { deny } : {}) };
78
+ }
79
+
80
+ /**
81
+ * The definition a new custom hat starts from: a copy of --from (or an empty hat), with
82
+ * --agents / --tools REPLACING the lists, the delegation tools added when the hat lists agents,
83
+ * the offer set (default 'members': a custom hat offers its orchestrator only what it lists),
84
+ * and budgets widened to fit. Pure: never mutates base.
85
+ */
86
+ export function buildCustomDefinition({ base = null, name = '', purpose, agents, tools, mode, offer } = {}) {
87
+ const def = base ? JSON.parse(JSON.stringify(base)) : emptyDefinition();
88
+ def.schema_version = 1;
89
+ def.agents = { orchestrator: 'quox', ...(def.agents || {}) };
90
+ if (!Array.isArray(def.agents.specialists)) def.agents.specialists = [];
91
+ def.tools = { ...(def.tools || {}) };
92
+ def.tools.explicit = Array.isArray(def.tools.explicit) ? [...def.tools.explicit] : [];
93
+ if (agents !== undefined) def.agents.specialists = [...agents];
94
+ if (tools !== undefined) def.tools.explicit = [...tools];
95
+ const autoAdded = ensureDelegationTools(def);
96
+ const o = offer === undefined ? 'members' : offer;
97
+ if (!HAT_OFFERS.includes(o)) throw new Error(`--offer must be ${HAT_OFFERS.join(' or ')} (got '${o}')`);
98
+ def.tools.offer = o;
99
+ if (purpose !== undefined && String(purpose).trim()) def.purpose = String(purpose).trim();
100
+ if (!def.purpose || base) {
101
+ if (purpose === undefined || !String(purpose).trim()) def.purpose = `${name || 'Custom'} work${def.agents.specialists.length ? ` with ${def.agents.specialists.join(', ')}` : ''}`;
102
+ }
103
+ fitBudgets(def);
104
+ applyMode(def, mode);
105
+ return { definition: def, autoAdded };
106
+ }
107
+
108
+ /**
109
+ * Apply `quox hat edit` options to a copy of a definition. Returns the new definition and a
110
+ * human list of changes (empty = nothing to do). --agents/--tools replace; --add-* / --remove-*
111
+ * adjust. A restrictive allow list follows tool adds/removes so the hat keeps authorizing exactly
112
+ * its members.
113
+ */
114
+ export function applyHatEdits(current, opts = {}) {
115
+ const def = JSON.parse(JSON.stringify(current || {}));
116
+ def.agents = { orchestrator: 'quox', ...(def.agents || {}) };
117
+ def.tools = { ...(def.tools || {}) };
118
+ let specialists = Array.isArray(def.agents.specialists) ? [...def.agents.specialists] : [];
119
+ let explicit = Array.isArray(def.tools.explicit) ? [...def.tools.explicit] : [];
120
+ const changes = [];
121
+ const beforeAgents = [...specialists];
122
+ const beforeTools = new Set(memberTools(def));
123
+
124
+ if (opts.agents !== undefined) specialists = [...opts.agents];
125
+ for (const a of opts.addAgents || []) if (!specialists.includes(a)) specialists.push(a);
126
+ if ((opts.removeAgents || []).length) specialists = specialists.filter(a => !opts.removeAgents.includes(a));
127
+ if (opts.tools !== undefined) explicit = [...opts.tools];
128
+ for (const t of opts.addTools || []) if (!explicit.includes(t)) explicit.push(t);
129
+ if ((opts.removeTools || []).length) {
130
+ explicit = explicit.filter(t => !opts.removeTools.includes(t));
131
+ if (Array.isArray(def.tools.bundles)) def.tools.bundles = def.tools.bundles.map(b => ({ ...b, tools: (b.tools || []).filter(t => !opts.removeTools.includes(t)) }));
132
+ }
133
+ def.agents.specialists = specialists;
134
+ def.tools.explicit = explicit;
135
+ const autoAdded = (opts.removeTools || []).some(t => DELEGATION_TOOLS.includes(t)) ? [] : ensureDelegationTools(def);
136
+
137
+ const agentsAdded = specialists.filter(a => !beforeAgents.includes(a));
138
+ const agentsRemoved = beforeAgents.filter(a => !specialists.includes(a));
139
+ if (agentsAdded.length) changes.push(`agents +${agentsAdded.join(', +')}`);
140
+ if (agentsRemoved.length) changes.push(`agents -${agentsRemoved.join(', -')}`);
141
+ const afterTools = new Set(memberTools(def));
142
+ const toolsAdded = [...afterTools].filter(t => !beforeTools.has(t));
143
+ const toolsRemoved = [...beforeTools].filter(t => !afterTools.has(t));
144
+ if (toolsAdded.length) changes.push(`tools +${toolsAdded.join(', +')}`);
145
+ if (toolsRemoved.length) changes.push(`tools -${toolsRemoved.join(', -')}`);
146
+
147
+ if (opts.purpose !== undefined && String(opts.purpose).trim() && String(opts.purpose).trim() !== def.purpose) {
148
+ def.purpose = String(opts.purpose).trim();
149
+ changes.push('purpose');
150
+ }
151
+ if (opts.offer !== undefined) {
152
+ if (!HAT_OFFERS.includes(opts.offer)) throw new Error(`--offer must be ${HAT_OFFERS.join(' or ')} (got '${opts.offer}')`);
153
+ if ((def.tools.offer || 'authorized') !== opts.offer) { def.tools.offer = opts.offer; changes.push(`offer ${opts.offer}`); }
154
+ }
155
+ const prevMode = def.authz?.mode === 'restrictive' ? 'restrictive' : 'permissive';
156
+ if (opts.mode !== undefined) {
157
+ applyMode(def, opts.mode);
158
+ if (opts.mode !== prevMode) changes.push(`mode ${opts.mode}`);
159
+ } else if (prevMode === 'restrictive' && Array.isArray(def.authz?.allow) && (toolsAdded.length || toolsRemoved.length)) {
160
+ const allow = new Set(def.authz.allow);
161
+ for (const t of toolsAdded) allow.add(t);
162
+ for (const t of toolsRemoved) allow.delete(t);
163
+ def.authz = { ...def.authz, allow: [...allow] };
164
+ }
165
+ fitBudgets(def);
166
+ return { definition: def, changes, autoAdded };
167
+ }
168
+
@@ -145,6 +145,14 @@ export async function fetchEngine({ dest, needsSudo, force, client, execFn, fsOp
145
145
  }
146
146
 
147
147
  const res = await client.get('/download/quoxgauge-bundle.tar.gz', { service: 'collector', raw: true });
148
+ // #988: a public install's collector has no DoneEngine bundle (dev servers build it from the private quox-gauge
149
+ // repo), so a 404 is a fact about this install, not a transient failure worth retrying.
150
+ if (res && res.status === 404) {
151
+ const err = new Error('DoneEngine is not part of this Quox install: this collector does not carry the DoneEngine bundle '
152
+ + '(it is delivered to Quox dev servers by `quox dev enable`). Nothing was changed.');
153
+ err.code = 'DONEENGINE_NOT_SHIPPED';
154
+ throw err;
155
+ }
148
156
  if (!res || !res.ok) {
149
157
  throw new Error(`Bundle download failed (status ${res ? res.status : 'no response'}) from /download/quoxgauge-bundle.tar.gz`);
150
158
  }