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,89 @@
1
+ /**
2
+ * /automate [task]: turn the conversation (or the task you name) into a persistent workflow.
3
+ * Real: the draft is ONE model call (draft.js); creation uses the quoxflow workflow store (POST /api/workflows) and
4
+ * activation registers its trigger (POST /api/workflows/:id/activate), the same calls as `quox workflow apply` and
5
+ * `quox trigger workflow-activate`. The model only fills a small, validated shape; node types are an allowlist.
6
+ */
7
+ import { draftJson, transcriptText } from './draft.js';
8
+
9
+ const STEP_TYPES = new Set(['agent:invoke', 'approval:gate', 'notification:deliver', 'util:log']);
10
+ const CRON_RE = /^\s*\S+(\s+\S+){4}\s*$/;
11
+ const why = (e) => `${e?.status ? `HTTP ${e.status}: ` : ''}${e?.message || 'failed'}`;
12
+ const slug = (s) => String(s).toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '').slice(0, 40) || 'workflow';
13
+
14
+ export const automatePrompt = (context) => [
15
+ 'Draft a persistent automation from the conversation below. Reply with ONE JSON object and nothing else. Use no tools.',
16
+ 'Shape: {"name":str,"description":str,"trigger":{"type":"schedule","cron":"5-field cron","timezone":"UTC"} or {"type":"webhook","path":"/name"},',
17
+ ' "steps":[{"id":str,"type":"agent:invoke"|"approval:gate"|"notification:deliver"|"util:log","label":str,"prompt":str (agent:invoke) or "message":str (others)}],',
18
+ ' "recovery":{"onFailure":"stop"|"continue","retry":bool}}.',
19
+ 'Infer the trigger and schedule from what the user wants; add an approval:gate before anything irreversible or external; keep 2 to 6 steps.',
20
+ '', '--- conversation ---', context, '--- end ---'
21
+ ].join('\n');
22
+
23
+ /** Validate the model draft and build the quoxflow workflow definition. -> { def, card[] } or { error } */
24
+ export function buildWorkflow(d, now = Date.now()) {
25
+ if (!d || typeof d.name !== 'string' || !d.name.trim()) return { error: 'the draft has no name' };
26
+ const t = d.trigger || {};
27
+ let trigger;
28
+ if (t.type === 'schedule' && typeof t.cron === 'string' && CRON_RE.test(t.cron)) trigger = { id: 'trigger', type: 'trigger:schedule', config: { cron: t.cron.trim(), timezone: t.timezone || 'UTC' } };
29
+ else if (t.type === 'webhook' && typeof t.path === 'string' && t.path.trim()) trigger = { id: 'trigger', type: 'trigger:webhook', config: { path: t.path.trim(), method: 'POST' } };
30
+ else return { error: 'the draft has no valid trigger (a 5-field cron schedule or a webhook path)' };
31
+ const steps = Array.isArray(d.steps) ? d.steps : [];
32
+ if (!steps.length || steps.length > 8) return { error: 'the draft needs between 1 and 8 steps' };
33
+ const nodes = [trigger];
34
+ for (const [i, s] of steps.entries()) {
35
+ if (!s || !STEP_TYPES.has(s.type)) return { error: `step ${i + 1} has a type that is not allowed (${s?.type})` };
36
+ const id = `s${i + 1}`, label = String(s.label || s.type);
37
+ const text = String(s.prompt || s.message || '').trim();
38
+ if (!text) return { error: `step ${i + 1} (${label}) has no prompt or message` };
39
+ const config = s.type === 'agent:invoke' ? { agent_id: 'quox', prompt: text, label }
40
+ : s.type === 'approval:gate' ? { label, message: text, approvers: ['*'], expiresIn: '48h' }
41
+ : s.type === 'notification:deliver' ? { title: label, message: text }
42
+ : { level: 'info', message: text, label };
43
+ nodes.push({ id, type: s.type, config });
44
+ }
45
+ const edges = nodes.slice(1).map((n, i) => ({ source: nodes[i].id, target: n.id }));
46
+ const stop = (d.recovery?.onFailure || 'stop') !== 'continue';
47
+ const retry = d.recovery?.retry === true;
48
+ const def = {
49
+ id: `${slug(d.name)}-${now.toString(36)}`, name: d.name.trim(), description: String(d.description || '').slice(0, 500),
50
+ nodes, edges, settings: { errorBehavior: stop ? 'stop' : 'continue', retryOnFailure: retry, saveEvidence: true },
51
+ metadata: { source: 'quoxon /automate' }
52
+ };
53
+ const when = trigger.type === 'trigger:schedule' ? `schedule ${trigger.config.cron} (${trigger.config.timezone})` : `webhook POST ${trigger.config.path}`;
54
+ const gates = nodes.filter((n) => n.type === 'approval:gate').map((n) => n.config.label);
55
+ const card = [
56
+ ['Workflow draft (nothing is created until you answer):', 'accent'],
57
+ ` Name ${def.name}`,
58
+ ` Trigger ${when}`,
59
+ ` Steps ${nodes.slice(1).map((n) => n.config.label || n.type).join(' > ')}`,
60
+ ` Approvals ${gates.length ? gates.join(', ') : 'none (it runs without asking)'}`,
61
+ ` Recovery ${stop ? 'stop on failure' : 'continue on failure'}${retry ? ', retry on' : ''}`
62
+ ];
63
+ return { def, card };
64
+ }
65
+
66
+ export function createAutomateCmd({ api, say, confirm, getState, getFields }) {
67
+ return {
68
+ async handle(arg) {
69
+ if (!api.workflowCreate) return say('Workflows are not available in this mode.', 'warn');
70
+ const ctx = [transcriptText(getState()), String(arg || '').trim() ? `User wants to automate: ${String(arg).trim()}` : ''].filter(Boolean).join('\n');
71
+ if (!ctx) return say('Nothing to automate yet. Do the task with Quox first, or say what: /automate every monday send me a signup digest.');
72
+ say('Drafting the workflow…', 'dim');
73
+ let d;
74
+ try { d = await draftJson({ api, prompt: automatePrompt(ctx), fields: getFields() }); }
75
+ catch (e) { return say(`Could not draft a workflow: ${e.message}. Nothing was created.`, 'warn'); }
76
+ const b = buildWorkflow(d);
77
+ if (b.error) return say(`Could not draft a usable workflow: ${b.error}. Nothing was created.`, 'warn');
78
+ confirm.ask(b.card, async () => {
79
+ let c;
80
+ try { c = await api.workflowCreate(b.def); } catch (e) { return say(`Could not create the workflow: ${why(e)}`, 'warn'); }
81
+ const id = c?.id || b.def.id;
82
+ try { await api.workflowActivate(id); } catch (e) { say(`Workflow ${id} was created but NOT activated (${why(e)}), so it will not run on its own. quox trigger workflow-activate ${id}`, 'warn'); return say(` See it: /workflow ${id}`); }
83
+ say(`✔ Workflow "${b.def.name}" created and active (id ${id}).`, 'ok');
84
+ say(` See it: /workflow ${id}`);
85
+ }, { prompt: 'Create and activate this workflow?' });
86
+ return undefined;
87
+ }
88
+ };
89
+ }
@@ -0,0 +1,140 @@
1
+ /**
2
+ * QUOXON-BROADCAST: pure helpers for /broadcast, /page and /ack (and `quox slot broadcast`).
3
+ * No I/O. v1 scope: all held slots or --slots, --priority urgent, --ack, /page. Scheduling, voice,
4
+ * fleet and org reach, bulletins and drafting are not built.
5
+ */
6
+ export const BROADCAST_USAGE = 'Usage: /broadcast [--slots a,b] [--priority urgent] [--ack] <text>';
7
+ export const PAGE_USAGE = 'Usage: /page <slot> <text>';
8
+ const NOT_YET = new Set(['--fleet', '--org', '--voice', '--at']);
9
+
10
+ /**
11
+ * -> { ok:true, text, slots|null, priority, ack } | { ok:false, message }.
12
+ * Flags may come before the text; `--all` is accepted (the default). `--priority=urgent` also works.
13
+ */
14
+ export function parseBroadcastArgs(arg) {
15
+ const toks = String(arg || '').trim().split(/\s+/).filter(Boolean);
16
+ let slots = null; let priority = 'normal'; let ack = false;
17
+ let i = 0;
18
+ for (; i < toks.length && toks[i].startsWith('--'); i += 1) {
19
+ const [flag, inline] = toks[i].split(/=(.*)/s);
20
+ if (NOT_YET.has(flag)) return { ok: false, message: `${flag} is not available yet (v1 sends to held slots in this org: --slots, --priority, --ack).` };
21
+ if (flag === '--all') { slots = null; continue; }
22
+ if (flag === '--ack') { ack = true; continue; }
23
+ const val = inline !== undefined ? inline : toks[++i];
24
+ if (flag === '--slots') {
25
+ const list = String(val || '').split(',').map((s) => s.trim().toLowerCase()).filter(Boolean);
26
+ if (!list.length) return { ok: false, message: '--slots needs a comma-separated list, e.g. --slots provisioner,quox2' };
27
+ slots = list; continue;
28
+ }
29
+ if (flag === '--priority') {
30
+ if (val !== 'urgent' && val !== 'normal') return { ok: false, message: '--priority is urgent or normal' };
31
+ priority = val; continue;
32
+ }
33
+ return { ok: false, message: `unknown flag ${flag}. ${BROADCAST_USAGE}` };
34
+ }
35
+ const text = toks.slice(i).join(' ');
36
+ if (!text) return { ok: false, message: BROADCAST_USAGE };
37
+ return { ok: true, text, slots, priority, ack };
38
+ }
39
+
40
+ /** `/page <slot> <text>` -> urgent, ack-required, one recipient. */
41
+ export function parsePageArgs(arg) {
42
+ const m = /^(\S+)\s+([\s\S]*\S[\s\S]*)$/.exec(String(arg || '').trim());
43
+ if (!m || m[1].startsWith('--')) return { ok: false, message: PAGE_USAGE };
44
+ return { ok: true, text: m[2].trim(), slots: [m[1].toLowerCase()], priority: 'urgent', ack: true };
45
+ }
46
+
47
+ const plural = (n) => (n === 1 ? 'session' : 'sessions');
48
+ const NAMES_SHOWN = 5;
49
+ const okSlots = (r) => (r.deliveries || []).filter((d) => d.status === 'delivered' || d.status === 'queued'); // RESTORE-TUI: queued has it (older servers)
50
+ const badSlots = (r) => (r.deliveries || []).filter((d) => d.status === 'failed' || d.status === 'unknown');
51
+ const roomC = (r) => ({ sent: 0, sending: 0, failed: 0, ...(r?.counts?.room || {}) });
52
+ const isAck = (r) => !!(r?.ack ?? r?.ack_required);
53
+ const namesRow = (r) => {
54
+ const n = okSlots(r).map((d) => d.slot);
55
+ return n.length > NAMES_SHOWN ? `${n.slice(0, NAMES_SHOWN).join(' ')} +${n.length - NAMES_SHOWN}` : n.join(' ');
56
+ };
57
+ const roomText = (rc, sep) => [rc.sent && `${rc.sent} sent`, rc.sending && `${rc.sending} sending`, rc.failed && `${rc.failed} failed`].filter(Boolean).join(sep);
58
+ const failText = (d) => `${d.slot}: ${d.status}${d.detail ? ` (${d.detail})` : ''}`;
59
+ const titleWord = (r) => {
60
+ const c = r?.counts || {};
61
+ if (!c.total) return 'not sent';
62
+ if (!c.delivered) return 'not sent';
63
+ return c.failed ? 'partly sent' : 'sent';
64
+ };
65
+
66
+ /**
67
+ * The sender's delivery card as data: { title, tone, rows: [[[text, role], ...], ...], foot }.
68
+ * Roles are theme roles: ok (green), warn (gold), error (red), prose. Rendered by render.js (framed) or
69
+ * flattened to text. "delivered" means the line is in the slot; the chat-room copy is its own row.
70
+ */
71
+ export function broadcastCard(r, { kind = 'broadcast' } = {}) {
72
+ const c = r?.counts || {};
73
+ const rc = roomC(r);
74
+ const rows = [];
75
+ if (!c.total) rows.push([['\u26A0 no held slots in this org to hear it', 'warn']]);
76
+ else if (c.delivered) {
77
+ rows.push([[`\u2714 ${c.delivered} ${c.delivered === 1 ? 'session has' : 'sessions have'} it`, 'ok']]);
78
+ if (namesRow(r)) rows.push([[namesRow(r), 'prose']]); // an older server sends no per-slot list: no empty row
79
+ }
80
+ for (const d of badSlots(r).slice(0, 3)) rows.push([[`\u2716 ${failText(d)}`, 'error']]);
81
+ if (badSlots(r).length > 3) rows.push([[`\u2716 +${badSlots(r).length - 3} more failed`, 'error']]);
82
+ if (c.delivered && roomText(rc, ' ')) rows.push([[`chat rooms: ${roomText(rc, ' \u00B7 ')}`, rc.failed ? 'error' : rc.sending ? 'warn' : 'ok']]);
83
+ if (isAck(r) && c.delivered) rows.push([[`acknowledged ${c.acknowledged || 0} / ${c.delivered}`, c.awaiting ? 'warn' : 'ok']]);
84
+ const tone = !c.total || (!c.delivered && !c.failed) ? 'warn' : c.failed || !c.delivered ? 'error' : 'ok';
85
+ return {
86
+ title: `\u{1F4E3} ${kind === 'page' ? 'PAGE' : 'BROADCAST'} ${titleWord(r)}`,
87
+ tone, rows, foot: `${r.id} \u00B7 /broadcast status <id>`,
88
+ narrow: broadcastNarrow(r),
89
+ };
90
+ }
91
+
92
+ /** One line for narrow terminals. */
93
+ export function broadcastNarrow(r) {
94
+ const c = r?.counts || {};
95
+ const rc = roomC(r);
96
+ if (!c.total) return '\u{1F4E3} no held slots to hear it \u26A0';
97
+ const rooms = `(rooms ${rc.sent}/${c.delivered})`;
98
+ if (c.failed) return `\u{1F4E3} sent to ${c.delivered} of ${c.total} ${plural(c.total)} \u2716 ${c.failed} failed ${rooms}`;
99
+ const ack = isAck(r) ? ` \u00B7 acked ${c.acknowledged || 0}/${c.delivered}` : '';
100
+ return `\u{1F4E3} sent to ${c.delivered} ${plural(c.delivered)} \u2714 ${rooms}${ack}`;
101
+ }
102
+
103
+ /** The same facts as plain text lines [[text, tone]] (CLI output, and the TUI when no card surface is wired). */
104
+ export function broadcastSummary(r) {
105
+ const c = r?.counts || {};
106
+ const rc = roomC(r);
107
+ const lines = [];
108
+ if (!c.total) return [[`Broadcast ${r.id}: no held slots in this org to hear it.`, 'warn']];
109
+ lines.push([`Broadcast ${r.id} ${titleWord(r)}: ${(c.delivered || 0) + (c.queued || 0)} of ${c.total} ${plural(c.total)} have it${okSlots(r).length ? ` (${okSlots(r).map((d) => d.slot).join(', ')})` : ''}`, c.failed ? 'warn' : 'plain']);
110
+ if (c.delivered && roomText(rc, ', ')) lines.push([` chat rooms: ${roomText(rc, ', ')}`, rc.failed ? 'warn' : 'plain']);
111
+ for (const d of badSlots(r)) lines.push([` ${failText(d)}`, 'warn']);
112
+ if (isAck(r) && c.delivered) lines.push([` acknowledged ${c.acknowledged || 0} / ${c.delivered}. Check: quox slot broadcast-status ${r.id}`, 'plain']);
113
+ return lines;
114
+ }
115
+
116
+ /** The sender's live line: "Broadcast delivery: delivered N / acknowledged M / awaiting K". */
117
+ export function deliveryLine(st) {
118
+ const c = st?.counts || {};
119
+ const base = `Broadcast delivery: delivered ${(c.delivered || 0) + (c.queued || 0)}`; // RESTORE-TUI: an older server still counts queued separately; queued has it too
120
+ return st?.ack_required ? `${base} / acknowledged ${c.acknowledged || 0} / awaiting ${c.awaiting || 0}` : base;
121
+ }
122
+
123
+ /** `/broadcast status <id>` -> { id } | null (anything else after "status" is just message text). */
124
+ export function parseStatusArgs(arg) {
125
+ const m = /^status\s+(bc_[0-9a-f]+)\s*$/.exec(String(arg || '').trim());
126
+ return m ? { id: m[1] } : null;
127
+ }
128
+
129
+ const BC_RE = /^(\u{1F6A8} URGENT|\u{1F4E3}) BROADCAST from ([^\n]*?): ([\s\S]*?)(?:\n\(ack with \/ack (bc_[0-9a-f]+)\))?$/u;
130
+ /** Recognise a broadcast line in the slot stream -> { urgent, sender, text, ackId } | null. */
131
+ export function parseBroadcastText(text) {
132
+ const m = BC_RE.exec(String(text || ''));
133
+ return m ? { urgent: m[1] !== '\u{1F4E3}', sender: m[2], text: m[3], ackId: m[4] || null } : null;
134
+ }
135
+
136
+ export const ACK_USAGE = 'Usage: /ack <broadcast id>';
137
+ export function parseAckArgs(arg) {
138
+ const id = String(arg || '').trim();
139
+ return /^bc_[0-9a-f]+$/.test(id) ? { ok: true, id } : { ok: false, message: ACK_USAGE };
140
+ }
@@ -0,0 +1,108 @@
1
+ /**
2
+ * QUOXON-BROADCAST: the I/O half of /broadcast, /page and /ack. app.js adds only switch cases that call these.
3
+ * One server call fans out (POST /api/v1/slots/broadcast); with --ack the sender then sees the delivery line
4
+ * update as recipients acknowledge. The poll is display only: the broadcast and its acks live on the server.
5
+ */
6
+ import { parseBroadcastArgs, parsePageArgs, parseAckArgs, parseStatusArgs, broadcastSummary, broadcastCard, BROADCAST_USAGE } from './broadcast.js';
7
+
8
+ const roomC = (r) => ({ sent: 0, sending: 0, failed: 0, ...(r?.counts?.room || {}) });
9
+ const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
10
+
11
+ export async function runBroadcast({ api, kind, arg, from, say, card = null, isClosed = () => false, pollMs = 4000, maxPolls = 30 }) {
12
+ if (!api.slotBroadcast) return say('Broadcast is not available in this mode.', 'warn');
13
+ const show = (data) => {
14
+ if (card) return card(broadcastCard(data, { kind }));
15
+ for (const [line, tone] of broadcastSummary(data)) say(line, tone);
16
+ return undefined;
17
+ };
18
+ const st0 = kind === 'page' ? null : parseStatusArgs(arg);
19
+ if (st0) {
20
+ const st = api.slotBroadcastStatus ? await api.slotBroadcastStatus(st0.id) : { ok: false, message: 'not available in this mode' };
21
+ return st.ok ? show(st.data) : say(`Broadcast status failed: ${st.message}`, 'warn');
22
+ }
23
+ const parsed = kind === 'page' ? parsePageArgs(arg) : parseBroadcastArgs(arg);
24
+ if (!parsed.ok) return say(parsed.message, parsed.message === BROADCAST_USAGE ? 'plain' : 'warn');
25
+ const r = await api.slotBroadcast({ text: parsed.text, slots: parsed.slots, priority: parsed.priority, ack: parsed.ack, from });
26
+ if (!r.ok) return say(`${kind === 'page' ? 'Page' : 'Broadcast'} failed: ${r.message}`, 'warn');
27
+ show(r.data);
28
+ // PRESENCE: it reached a human slot whose human is away; approvals to them will queue.
29
+ if (r.data?.human_presence?.away && r.data.human_presence.notice) say(`⏸ ${r.data.human_presence.notice}`, 'warn');
30
+ // POKE-WAKE: a page also asks each delivered slot's keeper to wake its idle session, so the page is read now,
31
+ // not at the session's next prompt. Runs beside the ack display; the page stands whatever the wake says.
32
+ const wakes = kind === 'page' && api.slotControl
33
+ ? Promise.all((r.data.deliveries || []).filter((d) => d.status === 'delivered').map((d) => runWake({ api, slot: d.slot, say, isClosed, pollMs: Math.max(pollMs, 1), maxPolls: 15 }).catch(() => {})))
34
+ : null;
35
+ const done = async (v) => { if (wakes) await wakes; return v; };
36
+ if (!api.slotBroadcastStatus || !r.data.counts?.delivered) return done(undefined);
37
+ // The card is history (printed once), so what changes afterwards arrives as short lines: acks as they come in,
38
+ // and one line when the chat-room copies settle. Display only: the broadcast and its acks live on the server.
39
+ let lastAck = r.data.counts.acknowledged ?? null;
40
+ let roomsDone = !roomC(r.data).sending;
41
+ const ackWanted = parsed.ack && r.data.counts.awaiting > 0;
42
+ if (roomsDone && !ackWanted) return done(undefined);
43
+ for (let i = 0; i < maxPolls && !isClosed(); i += 1) {
44
+ await sleep(pollMs);
45
+ let st = null;
46
+ try { st = await api.slotBroadcastStatus(r.data.id); } catch { st = null; }
47
+ if (!st?.ok) continue;
48
+ const c = st.data.counts || {};
49
+ const rc = roomC(st.data);
50
+ if (!roomsDone && !rc.sending) {
51
+ roomsDone = true;
52
+ say(rc.failed ? `chat rooms: ${rc.sent} sent, ${rc.failed} failed` : `chat rooms: all ${rc.sent} sent`, rc.failed ? 'warn' : 'ok');
53
+ }
54
+ if (parsed.ack && c.acknowledged !== undefined && c.acknowledged !== lastAck) {
55
+ lastAck = c.acknowledged;
56
+ say(`acknowledged ${c.acknowledged} / ${c.delivered}`, c.awaiting ? 'plain' : 'ok');
57
+ }
58
+ if (roomsDone && !(parsed.ack && c.awaiting)) return done(undefined);
59
+ }
60
+ return done(undefined);
61
+ }
62
+
63
+ /**
64
+ * FORCE-WAKE: `/poke|/wake|/slap|/nudge <slot> [text]`. `--force` is accepted anywhere as a no-op (every human
65
+ * wake already sets an unsent draft aside and puts it back) and is never page text. null = no slot given.
66
+ */
67
+ export function parsePokeArgs(restArg) {
68
+ const s = String(restArg || '').replace(/(^|\s)--force(?=\s|$)/g, '$1').trim();
69
+ const m = /^(\S+)(?:\s+([\s\S]+))?$/.exec(s);
70
+ return m ? { slot: m[1], text: m[2] ? m[2].trim() : null } : null;
71
+ }
72
+
73
+ /**
74
+ * POKE-WAKE: ask the slot's keeper to wake its session (slot control `wake`, human admin only, server-side).
75
+ * The keeper types one fixed "read your slot" line at an empty prompt; never the page text. Display only.
76
+ */
77
+ export async function runWake({ api, slot, say, isClosed = () => false, pollMs = 4000, maxPolls = 15 }) {
78
+ const r = await api.slotControl(slot, 'wake');
79
+ if (!r?.ok) {
80
+ if (r?.status === 403) return say(`${slot}: waking a session needs an org owner or admin; the page waits for its next check`, 'warn');
81
+ if (r?.status === 400) return say(`${slot}: this server does not support wake yet; the page waits for its next check`, 'warn');
82
+ if (r?.status === 409) return say(`${slot}: nobody holds this slot, so there is no session to wake`, 'warn');
83
+ return say(`${slot}: wake request failed (${r?.message || 'failed'}); the page waits for its next check`, 'warn');
84
+ }
85
+ const id = r.data?.control_id;
86
+ if (!id || !api.slotControlGet) return say(`${slot}: wake requested`, 'plain');
87
+ for (let i = 0; i < maxPolls && !isClosed(); i += 1) {
88
+ await sleep(pollMs);
89
+ let g = null;
90
+ try { g = await api.slotControlGet(slot, id); } catch { g = null; }
91
+ const st = g?.ok ? g.data?.status : null;
92
+ // WAKE-REAL: the waker is told which happened: a turn started, or Claude Code queued it mid-turn.
93
+ if (st === 'done' && /^queued\b/.test(String(g.data.result || ''))) return say(`${slot} ${g.data.result}`, 'ok');
94
+ if (st === 'done') return say(`${slot} woken: ${g.data.result || 'done'}`, 'ok');
95
+ if (st === 'failed') return say(`${slot} not woken: ${String(g.data.result || 'failed').replace(/^not woken:\s*/, '')}`, 'warn');
96
+ }
97
+ return say(`${slot} not woken yet: it is mid-turn, so its keeper wakes it as soon as the turn ends (retrying up to 10m), or its keeper is not running (/slot status ${slot})`, 'warn');
98
+ }
99
+
100
+ export async function runAck({ api, arg, slot, say }) {
101
+ const a = parseAckArgs(arg);
102
+ if (!a.ok) return say(a.message, 'warn');
103
+ if (!slot) return say('/ack answers as the slot this window holds; hold one with /slot <name>.', 'warn');
104
+ if (!api.slotAck) return say('Broadcast is not available in this mode.', 'warn');
105
+ const r = await api.slotAck(a.id, slot);
106
+ if (!r.ok) return say(`ack failed: ${r.message}`, 'warn');
107
+ return say(`Acknowledged ${a.id} as ${slot}.`, 'plain');
108
+ }
@@ -0,0 +1,30 @@
1
+ /**
2
+ * One card, one y/n. The answer is the next composer line (the /approve "y/N" pattern); a slash command typed
3
+ * instead drops the card. A direct human ask is already the authorization, so the card is the only gate.
4
+ * (Own copy for /undo and /wish; kept in this file so it does not depend on another branch's helper.)
5
+ */
6
+ import { askText } from '../ask.js';
7
+ export function createCard({ say, now = () => Date.now(), ttlMs = 120000 }) {
8
+ let pending = null;
9
+ return {
10
+ pending: () => Boolean(pending),
11
+ /** y/N/c: a chat about the ask keeps it open with a fresh window. */
12
+ touch() { if (pending) pending.at = now(); },
13
+ ask(lines, onYes, cancelText, { question = 'Go ahead?', reason = '', who = '', action = '' } = {}) {
14
+ pending = { onYes, at: now(), cancelText };
15
+ for (const l of lines) say(l);
16
+ say(askText(question, { reason, who, action }), 'ask'); // QUOXON-ASK: one shape (live 22:41: /wish ended in a bare "y/n")
17
+ },
18
+ /** -> true when this line was the answer (consumed). */
19
+ answer(text) {
20
+ if (!pending) return false;
21
+ const q = pending; pending = null;
22
+ const t = String(text || '').trim();
23
+ if (t.startsWith('/')) return false;
24
+ if (now() - q.at > ttlMs) { say('That card expired, so nothing was done. Run the command again.', 'dim'); return true; }
25
+ if (/^y(es)?$/i.test(t)) { Promise.resolve(q.onYes()).catch((e) => say(`Failed: ${e?.message || e}`, 'warn')); return true; }
26
+ say(q.cancelText, 'dim');
27
+ return true;
28
+ }
29
+ };
30
+ }
@@ -0,0 +1,114 @@
1
+ /**
2
+ * /challenge [focus]: brutaloop on demand. One read-only adversarial review turn over the last answer and the
3
+ * last turn's tool calls, on a different provider when one is connected (else another model on the same
4
+ * provider, and it says which). Costs one extra model turn. "Resolve these? y/N" sends the findings back to
5
+ * the original agent as a normal turn.
6
+ *
7
+ * deps: api, say(text, tone), getState() -> the events state, sendTurn(text) -> a normal turn to the original agent.
8
+ */
9
+ import { askText } from '../ask.js';
10
+ import { connectedChoices } from '../model.js';
11
+ import { lastOutput } from '../dragonModes.js';
12
+ import { textGate } from '../events.js';
13
+
14
+ const MAX_FINDING_LINES = 40;
15
+ const newTurnId = () => `QXN_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
16
+
17
+ /** Tool items of the last turn: everything after the last user item. */
18
+ export function collectTools(s) {
19
+ const all = [...(s?.history || []), ...(s?.blocks || [])];
20
+ let from = 0;
21
+ for (let i = all.length - 1; i >= 0; i--) if (all[i].kind === 'user' && !all[i].echo) { from = i + 1; break; }
22
+ return all.slice(from).filter((it) => it.kind === 'tool');
23
+ }
24
+
25
+ const toolLine = (t) => {
26
+ const r = t.receipt?.ward_seq != null ? ` receipt ward:${t.receipt.ward_seq}` : '';
27
+ return `- ${t.tool}${t.target ? ` ${t.target}` : ''} [${t.status || 'unknown'}]${t.resultSummary || t.summary ? ` ${String(t.resultSummary || t.summary).slice(0, 200)}` : ''}${r}`;
28
+ };
29
+
30
+ export function reviewPrompt({ answer, tools = [], focus = '' }) {
31
+ return [
32
+ 'You are an adversarial reviewer. Another agent gave the answer below. Review it; do not call tools.',
33
+ 'Find: factual errors, unsupported claims, missed failures, unsafe actions.',
34
+ 'Output one finding per line as: SEVERITY | finding | evidence it rests on. SEVERITY is HIGH, MEDIUM or LOW.',
35
+ 'Every finding must cite its evidence (a tool call, a receipt, or the text of the answer). Do not rewrite the answer.',
36
+ 'If you find nothing, say "No findings" and why.',
37
+ focus ? `Focus especially on: ${focus}` : '',
38
+ '',
39
+ 'ANSWER UNDER REVIEW:', answer, '',
40
+ tools.length ? `TOOL CALLS AND RECEIPTS FROM THAT TURN:\n${tools.map(toolLine).join('\n')}` : 'No tool calls in that turn.',
41
+ ].filter((x) => x !== '').join('\n');
42
+ }
43
+
44
+ export const resolvePrompt = (findings) => `An independent reviewer challenged your last answer. For each finding below, fix it or rebut it with evidence, one by one:\n\n${findings}`;
45
+
46
+ /** -> { provider, model?, note } | null. connected: [{ provider }]; models: ids on the answering provider. */
47
+ export function pickReviewer({ connected, answered, models = [] }) {
48
+ const other = (connected || []).find((c) => c.provider && c.provider !== answered?.provider);
49
+ if (other) return { provider: other.provider, note: `Reviewer: ${other.provider} (a different provider from ${answered?.provider || 'the answerer'}).` };
50
+ const same = (connected || []).some((c) => c.provider === answered?.provider);
51
+ const alt = same ? (models || []).find((m) => m && m !== answered?.model) : null;
52
+ if (alt) return { provider: answered.provider, model: alt, note: `Reviewer: ${answered.provider} ${alt} (same provider, different model: no other provider is connected).` };
53
+ return null;
54
+ }
55
+
56
+ export function createChallengeCmd({ api, say, getState, sendTurn, now = Date.now }) {
57
+ const st = { pending: null, busy: false };
58
+
59
+ async function run(focus = '') {
60
+ const s = getState();
61
+ if (st.busy) return say('A challenge is already running.', 'warn');
62
+ if (s.turn) return say('Wait for the current turn or press Esc first.', 'warn');
63
+ const o = lastOutput(s);
64
+ if (!o || o.kind !== 'answer') return say('Nothing to challenge yet: ask something first.', 'warn');
65
+ if (!api.connections) return say('/challenge is not available in this mode.', 'warn');
66
+ st.pending = null;
67
+ const answered = { provider: s.ctx?.provider || null, model: s.ctx?.model || null };
68
+ const res = await api.connections();
69
+ const caps = api.capabilities ? await api.capabilities() : null;
70
+ const connected = connectedChoices(res, caps);
71
+ let models = [];
72
+ if (!connected.some((c) => c.provider !== answered.provider) && api.providerModels && answered.provider) {
73
+ const r = await api.providerModels(answered.provider);
74
+ models = r?.ok ? (r.models || []).map((m) => m.id || m) : [];
75
+ }
76
+ const pick = pickReviewer({ connected, answered, models });
77
+ if (!pick) return say('No other provider or model is connected to review with, so /challenge would only ask the same model. /connect another provider first.', 'warn');
78
+ say(`${pick.note} One extra model turn.`, 'dim');
79
+ st.busy = true;
80
+ let text = '', gate = null, failed = null;
81
+ try {
82
+ for await (const ev of api.stream({ turnId: newTurnId(), message: reviewPrompt({ answer: o.text, tools: collectTools(s), focus: String(focus || '').trim() }), agent: 'quox', provider: pick.provider, ...(pick.model ? { model: pick.model } : {}) })) {
83
+ if (ev.type === 'chunk' || ev.type === 'text.delta' || ev.type === 'turn.started') { const g = textGate(gate, ev); gate = g.st; if (g.append) text += ev.content; }
84
+ else if (ev.type === 'done' && !text && ev.full_response) text = ev.full_response;
85
+ else if (ev.type === 'error') failed = ev.error || 'stream error';
86
+ }
87
+ } catch (e) { failed = e?.message || 'failed'; }
88
+ finally { st.busy = false; }
89
+ if (failed && !text.trim()) return say(`Challenge failed: ${failed}`, 'warn');
90
+ const body = text.trim();
91
+ if (!body) return say('The reviewer returned nothing.', 'warn');
92
+ const lines = body.split('\n').map((l) => l.trimEnd()).filter(Boolean);
93
+ for (const l of lines.slice(0, MAX_FINDING_LINES)) say(l, /^high\b/i.test(l) ? 'error' : /^medium\b/i.test(l) ? 'warn' : undefined);
94
+ if (lines.length > MAX_FINDING_LINES) say(`... ${lines.length - MAX_FINDING_LINES} more lines not shown.`, 'dim');
95
+ if (/^no findings/i.test(body)) return undefined;
96
+ st.pending = { findings: body, at: now() };
97
+ return say(askText('Resolve these?'), 'ask');
98
+ }
99
+
100
+ /** y/N to the resolve offer. true when the input was consumed. */
101
+ function answer(text) {
102
+ const p = st.pending;
103
+ if (!p) return false;
104
+ const t = String(text || '').trim();
105
+ if (t.startsWith('/')) { st.pending = null; return false; }
106
+ st.pending = null;
107
+ if (now() - p.at > 600000) return false;
108
+ if (/^y(es)?$/i.test(t)) { sendTurn(resolvePrompt(p.findings)); return true; }
109
+ say('Left the findings alone.', 'dim');
110
+ return /^no?$/i.test(t) ? true : false;
111
+ }
112
+
113
+ return { run, answer, get pending() { return st.pending; } };
114
+ }
@@ -0,0 +1,53 @@
1
+ /**
2
+ * QUOXON-FW: a slash line whose words name a real `quox` CLI leaf (`/plans list`, `/notes new "x"`) is that command.
3
+ * Pure resolution only; app.js runs it (read: in-window like a ! command; write: asks "Run it? y/N"; never: refuses).
4
+ * LEAVES is cliLeaves.json: path -> read|write|never, vendored from docs/matrix/sources/cli-leaf-policy.json
5
+ * (a test fails if they drift; regenerate with the one-liner in that test's failure message).
6
+ */
7
+ import { createRequire } from 'node:module';
8
+ import { tokenize } from '../bang.js';
9
+
10
+ export const LEAVES = createRequire(import.meta.url)('./cliLeaves.json');
11
+
12
+ // verbs people type that the CLI spells differently (only used when the result is a real leaf)
13
+ const ALIASES = { ls: 'list', lists: 'list', rm: 'remove', del: 'delete', new: 'add', create: 'add', info: 'show', get: 'show', aware: 'lucid', neighbors: 'neighbours' };
14
+
15
+ function variants(w) {
16
+ const lw = w.toLowerCase();
17
+ const out = new Set([lw]);
18
+ if (lw.endsWith('ies')) out.add(`${lw.slice(0, -3)}y`);
19
+ if (lw.endsWith('es')) out.add(lw.slice(0, -2));
20
+ if (lw.endsWith('s')) out.add(lw.slice(0, -1)); else out.add(`${lw}s`);
21
+ if (ALIASES[lw]) out.add(ALIASES[lw]);
22
+ for (const v of [...out]) if (ALIASES[v]) out.add(ALIASES[v]);
23
+ return [...out];
24
+ }
25
+
26
+ const MAX_DEPTH = 4;
27
+
28
+ /** -> { path, cls, args, display } | null. args is the full argv after `quox` (quoted args preserved). */
29
+ export function resolveCliSlash(cmd, restArg, leaves = LEAVES) {
30
+ const first = String(cmd || '').replace(/^\//, '');
31
+ if (!first || first.startsWith('-')) return null;
32
+ const rest = tokenize(String(restArg || ''));
33
+ const words = [first, ...rest];
34
+ const walk = (n) => { // all path spellings for the first n words
35
+ let acc = [[]];
36
+ for (let i = 0; i < n; i++) {
37
+ if (words[i].startsWith('-')) return [];
38
+ const vs = variants(words[i]);
39
+ acc = acc.flatMap(p => vs.map(v => [...p, v]));
40
+ }
41
+ return acc;
42
+ };
43
+ for (let n = Math.min(MAX_DEPTH, words.length); n >= 1; n--) {
44
+ for (const p of walk(n)) {
45
+ const path = p.join(' ');
46
+ if (Object.prototype.hasOwnProperty.call(leaves, path)) {
47
+ const args = [...p, ...words.slice(n)];
48
+ return { path, cls: leaves[path], args, display: `quox ${args.map(a => (/[\s"']/.test(a) || a === '' ? JSON.stringify(a) : a)).join(' ')}` };
49
+ }
50
+ }
51
+ }
52
+ return null;
53
+ }