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,72 @@
1
+ /**
2
+ * QUOXON-FW3: a message typed while the server is restarting is kept, not dropped (pure helpers).
3
+ * A send is only retried when the connection failed BEFORE any event arrived (so no turn started and
4
+ * nothing can run twice); the caller enforces that.
5
+ */
6
+ export const SERVER_RESTARTING = "Quox server is restarting. I'll send this when it is back. Esc cancels.";
7
+ export const MAX_WAIT_MS = 180000;
8
+
9
+ /** True for "could not reach the server at all" (refused / fetch failed), never for an HTTP answer. */
10
+ export function isServerDown(e) {
11
+ if (!e || e.status) return false;
12
+ const code = e.cause?.code || e.code || '';
13
+ const msg = String(e.message || '');
14
+ return /ECONNREFUSED|ECONNRESET|ENOTFOUND|EAI_AGAIN|UND_ERR_SOCKET/.test(String(code)) || /Could not connect to|fetch failed|ECONNREFUSED/i.test(msg);
15
+ }
16
+
17
+ /** gh #1157: resume during a collector restart. Connection-class failures (refused, fetch failed, hang up, 502/503/504) are worth retrying; 401/404 are answers. */
18
+ export function isResumeRetryable(e) {
19
+ if (!e) return false;
20
+ if (e.status) return [502, 503, 504].includes(Number(e.status));
21
+ return isServerDown(e) || /socket hang up|ECONNRESET|other side closed|terminated/i.test(String(e.message || ''));
22
+ }
23
+ /** 2, 4, 8, 15, 30 s, then 30 s steps: about 2 minutes in all before giving up. */
24
+ export const RESUME_RETRY_DELAYS = [2000, 4000, 8000, 15000, 30000, 30000, 30000];
25
+ export const RESUME_RECONNECTING = 'Quox server restarting, reconnecting to your conversation…';
26
+
27
+ /** 1s, 2s, 4s, 8s, then 10s (capped). */
28
+ export const backoffMs = (i) => Math.min(10000, 1000 * 2 ** i);
29
+
30
+ const sleepFor = (ms, signal) => new Promise((r) => {
31
+ if (signal?.aborted) return r();
32
+ const t = setTimeout(done, ms);
33
+ function done() { clearTimeout(t); signal?.removeEventListener?.('abort', done); r(); }
34
+ signal?.addEventListener?.('abort', done, { once: true });
35
+ });
36
+
37
+ /**
38
+ * Poll health with backoff until it answers 2xx. -> 'up' | 'cancelled' | 'timeout'.
39
+ * delays: optional array (tests); else backoffMs. Total waiting is bounded by maxMs of scheduled sleep.
40
+ */
41
+ export async function waitForServer({ health, signal, delays = null, maxMs = MAX_WAIT_MS }) {
42
+ let waited = 0;
43
+ for (let i = 0; ; i++) {
44
+ if (signal?.aborted) return 'cancelled';
45
+ const d = delays ? delays[Math.min(i, delays.length - 1)] : backoffMs(i);
46
+ if (waited >= maxMs || (delays && i >= delays.length * 4)) return 'timeout';
47
+ await sleepFor(d, signal);
48
+ waited += d;
49
+ if (signal?.aborted) return 'cancelled';
50
+ let r = null;
51
+ try { r = await health(3000); } catch { r = null; }
52
+ if (r?.ok) return 'up';
53
+ }
54
+ }
55
+
56
+ /**
57
+ * QUOXON-FW4: a stream that died mid-turn ("terminated" is undici's wording) gets a cause and a way
58
+ * forward instead of a bare word. Returns null when the error is not a transport/timeout failure.
59
+ */
60
+ export function explainTermination(e) {
61
+ if (!e || e.status) return null;
62
+ const msg = String(e.message || '');
63
+ const code = String(e.cause?.code || e.code || '');
64
+ if (e.name === 'TimeoutError' || /timed? ?out|ETIMEDOUT|UND_ERR_(HEADERS|BODY)_TIMEOUT/i.test(`${msg} ${code}`)) return `The turn timed out before the server finished.`;
65
+ if (/^terminated$/i.test(msg.trim()) || /ECONNRESET|UND_ERR_SOCKET|other side closed|premature close|aborted/i.test(`${msg} ${code}`)) {
66
+ return `The connection to the server was cut mid-turn (likely a server restart, proxy timeout or provider error).`;
67
+ }
68
+ return null;
69
+ }
70
+
71
+ /** The second line after a cut turn: the message is kept, and what to do next. */
72
+ export const RETRY_HINT = 'Your message is kept: press Up to recall it, then Enter to resend. Anything it started may or may not have finished; check before repeating it.';
@@ -0,0 +1,307 @@
1
+ /**
2
+ * QUOXON roster: what is actually running on this instance for this org. Pure
3
+ * functions only (normalise server rows, build the view); fetching lives in api.js.
4
+ * Rows come from real list endpoints; a source that cannot answer contributes
5
+ * nothing (never a placeholder row).
6
+ */
7
+ import { clip } from './theme.js';
8
+
9
+ export const GLYPH = { running: '◐', waiting: '⏸', done: '✔', failed: '✖' };
10
+ /** A row that ended without finishing says HOW: failed is the only error; the rest are neutral (no error colour). */
11
+ export const OUTCOME_GLYPH = { failed: '✖', cancelled: '○', expired: '○', rejected: '⊘' };
12
+ export const FRESH_MS = 10 * 60 * 1000; // finished rows linger this long
13
+ export const USER_DONE_MS = 20 * 1000; // a user-started completion vanishes quickly: rows come and go
14
+ export const PENDING_FRESH_MS = 24 * 3600 * 1000; // an older "pending" is stale, not waiting
15
+ export const MAX_ROWS = 4;
16
+ export const MIN_FULL_COLS = 60;
17
+ export const MIN_FULL_ROWS = 24;
18
+
19
+ /** Server timestamps: epoch ms, ISO, or SQLite "YYYY-MM-DD HH:MM:SS" (UTC, no zone). */
20
+ export function parseTime(v) {
21
+ if (v == null || v === '') return null;
22
+ if (typeof v === 'number') return v;
23
+ const s = String(v);
24
+ const t = Date.parse(/^\d{4}-\d\d-\d\d \d\d:\d\d(:\d\d)?$/.test(s) ? s.replace(' ', 'T') + 'Z' : s);
25
+ return Number.isFinite(t) ? t : null;
26
+ }
27
+
28
+ export function elapsed(ms) {
29
+ if (ms == null || !Number.isFinite(ms)) return '';
30
+ const s = Math.max(0, Math.floor(ms / 1000));
31
+ if (s < 60) return `${s}s`;
32
+ const m = Math.floor(s / 60);
33
+ if (m < 60) return `${m}m`;
34
+ const h = Math.floor(m / 60);
35
+ if (h < 24) return `${h}h${String(m % 60).padStart(2, '0')}`;
36
+ return `${Math.floor(h / 24)}d`;
37
+ }
38
+
39
+ const ACTIVE_RE = /^(running|planning|decompos|executing|in_progress|active)/;
40
+ const WAITING_RE = /^(paused|awaiting|blocked|plan_review|pending_approval|waiting)/;
41
+ const FAILED = new Set(['failed', 'error', 'halted', 'cancelled', 'canceled', 'timed_out', 'timeout', 'expired', 'rejected']);
42
+ /** The word for how an ended row ended (state stays 'failed' for the ended-badly group; this says which). */
43
+ export function outcomeOf(status) {
44
+ const st = String(status || '').toLowerCase();
45
+ if (st === 'cancelled' || st === 'canceled') return 'cancelled';
46
+ if (st === 'expired') return 'expired';
47
+ if (st === 'rejected') return 'rejected';
48
+ return 'failed';
49
+ }
50
+ /** Word, glyph and whether it is an error, for a row. Non-failed states return their own state. */
51
+ export function endWord(r) { return r.state === 'failed' ? outcomeOf(r.status) : r.state; }
52
+ export const glyphOf = (r) => (r.state === 'failed' ? OUTCOME_GLYPH[endWord(r)] : GLYPH[r.state]);
53
+
54
+ /** How long a finished row lingers before it leaves the roster (null while running/waiting). */
55
+ const expiryFor = (state, doneMs) => state === 'done' ? doneMs : state === 'failed' ? FRESH_MS : null;
56
+
57
+ /** -> state or null (not shown). */
58
+ function stateOf(status, { startedAt, createdAt, finishedAt, now, doneMs = FRESH_MS }) {
59
+ const st = String(status || '').toLowerCase();
60
+ if (ACTIVE_RE.test(st)) return 'running';
61
+ if (WAITING_RE.test(st)) return 'waiting';
62
+ if (st === 'pending' || st === 'queued') {
63
+ const t = createdAt ?? startedAt;
64
+ return t != null && now - t < PENDING_FRESH_MS ? 'waiting' : null;
65
+ }
66
+ if (st === 'completed' || st === 'complete' || st === 'succeeded' || FAILED.has(st)) {
67
+ if (finishedAt == null) return null;
68
+ const ok = st === 'completed' || st === 'complete' || st === 'succeeded';
69
+ if (now - finishedAt > (ok ? doneMs : FRESH_MS)) return null;
70
+ return ok ? 'done' : 'failed';
71
+ }
72
+ return null;
73
+ }
74
+
75
+ const latest = (...ts) => { const v = ts.filter((t) => t != null); return v.length ? Math.max(...v) : null; };
76
+
77
+ export function fromObjective(o, now = Date.now()) {
78
+ const startedAt = parseTime(o.started_at);
79
+ const createdAt = parseTime(o.created_at);
80
+ const finishedAt = parseTime(o.completed_at);
81
+ // Objectives and loops are always user-started work.
82
+ const state = stateOf(o.status, { startedAt, createdAt, finishedAt, now, doneMs: USER_DONE_MS });
83
+ if (!state) return null;
84
+ const loop = o.execution_mode === 'loop';
85
+ let activity = '';
86
+ if (state === 'failed' && o.error_message) activity = String(o.error_message);
87
+ else if (loop && o.max_iterations) activity = `iter ${o.iteration_count || 0}/${o.max_iterations}`;
88
+ else if (o.task_count) activity = `${o.tasks_completed || 0}/${o.task_count} tasks`;
89
+ else if (state === 'waiting') activity = 'waiting to start';
90
+ const from = startedAt ?? createdAt;
91
+ return {
92
+ key: `objective:${o.id}`, id: o.id, source: 'objectives', background: false, kind: loop ? 'loop' : 'objective', state,
93
+ name: o.title || o.id, activity, status: o.status,
94
+ startedAt: from, finishedAt, ageMs: from != null ? (state === 'done' || state === 'failed' ? (finishedAt ?? now) - from : now - from) : null,
95
+ expiryMs: expiryFor(state, USER_DONE_MS),
96
+ progressAt: latest(parseTime(o.updated_at), parseTime(o.last_progress_at), parseTime(o.last_heartbeat_at)),
97
+ detail: { description: o.description, error: o.error_message, tokens: o.tokens_used, toolCalls: o.tool_calls_used }
98
+ };
99
+ }
100
+
101
+ const USER_TRIGGERS = new Set(['manual', 'chat', 'cli', 'user']);
102
+ const BACKGROUND_BY = /^(schedule|cron|interval|webhook|event|system)\b/i;
103
+ /**
104
+ * Is this workflow execution background work (hidden from the roster by default)?
105
+ * Fields relied on (live /api/executions rows, checked 2026-10-12): `triggerData.trigger`
106
+ * ('schedule' on every live row) and `triggeredBy` ('schedule:trigger', 'event:<node>',
107
+ * 'webhook:<node>' set by quoxflow's trigger-bootstrap). Rule: a background-looking triggeredBy
108
+ * always wins; otherwise user-started only if the trigger is manual/chat/cli/user OR triggeredBy
109
+ * equals the signed-in user's id. Unknown trigger with no such evidence is background.
110
+ */
111
+ export function isBackgroundExecution(e, userId = null) {
112
+ const by = e?.triggeredBy == null ? '' : String(e.triggeredBy);
113
+ if (BACKGROUND_BY.test(by)) return true;
114
+ // quoxflow records a person-started run as user:<id> (RunActor); a bare id is an older row
115
+ if (userId && by && (by === String(userId) || by === `user:${userId}`)) return false;
116
+ return !USER_TRIGGERS.has(String(e?.triggerData?.trigger || '').toLowerCase());
117
+ }
118
+
119
+ export function fromExecution(e, now = Date.now(), { userId = null } = {}) {
120
+ const startedAt = parseTime(e.startedAt);
121
+ const finishedAt = parseTime(e.completedAt);
122
+ const background = isBackgroundExecution(e, userId);
123
+ const state = stateOf(e.status, { startedAt, createdAt: startedAt, finishedAt, now, doneMs: background ? FRESH_MS : USER_DONE_MS });
124
+ if (!state) return null;
125
+ let activity = '';
126
+ if (state === 'failed' && e.error) activity = typeof e.error === 'string' ? e.error : (e.error.message || JSON.stringify(e.error));
127
+ else if (e.nodeCount) activity = `${e.nodeCount} node${e.nodeCount === 1 ? '' : 's'}`;
128
+ else if (e.triggerData?.trigger) activity = `via ${e.triggerData.trigger}`;
129
+ return {
130
+ key: `execution:${e.id}`, id: e.id, source: 'executions', kind: 'workflow', background, state,
131
+ name: e.workflowName || e.workflowId || e.id, activity, status: e.status,
132
+ startedAt, finishedAt, ageMs: startedAt != null ? (state === 'done' || state === 'failed' ? (finishedAt ?? now) - startedAt : now - startedAt) : null,
133
+ expiryMs: expiryFor(state, background ? FRESH_MS : USER_DONE_MS),
134
+ progressAt: latest(parseTime(e.updatedAt), parseTime(e.lastHeartbeatAt)),
135
+ detail: { workflowId: e.workflowId, correlationId: e.correlationId, trigger: e.triggerData?.trigger, error: e.error }
136
+ };
137
+ }
138
+
139
+ /** A pending approval (inbox item) for this user/org -> amber waiting row, always shown. */
140
+ export function fromApproval(it, now = Date.now()) {
141
+ if (!it || !it.id) return null;
142
+ const m = it.payload?.approval_context?.method || {};
143
+ const name = m.tool ? (m.target ? `${m.tool} on ${m.target}` : m.tool) : String(it.title || it.summary || it.id);
144
+ const createdAt = parseTime(it.created_at ?? it.createdAt);
145
+ return { key: `approval:${it.id}`, id: it.id, source: 'approvals', kind: 'approval', state: 'waiting', background: false, name, activity: '/approvals', status: 'pending',
146
+ startedAt: createdAt, finishedAt: null, ageMs: createdAt != null ? now - createdAt : null, detail: { description: it.title } };
147
+ }
148
+
149
+ /** Heartbeat style system work: nobody wants a row or a notification for it, working or failing. */
150
+ export const NOISE_NAME = /heartbeat|health[ _-]?check|keep[ _-]?alive|\bping\b/i;
151
+ export const isNoise = (r) => Boolean(r.background) && NOISE_NAME.test(String(r.name || ''));
152
+
153
+ /** Rows the user should see: background rows only with `all` (/roster all). */
154
+ export function selectRows(rows, { all = false } = {}) {
155
+ return all ? rows : rows.filter(r => !r.background && !isNoise(r));
156
+ }
157
+
158
+ /** One line per workflow that is failing in the background (deduped); these feed the notifications bar. */
159
+ export function backgroundAlerts(rows) {
160
+ const by = new Map();
161
+ for (const r of rows) if (r.background && !isNoise(r) && r.state === 'failed') by.set(r.name, (by.get(r.name) || 0) + 1);
162
+ return [...by].map(([name, n]) => `✖ ${name} failing (${n} in ${FRESH_MS / 60000}m) · /roster all`);
163
+ }
164
+
165
+ /** When the row last changed state: it started, or it finished (done/failed). */
166
+ export const changedAt = (r) => (r.state === 'done' || r.state === 'failed' ? r.finishedAt : null) ?? r.startedAt ?? 0;
167
+
168
+ /** Approvals pinned on top (oldest first, they need action); everything else most recent change first. */
169
+ export function sortRows(rows) {
170
+ const ap = (r) => (r.kind === 'approval' ? 0 : 1);
171
+ return [...rows].sort((a, b) => ap(a) - ap(b) || (ap(a) === 0 ? (a.startedAt ?? 0) - (b.startedAt ?? 0) : changedAt(b) - changedAt(a)));
172
+ }
173
+
174
+ export const isExpired = (r, now = Date.now()) => r.expiryMs != null && r.finishedAt != null && now - r.finishedAt > r.expiryMs;
175
+
176
+ /** Tone steps, brightest first (theme colour names). Position among non-approval rows, and for finished rows age toward expiry. */
177
+ export const TONES = ['text', 'placeholder', 'dim', 'faint'];
178
+ export function toneName(r, pos, now = Date.now()) {
179
+ if (r.kind === 'approval') return TONES[0];
180
+ let step = Math.min(Math.max(0, pos), TONES.length - 1);
181
+ if (r.expiryMs && r.finishedAt != null) {
182
+ const frac = Math.max(0, now - r.finishedAt) / r.expiryMs;
183
+ step = Math.max(step, frac < 0.25 ? 0 : frac < 0.5 ? 1 : frac < 0.75 ? 2 : 3);
184
+ }
185
+ return TONES[step];
186
+ }
187
+
188
+ /** Live age text: a clock for running/waiting rows, recency ("done 3s ago") for finished ones. */
189
+ export function ageText(r, now = Date.now()) {
190
+ if (r.state === 'done' || r.state === 'failed') return r.finishedAt != null ? `${endWord(r)} ${elapsed(now - r.finishedAt)} ago` : '';
191
+ return r.startedAt != null ? elapsed(now - r.startedAt) : '';
192
+ }
193
+
194
+ /* ---- pulse: is it moving? ---------------------------------------------------------------- */
195
+
196
+ export const PULSE_MOVING_MS = 2 * 60 * 1000; // progress this recently = moving
197
+ export const PULSE_STALL_MS = 15 * 60 * 1000; // running with no progress this long = stalled
198
+ export const SPIN = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
199
+ export const SPIN_MS = 120;
200
+
201
+ const sigOf = (r) => `${r.state}|${r.status}|${r.activity}`;
202
+
203
+ /**
204
+ * Remember what each row looked like at the last poll so "state changed / iteration advanced" is noticed.
205
+ * Sets r.progressAt (newest of the API's own timestamp and the change we saw; null = nothing seen yet) and
206
+ * r.watchSince (when we first saw the row). Mutates rows and memo (key -> { sig, watchSince, changedAt }).
207
+ */
208
+ export function applyProgress(rows, memo, now = Date.now()) {
209
+ const keep = new Set();
210
+ for (const r of rows) {
211
+ keep.add(r.key);
212
+ const sig = sigOf(r);
213
+ let m = memo.get(r.key);
214
+ if (!m) { m = { sig, watchSince: now, changedAt: null }; memo.set(r.key, m); }
215
+ else if (m.sig !== sig) { m.sig = sig; m.changedAt = now; }
216
+ r.progressAt = latest(r.progressAt, m.changedAt);
217
+ r.watchSince = m.watchSince;
218
+ }
219
+ for (const k of [...memo.keys()]) if (!keep.has(k)) memo.delete(k);
220
+ return rows;
221
+ }
222
+
223
+ /** -> { kind: 'moving' | 'idle' | 'stalled' | 'none', glyph, role }. motion=false gives static glyphs. */
224
+ export function pulseOf(r, now = Date.now(), { motion = false } = {}) {
225
+ if (r.kind === 'approval' || r.state === 'done' || r.state === 'failed') return { kind: 'none', glyph: ' ', role: 'dim' };
226
+ if (r.state !== 'running') return { kind: 'idle', glyph: '·', role: 'dim' };
227
+ const last = latest(r.progressAt, r.startedAt != null && now - r.startedAt < PULSE_MOVING_MS ? r.startedAt : null);
228
+ if (last != null && now - last < PULSE_MOVING_MS) return { kind: 'moving', glyph: motion ? SPIN[Math.floor(now / SPIN_MS) % SPIN.length] : '●', role: 'sky' };
229
+ const ref = last ?? r.watchSince;
230
+ if (ref != null && now - ref > PULSE_STALL_MS) return { kind: 'stalled', glyph: '!', role: 'warn' };
231
+ return { kind: 'idle', glyph: '·', role: 'dim' };
232
+ }
233
+
234
+ export function countsLine(rows) {
235
+ const n = (s) => rows.filter(r => r.state === s).length;
236
+ const o = (w) => rows.filter(r => r.state === 'failed' && endWord(r) === w).length;
237
+ return [['running', 'running', n('running'), GLYPH.running], ['waiting', 'waiting', n('waiting'), GLYPH.waiting],
238
+ ['failed', 'failed', o('failed'), OUTCOME_GLYPH.failed], ['cancelled', 'cancelled', o('cancelled'), OUTCOME_GLYPH.cancelled],
239
+ ['expired', 'expired', o('expired'), OUTCOME_GLYPH.expired], ['rejected', 'rejected', o('rejected'), OUTCOME_GLYPH.rejected], ['done', 'finished', n('done'), GLYPH.done]]
240
+ .filter(([, , k]) => k).map(([, w, k, g]) => `${g} ${k} ${w}`).join(' · ');
241
+ }
242
+
243
+ /**
244
+ * View model. mode: 'hidden' (off or nothing running) | 'summary' (narrow or short terminal) | 'full'.
245
+ * lines: [{ state, text, selected }] where text is already clipped to cols.
246
+ */
247
+ /**
248
+ * Two or more waiting approvals are ONE row ("⏸ 4 approvals waiting · oldest 41m · newest: <title>… · /approvals"), not
249
+ * one row each plus a summary line (owner, live 05:29): the bottom area must never grow with the inbox. A single approval
250
+ * keeps its own row. Focus (the user is walking the roster) shows the real rows so selection stays truthful.
251
+ */
252
+ export function collapseApprovals(rows, now = Date.now()) {
253
+ const aps = rows.filter(r => r.kind === 'approval' && r.state === 'waiting');
254
+ if (aps.length < 2) return rows;
255
+ const started = aps.map(r => r.startedAt).filter(x => x != null);
256
+ const newest = aps.reduce((a, b) => ((b.startedAt ?? -Infinity) > (a.startedAt ?? -Infinity) ? b : a));
257
+ const one = { key: 'approval:*', id: '*', source: 'approvals', kind: 'approval', state: 'waiting', background: false, collapsed: true, count: aps.length,
258
+ name: `${aps.length} approvals waiting`, activity: '/approvals', status: 'pending', startedAt: started.length ? Math.min(...started) : null, finishedAt: null,
259
+ oldestMs: started.length ? now - Math.min(...started) : null, newestTitle: String(newest.detail?.description || newest.name || ''), detail: {} };
260
+ let placed = false;
261
+ return rows.flatMap(r => (aps.includes(r) ? (placed ? [] : (placed = true, [one])) : [r]));
262
+ }
263
+
264
+ export function rosterView({ rows, cols, termRows = 40, max = MAX_ROWS, on = true, sel = 0, focus = false, now = Date.now(), motion = false }) {
265
+ if (!on || !rows.length) return { mode: 'hidden', lines: [], more: 0 };
266
+ if (!focus) rows = collapseApprovals(rows, now);
267
+ if (cols < MIN_FULL_COLS || termRows < MIN_FULL_ROWS) {
268
+ return { mode: 'summary', lines: [], more: 0, summary: clip(' ' + countsLine(rows) + ' · /roster', cols - 1) };
269
+ }
270
+ const shown = rows.slice(0, max);
271
+ const ageW = Math.max(5, ...shown.map(r => [...ageText(r, now)].length));
272
+ let pos = 0;
273
+ const kindW = Math.min(9, Math.max(...shown.map(r => r.kind.length)));
274
+ const lines = shown.map((r, i) => {
275
+ const el = ageText(r, now).padStart(ageW);
276
+ const tone = toneName(r, pos, now); if (r.kind !== 'approval') pos++;
277
+ const actW = Math.min(18, Math.max(0, ...shown.map(x => [...(x.activity || '')].length)));
278
+ const act = clip(r.activity || '', actW).padEnd(actW);
279
+ const fixed = 1 + 1 + 1 + kindW + 1 + 1 + actW + 1 + ageW + 2; // pulse column (space + glyph); marker glyph kind name act elapsed
280
+ const nameW = Math.max(8, cols - 2 - fixed - 1);
281
+ const name = clip(r.name, nameW).padEnd(nameW);
282
+ const marker = focus && i === sel ? '›' : ' ';
283
+ if (r.collapsed) { // one summary row: count, oldest age, newest title, where to go; clipped to the line
284
+ const head = `${r.count} approvals waiting · oldest ${elapsed(r.oldestMs)} · newest: `, tail = ' · /approvals';
285
+ const room = cols - 5 - [...head].length - [...tail].length;
286
+ const text = room >= 12 ? `${head}${clip(r.newestTitle, room)}${tail}` : clip(`${r.count} approvals waiting · oldest ${elapsed(r.oldestMs)}${tail}`, cols - 4); // too narrow for a title
287
+ return { key: r.key, kind: 'approval', state: r.state, tone: toneName(r, pos, now), selected: false, marker: ' ', glyph: GLYPH[r.state], rest: ' ' + text, pulse: '', pulseRole: 'dim', pulseKind: 'none', text: ` ${GLYPH[r.state]} ${text}` };
288
+ }
289
+ const rest = `${r.kind.padEnd(kindW)} ${name} ${act} ${el}`;
290
+ const p = pulseOf(r, now, { motion });
291
+ return { key: r.key, kind: r.kind, state: r.state, tone, selected: focus && i === sel, marker, glyph: glyphOf(r), glyphRole: r.state === 'failed' && endWord(r) !== 'failed' ? 'dim' : null, rest: ' ' + rest, pulse: ' ' + p.glyph, pulseRole: p.role, pulseKind: p.kind, text: `${marker}${glyphOf(r)} ${rest} ${p.glyph}` };
292
+ });
293
+ return { mode: 'full', lines, more: Math.max(0, rows.length - shown.length) };
294
+ }
295
+
296
+ export function peekLines(row, now = Date.now()) {
297
+ if (!row) return [];
298
+ const age = ageText(row, now);
299
+ const out = [`${row.kind} ${row.id}`, `status ${row.status} · ${endWord(row)}${age ? ` · ${age}` : ''}`, `name ${row.name}`];
300
+ if (row.activity) out.push(`activity ${row.activity}`);
301
+ const d = row.detail || {};
302
+ if (d.description) out.push(`goal ${d.description}`);
303
+ if (d.workflowId) out.push(`workflow ${d.workflowId}`);
304
+ if (d.trigger) out.push(`trigger ${d.trigger}`);
305
+ if (d.error && row.state === 'failed') out.push(`error ${typeof d.error === 'string' ? d.error : JSON.stringify(d.error)}`);
306
+ return out;
307
+ }
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Bare `quox` is the conversation. Decide, from argv alone, whether this
3
+ * invocation belongs to the QUOXON client (no subcommand, only client flags).
4
+ * Anything with a subcommand, --help or --version stays with commander.
5
+ */
6
+ const VALUE_FLAGS = new Set(['-p', '--profile', '-n', '--name']);
7
+ const LEVELS = new Set(['off', 'on', 'full']); // `--verbose` alone means on; it only takes a value that is a level
8
+ const PRINT_VALUE_FLAGS = new Set(['--output', '--conversation', '--turn-id', '--timeout', '--provider', '--model', '--agent', '--prompt-profile']);
9
+ const BOOL_FLAGS = new Set(['--demo', '--autoplay', '--demo-onboarding', '--no-clear', '--color', '--service-key']);
10
+ const ALL_FLAGS = new Set([...VALUE_FLAGS, ...PRINT_VALUE_FLAGS, ...BOOL_FLAGS, '--print', '--resume', '--autoplay-exit', '-h', '--help', '--']);
11
+
12
+ export function routesToQuoxon(argv, isTTY) {
13
+ let print = false;
14
+ let help = false;
15
+ const dd = argv.indexOf('--');
16
+ const head = dd === -1 ? argv : argv.slice(0, dd);
17
+ const hasPrint = head.some(a => a === '--print' || a.startsWith('--print='));
18
+ for (let i = 0; i < argv.length; i++) {
19
+ const a = argv[i];
20
+ if (a === '--') { return print; } // everything after -- is the prompt
21
+ if (a === '--print') { print = true; const n = argv[i + 1]; if (n !== undefined && !ALL_FLAGS.has(n) && !/^--(profile|verbose|output|conversation|turn-id|timeout|print|provider|model|agent|prompt-profile)=/.test(n)) i++; }
22
+ else if (a.startsWith('--print=')) print = true;
23
+ else if (a === '-h' || a === '--help') help = true;
24
+ else if (a === '--verbose') { if (LEVELS.has(argv[i + 1])) i++; }
25
+ else if (a === '--resume') { const n = argv[i + 1]; if (n !== undefined && !n.startsWith('-')) i++; } // optional id or name
26
+ else if (a === '--autoplay-exit') { if (/^\d+(\.\d+)?$/.test(argv[i + 1] || '')) i++; } // optional seconds
27
+ else if (a.startsWith('--resume=')) { /* inline value */ }
28
+ else if (VALUE_FLAGS.has(a)) i++;
29
+ else if (/^--(profile|verbose|name)=/.test(a)) { /* inline value */ }
30
+ else if (BOOL_FLAGS.has(a)) { /* no value */ }
31
+ else if (PRINT_VALUE_FLAGS.has(a)) i++;
32
+ else if (/^--(output|conversation|turn-id|timeout|provider|model|agent|prompt-profile)=/.test(a)) { /* inline value */ }
33
+ else if (hasPrint && !a.startsWith('-')) { print = true; } // the prompt, wherever it sits among the flags
34
+ else return false; // subcommand, positional, --help, --version, unknown flag
35
+ }
36
+ if (print) return true;
37
+ if (help) return false; // plain `quox --help` is commander's
38
+ return Boolean(isTTY); // interactive client needs a terminal; scripts keep the banner
39
+ }