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,176 @@
1
+ import React from 'react';
2
+ import { render } from 'ink';
3
+ import { realpathSync } from 'node:fs';
4
+ import { App } from './app.js';
5
+ import { inkRenderOptions, inkStdout } from './term.js';
6
+ import { createDemoApi } from './demo.js';
7
+ import { DEMO_LABEL } from './demo.fixtures.js';
8
+ import { AUTOPLAY_LABEL, autoplayOn } from './demo.autoplay.js';
9
+ import { captureEarlyInput } from './earlyInput.js';
10
+ import { shouldShowWelcome, markWelcomeSeen } from './welcome.js';
11
+ import { loadRules, rulesContext } from './rules.js';
12
+ import { createTranscript } from './transcript.js';
13
+ import { createScreenRecorder, screenFramesEnabled } from './screenFrames.js';
14
+ import { applySettings } from './slash/settings.js';
15
+ import { headOf, RUNNING_ROOT, execRestart, restartPlan, checkRestart, startBuildWatch, settleMsFrom, restoreTerminal, RESTART_SLOT_ENV, RESTART_ATTACH_ENV, RESTART_NOTE_ENV, RESTART_MODE_ENV } from './slash/restart.js';
16
+ import { readLastSeen, writeLastSeen } from './away.js';
17
+ import { fileHistory } from './promptHistory.js';
18
+ import { takeLauncherHandoff, writeRestartHandoff, RESTART_EXIT_CODE } from './launcher.js';
19
+
20
+ export { parseArgs, USAGE, pickProfile, choosePick, chatCredentialProblem, noServerConfigured, printAuthMessage } from './headless.js';
21
+ import { parseArgs, USAGE, noServerConfigured, mainPrint, pickProfile, chatCredentialProblem } from './headless.js';
22
+
23
+ export { captureEarlyInput } from './earlyInput.js';
24
+
25
+ /**
26
+ * Clear the screen before the chat client? Never right after Getting started: its finale (the one-time
27
+ * dashboard link, a password shown once) is on screen and in scrollback, and ESC[3J would erase both.
28
+ */
29
+ export function shouldClearBeforeChat({ isTTY, noClear, fromGettingStarted }) {
30
+ return Boolean(isTTY) && !noClear && !fromGettingStarted;
31
+ }
32
+
33
+ export async function main(argv = process.argv.slice(2)) {
34
+ const opts = parseArgs(argv);
35
+ // Raw mode FIRST: the awaits below (module loads, config, health) must not leave the tty cooked.
36
+ // bin/quox.js already turned it on before loading anything heavy; this returns that same capture.
37
+ const early = !opts.print ? captureEarlyInput() : null;
38
+ if (opts.help) { early?.release(); console.log(USAGE); return; }
39
+ if (opts.errors.length) { early?.release(); process.stderr.write(`quox: ${opts.errors.join('; ')}\n${USAGE}\n`); process.exitCode = 1; return; }
40
+ const cwd = process.cwd().replace(process.env.HOME || '\0', '~');
41
+ const { resolveCliVersion } = await import('../core/version.js');
42
+ let version = '0.3.1';
43
+ try { version = resolveCliVersion?.() || version; } catch { /* keep default */ }
44
+ if (opts.print) return mainPrint(opts);
45
+ let replay = null;
46
+ let fromGettingStarted = false;
47
+ if (opts.demoOnboarding || (!opts.demo && await noServerConfigured(opts, await import('../core/config.js')))) {
48
+ // Getting started (FIRST_RUN_JOURNEY.md C2a): a separate view, never the chat client talking.
49
+ if (process.stdout.isTTY && !opts.noClear) process.stdout.write('\x1b[2J\x1b[3J\x1b[H');
50
+ const welcome = shouldShowWelcome({ print: false });
51
+ if (welcome && !opts.demoOnboarding) markWelcomeSeen();
52
+ const { runGettingStarted } = await import('./onboarding/index.js');
53
+ const r = await runGettingStarted({ version, cwd, welcome, earlyInput: early, demo: opts.demoOnboarding });
54
+ if (r?.action !== 'connected') return;
55
+ // signed in (an existing server, or the one just installed): carry on into the conversation,
56
+ // and a fresh install replays the original request as the first real turn
57
+ replay = r.replay || null;
58
+ fromGettingStarted = true;
59
+ }
60
+ let props;
61
+ let restart = null; // set by /restart: run the installed quox here once the app has let go of the terminal
62
+ if (opts.demo) {
63
+ const auto = autoplayOn(opts.autoplay) ? { exitAfterMs: opts.autoplayExit != null ? opts.autoplayExit * 1000 : (process.env.QUOX_DEMO_AUTOPLAY_EXIT ? Number(process.env.QUOX_DEMO_AUTOPLAY_EXIT) * 1000 : null) } : null;
64
+ // /restart works in the demo too (a fresh demo, nothing to resume): the same hand-over, testable with no server
65
+ // QUOX_DEMO_DECISIONS: demo-only pty test seam for the walkthrough proofs (a decisions state file; never a real server)
66
+ props = { api: createDemoApi({ objects: true, decisionsFile: process.env.QUOX_DEMO_DECISIONS || null }), profile: 'demo', org: 'demo-org', demoLabel: auto ? AUTOPLAY_LABEL : DEMO_LABEL, autoplay: auto ? null : 'Show me what you can do (demo)', demoAuto: auto, onRestart: (r) => { restart = { ...r, conversationId: null }; }, onDemo: () => { restart = { demo: true }; }, restartCheck: checkRestart };
67
+ } else {
68
+ const cfgMod = await import('../core/config.js');
69
+ const { createAuth } = await import('../core/auth.js');
70
+ const { createClient } = await import('../core/client.js');
71
+ const { createApi } = await import('./api.js');
72
+ const probe = cfgMod.loadConfig();
73
+ const profiles = probe.listProfiles?.() || [];
74
+ const missing = opts.profile && !profiles.some(p => p.name === opts.profile);
75
+ const pick = pickProfile(opts.profile, cfgMod);
76
+ const config = missing ? probe : cfgMod.loadConfig(pick.name);
77
+ const { createWindowClient, carryOrg, RESTART_ORG_ENV } = await import('./windowOrg.js');
78
+ const win = createWindowClient({ config, auth: createAuth(config), createClient }); // #1034: /org switch is window-scoped
79
+ const api = createApi({ ...win, config });
80
+ const pname = missing ? opts.profile : (config.getActiveProfileName?.() || 'default');
81
+ const problem = chatCredentialProblem({ profileArg: opts.profile, profiles, hasStoredLogin: missing ? false : Boolean(config.getAuth?.()?.access_token), profileName: pname, serviceKeyFlag: opts.serviceKey });
82
+ // Z2H: a dead session (refresh rejected) or a cleared login on a human profile is ONE signed-out state, answered
83
+ // by a single card and /login, not scattered digest/approvals/chat errors. Transient failures read as alive.
84
+ let signedOut = null;
85
+ if (!missing && !opts.serviceKey) {
86
+ if (problem && !pick.note) signedOut = { reason: null };
87
+ else if (!problem) {
88
+ const pr = await Promise.race([api.probeSession(), new Promise(r => setTimeout(() => r({ alive: true }), 4000))]).catch(() => ({ alive: true }));
89
+ if (!pr.alive) signedOut = { reason: pr.reason || null };
90
+ }
91
+ }
92
+ // The health probe runs inside the app (background); the UI is up and typing works immediately.
93
+ const startup = async () => {
94
+ if (signedOut) return null;
95
+ if (problem) return problem.message;
96
+ if (pick.note) return pick.note;
97
+ const hl = await api.health(8000);
98
+ return hl.ok ? null : hl.absent ? `No QuoxCORE running at ${hl.url}` : `QuoxCORE at ${hl.url} is not answering (${hl.status}); messages may be slow`;
99
+ };
100
+ // /restart hand-over: re-enter the predecessor window's org in this window only (the profile is untouched).
101
+ const carried = !missing && !signedOut && !problem ? await carryOrg(api, process.env) : (delete process.env.QUOX_RESTART_ORG, null);
102
+ const startupCarry = async () => (carried?.error ? `Could not re-enter org ${carried.id} after the restart (${carried.error}). This window is in the profile's org.` : startup());
103
+ const saved = api.settings();
104
+ applySettings(saved);
105
+ if (!opts.verboseSet) opts.verbose = ['off', 'on', 'full'].includes(saved.verbose) ? saved.verbose : 'off'; // protocol lines are opt-in: /verbose on
106
+ // PROFILE-SWITCH: build a signed-in profile's api for an in-place window switch (the App only asks after a y or
107
+ // /profile). The window org rides along; the profile file's default is never moved (loadConfig(name) is a lens).
108
+ const residentNames = () => (cfgMod.loadConfig().listResidentProfiles?.() || []).map(r => r.name);
109
+ const switchProfile = async (name, { org: winOrg = null } = {}) => {
110
+ const row = (cfgMod.loadConfig().listProfiles?.() || []).find(p => p.name === name);
111
+ if (!row || !row.loggedIn) return { ok: false, reason: 'not_signed_in' };
112
+ const c2 = cfgMod.loadConfig(name);
113
+ const a2 = createApi({ ...createWindowClient({ config: c2, auth: createAuth(c2), createClient }), config: c2 });
114
+ const pr = await Promise.race([a2.probeSession(), new Promise(r => setTimeout(() => r({ alive: true }), 4000))]).catch(() => ({ alive: true }));
115
+ if (!pr.alive) return { ok: false, reason: 'not_signed_in' };
116
+ const c = winOrg ? await carryOrg(a2, { [RESTART_ORG_ENV]: winOrg }) : null;
117
+ const note = c?.error ? `Could not re-enter org ${winOrg} (${c.error}); this window is in ${name}'s org.` : null;
118
+ return { ok: true, api: a2, agentLogin: residentNames().includes(name), orgName: (c && !c.error && c.name) || c2.getAuth?.()?.org_name || null, note };
119
+ };
120
+ const loginCandidates = profiles.filter(p => !p.loggedIn && !residentNames().includes(p.name)).map(p => p.name);
121
+ props = { api, switchProfile, loginCandidates, away: { read: readLastSeen, write: writeLastSeen }, modelChoice: opts.provider, resume: opts.resume ?? null, onRestart: (r) => { restart = r; }, onDemo: () => { restart = { demo: true }; }, restartCheck: checkRestart, buildWatch: (o) => startBuildWatch({ ...o, settleMs: settleMsFrom() }), startSha: headOf(RUNNING_ROOT), rules: loadRules(), profile: pname, agentLogin: (probe.listResidentProfiles?.() || []).some(r => r.name === pname), humanProfiles: profiles.filter(p => p.loggedIn && !(probe.listResidentProfiles?.() || []).some(r => r.name === p.name)).map(p => p.name), org: missing ? null : ((carried && !carried.error && carried.name) || config.getAuth?.()?.org_name || null), startup: startupCarry, healthRecheck: () => api.health(8000), blocked: problem && !signedOut ? problem.message : null, signedOut, autoplay: replay };
122
+ }
123
+ // Interactive start: a clean screen under the intro (never when piped; NO_COLOR still clears),
124
+ // except straight after Getting started, whose finale must stay readable.
125
+ if (shouldClearBeforeChat({ isTTY: process.stdout.isTTY, noClear: opts.noClear, fromGettingStarted })) process.stdout.write('\x1b[2J\x1b[3J\x1b[H');
126
+ // Z2H-R5 C: do not advertise /slot where the licence check says no (the server's own capabilities answer, short wait).
127
+ let slotsAvailable = true;
128
+ if (!opts.demo && process.stdout.isTTY && props.api?.capabilities && !props.signedOut && !props.blocked) {
129
+ try {
130
+ const caps = await Promise.race([props.api.capabilities(), new Promise(res => setTimeout(() => res(null), 2000))]);
131
+ const c = caps?.ok ? caps.capabilities.find(x => x.id === 'slots') : null;
132
+ if (c && c.availability === 'unavailable' && /not in your plan/i.test(String(c.reason || ''))) slotsAvailable = false;
133
+ } catch { /* unknown: leave the invite as it was */ }
134
+ }
135
+ const welcome = shouldShowWelcome({ print: opts.print });
136
+ if (welcome) markWelcomeSeen();
137
+ const transcript = opts.demo ? null : createTranscript({ meta: { version, cols: process.stdout.columns, rows: process.stdout.rows, profile: props.profile, org: props.org, cwd } });
138
+ const onResize = () => transcript?.resize(process.stdout.columns, process.stdout.rows);
139
+ if (transcript) process.stdout.on('resize', onResize);
140
+ // SCREEN-FRAMES: what the screen showed, settled, into the same local transcript (QUOX_SCREEN_FRAMES=0 turns it off).
141
+ const screenRec = transcript && process.stdout.isTTY && screenFramesEnabled(process.env)
142
+ ? createScreenRecorder({ write: (rec) => transcript.screen(rec), cols: () => process.stdout.columns, rows: () => process.stdout.rows })
143
+ : null;
144
+ const restartSlot = opts.demo ? null : (process.env[RESTART_SLOT_ENV] || null); delete process.env[RESTART_SLOT_ENV]; // one hand-over only
145
+ const restartAttach = opts.demo ? null : (process.env[RESTART_ATTACH_ENV] || null); delete process.env[RESTART_ATTACH_ENV];
146
+ const restartMode = opts.demo ? null : (process.env[RESTART_MODE_ENV] === 'plan' ? 'plan' : null); delete process.env[RESTART_MODE_ENV]; // PLAN MODE: window-scoped, carried once
147
+ const restartNote = opts.demo ? null : (process.env[RESTART_NOTE_ENV] || null); delete process.env[RESTART_NOTE_ENV]; // e.g. a failed /update, said once in the restarted client
148
+ if (restartNote && !props.introNote) props.introNote = restartNote;
149
+ const app = render(React.createElement(App, { ...props, restartSlot, restartAttach, ...(restartMode ? { mode: restartMode } : {}), welcome, tipStartup: !fromGettingStarted && !opts.demo && Boolean(process.stdout.isTTY), whatsNewStartup: !opts.demo && Boolean(process.stdout.isTTY), version, cwd, verbose: opts.verbose, earlyInput: early, sessionName: opts.name, resumeConversation: opts.conversation || null, invite: Boolean(process.stdout.isTTY) && !opts.name, slotsAvailable, transcript, historyStore: opts.demo ? null : fileHistory() }), inkRenderOptions(process.stdout, { tap: screenRec?.tap }));
150
+ try { await app.waitUntilExit(); screenRec?.stop(); transcript?.end(restart ? 'restart' : 'exit'); }
151
+ catch (e) { screenRec?.stop(); transcript?.end(`crash: ${e?.message || e}`); throw e; }
152
+ finally { screenRec?.stop(); process.stdout.off('resize', onResize); }
153
+ if (!restart) return;
154
+ if (restart.update) { // /update said y: the update owns the terminal (npm prompts, sudo), then the same restart either way
155
+ const { runUpdate } = await import('../core/selfUpdate.js');
156
+ const plan = restart.update;
157
+ restoreTerminal();
158
+ process.stdout.write(`\nUpdating quox: ${plan.command.display}\n`);
159
+ const u = runUpdate(plan);
160
+ if (u.ok) process.stdout.write(`\u2714 Update finished (exit 0). Restarting into this conversation\u2026\n`);
161
+ else {
162
+ const note = `Update failed: ${plan.command.display} ${u.error ? `could not start (${u.error})` : `exited ${u.code}`}. Restarting on the build that is installed now. Run it yourself to see why: ${plan.manual}`;
163
+ process.stdout.write(`\u2716 ${note}\n`);
164
+ process.env[RESTART_NOTE_ENV] = note; // the restarted client (same build) says it again in the conversation
165
+ }
166
+ }
167
+ // The app preflighted the installed quox before letting go, so a failure here is rare (it changed in between).
168
+ const how = { argv: restart.demo ? ['--demo', '--autoplay'] : argv, conversationId: restart.demo ? null : restart.conversationId, profile: opts.demo ? null : (restart.profile || props.profile), name: restart.name || opts.name || null, slot: restart.demo ? null : (restart.slot || null), attach: restart.demo ? null : (restart.attach || null), org: restart.demo ? null : (restart.org || null), mode: restart.demo ? null : (restart.mode || null), bin: restart.bin || undefined };
169
+ // QUOXON-RESTART-LEAK: under the launcher this process EXITS and the launcher runs the successor, so exactly one
170
+ // client stays alive per terminal. Without one (QUOX_NO_LAUNCHER=1) it falls back to waiting on a nested child.
171
+ const launched = takeLauncherHandoff();
172
+ if (launched && writeRestartHandoff(launched, restartPlan(how))) { restoreTerminal(); process.exitCode = RESTART_EXIT_CODE; return; }
173
+ const r = execRestart(how);
174
+ if (r.error) { process.stderr.write(`quox: could not restart (${r.bin}: ${r.error})${restart.conversationId ? `; resume with: quox --resume ${restart.conversationId}` : ''}\n`); process.exitCode = 1; return; }
175
+ process.exitCode = r.code;
176
+ }
@@ -0,0 +1,341 @@
1
+ /**
2
+ * Terminal markdown for QUOXON. `marked` supplies the LEXER only; every token is
3
+ * rendered by our own Ink components in the Quox style (no marked-terminal).
4
+ *
5
+ * Streaming contract:
6
+ * splitSettled(text) -> { settled, rest } settled = complete top-level blocks
7
+ * (safe to move to <Static>), rest = the
8
+ * unfinished tail (re-rendered live).
9
+ * healInline(text) hides half-typed syntax in the live tail
10
+ * (`**bo`, `` `co ``, `[txt](ht`).
11
+ * An unclosed ``` fence is a single code token to the end of text, so it renders
12
+ * as code while streaming and never as raw backticks.
13
+ */
14
+ import React from 'react';
15
+ import { Box, Text, Transform } from 'ink';
16
+ import { graphemes } from './textBuffer.js';
17
+ import { c, mono, gradient, bulletRole } from './theme.js';
18
+
19
+ const h = React.createElement;
20
+
21
+ import { lex, splitSettled } from './markdownSettle.js';
22
+
23
+ export { lex, splitSettled }; // QUOXON-LATENCY: defined in markdownSettle.js so --print never loads Ink
24
+
25
+ export function healInline(text) {
26
+ let t = text;
27
+ const fence = (t.match(/^ {0,3}(```|~~~)/gm) || []).length;
28
+ if (fence % 2 === 1) return t; // inside an open fence: leave verbatim, it renders as code
29
+ const cut = (i) => { t = t.slice(0, i); };
30
+ const ticks = (t.match(/`/g) || []).length;
31
+ if (ticks % 2 === 1) cut(t.lastIndexOf('`'));
32
+ const bold = t.split('**').length - 1;
33
+ if (bold % 2 === 1) cut(t.lastIndexOf('**'));
34
+ const tilde = t.split('~~').length - 1;
35
+ if (tilde % 2 === 1) cut(t.lastIndexOf('~~'));
36
+ const lb = t.lastIndexOf('[');
37
+ if (lb >= 0 && !/\]\([^)]*\)/.test(t.slice(lb)) && /^\[[^\]]*(\]\(?[^)\s]*)?$/.test(t.slice(lb))) cut(lb);
38
+ return t;
39
+ }
40
+
41
+ // ---- wrapped text ------------------------------------------------------------------------------
42
+ /**
43
+ * Ink wraps with wrap-ansi `trim: false`: when a row fills the width exactly, the space before the next
44
+ * word starts the continuation row (" AI agents."). Drop that one space on wrapped rows (index > 0),
45
+ * after any leading colour codes. Width is unchanged, so layout and row counts are unaffected.
46
+ */
47
+ export const dropLeadSpace = (line, i) => (i > 0 ? line.replace(/^((?:\x1b\[[0-9;]*m)*) /, '$1') : line);
48
+ /** <Text> whose wrapped continuation rows never start with a stray space. */
49
+ export const WText = (props) => h(Transform, { transform: dropLeadSpace }, h(Text, props));
50
+
51
+ // ---- hyperlinks (OSC 8) --------------------------------------------------------------------------
52
+ export function supportsHyperlinks(env = process.env, isTTY = Boolean(process.stdout?.isTTY)) {
53
+ if (!isTTY || env.NO_COLOR || env.QUOX_HYPERLINKS === '0') return false;
54
+ if (env.QUOX_HYPERLINKS === '1') return true;
55
+ if (env.KITTY_WINDOW_ID || env.WT_SESSION) return true;
56
+ if (['iTerm.app', 'WezTerm', 'vscode', 'ghostty'].includes(env.TERM_PROGRAM)) return true;
57
+ return Number(env.VTE_VERSION) >= 5000;
58
+ }
59
+ const osc8 = (url, text) => `\x1b]8;;${url}\x1b\\${text}\x1b]8;;\x1b\\`;
60
+
61
+ // ---- inline ----------------------------------------------------------------------------------
62
+ export function inlineText(tokens = []) {
63
+ return tokens.map(t => {
64
+ if (t.tokens) return inlineText(t.tokens);
65
+ if (t.type === 'br') return ' ';
66
+ return t.text ?? t.raw ?? '';
67
+ }).join('').replace(/&amp;/g, '&').replace(/&lt;/g, '<').replace(/&gt;/g, '>').replace(/&quot;/g, '"').replace(/&#39;/g, "'");
68
+ }
69
+
70
+ /** A heading word painted sky -> indigo -> violet, bold (plain bold under NO_COLOR). */
71
+ export const Heading = ({ text, underline = false }) => h(Text, { bold: true, underline },
72
+ ...(mono() ? [String(text)] : gradient(text).map((g, i) => h(Text, { key: i, color: g.color }, g.ch))));
73
+
74
+ /** Prose with numbers and quantities picked out in the number role. Characters unchanged. */
75
+ const NUM = /(?<![\w.#/-])\d+(?:[.,:-]\d+)*(?:%|ms|s|k|m|h|d|x|KB|MB|GB)?(?!\w)/g;
76
+ export function numberRuns(text, key = 'n') {
77
+ const s = String(text);
78
+ if (mono()) return [s];
79
+ const out = [];
80
+ let i = 0;
81
+ for (const m of s.matchAll(NUM)) {
82
+ if (m.index > i) out.push(s.slice(i, m.index));
83
+ out.push(h(Text, { key: `${key}#${m.index}`, color: c('number') }, m[0]));
84
+ i = m.index + m[0].length;
85
+ }
86
+ if (i < s.length) out.push(s.slice(i));
87
+ return out;
88
+ }
89
+
90
+ const unesc = (s) => String(s).replace(/&amp;/g, '&').replace(/&lt;/g, '<').replace(/&gt;/g, '>').replace(/&quot;/g, '"').replace(/&#39;/g, "'");
91
+
92
+ function inline(tokens = [], style = {}, key = 'i') {
93
+ return tokens.map((t, i) => {
94
+ const k = `${key}.${i}`;
95
+ switch (t.type) {
96
+ case 'strong': return h(Text, { key: k, bold: true, color: c('value') }, ...inline(t.tokens, style, k));
97
+ case 'em': return h(Text, { key: k, italic: true }, ...inline(t.tokens, style, k));
98
+ case 'del': return h(Text, { key: k, strikethrough: true }, ...inline(t.tokens, style, k));
99
+ case 'codespan': return mono()
100
+ ? h(Text, { key: k }, '`' + unesc(t.text) + '`')
101
+ : h(Text, { key: k, color: c('code'), backgroundColor: c('codeBg') }, ' ' + unesc(t.text) + ' ');
102
+ case 'br': return h(Text, { key: k }, '\n');
103
+ case 'link': {
104
+ const label = inlineText(t.tokens) || t.href;
105
+ const shown = supportsHyperlinks() ? osc8(t.href, label) : label;
106
+ return h(Text, { key: k }, h(Text, { color: c('sky'), underline: true }, shown),
107
+ label !== t.href ? h(Text, { color: c('muted') }, ` (${t.href})`) : null);
108
+ }
109
+ case 'image': return h(Text, { key: k, color: c('dim') }, `[image: ${t.text || t.href}]`);
110
+ case 'escape': return h(Text, { key: k }, t.text);
111
+ case 'html': return h(Text, { key: k, color: c('dim') }, t.text);
112
+ case 'text': return t.tokens ? h(Text, { key: k }, ...inline(t.tokens, style, k)) : h(Text, { key: k }, ...numberRuns(unesc(t.text), k));
113
+ default: return h(Text, { key: k }, unesc(t.text ?? t.raw ?? ''));
114
+ }
115
+ });
116
+ }
117
+
118
+ // ---- tables ----------------------------------------------------------------------------------
119
+ const w = (s) => graphemes(s).length;
120
+ const padTo = (s, n) => s + ' '.repeat(Math.max(0, n - w(s)));
121
+
122
+ /** Hard-wrap plain text to `width` columns at word boundaries (long words split). Never drops text. Always >= 1 line. */
123
+ export function wrapCell(text, width) {
124
+ const width_ = Math.max(1, width);
125
+ const out = [];
126
+ for (const para of String(text ?? '').split('\n')) {
127
+ let cur = '';
128
+ for (const word of para.split(/\s+/).filter(Boolean)) {
129
+ let g = graphemes(word).map(x => x.text);
130
+ if (cur && w(cur) + 1 + g.length <= width_) { cur += ' ' + word; continue; }
131
+ if (cur) { out.push(cur); cur = ''; }
132
+ while (g.length > width_) { out.push(g.slice(0, width_).join('')); g = g.slice(width_); }
133
+ cur = g.join('');
134
+ }
135
+ out.push(cur);
136
+ }
137
+ return out;
138
+ }
139
+
140
+ /**
141
+ * Plain-text table layout: { mode: 'grid'|'vertical', lines: [{ text, head?, rule? }] }. Pure, for tests.
142
+ * Grid when it fits, else vertical key/value blocks whose values wrap under a hanging indent. No cell is ever truncated
143
+ * (TUI-UX #3: the grounding warning named an id that sat in a clipped cell).
144
+ */
145
+ export function layoutTable(header, rows, cols) {
146
+ const n = header.length;
147
+ const widths = header.map((hd, i) => Math.max(w(hd), ...rows.map(r => w(r[i] ?? '')), 1));
148
+ const total = widths.reduce((a, b) => a + b, 0) + 3 * (n - 1);
149
+ const gridLines = (ws) => {
150
+ const cellLines = (r) => {
151
+ const cells = r.map((cell, i) => wrapCell(cell ?? '', ws[i]));
152
+ const h_ = Math.max(...cells.map(x => x.length));
153
+ return Array.from({ length: h_ }, (_, k) => cells.map((x, i) => padTo(x[k] ?? '', ws[i])).join(' │ ').replace(/\s+$/, ''));
154
+ };
155
+ const rule = ws.map(x => '─'.repeat(x)).join('─┼─');
156
+ return [...cellLines(header).map(text => ({ text, head: true })), { text: rule, rule: true }, ...rows.flatMap(r => cellLines(r).map(text => ({ text })))];
157
+ };
158
+ if (total <= cols) return { mode: 'grid', lines: gridLines(widths) };
159
+ // vertical key: value, one block per row; values wrap under a hanging indent
160
+ const lines = [];
161
+ const keyW = Math.min(Math.max(...header.map(w)), Math.floor(cols / 3));
162
+ const valW = Math.max(8, cols - keyW - 2);
163
+ rows.forEach((r, ri) => {
164
+ if (ri) lines.push({ text: '' });
165
+ header.forEach((hd, i) => {
166
+ const keyLines = wrapCell(hd, keyW);
167
+ const val = wrapCell(r[i] ?? '', valW);
168
+ const count = Math.max(keyLines.length, val.length);
169
+ for (let k = 0; k < count; k++) lines.push({ text: `${padTo(keyLines[k] ?? '', keyW)} ${val[k] ?? ''}`.replace(/\s+$/, ''), key: k === 0 ? keyW : undefined });
170
+ });
171
+ });
172
+ return { mode: 'vertical', lines };
173
+ }
174
+
175
+ function Table({ t, cols }) {
176
+ const header = t.header.map(x => inlineText(x.tokens));
177
+ const rows = t.rows.map(r => r.map(x => inlineText(x.tokens)));
178
+ const lay = layoutTable(header, rows, cols);
179
+ return h(Box, { flexDirection: 'column' }, ...lay.lines.map((l, i) => h(Text, {
180
+ key: i, bold: l.head, color: l.rule ? c('muted') : (l.head ? c('label') : undefined), wrap: 'wrap'
181
+ }, l.text || ' ')));
182
+ }
183
+
184
+ // ---- blocks ----------------------------------------------------------------------------------
185
+ const rule = (cols, label) => {
186
+ if (!label) return '─'.repeat(cols);
187
+ const lead = `── ${label} `;
188
+ return lead + '─'.repeat(Math.max(0, cols - w(lead)));
189
+ };
190
+
191
+ /** Fenced code top rule: dim teal line, the language label in the icon role. Same characters as rule(). */
192
+ function codeRule(cols, label) {
193
+ const line = rule(cols, label);
194
+ if (!label) return h(Text, { color: c('codeRule') }, line);
195
+ return h(Text, null, h(Text, { color: c('codeRule') }, '── '), h(Text, { color: c('icon') }, label), h(Text, { color: c('codeRule') }, line.slice(3 + label.length)));
196
+ }
197
+
198
+ function List({ t, cols, depth }) {
199
+ const start = typeof t.start === 'number' ? t.start : 1;
200
+ return h(Box, { flexDirection: 'column' }, ...t.items.map((it, i) => {
201
+ const marker = t.ordered ? `${start + i}.` : (depth % 2 ? '◦' : '•');
202
+ const mw = w(marker) + 1;
203
+ return h(Box, { key: i },
204
+ h(Box, { width: mw, flexShrink: 0 }, h(Text, { color: c(bulletRole(depth)) }, marker)),
205
+ h(Box, { flexDirection: 'column', flexGrow: 1, flexShrink: 1 }, ...blocks(it.tokens, cols - mw, depth + 1, `li${i}`)));
206
+ }));
207
+ }
208
+
209
+ function blocks(tokens = [], cols, depth = 0, key = 'b') {
210
+ const out = [];
211
+ tokens.forEach((t, i) => {
212
+ const k = `${key}.${i}`;
213
+ switch (t.type) {
214
+ case 'space': return;
215
+ case 'heading': {
216
+ out.push(h(Box, { key: k, marginTop: depth ? 0 : 1 }, h(Transform, { transform: dropLeadSpace }, h(Heading, { text: inlineStr(t.tokens), underline: t.depth === 1 && mono() }))));
217
+ return;
218
+ }
219
+ case 'paragraph': case 'text':
220
+ out.push(h(Box, { key: k }, h(WText, null, ...inline(t.tokens || [{ type: 'text', text: t.text }], {}, k))));
221
+ return;
222
+ case 'code': {
223
+ const lines = String(t.text).split('\n');
224
+ out.push(h(Box, { key: k, flexDirection: 'column', width: cols },
225
+ codeRule(cols, t.lang ? String(t.lang).split(/\s+/)[0] : ''),
226
+ ...lines.map((ln, j) => h(Text, { key: j, color: c('text') }, ln || ' ')),
227
+ h(Text, { color: c('codeRule') }, rule(cols))));
228
+ return;
229
+ }
230
+ case 'list': out.push(h(List, { key: k, t, cols, depth })); return;
231
+ case 'blockquote':
232
+ out.push(h(Box, { key: k },
233
+ h(Box, { width: 2, flexShrink: 0 }, h(Text, { color: c('label') }, '▎ ')),
234
+ h(Box, { flexDirection: 'column', flexGrow: 1, flexShrink: 1 }, ...blocks(t.tokens, cols - 2, depth + 1, k))));
235
+ return;
236
+ case 'hr': out.push(h(Text, { key: k, color: c('dim') }, '─'.repeat(cols))); return;
237
+ case 'table': out.push(h(Table, { key: k, t, cols })); return;
238
+ case 'html': out.push(h(Text, { key: k, color: c('dim') }, t.text.trim())); return;
239
+ case 'def': return;
240
+ default: out.push(h(Text, { key: k }, unesc(t.raw || '')));
241
+ }
242
+ });
243
+ return out;
244
+ }
245
+
246
+ /** Render markdown text. live = unfinished tail of a streaming answer. */
247
+ export function Markdown({ text, cols, live = false }) {
248
+ const src = live ? healInline(text) : text;
249
+ if (!src.trim()) return null;
250
+ const kids = blocks(lex(src), cols).map((el, i) => h(Box, { key: el.key ?? i, marginTop: i ? 1 : 0, flexDirection: 'column' }, el));
251
+ return h(Box, { flexDirection: 'column', width: cols }, ...kids);
252
+ }
253
+
254
+ // ---- height (sizes the live region; must match what Ink lays out) ---------------------------------
255
+ /** Rows one line takes in Ink's Text wrap (wrap-ansi 9, trim: false, hard: true), plain text only. */
256
+ function wrapLineRows(line, cols) {
257
+ if (cols <= 0) return 1;
258
+ const words = line.split(' ');
259
+ const rows = [0];
260
+ words.forEach((word, i) => {
261
+ let len = rows[rows.length - 1];
262
+ const wl = w(word);
263
+ if (i !== 0) {
264
+ if (len >= cols) { rows.push(0); len = 0; }
265
+ rows[rows.length - 1] = ++len;
266
+ }
267
+ if (wl > cols) { // hard-break a word longer than the line
268
+ const remaining = cols - len;
269
+ const startHere = 1 + Math.floor((wl - remaining - 1) / cols);
270
+ const startNext = Math.floor((wl - 1) / cols);
271
+ if (startNext < startHere) rows.push(0);
272
+ let vis = rows[rows.length - 1];
273
+ const chars = graphemes(word);
274
+ chars.forEach((_, k) => {
275
+ if (vis + 1 <= cols) rows[rows.length - 1] = ++vis;
276
+ else { rows.push(1); vis = 1; }
277
+ if (vis === cols && k < chars.length - 1) { rows.push(0); vis = 0; }
278
+ });
279
+ if (!vis && rows.length > 1 && rows[rows.length - 1] === 0) rows.pop();
280
+ return;
281
+ }
282
+ if (len + wl > cols && len > 0 && wl > 0) { rows.push(0); len = 0; }
283
+ rows[rows.length - 1] = len + wl;
284
+ });
285
+ return rows.length;
286
+ }
287
+
288
+ /** Rows a plain string takes when Ink wraps it at `cols`. */
289
+ export function wrapRows(text, cols) {
290
+ return String(text).replace(/\r\n/g, '\n').split('\n').reduce((n, l) => n + wrapLineRows(l, cols), 0);
291
+ }
292
+
293
+ function inlineStr(tokens = []) {
294
+ return tokens.map(t => {
295
+ switch (t.type) {
296
+ case 'strong': case 'em': case 'del': return inlineStr(t.tokens);
297
+ case 'codespan': return mono() ? '`' + unesc(t.text) + '`' : ' ' + unesc(t.text) + ' ';
298
+ case 'br': return '\n';
299
+ case 'link': { const label = inlineText(t.tokens) || t.href; return label + (label !== t.href ? ` (${t.href})` : ''); }
300
+ case 'image': return `[image: ${t.text || t.href}]`;
301
+ case 'escape': case 'html': return t.text;
302
+ case 'text': return t.tokens ? inlineStr(t.tokens) : unesc(t.text);
303
+ default: return unesc(t.text ?? t.raw ?? '');
304
+ }
305
+ }).join('');
306
+ }
307
+
308
+ /** Heights of the elements blocks() would produce, in order (space/def produce none). */
309
+ function blockRows(tokens = [], cols, depth = 0) {
310
+ const out = [];
311
+ for (const t of tokens) {
312
+ switch (t.type) {
313
+ case 'space': case 'def': break;
314
+ case 'heading': out.push(wrapRows(inlineStr(t.tokens), cols) + (depth ? 0 : 1)); break;
315
+ case 'paragraph': case 'text': out.push(wrapRows(inlineStr(t.tokens || [{ type: 'text', text: t.text }]), cols)); break;
316
+ case 'code': out.push(2 + String(t.text).split('\n').reduce((n, ln) => n + wrapRows(ln || ' ', cols), 0)); break;
317
+ case 'list': {
318
+ out.push(t.items.reduce((n, it, i) => {
319
+ const marker = t.ordered ? `${(typeof t.start === 'number' ? t.start : 1) + i}.` : '•';
320
+ const inner = blockRows(it.tokens, cols - (w(marker) + 1), depth + 1).reduce((a, b) => a + b, 0);
321
+ return n + Math.max(1, inner);
322
+ }, 0));
323
+ break;
324
+ }
325
+ case 'blockquote': out.push(Math.max(1, blockRows(t.tokens, cols - 2, depth + 1).reduce((a, b) => a + b, 0))); break;
326
+ case 'hr': out.push(1); break;
327
+ case 'table': out.push(layoutTable(t.header.map(x => inlineText(x.tokens)), t.rows.map(r => r.map(x => inlineText(x.tokens))), cols).lines.length); break;
328
+ case 'html': out.push(wrapRows(t.text.trim(), cols)); break;
329
+ default: out.push(wrapRows(unesc(t.raw || ''), cols));
330
+ }
331
+ }
332
+ return out;
333
+ }
334
+
335
+ /** Rows <Markdown text cols live/> occupies. Pure; mirrors Markdown() above. */
336
+ export function markdownRows(text, cols, live = false) {
337
+ const src = live ? healInline(text) : text;
338
+ if (!src.trim()) return 0;
339
+ const rows = blockRows(lex(src), cols);
340
+ return rows.reduce((a, b) => a + b, 0) + Math.max(0, rows.length - 1);
341
+ }
@@ -0,0 +1,19 @@
1
+ /**
2
+ * The streaming split, without the renderer. events.js (and so `quox --print`) needs only
3
+ * splitSettled; importing it from markdown.js loaded React + Ink (~2 s cold) on every
4
+ * headless turn before the request was even sent (QUOXON-LATENCY). markdown.js re-exports
5
+ * both names, so the interactive client is unchanged.
6
+ */
7
+ import { Lexer } from 'marked';
8
+
9
+ export const lex = (src) => new Lexer({ gfm: true, breaks: false }).lex(src);
10
+
11
+ export function splitSettled(text) {
12
+ const tokens = lex(text);
13
+ let last = -1;
14
+ for (let i = tokens.length - 1; i >= 0; i--) if (tokens[i].type !== 'space') { last = i; break; }
15
+ if (last <= 0) return { settled: '', rest: text };
16
+ let off = 0;
17
+ for (let i = 0; i < last; i++) off += tokens[i].raw.length;
18
+ return { settled: text.slice(0, off), rest: text.slice(off) };
19
+ }
@@ -0,0 +1,46 @@
1
+ {
2
+ "_comment": "Vendored from ~/cli.quox.ai/matrix/domains.json (the proof matrix, 40 domain ids). Source: https://github.com/quoxai/cli.quox.ai matrix/domains.json. Tips name a domain from this list so the matrix can ingest them. When the matrix becomes canonical this file is replaced by the matrix export.",
3
+ "domains": [
4
+ "chat",
5
+ "providers",
6
+ "approvals",
7
+ "receipts",
8
+ "safety",
9
+ "hats",
10
+ "fleet",
11
+ "proxmox",
12
+ "monitoring",
13
+ "lucid",
14
+ "memory",
15
+ "qortex",
16
+ "vault",
17
+ "agents",
18
+ "workflows",
19
+ "skills",
20
+ "objectives",
21
+ "mail",
22
+ "calendar",
23
+ "contacts",
24
+ "notes",
25
+ "actions",
26
+ "voice",
27
+ "quoxchat",
28
+ "seo",
29
+ "plan",
30
+ "signal",
31
+ "browser",
32
+ "lens",
33
+ "social",
34
+ "comms",
35
+ "sessions",
36
+ "code",
37
+ "security",
38
+ "spend",
39
+ "files",
40
+ "plugins",
41
+ "identity",
42
+ "install",
43
+ "compliance",
44
+ "mind"
45
+ ]
46
+ }