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,263 @@
1
+ /**
2
+ * Getting started: EVERY line the setup guide shows lives in this file, so the owner can review the whole
3
+ * first impression in one place (FIRST_RUN_JOURNEY.md, "Copy review"). House voice: no em dashes, no
4
+ * double hyphens in prose, `Quox` mixed case, nothing claimed that the code does not do.
5
+ *
6
+ * Functions take the facts they print (a URL, a size, a provider name); nothing here computes anything.
7
+ */
8
+ import { askText } from '../ask.js';
9
+
10
+ export const LABEL = 'Getting started';
11
+ export const LABEL_SUB = 'setup guide · no AI yet, every line here is scripted';
12
+
13
+ // The Q says HELLO itself, decoded in beside the mark right after the intro (qmotion.js HelloIntro); the
14
+ // guide then carries on with GREETING_REST. GREETING is the whole sentence, for anywhere that shows it at once.
15
+ export const HELLO = "Hi, I'm Quox.";
16
+ export const GREETING_REST = 'I run AI agents for you on your own machine, and I keep receipts you can check for what they do.';
17
+ export const GREETING = `${HELLO} ${GREETING_REST}`;
18
+ export const QUESTION = 'What would you like help with?';
19
+ export const EXAMPLES = ['watch my servers', 'automate something', 'code with agents', 'sort my email', 'just look around'];
20
+ export const INPUT_PLACEHOLDER = 'Type anything, or a number from the list';
21
+
22
+ /** One tailored line per intent: what Quox will do for that. */
23
+ export const INTENT_LINES = {
24
+ servers: 'Quox can keep an eye on your servers, tell you what changed, and ask you before it touches anything.',
25
+ automate: 'Quox can run that as a workflow on a schedule, with an approval step wherever you want one.',
26
+ code: 'Quox can run coding agents on your repos, and every change they make leaves a receipt you can check.',
27
+ email: 'Quox can sort your inbox and draft replies. Nothing is sent without your say so.',
28
+ explore: 'Good plan. Once your Quox is running I will show you around, with real agents and real receipts.'
29
+ };
30
+
31
+ /** Off-script: an honest deferral, shown instantly (no model is running yet). */
32
+ export const DEFERRAL = 'I can answer that properly once your Quox is running.';
33
+
34
+ // The install time is NOT promised as a number until it has been measured on a clean machine (C2 exit).
35
+ export const OFFER = "To do that I need a QuoxCORE, the engine your agents run in. It runs here in Docker, it's free for your own use, and the first install builds from source, so it takes a while.";
36
+ export const OFFER_ASK = askText('Set it up now?', { keys: '(Y/n)', who: 'Quox', action: 'connect an AI and install the Quox server, step by step' });
37
+ export const ALREADY = 'Already have one? /connect server <url>';
38
+ export const DECLINED = 'No problem. Run quox any time and we will pick up here.';
39
+ export const DECLINED_HINT = 'Type yes to set up now, /connect server <url> to use one you have, or /exit.';
40
+
41
+ export const RESUME = 'Picking up where we left off.';
42
+ export const resumeRequest = (text) => `You asked: "${text}"`;
43
+
44
+ // ---- /connect server ---------------------------------------------------------------------------
45
+ export const CONNECT_USAGE = 'Usage: /connect server <url> for example /connect server https://quox.example.com';
46
+ export const connectBadUrl = (u) => `That does not look like a server address: ${u}. Use the full URL, starting with https://`;
47
+ export const connectHandoff = (url) => `Connecting to ${url}. Sign in with your QuoxCORE email and password.`;
48
+ export const CONNECT_DONE = 'Signed in. Starting Quox.';
49
+ export const connectChecking = (url) => `Checking ${url} is a QuoxCORE server...`;
50
+ export const CONNECT_CANCELLED = 'Cancelled. Nothing was saved: the previous server address is back.';
51
+ export const connectFailed = (url) => `Sign-in to ${url} did not complete. Check the address, then try /connect server again.`;
52
+ export const CONNECT_INTENT_LINE = 'Great. Point me at it with /connect server <url> and sign in, and we go straight to your agents.';
53
+
54
+ // ---- preflight ---------------------------------------------------------------------------------
55
+ // FIRSTRUN: the guide offers to fix Docker itself (dockerOffer.js), so nobody has to leave it to do so.
56
+ export const DOCKER_OFFER_QUESTION = {
57
+ install: 'Install Docker for you now?',
58
+ group: 'Add you to the docker group now?',
59
+ relaunch: 'Carry on now with the docker group, without logging out?'
60
+ };
61
+ export const DOCKER_OFFER_HINT = 'y yes · r check again · q stop';
62
+ export const DOCKER_OFFER_RUNNING = 'Running (sudo may ask for your password):';
63
+ export const DOCKER_OFFER_FAILED = 'That did not finish. Fix what it said, then run quox to pick up where you left off.';
64
+ export const DOCKER_OFFER_RELAUNCH = 'Starting quox again with the docker group.';
65
+ export const PREFLIGHT_TITLE = 'Checking this machine';
66
+ export const PREFLIGHT_RETRY = 'r to check again · q to stop';
67
+ export const PREFLIGHT_RETRY_DRY = 'r to check again · c to continue anyway (dry run) · q to stop';
68
+ export const PREFLIGHT_CONTINUED = 'Continuing anyway: dry run, so nothing will be installed on this machine.';
69
+ export const PREFLIGHT_OK = 'This machine is ready.';
70
+ export const PREFLIGHT_FAIL = 'Fix the items above, then press r to check again.';
71
+ export const SETUP_DOCS = 'https://quox.ai/docs/setup';
72
+
73
+ export const CHECK = {
74
+ docker: {
75
+ name: 'DOCKER',
76
+ ok: (v) => `Docker ${v}, daemon reachable`,
77
+ missing: 'Docker is not installed',
78
+ missingFix: 'Install Docker, then press r.',
79
+ missingLink: 'https://docs.docker.com/get-docker/',
80
+ perm: 'Docker is installed, but this user cannot reach the daemon',
81
+ permFix: 'Run: sudo usermod -aG docker $USER && newgrp docker then press r.',
82
+ permStale: 'Docker is installed, and you are in the docker group, but this terminal started before that',
83
+ permStaleFix: 'Pressing r cannot fix this: a running terminal never gains a new group. Run: newgrp docker (or open a new terminal), then run: quox',
84
+ down: 'Docker is installed, but the daemon is not running',
85
+ downFix: 'Start Docker (Docker Desktop, or: sudo systemctl start docker), then press r.',
86
+ link: 'https://docs.docker.com/engine/install/'
87
+ },
88
+ compose: {
89
+ name: 'COMPOSE',
90
+ ok: (v) => `Compose v${String(v).replace(/^v/, '')}`,
91
+ missing: 'Docker Compose v2 was not found',
92
+ missingFix: 'Install the Compose plugin (it ships with Docker Desktop), then press r.',
93
+ old: (v) => `Compose ${v} is too old, v2 is needed`,
94
+ link: 'https://docs.docker.com/compose/install/'
95
+ },
96
+ tools: {
97
+ name: 'TOOLS',
98
+ ok: 'git and openssl found',
99
+ missing: (list) => `Not found: ${list.join(', ')}`,
100
+ fix: (list) => `Install ${list.join(' and ')} with your package manager, then press r.`,
101
+ link: 'https://quox.ai/docs/setup'
102
+ },
103
+ disk: {
104
+ name: 'DISK',
105
+ ok: (gb) => `${gb} GB free`,
106
+ low: (gb, rec) => `${gb} GB free, ${rec} GB recommended (it may run out while building)`,
107
+ fail: (gb, min) => `${gb} GB free, at least ${min} GB needed`,
108
+ fix: (min) => `Free up space until at least ${min} GB is available, then press r.`,
109
+ link: 'https://quox.ai/docs/setup'
110
+ },
111
+ ram: {
112
+ name: 'MEMORY',
113
+ ok: (gb) => `${gb} GB of RAM`,
114
+ low: (gb, rec) => `${gb} GB of RAM, ${rec} GB recommended (it will run, slowly)`,
115
+ fail: (gb, min) => `${gb} GB of RAM, at least ${min} GB needed`,
116
+ fix: (min) => `Quox needs a machine with at least ${min} GB of RAM.`,
117
+ link: 'https://quox.ai/docs/setup'
118
+ },
119
+ ports: {
120
+ name: 'PORTS',
121
+ ok: (n) => `${n} ports free`,
122
+ busy: (list) => `In use: ${list.length > 5 ? `${list.slice(0, 4).join(', ')} and ${list.length - 4} more` : list.join(', ')}`,
123
+ ownInstall: 'In use by the Quox being installed here',
124
+ quoxFix: 'Quox looks like it is already running here. Use it with /connect server https://localhost:3000, or stop it first.',
125
+ fix: (p) => `Stop whatever is using port ${p} (see: ss -ltnp 'sport = :${p}'), then press r.`,
126
+ link: 'https://quox.ai/docs/setup'
127
+ },
128
+ running: 'checking'
129
+ };
130
+
131
+ // ---- credential --------------------------------------------------------------------------------
132
+ export const CRED_TITLE = 'Which AI should your agents use?';
133
+ export const CRED_HINT = '↑↓ to choose · Enter to pick';
134
+ export const CRED_OPTIONS = {
135
+ chatgpt: { label: 'Sign in with ChatGPT', note: 'coming soon' },
136
+ openai: { label: 'OpenAI API key', note: '' },
137
+ anthropic: { label: 'Claude API key', note: '' },
138
+ ollama: { label: 'Ollama on this machine', note: 'found at localhost:11434' },
139
+ // B3: offered even when nothing answers locally; the user enters the LAN URL of the machine running it.
140
+ ollamaLan: { label: 'Ollama on another machine', note: 'enter its URL' },
141
+ skip: { label: 'Skip for now', note: 'agents will be limited' }
142
+ };
143
+ export const credPrompt = (label) => `Paste your ${label}. It stays in memory only: never written to disk, history or the transcript.`;
144
+ export const CRED_INPUT_HINT = 'Enter to use it · Esc to go back';
145
+ export const credHeld = (label, fp) => `${label} held in memory (fingerprint ${fp}). It is stored in your Quox vault after install, never on disk here.`;
146
+ export const credConsent = (label) => `${label} is a cloud AI: your messages and tool results are sent to it, so Quox needs your OK once. Say no and nothing goes to it until you give it later with /consent grant openai (or Settings > Privacy in the dashboard). A local model (Ollama) needs no consent.`;
147
+ // QUOXON-Z2H lane R: the one consent question at the credential step. Default No: cloud processing stays opt-in.
148
+ export const credConsentAsk = (who) => askText(`Allow Quox to send your conversations to ${who}?`, { keys: 'y/N', who: 'Quox', action: `send your messages and any tool results to ${who}, a third party, when it answers` });
149
+ export const CRED_CONSENT_HINT = 'y yes · n or Enter no';
150
+ export const credConsentYes = (who) => `Yes. Your OK for ${who} is recorded as soon as your owner account exists. Withdraw it any time in Settings > Privacy.`;
151
+ export const credConsentNo = (who, provider) => `No. ${who} receives nothing until you give your OK: /consent grant ${provider}, or Settings > Privacy in the dashboard.`;
152
+ export const CRED_EMPTY = 'Nothing was pasted. Paste the key, or Esc to choose again.';
153
+ export const CRED_OLLAMA = 'Ollama it is. The Quox server runs in Docker and cannot reach "localhost", so after install connect it by this machine\'s LAN address: start Ollama with OLLAMA_HOST=0.0.0.0, then /connect ollama http://<lan-ip>:11434';
154
+ export const OLLAMA_URL_PROMPT = 'The Ollama URL on your network, for example http://<lan-ip>:11434. Not a secret. On that machine, start Ollama with OLLAMA_HOST=0.0.0.0 and allow port 11434.';
155
+ export const OLLAMA_URL_HINT = 'Enter to use it · Esc to go back';
156
+ export const OLLAMA_URL_BAD = 'That does not look like an Ollama URL. Use http://<host>:11434, or Esc to choose again.';
157
+ export const ollamaChosen = (url) => `Ollama it is, at ${url}. After install, run /connect ollama ${url} so the server checks it and lists its models.`;
158
+ export const CRED_SKIPPED = 'Skipped. Until you add an AI your agents are limited: they cannot think or answer for themselves. Add one later with /connect.';
159
+ export const CRED_CHATGPT_SOON = 'Sign in with ChatGPT is coming soon. Pick another option for now.';
160
+
161
+ // ---- install -----------------------------------------------------------------------------------
162
+ export const INSTALL_TITLE = 'Installing Quox';
163
+ export const INSTALL_DRY = 'dry run: nothing is downloaded, built or started';
164
+ export const INSTALL_HINT = 'v to show the log · Ctrl+C to stop (you can pick it up again)';
165
+ export const STAGES = {
166
+ fetch: 'Fetch the source',
167
+ configure: 'Configure secrets and certificates',
168
+ build: 'Build the images',
169
+ start: 'Start the services',
170
+ health: 'Wait until healthy'
171
+ };
172
+ /** Z2H-IMAGES: the build stage relabels itself once setup.sh says whether it is downloading or building. */
173
+ export const BUILD_LABELS = { download: 'Download the images', build: 'Build the images' };
174
+ export const INSTALL_RERUN_HINT = 'It is safe to run the installer again: finished steps are kept and the build is cached.';
175
+ export const INSTALL_LOG_PATH = (p) => `Full install log: ${p}`;
176
+ export const INSTALL_FAILED = (stage) => `The install stopped at: ${stage}. Press v for the log, r to try again.`;
177
+ export const INSTALL_NOT_YET = 'Installing from here arrives in the next release. For now, run this in another terminal:';
178
+ export const INSTALL_COMMAND = 'curl -fsSL https://get.quox.ai | sh';
179
+ export const INSTALL_NOT_YET_AFTER = 'Then run quox again and type /connect server https://localhost:3000';
180
+ export const INSTALL_KEY_GONE = 'Your key was not kept: it only ever lived in memory. You will add it again after install.';
181
+ export const installWhere = (dir) => `Installing into ${dir}`;
182
+ export const installScriptLead = (url, bytes) => `Installer ${url} (${Math.max(1, Math.round(bytes / 1024))} KB), SHA256`;
183
+ export const installScript = (url, sha, bytes) => `${installScriptLead(url, bytes)} ${sha}`;
184
+ export const INSTALL_STOP_ASK = askText('Stop the install?', { reason: 'You can pick it up next time.', keys: 'y/N' });
185
+ export const INSTALL_STOP_KEEP = 'Carrying on.';
186
+ export const INSTALL_STOPPED = 'Install stopped. Run quox to pick up where you left off.';
187
+ export const INSTALL_EARLIER = 'done earlier';
188
+ export const INSTALL_HEALTH_ONLY = 'Your Quox was already started last time, so this only checks that it is healthy.';
189
+ export const INSTALL_DEGRADED = 'Some services are still starting. Press r to check again in a minute, or v for the log.';
190
+ export const INSTALL_FAIL_HINT = 'v log · r try again · Ctrl+C stop';
191
+
192
+ // ---- owner account (C2c) -----------------------------------------------------------------------
193
+ export const OWNER_TITLE = 'Your owner account';
194
+ export const OWNER_WHY = 'This account owns your Quox. You sign in to the dashboard with it.';
195
+ export const OWNER_EMAIL_PLACEHOLDER = 'your email address';
196
+ export const OWNER_EMAIL_BAD = 'That does not look like an email address.';
197
+ export const OWNER_PW_PROMPT = 'Choose a password: 12 or more characters with upper and lower case, a number and a symbol. Or press Enter on an empty line and I will make a strong one.';
198
+ export const OWNER_PW_HINT = 'Enter to use it · Enter on empty to generate one · Esc to change the email';
199
+ export const ownerPwShownOnce = (pw) => `Your password, shown once: ${pw}`;
200
+ export const OWNER_PW_SAVE = 'Save it in your password manager now. Quox keeps only a sign-in token on this machine, never the password.';
201
+ export const OWNER_EXISTS = 'This Quox already has an owner. Enter that account\'s email and password to sign in.';
202
+
203
+ // ---- finishing ---------------------------------------------------------------------------------
204
+ export const FINISH_TITLE = 'Finishing';
205
+ export const FIN = {
206
+ account: { name: 'ACCOUNT', running: 'creating your owner account', ok: (e) => `owner ${e}`, existing: (e) => `existing owner ${e}` },
207
+ signin: { name: 'SIGN-IN', running: 'signing you in', ok: (org) => `signed in${org ? ` to ${org}` : ''}, token saved` },
208
+ vault: {
209
+ name: 'AI KEY', running: (label) => `testing your ${label}, then storing it in your vault`,
210
+ skipped: 'no key to store', ollama: 'Ollama: add it to your vault with quox vault create --type ollama'
211
+ },
212
+ consent: { name: 'CONSENT', running: (who) => `recording your OK for ${who}`, ok: (who) => `OK recorded for ${who}`, fail: (e, provider) => `not recorded (${e}), later: /consent grant ${provider}` },
213
+ link: { name: 'DASHBOARD', running: 'making your one-time sign-in link', ok: 'one-time link ready (10 minutes, single use)', fail: (e) => `no link (${e}), sign in with your owner account instead` }
214
+ };
215
+ export const KEY_GONE_AFTER = 'The key is gone from this terminal\'s memory now.';
216
+ export const keyNotStored = (provider) => `Add it again any time with /connect ${provider}.`;
217
+
218
+ // ---- finale ------------------------------------------------------------------------------------
219
+ export const FINALE_DRY_BANNER = 'Dry run: this is the planned finish. Nothing was installed.';
220
+ export const FINALE_RUNNING = 'Your Quox is running.';
221
+ export const REPLAY_TOUR = 'Give me a short tour of what you can do here.';
222
+ export const finaleReplay = (text) => text ? `Your first real turn sends what you asked: "${text}"` : 'Your first real turn: a short tour of what your agents can do.';
223
+ export const FINALE_REPLAY_DRY = '(the reply and its receipt appear here once the install is real)';
224
+ export const finaleDashboard = (url) => `Your dashboard is ready: ${url} (one-time sign-in link)`;
225
+ export const finaleDashboardPlain = (url) => `Your dashboard is ready: ${url} (sign in with your owner account)`;
226
+ // When the line does not fit the terminal, the URL goes on its own unwrapped line so it stays clickable.
227
+ export const FINALE_DASHBOARD_LEAD = 'Your dashboard is ready (one-time sign-in link, 10 minutes):';
228
+ export const FINALE_DASHBOARD_LEAD_PLAIN = 'Your dashboard is ready (sign in with your owner account):';
229
+ export const FINALE_CERT = 'Your browser will warn about the certificate the first time: it is the self-signed one this install made for you.';
230
+ export const FINALE_PROOF = 'Everything you just did is there, with the proof.';
231
+ export const FINALE_TIPS_TITLE = 'Three things to try:';
232
+ export const TIPS = {
233
+ servers: ['/observers shows what Quox can see right now, and what it cannot', '/connect shows what is connected and adds AI keys safely', 'Just run quox any time; your conversations are kept on your server'],
234
+ automate: ['/skills lists what your agents already know how to do', '/approvals shows anything waiting for your yes', 'Just run quox any time; your conversations are kept on your server'],
235
+ code: ['/attach <agent> sends your turns to one agent, /detach comes back', '/connect shows what is connected and adds AI keys safely', 'Just run quox any time; your conversations are kept on your server'],
236
+ email: ['/approvals shows anything waiting for your yes; nothing is sent without it', '/connect shows what is connected and adds AI keys safely', 'Just run quox any time; your conversations are kept on your server'],
237
+ explore: ['/help lists every command', '/attach <agent> sends your turns to one agent, /detach comes back', 'Just run quox any time; your conversations are kept on your server']
238
+ };
239
+ TIPS.offscript = TIPS.explore;
240
+ export const FINALE_TIPS = TIPS.explore; // the dry run and any intent without its own set
241
+ // K2: one gentle, honest next connection that fits what they said they wanted.
242
+ export const K2 = {
243
+ servers: 'You said you want to watch your servers. None are connected yet. Add your first with /hosts add (it needs no AI), or on the dashboard Fleet page.',
244
+ automate: 'You said you want to automate something. Already use n8n? Bring a workflow across with: quox workflow import-n8n --file <path>',
245
+ code: 'You said you want to code with agents. Connect GitHub so they can see your repos: quox vault create --type github',
246
+ email: 'You said you want help with email. Connect your mailbox: quox mail connect --provider gmail (or outlook, icloud)',
247
+ explore: 'Want your agents to do more? /connect shows what is connected and what you can add.'
248
+ };
249
+ K2.offscript = K2.explore;
250
+ export const K2_SERVERS_NO_INSTALLER = 'You said you want to watch your servers. None are connected yet, and this install cannot enrol hosts yet because its host installer is not available.';
251
+ export const k2NoAi = (provider) => `Your agents have no AI yet, so they cannot answer for themselves. Connect one now? /connect ${provider}`;
252
+ export const FINALE_EXIT = 'Enter to start talking to your Quox';
253
+ export const FINALE_EXIT_DRY = 'Enter to finish';
254
+
255
+ // ---- help, misc --------------------------------------------------------------------------------
256
+ export const HELP = [
257
+ ['/connect server <url>', 'use a QuoxCORE you already have'],
258
+ ['/exit', 'leave; next time we pick up here']
259
+ ];
260
+ export const SLASH_UNKNOWN = 'Only /connect server, /help and /exit work until your Quox is running.';
261
+ export const BYE = 'See you soon. Run quox to pick up where you left off.';
262
+ export const NO_SERVER_PRINT = 'Run quox (without --print) to get started.';
263
+ export const FINALE_HOSTS_NO_AI = 'No AI needed to add a host: /hosts add shows the one command to run on that machine.';
@@ -0,0 +1,108 @@
1
+ /**
2
+ * The credential step: which AI the agents use, and the key, held in memory only.
3
+ *
4
+ * `requestCredential(provider)` is THE hook for the K1 secure key card (/connect, branch session/quox-connect).
5
+ * Until that merges, the broker below backs it with this view's own masked input. Same rules either way: the
6
+ * secret never enters a transcript, history item, journey file, config file or event stream, and the only
7
+ * thing ever shown or persisted about it is its fingerprint.
8
+ */
9
+ import { createHash } from 'node:crypto';
10
+ import { CRED_OPTIONS } from './copy.js';
11
+
12
+ export const PROVIDERS = ['chatgpt', 'openai', 'anthropic', 'ollama', 'skip'];
13
+ export const KEY_PROVIDERS = new Set(['openai', 'anthropic']);
14
+ // Sign in with ChatGPT stays visible but unselectable until OpenAI approves the integration.
15
+ export const CHATGPT_ENABLED = false;
16
+
17
+ /**
18
+ * Options in display order. #1288: the choices that work come first. Sign in with ChatGPT is not built
19
+ * yet (waiting on OpenAI), so while it is off it is listed LAST as "coming soon", never first; once it
20
+ * is on it leads (OpenAI-first). Ollama is always offered (B3): "on this machine" first when
21
+ * localhost:11434 answered, else "on another machine" (asks for its LAN URL) before Skip.
22
+ */
23
+ export function credentialOptions({ ollama = false, chatgpt = CHATGPT_ENABLED } = {}) {
24
+ const working = ollama ? ['ollama', 'openai', 'anthropic', 'skip'] : ['openai', 'anthropic', 'ollama', 'skip'];
25
+ const order = chatgpt ? ['chatgpt', ...working] : [...working, 'chatgpt'];
26
+ return order.map(id => {
27
+ if (id === 'ollama') return { id, ...(ollama ? CRED_OPTIONS.ollama : CRED_OPTIONS.ollamaLan), detected: Boolean(ollama), disabled: false };
28
+ return { id, ...CRED_OPTIONS[id], disabled: id === 'chatgpt' && !chatgpt };
29
+ });
30
+ }
31
+
32
+ /** The next selectable row from `sel` in direction dir (1 down, -1 up), wrapping; disabled rows are skipped. */
33
+ export function nextSelectable(options, sel, dir) {
34
+ const n = options.length;
35
+ if (!n) return 0;
36
+ for (let k = 1; k <= n; k++) {
37
+ const i = (((sel + dir * k) % n) + n) % n;
38
+ if (!options[i].disabled) return i;
39
+ }
40
+ return sel;
41
+ }
42
+
43
+ /** A typed Ollama URL -> normalised http(s) URL (bare host gets http:// and :11434) | null. */
44
+ export function normaliseOllamaUrl(text) {
45
+ let v = String(text || '').trim();
46
+ if (!v || /\s/.test(v)) return null;
47
+ const bare = !/^[a-z][a-z0-9+.-]*:\/\//i.test(v);
48
+ if (bare) v = `http://${v}`;
49
+ let u;
50
+ try { u = new URL(v); } catch { return null; }
51
+ if (u.protocol !== 'http:' && u.protocol !== 'https:') return null;
52
+ if (u.username || u.password || !u.hostname) return null;
53
+ if (bare && !u.port) u.port = '11434';
54
+ return u.toString().replace(/\/$/, '');
55
+ }
56
+
57
+ export const fingerprint = (secret) => 'sha256:' + createHash('sha256').update(String(secret)).digest('hex').slice(0, 8);
58
+
59
+ /** A secret that refuses to serialise: JSON, String() and util.inspect all show a redaction. */
60
+ export function holdSecret(provider, value) {
61
+ let v = String(value);
62
+ const fp = fingerprint(v);
63
+ const redacted = `[${provider} key ${fp}]`;
64
+ return Object.freeze({
65
+ provider,
66
+ fingerprint: fp,
67
+ reveal: () => v, // the ONE accessor: C2c hands it to the new instance's vault API, then drops it
68
+ drop: () => { v = ''; },
69
+ toJSON: () => redacted,
70
+ toString: () => redacted,
71
+ [Symbol.for('nodejs.util.inspect.custom')]: () => redacted
72
+ });
73
+ }
74
+
75
+ /**
76
+ * Broker behind requestCredential(): a single pending request the view renders as a masked card.
77
+ * K1 swap: replace createCredentialBroker().request with the secure card call; the view keeps working.
78
+ */
79
+ export function createCredentialBroker() {
80
+ let pending = null;
81
+ const listeners = new Set();
82
+ const emit = () => { for (const fn of listeners) fn(pending); };
83
+ return {
84
+ /** requestCredential(provider) -> Promise<held secret | null (cancelled)> */
85
+ request(provider) {
86
+ if (pending) pending.resolve(null);
87
+ return new Promise((resolve) => {
88
+ pending = { provider, resolve: (val) => { pending = null; emit(); resolve(val); } };
89
+ emit();
90
+ });
91
+ },
92
+ submit(value) { if (pending && String(value).length) pending.resolve(holdSecret(pending.provider, value)); },
93
+ cancel() { pending?.resolve(null); },
94
+ get pending() { return pending ? { provider: pending.provider } : null; },
95
+ subscribe(fn) { listeners.add(fn); return () => listeners.delete(fn); }
96
+ };
97
+ }
98
+
99
+ /**
100
+ * THE hook the view calls: requestCredential(provider) -> Promise<held secret | null>.
101
+ * K1 merge (session/quox-connect): return the secure key card's result here instead of broker.request(provider).
102
+ * Whatever backs it must keep the rules above (memory only, fingerprint the only trace).
103
+ */
104
+ export function createRequestCredential(broker) {
105
+ return function requestCredential(provider) {
106
+ return broker.request(provider);
107
+ };
108
+ }
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Should bare `quox` open Getting started instead of the chat client?
3
+ *
4
+ * Yes only when nothing says a server exists: no profile is signed in (human or resident), no profile points
5
+ * anywhere but the built-in default URL, no QUOX_URL, and the user did not ask for a specific profile or for
6
+ * the ambient service key. Anyone who has ever configured a server keeps today's honest "Not signed in"
7
+ * message instead (they need `quox login`, not an installer).
8
+ */
9
+ export const DEFAULT_URL = 'http://localhost:3000';
10
+
11
+ export function needsGettingStarted({ profiles = [], residents = [], profileArg = null, env = process.env, serviceKeyFlag = false, journey = null } = {}) {
12
+ if (profileArg) return false;
13
+ if (env.QUOX_URL) return false;
14
+ if ((serviceKeyFlag || env.QUOX_FORCE_SERVICE_KEY) && env.QUOX_SERVICE_KEY) return false;
15
+ if (residents.length) return false;
16
+ if (profiles.some(p => p.loggedIn)) return false;
17
+ // A journey this guide started (install or finish under way) keeps it here, even after the
18
+ // finish step pointed the profile at the new instance: nobody is signed in yet.
19
+ if (journey?.installStage || journey?.step === 'owner' || journey?.step === 'finishing') return true;
20
+ if (profiles.some(p => p.url && p.url.replace(/\/+$/, '') !== DEFAULT_URL)) return false;
21
+ return true;
22
+ }
@@ -0,0 +1,45 @@
1
+ /**
2
+ * FIRSTRUN (2026-10-19): the guide OFFERS to fix Docker instead of saying "install Docker, then press r".
3
+ *
4
+ * install Docker missing (Linux): Docker's official script, then add this user to the docker group
5
+ * group Docker installed, this user not in the docker group: add them
6
+ * relaunch in the group, but this terminal started before that: nothing to run with sudo
7
+ *
8
+ * A yes leaves the Ink view (the journey is saved at preflight), runs the command with the real terminal
9
+ * attached so sudo can ask for a password, then starts quox again under `sg docker`, so the new group applies
10
+ * without logging out. The relaunched quox picks up where the guide left off.
11
+ */
12
+ import { spawnSync } from 'node:child_process';
13
+ import { askText } from '../ask.js';
14
+ import * as T from './copy.js';
15
+
16
+ export const DOCKER_INSTALL_CMD = 'curl -fsSL https://get.docker.com | sudo sh && sudo usermod -aG docker "$USER"';
17
+ export const DOCKER_GROUP_CMD = 'sudo usermod -aG docker "$USER"';
18
+ const COMMANDS = { install: DOCKER_INSTALL_CMD, group: DOCKER_GROUP_CMD, relaunch: null };
19
+
20
+ /** rows -> { kind, command, ask } for the first row the guide can fix, or null. */
21
+ export function dockerOffer(rows) {
22
+ const r = (rows || []).find(x => x?.status === 'fail' && x.offer && x.offer in COMMANDS);
23
+ if (!r) return null;
24
+ const kind = r.offer;
25
+ const command = COMMANDS[kind];
26
+ const q = T.DOCKER_OFFER_QUESTION[kind];
27
+ const action = command ? `run: ${command} then start quox again with the docker group` : 'start quox again with the docker group (sg docker), no sudo';
28
+ return { kind, command, ask: askText(q, { keys: 'y/N', who: 'Quox', action }) };
29
+ }
30
+
31
+ const shq = (s) => `'${String(s).replace(/'/g, `'\\''`)}'`;
32
+
33
+ /** Runs the offer with the terminal attached. -> { action: 'exit', status } */
34
+ export function runDockerOffer(kind, { spawn = spawnSync, out = (s) => process.stdout.write(s), node = process.execPath, bin } = {}) {
35
+ const command = COMMANDS[kind];
36
+ if (command) {
37
+ out(`\n${T.DOCKER_OFFER_RUNNING}\n ${command}\n\n`);
38
+ const r = spawn('sh', ['-c', command], { stdio: 'inherit' });
39
+ if (r?.status !== 0) { out(`\n${T.DOCKER_OFFER_FAILED}\n`); return { action: 'exit', status: r?.status ?? 1 }; }
40
+ }
41
+ out(`\n${T.DOCKER_OFFER_RELAUNCH}\n`);
42
+ const again = spawn('sg', ['docker', '-c', `exec ${shq(node)} ${shq(bin)}`], { stdio: 'inherit' });
43
+ if (again?.error) { out(`${T.CHECK.docker.permStaleFix}\n`); return { action: 'exit', status: 1 }; }
44
+ return { action: 'exit', status: again?.status ?? 0 };
45
+ }
@@ -0,0 +1,33 @@
1
+ /**
2
+ * FIRSTRUN (2026-10-19): a failed install says WHY in one plain line, for the causes a stranger can act on.
3
+ * Input: installer output plus the tail of the build log setup.sh names. Output: { kind, host?, message } | null.
4
+ * Prebuilt images being unavailable ("error from registry: denied") is never a cause: the installer builds instead.
5
+ */
6
+ const RETRY = 'then press r to try again.';
7
+
8
+ const NETWORK = [
9
+ /Could not connect to ([a-z0-9.-]+\.[a-z]{2,}):\d+/i,
10
+ /Temporary failure resolving '([^']+)'/i,
11
+ /Failed to fetch https?:\/\/([a-z0-9.-]+\.[a-z]{2,})\/\S*\s+(?:Could not connect|Unable to connect|Connection failed|Temporary failure)/i,
12
+ /request to https?:\/\/([a-z0-9.-]+\.[a-z]{2,})\/\S* failed, reason: (?:connect )?(?:ETIMEDOUT|ECONNRESET|ECONNREFUSED|EAI_AGAIN|ENOTFOUND)/i,
13
+ /getaddrinfo (?:EAI_AGAIN|ENOTFOUND) ([a-z0-9.-]+\.[a-z]{2,})/i
14
+ ];
15
+
16
+ export function explainInstallFailure(text) {
17
+ const t = String(text ?? '');
18
+ if (!t.trim()) return null;
19
+ for (const re of NETWORK) {
20
+ const m = re.exec(t);
21
+ if (m) {
22
+ const host = m[1].toLowerCase();
23
+ return { kind: 'network', host, message: `The build could not reach ${host}, a package server. Check this machine's internet connection, firewall or proxy, ${RETRY}` };
24
+ }
25
+ }
26
+ if (/no space left on device/i.test(t)) {
27
+ return { kind: 'disk', message: `The disk filled up during the build. Free some space (docker system prune -f frees old build cache), ${RETRY}` };
28
+ }
29
+ if (/heap out of memory|exit code: 137\b|\bOOMKilled\b|Cannot allocate memory/i.test(t)) {
30
+ return { kind: 'memory', message: `The build ran out of memory. Close other programs or give this machine more RAM (8 GB is recommended), ${RETRY}` };
31
+ }
32
+ return null;
33
+ }
@@ -0,0 +1,134 @@
1
+ /**
2
+ * C2c: finishing a fresh install from the CLI (FIRST_RUN_JOURNEY.md steps 6, 7 and 9).
3
+ *
4
+ * createOwner POST /api/setup/admin the instance's own first-owner route (refuses once an
5
+ * owner exists; creates user, default org, membership)
6
+ * signIn POST /api/auth/login via core/auth.js login(): the profile stores the login
7
+ * token in its existing format. The password is never stored.
8
+ * storeCredential connect.js connectFlow server-side test, then the governed vault write as the
9
+ * org default (POST /api/orgs/:org/vault, audited, label
10
+ * "<Name> …last4"). The held key is dropped right after.
11
+ * loginLink POST /api/auth/login-link a 10 minute, single-use, user+org bound sign-in link,
12
+ * joined to the dashboard URL the installer printed.
13
+ *
14
+ * The CLI talks to the services the way every other command does: profile url https://localhost:3000,
15
+ * services derived to their loopback ports (auth 127.0.0.1:3101), so the self-signed edge certificate
16
+ * never meets the CLI. Only the browser sees it, through the link.
17
+ */
18
+ import { randomBytes, randomInt } from 'node:crypto';
19
+ import { connectFlow } from '../connect.js';
20
+
21
+ export const LOCAL_PROFILE_URL = 'https://localhost:3000';
22
+
23
+ // The auth service's rules (services/auth/utils/passwordValidation.js).
24
+ const SPECIAL = /[!@#$%^&*()_+\-=[\]{};':"\\|,.<>/?`~]/;
25
+ export function passwordProblem(pw) {
26
+ const p = String(pw ?? '');
27
+ if (p.length < 12) return 'Use at least 12 characters.';
28
+ if (p.length > 256) return 'Use at most 256 characters.';
29
+ if (!/[A-Z]/.test(p)) return 'Add an uppercase letter.';
30
+ if (!/[a-z]/.test(p)) return 'Add a lowercase letter.';
31
+ if (!/[0-9]/.test(p)) return 'Add a number.';
32
+ if (!SPECIAL.test(p)) return 'Add a special character, for example - or !';
33
+ return null;
34
+ }
35
+ export const emailOk = (e) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(String(e ?? '').trim());
36
+
37
+ /** 3 groups of 6 from an unambiguous alphabet, joined with '-', plus one guaranteed digit and capital. */
38
+ export function generatePassword() {
39
+ const A = 'abcdefghjkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789';
40
+ for (;;) {
41
+ const bytes = randomBytes(18);
42
+ const groups = [0, 1, 2].map(g => Array.from(bytes.subarray(g * 6, g * 6 + 6), b => A[b % A.length]).join(''));
43
+ const pw = `${groups.join('-')}-${randomInt(2, 10)}${'ABCDEFGHJKLMNPQRSTUVWXYZ'[randomInt(0, 24)]}`;
44
+ if (!passwordProblem(pw)) return pw;
45
+ }
46
+ }
47
+
48
+ const apiError = (e, fallback) => (e?.message && !/^\s*$/.test(e.message) ? e.message : fallback);
49
+
50
+ /**
51
+ * -> finisher { kind, profileUrl, createOwner, signIn, storeCredential, loginLink }
52
+ * Dependencies are the CLI's own modules; tests run them for real against a fake instance.
53
+ */
54
+ export async function createFinisher({ profileUrl = LOCAL_PROFILE_URL, fetchImpl = globalThis.fetch } = {}) {
55
+ const { loadConfig } = await import('../../core/config.js');
56
+ const { createAuth } = await import('../../core/auth.js');
57
+ const { createClient } = await import('../../core/client.js');
58
+ const { createApi } = await import('../api.js');
59
+
60
+ // Nothing is written here: the profile is pointed at the new instance only at sign-in, so leaving
61
+ // Getting started early never leaves a half-configured profile behind.
62
+ const config = loadConfig();
63
+ const auth = createAuth(config);
64
+ const client = createClient(config, auth);
65
+ const authUrl = () => config.getServiceUrl('auth');
66
+
67
+ return {
68
+ kind: 'real',
69
+ profileUrl,
70
+ authUrl,
71
+
72
+ /** -> { ok: true } | { ok: false, existed?: true, error } */
73
+ async createOwner({ email, password, name }) {
74
+ const display = name || String(email).split('@')[0];
75
+ let r;
76
+ try {
77
+ r = await fetchImpl(`${authUrl()}/api/setup/admin`, {
78
+ method: 'POST', headers: { 'Content-Type': 'application/json' },
79
+ body: JSON.stringify({ email: String(email).trim(), password, name: display, display_name: display })
80
+ });
81
+ } catch (e) { return { ok: false, error: `the auth service did not answer: ${e?.cause?.code || e?.message}` }; }
82
+ let body = null;
83
+ try { body = await r.json(); } catch { /* not json */ }
84
+ if (r.ok && body?.success) return { ok: true };
85
+ if (r.status === 400 && body?.error === 'admin_exists') return { ok: false, existed: true, error: body.message };
86
+ return { ok: false, error: body?.message || `HTTP ${r.status}` };
87
+ },
88
+
89
+ /** -> { ok: true, org } | { ok: false, error }. Stores the login token in the active profile. */
90
+ async signIn({ email, password }) {
91
+ try {
92
+ config.setProfileConnection({ url: profileUrl });
93
+ const data = await auth.login(authUrl(), String(email).trim(), password);
94
+ if (data?.mfa_required) return { ok: false, error: 'This account uses MFA. Finish signing in with: quox login' };
95
+ return { ok: true, org: data?.org?.name || null };
96
+ } catch (e) { return { ok: false, error: apiError(e, 'sign-in failed') }; }
97
+ },
98
+
99
+ /** held: a held secret from credential.js (or null). -> connectFlow result | { ok: false, skipped: true } */
100
+ async storeCredential(held) {
101
+ if (!held || typeof held.reveal !== 'function') return { ok: false, skipped: true };
102
+ try {
103
+ const api = createApi({ client, config, auth });
104
+ return await connectFlow(api, held.provider, held.reveal());
105
+ } finally {
106
+ held.drop();
107
+ }
108
+ },
109
+
110
+ /** QUOXON-Z2H lane R: the owner said yes at the credential step; record it as their own act. -> { ok } | { ok: false, error } */
111
+ async grantConsent(provider) {
112
+ try { await createApi({ client, config, auth }).grantConsent(provider); return { ok: true }; }
113
+ catch (e) { return { ok: false, error: apiError(e, 'consent not recorded') }; }
114
+ },
115
+
116
+ /** Z2H-R5 E: can this server serve its host installer? -> { ok, status } | null (unknown). Reads only. */
117
+ async hostInstaller() {
118
+ try {
119
+ const api = createApi({ client, config, auth });
120
+ const base = await api.hostsBaseUrl();
121
+ return await api.hostInstallCheck(base);
122
+ } catch { return null; }
123
+ },
124
+
125
+ /** -> { ok: true, url, expiresAt, ttlSeconds } | { ok: false, error } */
126
+ async loginLink(dashboardUrl) {
127
+ try {
128
+ const r = await client.post('/api/auth/login-link', { service: 'auth', body: {}, retries: 0 });
129
+ if (!r?.path || !/^\/api\/auth\/login-link\/consume\?t=/.test(r.path)) return { ok: false, error: 'unexpected answer from the auth service' };
130
+ return { ok: true, url: new URL(r.path, dashboardUrl || profileUrl).href, expiresAt: r.expires_at, ttlSeconds: r.ttl_seconds };
131
+ } catch (e) { return { ok: false, error: apiError(e, 'could not create the link') }; }
132
+ }
133
+ };
134
+ }