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,182 @@
1
+ /**
2
+ * Data for the inline object views, from the real services only. Every read is bounded (timeouts are
3
+ * short on purpose: an inline card must not hang the composer) and every failure comes back as a
4
+ * reason string, never as an empty result. Status is checked before anything is parsed: the client
5
+ * throws on non-2xx, and the throw is what becomes the reason.
6
+ */
7
+ import fs from 'node:fs';
8
+ import path from 'node:path';
9
+ import os from 'node:os';
10
+ import { fileURLToPath } from 'node:url';
11
+ import { findSkill } from '../skills.js';
12
+ import { packFrom } from './ladder.js';
13
+ import { slotFor } from './agent.js';
14
+ import { listFailure } from '../session.js';
15
+ import { resolveEndpoint } from '../../api/endpoints.js';
16
+ import { fleetFetchers } from './fleet.js';
17
+ import { healthFetchers } from './health.js';
18
+ import { proveFetchers } from './prove.js';
19
+ import { replayFetchers } from './replay.js';
20
+
21
+ const HERE = path.dirname(fileURLToPath(import.meta.url));
22
+ const ASSISTANTS_DIR = path.resolve(HERE, '../../../../src/config/entities/assistants');
23
+ const listOf = (d, ...keys) => { for (const k of keys) if (Array.isArray(d?.[k])) return d[k]; return Array.isArray(d) ? d : []; };
24
+ const why = (e) => (e?.status ? `HTTP ${e.status}` : /timed out/i.test(e?.message || '') ? 'timed out' : e?.message || 'failed');
25
+
26
+ /** The shipped assistant identities: id -> { name, tagline, description }. */
27
+ export function bundledIdentities(dir = ASSISTANTS_DIR) {
28
+ const out = new Map();
29
+ let files = [];
30
+ try { files = fs.readdirSync(dir).filter(f => f.endsWith('.json')); } catch { return out; }
31
+ for (const f of files) {
32
+ try {
33
+ const j = JSON.parse(fs.readFileSync(path.join(dir, f), 'utf8'));
34
+ if (j?.id) out.set(j.id, { name: j.identity?.name || j.id, tagline: j.identity?.tagline || null, description: j.identity?.description || null });
35
+ } catch { /* skip unreadable */ }
36
+ }
37
+ return out;
38
+ }
39
+
40
+ export function createObjectsApi({ client, orgId = () => null, home = os.homedir(), identities = bundledIdentities, profile = null }) {
41
+ const get = (service, p, query, timeout = 12000) => client.get(p, { service, query, retries: 0, timeout });
42
+ const post = (service, p, body, timeout = 8000) => client.post(p, { service, body, retries: 0, timeout });
43
+ const org = () => { const o = orgId(); return typeof o === 'string' ? o : null; };
44
+ let ids = null;
45
+ const idents = () => (ids ??= identities());
46
+ const nameOf = (id) => idents().get(id)?.name || id;
47
+
48
+ async function verifyReceipt(envelopeId, timeoutS = 8) {
49
+ try { const d = await post('collector', '/ward/verify-receipt', { source_id: envelopeId, source_kind: 'AEE' }, timeoutS * 1000); return { ok: true, result: d?.result || d }; }
50
+ catch (e) { return { ok: false, error: why(e), timeout: /timed out/i.test(e?.message || '') ? timeoutS : null }; }
51
+ }
52
+ async function aeeGet(id) {
53
+ try { const d = await get('collector', `/aee/${encodeURIComponent(id)}`, undefined, 10000); return { ok: true, env: d?.envelope || d }; }
54
+ catch (e) { return { ok: false, status: e?.status, error: why(e) }; }
55
+ }
56
+
57
+ /** Workflow by id or display name (quoxflow GET /api/workflows). -> { id, name, definition } | null */
58
+ async function findWorkflow(ref) {
59
+ const r = String(ref || '').trim();
60
+ try { const d = await get('quoxflow', `/api/workflows/${encodeURIComponent(r)}`); const w = d?.data || d; if (w?.id) return w; } catch (e) { if (e?.status && e.status !== 404) throw e; }
61
+ const all = listOf(await get('quoxflow', '/api/workflows', { limit: 100 }), 'data', 'workflows', 'items');
62
+ const lc = r.toLowerCase();
63
+ return all.find(w => String(w.name || '').toLowerCase() === lc) || all.find(w => String(w.name || '').toLowerCase().includes(lc)) || null;
64
+ }
65
+ async function pageExecutions(workflowId, status, max = 500) {
66
+ const out = [];
67
+ for (let offset = 0; offset < max; offset += 100) {
68
+ const rows = listOf(await get('quoxflow', '/api/executions', { workflowId, status, limit: 100, offset }), 'data', 'executions');
69
+ out.push(...rows);
70
+ if (rows.length < 100) break;
71
+ }
72
+ return out;
73
+ }
74
+
75
+ const self = {
76
+ ...fleetFetchers({ get, org, listOf, why, resolveEndpoint }),
77
+ ...healthFetchers({ get, org, listOf, why, resolveEndpoint }),
78
+ ...replayFetchers({ get, listOf, why, verifyReceipt: (id, t) => verifyReceipt(id, t), aeeGet: (id) => aeeGet(id) }),
79
+ ...proveFetchers({ get, listOf, resolveEndpoint, self: { proof: (t) => self.proof(t) } }),
80
+ /** E1 */
81
+ async skill(name) {
82
+ const all = listOf(await get('collector', '/quoxflow/skills', { orgId: org() || undefined }), 'data', 'skills');
83
+ const hit = findSkill(all, name);
84
+ if (!hit) return { error: `No skill named "${name}". /skills lists them.`, tone: 'warn' };
85
+ let skill = hit;
86
+ try { const d = await get('collector', `/quoxflow/skills/${encodeURIComponent(hit.id)}`, { orgId: org() || undefined }); skill = d?.data || d || hit; } catch { /* the list row is the same record */ }
87
+ let scoreboard = null;
88
+ // The org-scoped per-skill route; 404 = no recorded runs. (The bulk /scoreboards list is not
89
+ // org-filtered in quoxflow, so it is deliberately not used here.)
90
+ try { const d = await get('quoxflow', `/api/quox-skills/${encodeURIComponent(skill.id)}/scoreboard`, undefined, 8000); scoreboard = { ok: true, row: d?.data || null }; }
91
+ catch (e) { scoreboard = e?.status === 404 ? { ok: true, row: null } : { ok: false, error: why(e) }; }
92
+ return { data: { skill, scoreboard, agentName: nameOf } };
93
+ },
94
+
95
+ /** E2: ref = execution id / correlation id, or a workflow id or name (its latest run). */
96
+ async workflowRun(ref) {
97
+ let execution = null;
98
+ try { const d = await get('quoxflow', `/api/executions/${encodeURIComponent(ref)}`); execution = d?.data || d; } catch (e) { if (e?.status && e.status !== 404) throw e; }
99
+ if (!execution?.id) {
100
+ const wf = await findWorkflow(ref);
101
+ if (!wf) return { error: `No workflow or run called "${ref}".`, tone: 'warn' };
102
+ const rows = listOf(await get('quoxflow', '/api/executions', { workflowId: wf.id, limit: 1 }), 'data', 'executions');
103
+ if (!rows.length) return { error: `${wf.name || wf.id} has never run.`, tone: 'warn' };
104
+ execution = rows[0];
105
+ }
106
+ let envelopes = null, def = null;
107
+ try { const d = await get('quoxflow', `/api/executions/${encodeURIComponent(execution.id)}/envelopes`); envelopes = listOf(d?.data || d, 'envelopes'); } catch { envelopes = null; }
108
+ try { const d = await get('quoxflow', `/api/workflows/${encodeURIComponent(execution.workflowId)}`); def = (d?.data || d)?.definition || null; } catch { def = null; }
109
+ return { data: { execution, envelopes, def } };
110
+ },
111
+
112
+ /** E3 */
113
+ async crystal(ref) {
114
+ const wf = await findWorkflow(ref);
115
+ if (!wf) return { error: `No workflow called "${ref}".`, tone: 'warn' };
116
+ const [completed, failed] = await Promise.all([pageExecutions(wf.id, 'completed'), pageExecutions(wf.id, 'failed')]);
117
+ return { data: { workflow: { id: wf.id, name: wf.name }, executions: [...completed, ...failed], def: wf.definition || null } };
118
+ },
119
+
120
+ /** E4 */
121
+ async agent(name) {
122
+ const q = String(name || '').trim().toLowerCase();
123
+ let toolMap = null, toolErr = null, toolFail = null;
124
+ try { toolMap = (await client.get('/api/v1/tools/agents', { service: 'collector', retries: 0, timeout: 10000 }))?.agentTools || null; } catch (e) { toolErr = why(e); toolFail = e; }
125
+ let orgAgents = [];
126
+ try { if (org()) orgAgents = listOf(await get('auth', `/api/orgs/${org()}/agents`, { includeTools: 'false' }), 'agents', 'data'); } catch { /* optional */ }
127
+ const known = new Set([...Object.keys(toolMap || {}), ...idents().keys(), ...orgAgents.map(a => a.agent_id)]);
128
+ let id = [...known].find(k => k.toLowerCase() === q);
129
+ if (!id) id = [...known].find(k => String(nameOf(k)).toLowerCase() === q) || orgAgents.find(a => String(a.name || '').toLowerCase() === q)?.agent_id;
130
+ if (!id && toolFail) return { error: `Couldn't check agents: ${listFailure(toolFail, profile)}`, tone: 'warn' }; // a failed list is a failure, never "no such agent"
131
+ if (!id) return { error: `No agent called "${name}".`, tone: 'warn' };
132
+ const record = orgAgents.find(a => a.agent_id === id) || null;
133
+ const ident = idents().get(id) || {};
134
+ let slot = null;
135
+ try { slot = slotFor(listOf(await get('collector', '/api/v1/slots', undefined, 10000), 'slots'), id); } catch { slot = null; }
136
+ let last = null, lastErr = null, receipt = null;
137
+ try { last = listOf(await get('collector', '/aee/query', { from: `agent.${id}`, limit: 1 }, 10000), 'envelopes')[0] || null; } catch (e) { lastErr = why(e); }
138
+ if (last?.id) receipt = await verifyReceipt(last.id);
139
+ return { data: { id, name: ident.name || record?.name || id, tagline: ident.tagline, description: record?.description || ident.description || null, status: record?.status || null, record, tools: toolMap ? (toolMap[id] || []) : null, toolsErr: toolErr, slot, last, lastErr, receipt } };
140
+ },
141
+
142
+ /** E6 */
143
+ async memory(query) {
144
+ const d = await get('memory', '/api/memory/search', { q: query, limit: 10 });
145
+ return { data: { query, results: listOf(d, 'results', 'memories', 'data') } };
146
+ },
147
+
148
+ /** E7 */
149
+ async rules() {
150
+ let policies;
151
+ const o = org();
152
+ if (!o) policies = { ok: false, error: 'no org on this profile' };
153
+ else {
154
+ try { policies = { ok: true, list: listOf(await get('collector', `/orgs/${o}/governance/policies`, undefined, 15000), 'policies') }; }
155
+ catch (e) { policies = { ok: false, error: why(e) }; }
156
+ }
157
+ const pack = packFrom((f) => fs.readFileSync(path.join(home, '.claude', 'skills', f), 'utf8'));
158
+ return { data: { policies, pack } };
159
+ },
160
+
161
+ /** D1 */
162
+ async proof(tool) {
163
+ const envelope = await aeeGet(tool.envelopeId);
164
+ let aocl = null;
165
+ const corr = envelope.ok ? envelope.env?.corr : null;
166
+ if (corr) {
167
+ try { aocl = { ok: true, list: listOf(await get('collector', '/aee/query', { corr, limit: 50 }, 10000), 'envelopes').filter(e => /^aocl\./.test(String(e.intent || ''))) }; }
168
+ catch (e) { aocl = { ok: false, error: why(e) }; }
169
+ }
170
+ const receipt = await verifyReceipt(tool.envelopeId);
171
+ return { data: { tool, envelope, aocl, receipt } };
172
+ },
173
+
174
+ /** D3 */
175
+ async reconcile(tools) {
176
+ const items = [];
177
+ for (const t of tools) items.push({ tool: t.tool, envelopeId: t.envelopeId || null, record: t.envelopeId ? await aeeGet(t.envelopeId) : null });
178
+ return { data: { items } };
179
+ }
180
+ };
181
+ return self;
182
+ }
@@ -0,0 +1,149 @@
1
+ /**
2
+ * /fleet: computers, agents, missions and SubFleets in one compact block, with health. Read-only.
3
+ * Sources (the same routes `quox fleet ...` and `quox objective list` use): GET /api/v1/agents
4
+ * (heartbeats), GET /api/v1/fleet/hosts (Bastion registry), org agents, GET /api/objectives. A source
5
+ * that could not be read is named on the "Can't see" line, never counted as zero. SubFleets have an
6
+ * RFC but no API yet, so that row says so. Moving work is not here: the hint points at plain words.
7
+ */
8
+ import { seg, fit, fitRow, ago, plural, boxWidth } from './model.js';
9
+ import { fromObjective } from '../roster.js';
10
+
11
+ const OFFLINE = /^(dead|offline|down|disconnected|unreachable)$/;
12
+ const HEALTHY = /^(healthy|ok|good)$/;
13
+ const DEGRADED = /^(warning|warn|degraded|stale)$/;
14
+ const UNHEALTHY = /^(critical|unhealthy|error|failed|fail)$/;
15
+ const FLEET_OVERVIEW_WORDS = new Set(['health', 'status', 'list', 'all', 'overview', 'summary', 'hosts', 'agents', 'quoxagents']);
16
+
17
+ export const ORDER = ['healthy', 'degraded', 'unhealthy', 'offline', 'unknown'];
18
+ const SEVERITY = { unhealthy: 0, offline: 1, degraded: 2, unknown: 3, healthy: 4 };
19
+
20
+ /** A heartbeat row or a Bastion host row -> healthy | degraded | unhealthy | offline | unknown. */
21
+ export function healthOf(row) {
22
+ const s = row?.status;
23
+ const st = String(typeof s === 'object' && s ? s.state ?? '' : s ?? '').toLowerCase();
24
+ const h = String(typeof s === 'object' && s ? s.health ?? '' : '').toLowerCase();
25
+ if (OFFLINE.test(st) || OFFLINE.test(h)) return 'offline';
26
+ if (UNHEALTHY.test(h) || UNHEALTHY.test(st)) return 'unhealthy';
27
+ if (DEGRADED.test(h) || DEGRADED.test(st)) return 'degraded';
28
+ if (HEALTHY.test(h) || HEALTHY.test(st)) return 'healthy';
29
+ return 'unknown';
30
+ }
31
+
32
+ const listOk = (s) => (s?.ok ? s.list || [] : null);
33
+
34
+ /** d: { agents, hosts, orgAgents, missions } each { ok, list } | { ok:false, error } -> merged view model. */
35
+ export function collectFleet(d, now = Date.now()) {
36
+ const byId = new Map();
37
+ const cant = [];
38
+ const sources = [['heartbeats', d.agents], ['hosts', d.hosts]];
39
+ for (const [label, src] of sources) {
40
+ if (!src) continue;
41
+ if (!src.ok) { cant.push(`${label} (${src.error || 'failed'})`); continue; }
42
+ for (const r of src.list || []) {
43
+ const id = r.host_id || r.id || r.hostname;
44
+ if (!id) continue;
45
+ const cur = byId.get(id) || { id };
46
+ if (label === 'heartbeats') {
47
+ const s = r.status;
48
+ byId.set(id, { ...cur, health: healthOf(r), version: r.version ?? cur.version, lastSeenS: typeof s === 'object' ? s?.last_seen_seconds : undefined, heartbeat: true });
49
+ } else {
50
+ byId.set(id, { ...cur, ip: r.ip ?? cur.ip, group: r.group ?? cur.group, registryHealth: healthOf(r), health: cur.heartbeat ? cur.health : healthOf(r) });
51
+ }
52
+ }
53
+ }
54
+ const computers = [...byId.values()].sort((a, b) => SEVERITY[a.health] - SEVERITY[b.health] || a.id.localeCompare(b.id));
55
+ const counts = Object.fromEntries(ORDER.map(k => [k, 0]));
56
+ for (const c of computers) counts[c.health]++;
57
+ const org = listOk(d.orgAgents);
58
+ if (d.orgAgents && !d.orgAgents.ok) cant.push(`agents (${d.orgAgents.error || 'failed'})`);
59
+ const agents = org ? { active: org.filter(a => !a.status || a.status === 'active').length, other: org.filter(a => a.status && a.status !== 'active').length } : null;
60
+ let missions = null;
61
+ if (d.missions && !d.missions.ok) cant.push(`missions (${d.missions.error || 'failed'})`);
62
+ else if (d.missions) {
63
+ const rows = (d.missions.list || []).map(o => fromObjective(o, now)).filter(Boolean);
64
+ missions = { running: rows.filter(r => r.state === 'running').length, waiting: rows.filter(r => r.state === 'waiting').length, loops: rows.filter(r => r.kind === 'loop' && (r.state === 'running' || r.state === 'waiting')).length, rows: rows.filter(r => r.state === 'running' || r.state === 'waiting') };
65
+ }
66
+ return { computers, counts, agents, missions, cant };
67
+ }
68
+
69
+ const ROLE = { healthy: 'ok', degraded: 'warn', unhealthy: 'error', offline: 'error', unknown: 'muted' };
70
+ const HINT = 'ask in plain words to move work';
71
+
72
+ /** d: { agents, hosts, orgAgents, missions, now } -> view { box, rows } */
73
+ export function fleetCard(d, cols) {
74
+ const now = d.now ?? Date.now();
75
+ const f = collectFleet(d, now);
76
+ const w = boxWidth(cols, 78), inner = w - 4;
77
+ const L = (label, parts) => [seg(label.padEnd(12), 'muted'), ...parts];
78
+ const rows = [];
79
+ if (f.computers.length || (d.agents?.ok || d.hosts?.ok)) {
80
+ const bits = [];
81
+ for (const k of ORDER) if (f.counts[k]) { if (bits.length) bits.push(seg(' · ', 'muted')); bits.push(seg(`${f.counts[k]} ${k}`, ROLE[k], k !== 'healthy')); }
82
+ rows.push(L('Computers', [seg(`${f.computers.length} `, 'value', true), ...bits]));
83
+ const bad = f.computers.filter(c => c.health !== 'healthy');
84
+ if (bad.length) rows.push([seg('not healthy'.padEnd(12), 'muted'), seg(fit(bad.map(c => `${c.id} ${c.health}`).join(', '), inner - 12), 'warn')]);
85
+ } else rows.push(L('Computers', [seg('?', 'warn'), seg(' not read', 'muted')]));
86
+ rows.push(f.agents ? L('Agents', [seg(`${f.agents.active} active`, 'value'), ...(f.agents.other ? [seg(` · ${f.agents.other} other`, 'muted')] : [])]) : L('Agents', [seg('?', 'warn')]));
87
+ if (f.missions) {
88
+ const m = f.missions;
89
+ const extra = [m.waiting ? plural(m.waiting, 'waiting', 'waiting') : null, m.loops ? plural(m.loops, 'loop') : null].filter(Boolean);
90
+ rows.push(L('Missions', [seg(`${m.running} running`, 'value'), ...(extra.length ? [seg(` · ${extra.join(' · ')}`, 'muted')] : [])]));
91
+ for (const r of m.rows.slice(0, 3)) rows.push([seg(' ', 'muted'), seg(fit(`${r.name}${r.activity ? ` · ${r.activity}` : ''}`, inner - 2), 'muted')]);
92
+ if (m.rows.length > 3) rows.push([seg(` …and ${m.rows.length - 3} more`, 'muted')]);
93
+ } else rows.push(L('Missions', [seg('?', 'warn')]));
94
+ rows.push(L('SubFleets', [seg('none yet', 'muted'), seg(w < 60 ? '' : ' (designed, no API in this Quox)', 'muted')]));
95
+ if (f.cant.length) rows.push([seg("Can't see ", 'warn'), seg(fit(f.cant.join(', '), inner - 12), 'warn')]);
96
+ rows.push([seg(HINT, 'muted')]);
97
+ return { box: { width: w, title: 'Fleet', titleRole: 'sky', border: 'sky' }, rows: rows.map(r => fitRow(r, inner)) };
98
+ }
99
+
100
+ /** d: { host, now } -> view for one computer. */
101
+ export function hostCard(d, cols) {
102
+ const h = d.host;
103
+ const w = boxWidth(cols, 66), inner = w - 4;
104
+ const L = (label, v, role = 'value') => [seg(label.padEnd(8), 'muted'), seg(fit(v, inner - 8), role)];
105
+ const rows = [L('health', h.health, ROLE[h.health])];
106
+ if (h.ip) rows.push(L('ip', h.ip));
107
+ if (h.group) rows.push(L('group', h.group));
108
+ if (h.version) rows.push(L('version', h.version));
109
+ if (typeof h.lastSeenS === 'number') rows.push(L('seen', `${ago(Date.now() - h.lastSeenS * 1000, Date.now()) || '0s'} ago`, 'muted'));
110
+ if (!h.heartbeat) rows.push(L('agent', 'no heartbeat (in the registry only)', 'muted'));
111
+ rows.push([seg(HINT, 'muted')]);
112
+ return { box: { width: w, title: h.id, titleRole: 'sky', right: h.health, rightRole: ROLE[h.health], border: 'sky' }, rows };
113
+ }
114
+
115
+ /** Builder registered as BUILDERS.fleet: one host when d.host is set, else the whole fleet. */
116
+ export function fleetView(d, cols) { return d.host ? hostCard(d, cols) : fleetCard(d, cols); }
117
+
118
+ /** Fetchers for createObjectsApi (kept here so fetch.js only spreads them in). */
119
+ export function fleetFetchers({ get, org, listOf, why, resolveEndpoint }) {
120
+ const read = async (fn) => { try { return { ok: true, list: await fn() }; } catch (e) { return { ok: false, error: why(e) }; } };
121
+ return {
122
+ /** Host ids for /fleet <TAB>: [{ value, desc }]; a failed read suggests nothing. */
123
+ async fleetNames() {
124
+ const hb = resolveEndpoint('v1.agents.list');
125
+ const rows = listOf(await get(hb.service, hb.path, undefined, 6000), 'agents');
126
+ return rows.map(r => r.host_id || r.id).filter(Boolean).map(id => ({ value: String(id), desc: healthOf(rows.find(r => (r.host_id || r.id) === id)) }));
127
+ },
128
+ /** E-fleet: name '' = the whole fleet, else one computer by id (case-insensitive, then prefix). */
129
+ async fleet(name) {
130
+ const q = String(name || '').trim().toLowerCase();
131
+ const hb = resolveEndpoint('v1.agents.list'), hs = resolveEndpoint('v1.fleet.hosts.list'), ob = resolveEndpoint('objectives.list');
132
+ const [agents, hosts, orgAgents, missions] = await Promise.all([
133
+ read(async () => listOf(await get(hb.service, hb.path, undefined, 10000), 'agents')),
134
+ read(async () => listOf(await get(hs.service, hs.path, undefined, 10000), 'hosts')),
135
+ org() ? read(async () => { const ep = resolveEndpoint('agents.list', { orgId: org() }); return listOf(await get(ep.service, ep.path, { includeTools: 'false' }, 10000), 'agents', 'data'); }) : Promise.resolve(null),
136
+ read(async () => listOf(await get(ob.service, ob.path, { limit: 100 }, 10000), 'objectives'))
137
+ ]);
138
+ const data = { agents, hosts, orgAgents, missions, now: Date.now() };
139
+ if (!q) return { data };
140
+ const f = collectFleet(data, data.now);
141
+ const host = f.computers.find(c => c.id.toLowerCase() === q) || f.computers.find(c => c.id.toLowerCase().startsWith(q));
142
+ if (host) return { data: { host, now: data.now } };
143
+ // owner 2026-10-15 typed "/fleet health": overview words mean the whole fleet (a real host by that name still wins above)
144
+ if (FLEET_OVERVIEW_WORDS.has(q)) return { data };
145
+ if (!agents.ok && !hosts.ok) return { error: `Couldn't check hosts: ${agents.error}.`, tone: 'warn' }; // a failed list is never "no such host"
146
+ return { error: `No host called "${name}". /fleet lists them.`, tone: 'warn' };
147
+ }
148
+ };
149
+ }
@@ -0,0 +1,186 @@
1
+ /**
2
+ * /health (and /core): a compact summary of what the Core dashboard's overview (/dashboard) shows.
3
+ * Read-only, no model call, server-side reads only (the same truth the dashboard reads):
4
+ * services GET collector /api/v1/health/aggregate (the dashboard's service ring)
5
+ * computers GET /api/v1/agents heartbeats + GET /api/v1/fleet/hosts (as /fleet)
6
+ * agents org agents (as /fleet)
7
+ * approvals GET auth /api/orgs/:org/inbox/stats (the dashboard's "Attention needed")
8
+ * missions GET tasks /api/objectives (the dashboard's live objectives)
9
+ * failures GET quoxflow /api/executions?status=failed&since=24h
10
+ * licence GET auth /api/setup/licensing/entitlements
11
+ * A section whose read failed says "unavailable: <reason>"; an error body is never shown as zero.
12
+ * /status stays the session panel; /collector-health still goes to /status.
13
+ */
14
+ import { seg, fit, fitRow, plural, boxWidth } from './model.js';
15
+ import { collectFleet, fleetFetchers } from './fleet.js';
16
+
17
+ const DAY_MS = 24 * 3600 * 1000;
18
+ const SVC_ROLE = { ok: 'ok', degraded: 'warn', down: 'error' };
19
+ const reasons = (...srcs) => [...new Set(srcs.filter(s => s && !s.ok).map(s => s.error || 'failed'))].join(', ');
20
+
21
+ /** d: { aggregate, agents, hosts, orgAgents, missions, inbox, failures, licence, now } -> per-section model ({ error } when unread). */
22
+ export function collectHealth(d) {
23
+ const now = d.now ?? Date.now();
24
+ const out = {};
25
+
26
+ const a = d.aggregate;
27
+ if (!a?.ok) out.services = { error: a?.error || 'not read' };
28
+ else {
29
+ const all = Object.entries(a.data?.services || {});
30
+ // Z2H run-6: an optional service this install does not ship (collector says not_installed) is neither up nor down.
31
+ const entries = all.filter(([, s]) => s?.status !== 'not_installed');
32
+ out.services = {
33
+ up: entries.filter(([, s]) => s?.status === 'ok').length,
34
+ total: entries.length,
35
+ score: typeof a.data?.score === 'number' ? a.data.score : null,
36
+ bad: entries.filter(([, s]) => s?.status !== 'ok').map(([name, s]) => ({ name, status: s?.status || 'unknown' })),
37
+ notInstalled: all.filter(([, s]) => s?.status === 'not_installed').map(([name]) => name),
38
+ };
39
+ }
40
+
41
+ const f = collectFleet({ agents: d.agents, hosts: d.hosts, orgAgents: d.orgAgents, missions: d.missions }, now);
42
+ if (d.agents?.ok || d.hosts?.ok) {
43
+ out.computers = { healthy: f.counts.healthy, total: f.computers.length, bad: f.computers.filter(c => c.health !== 'healthy').map(c => ({ id: c.id, health: c.health })), partial: reasons(d.agents, d.hosts) || null };
44
+ } else out.computers = { error: reasons(d.agents, d.hosts) || 'not read' };
45
+
46
+ if (!d.orgAgents) out.agents = { error: 'no org selected' };
47
+ else out.agents = f.agents ? { ...f.agents } : { error: d.orgAgents.error || 'failed' };
48
+
49
+ out.missions = f.missions ? { running: f.missions.running, waiting: f.missions.waiting, loops: f.missions.loops } : { error: d.missions?.error || 'not read' };
50
+
51
+ const ib = d.inbox;
52
+ if (!ib?.ok) out.approvals = { error: ib?.error || 'not read' };
53
+ else {
54
+ const s = ib.data || {};
55
+ out.approvals = { approvals: Number(s.pending_approvals) || 0, active: Number(s.total_active) || 0, urgent: Number(s.urgent) || 0, overdue: Number(s.overdue) || 0 };
56
+ }
57
+
58
+ const fl = d.failures;
59
+ if (!fl?.ok) out.failures = { error: fl?.error || 'not read' };
60
+ else {
61
+ const list = fl.list || [];
62
+ const r = list[0];
63
+ out.failures = { count: typeof fl.total === 'number' ? fl.total : list.length, last: r ? (r.workflowName || r.workflow_name || r.name || r.workflowId || r.workflow_id || r.id || null) : null };
64
+ }
65
+
66
+ const li = d.licence;
67
+ if (!li?.ok) out.licence = { error: li?.error || 'not read' };
68
+ else {
69
+ const L = li.data || {};
70
+ const leases = Array.isArray(L.licenses) ? L.licenses : [];
71
+ const plugins = Array.isArray(L.entitlements) ? L.entitlements.length : 0;
72
+ const errors = Array.isArray(L.entitlement_errors) ? L.entitlement_errors.length : 0;
73
+ if (!leases.length) out.licence = { core: true, plugins, errors };
74
+ else {
75
+ const plans = [...new Set(leases.flatMap(x => Array.isArray(x.plans) ? x.plans : []))];
76
+ const exp = leases.map(x => Date.parse(x.expires_at)).filter(Number.isFinite).sort((x, y) => x - y)[0];
77
+ out.licence = { core: false, plans, plugins, errors, expiresAt: Number.isFinite(exp) ? exp : null, expired: Number.isFinite(exp) && exp < now };
78
+ }
79
+ }
80
+ return out;
81
+ }
82
+
83
+ /** Overall verdict for the title: partial (a section unread) > needs attention > all good. */
84
+ function verdict(h) {
85
+ if (Object.values(h).some(s => s?.error)) return ['partial', 'warn'];
86
+ const attention = h.services.up < h.services.total || h.computers.bad.length || h.failures.count || h.approvals.approvals || h.approvals.urgent || h.approvals.overdue || h.licence.errors || h.licence.expired;
87
+ return attention ? ['needs attention', 'warn'] : ['all good', 'ok'];
88
+ }
89
+
90
+ const HINT = [seg('/fleet', 'key'), seg(' computers · ', 'label'), seg('/status', 'key'), seg(' this session · ', 'label'), seg('/dashboard', 'key'), seg(' open it', 'label')];
91
+
92
+ /** d -> view { box, rows }. */
93
+ export function healthCard(d, cols) {
94
+ const h = collectHealth(d);
95
+ const w = boxWidth(cols, 78), inner = w - 4;
96
+ const L = (label, parts) => [seg(label.padEnd(11), 'label'), ...parts];
97
+ const na = (s) => [seg('unavailable: ', 'warn'), seg(s.error, 'warn')];
98
+ const sep = () => seg(' · ', 'label');
99
+ const rows = [];
100
+
101
+ const s = h.services;
102
+ if (s.error) rows.push(L('Services', na(s)));
103
+ else {
104
+ const parts = [seg(`${s.up}/${s.total} up`, s.up === s.total ? 'ok' : 'warn', true)];
105
+ for (const b of s.bad) parts.push(sep(), seg(`${b.name} ${b.status}`, SVC_ROLE[b.status] || 'warn'));
106
+ for (const n of s.notInstalled || []) parts.push(sep(), seg(`${n} not installed`, 'value'));
107
+ rows.push(L('Services', parts));
108
+ }
109
+
110
+ const c = h.computers;
111
+ if (c.error) rows.push(L('Computers', na(c)));
112
+ else if (!c.total) rows.push(L('Computers', [seg('none connected', 'value')]));
113
+ else {
114
+ const parts = [seg(`${c.healthy}/${c.total} healthy`, c.healthy === c.total ? 'ok' : 'warn', true)];
115
+ if (c.bad.length) parts.push(sep(), seg(fit(c.bad.map(x => `${x.id} ${x.health}`).join(', '), inner), c.bad.some(x => x.health === 'offline' || x.health === 'unhealthy') ? 'error' : 'warn'));
116
+ if (c.partial) parts.push(sep(), seg(`partial: ${c.partial}`, 'warn'));
117
+ rows.push(L('Computers', parts));
118
+ }
119
+
120
+ const ag = h.agents;
121
+ rows.push(L('Agents', ag.error ? na(ag) : [seg(`${ag.active} active`, 'value', true), ...(ag.other ? [sep(), seg(`${ag.other} other`, 'value')] : [])]));
122
+
123
+ const ap = h.approvals;
124
+ if (ap.error) rows.push(L('Approvals', na(ap)));
125
+ else {
126
+ const parts = [seg(ap.approvals ? `${ap.approvals} open` : 'none open', ap.approvals ? 'warn' : 'ok', true)];
127
+ if (ap.active) parts.push(sep(), seg(`${ap.active} in inbox`, 'value'));
128
+ if (ap.urgent) parts.push(sep(), seg(`${ap.urgent} urgent`, 'error'));
129
+ if (ap.overdue) parts.push(sep(), seg(`${ap.overdue} overdue`, 'error'));
130
+ rows.push(L('Approvals', parts));
131
+ }
132
+
133
+ const m = h.missions;
134
+ if (m.error) rows.push(L('Missions', na(m)));
135
+ else {
136
+ const parts = [seg(`${m.running} running`, 'value', true)];
137
+ if (m.waiting) parts.push(sep(), seg(`${m.waiting} waiting`, 'warn'));
138
+ if (m.loops) parts.push(sep(), seg(plural(m.loops, 'loop'), 'value'));
139
+ rows.push(L('Missions', parts));
140
+ }
141
+
142
+ const fl = h.failures;
143
+ if (fl.error) rows.push(L('Failures', na(fl)));
144
+ else if (!fl.count) rows.push(L('Failures', [seg('none in 24h', 'ok')]));
145
+ else rows.push(L('Failures', [seg(`${plural(fl.count, 'failed run')} in 24h`, 'error', true), ...(fl.last ? [sep(), seg(`last: ${fl.last}`, 'value')] : [])]));
146
+
147
+ const li = h.licence;
148
+ if (li.error) rows.push(L('Licence', na(li)));
149
+ else {
150
+ const parts = li.core ? [seg('Core (free)', 'value', true)] : [seg(li.plans.length ? li.plans.join(', ') : 'licensed', 'value', true)];
151
+ if (li.plugins) parts.push(sep(), seg(plural(li.plugins, 'plugin'), 'value'));
152
+ if (!li.core && li.expiresAt) parts.push(sep(), seg(li.expired ? `expired ${new Date(li.expiresAt).toISOString().slice(0, 10)}` : `until ${new Date(li.expiresAt).toISOString().slice(0, 10)}`, li.expired ? 'error' : 'value'));
153
+ if (li.errors) parts.push(sep(), seg(plural(li.errors, 'licence error'), 'error'));
154
+ rows.push(L('Licence', parts));
155
+ }
156
+
157
+ rows.push(HINT);
158
+ const [right, rightRole] = verdict(h);
159
+ return { box: { width: w, title: 'Health', titleRole: 'sky', right, rightRole, border: 'sky' }, rows: rows.map(r => fitRow(r, inner)) };
160
+ }
161
+
162
+ /** Fetchers for createObjectsApi. Every read is bounded and every failure carries its reason. */
163
+ export function healthFetchers({ get, org, listOf, why, resolveEndpoint }) {
164
+ const fleet = fleetFetchers({ get, org, listOf, why, resolveEndpoint });
165
+ const read = async (fn) => { try { return { ok: true, ...(await fn()) }; } catch (e) { return { ok: false, error: why(e) }; } };
166
+ const noOrg = { ok: false, error: 'no org selected' };
167
+ return {
168
+ /** -> { data } for the health card (now injectable for tests). */
169
+ async health(now = Date.now()) {
170
+ const ag = resolveEndpoint('v1.health.aggregate.list'), ex = resolveEndpoint('executions.list'), lic = resolveEndpoint('setup.licensing.entitlements.list');
171
+ const o = org();
172
+ const [fl, aggregate, inbox, failures, licence] = await Promise.all([
173
+ fleet.fleet(''),
174
+ read(async () => ({ data: await get(ag.service, ag.path, undefined, 15000) })),
175
+ o ? read(async () => { const ep = resolveEndpoint('inbox.stats.list', { orgId: o }); return { data: await get(ep.service, ep.path, undefined, 8000) }; }) : Promise.resolve(noOrg),
176
+ read(async () => {
177
+ const d = await get(ex.service, ex.path, { status: 'failed', since: new Date(now - DAY_MS).toISOString(), limit: 5 }, 8000);
178
+ const total = d?.pagination?.total;
179
+ return { list: listOf(d, 'data', 'executions'), total: typeof total === 'number' ? total : undefined };
180
+ }),
181
+ read(async () => ({ data: await get(lic.service, lic.path, undefined, 8000) })),
182
+ ]);
183
+ return { data: { ...fl.data, aggregate, inbox, failures, licence, now } };
184
+ }
185
+ };
186
+ }
@@ -0,0 +1,106 @@
1
+ /**
2
+ * Inline object views: one entry point for app.js. `runObjectCommand` fetches and returns either an
3
+ * object item ({ type, data }) that history renders with <ObjectView/>, or a note ({ text, tone }).
4
+ * The view itself is rebuilt from data at render width (resize reprints history), so items stay
5
+ * pure data.
6
+ */
7
+ import { skillCard } from './skill.js';
8
+ import { stepFlow } from './workflow.js';
9
+ import { crystalCard } from './crystal.js';
10
+ import { agentCard } from './agent.js';
11
+ import { memoryFacts } from './memory.js';
12
+ import { rulesLadder } from './ladder.js';
13
+ import { proofChain, reconcileView } from './proof.js';
14
+ import { awayCard } from './away.js';
15
+ import { sitrepCard } from './sitrep.js';
16
+ import { fleetView } from './fleet.js';
17
+ import { healthCard } from './health.js';
18
+ import { proveView, lastTurnCalls } from './prove.js';
19
+ import { replayView, parseReplayArg } from './replay.js';
20
+ import { mirrorCard } from './mirror.js';
21
+ import { peekCard } from './peek.js';
22
+
23
+ export { skillCard, stepFlow, crystalCard, agentCard, memoryFacts, rulesLadder, proofChain, reconcileView, awayCard, sitrepCard };
24
+ export { createObjectsApi } from './fetch.js';
25
+ export { decodeRow, arrivalSeconds } from './model.js';
26
+
27
+ export const BUILDERS = { skill: skillCard, workflow: stepFlow, crystal: crystalCard, agent: agentCard, memory: memoryFacts, rules: rulesLadder, proof: proofChain, reconcile: reconcileView, away: awayCard, sitrep: sitrepCard, fleet: fleetView, health: healthCard, prove: proveView, replay: replayView, mirror: mirrorCard, peek: peekCard };
28
+
29
+ /** -> view { box?, rows } for an object item at this width (now injected for tests). */
30
+ export function buildObject(obj, cols, now = Date.now()) {
31
+ const b = BUILDERS[obj?.type];
32
+ if (!b) return { rows: [] };
33
+ return b({ now, ...obj.data }, cols);
34
+ }
35
+
36
+ /** Tool blocks of this session that carry an envelope id, newest last. */
37
+ export function toolCalls(items) {
38
+ return (items || []).filter(b => b && b.kind === 'tool' && b.status !== 'running');
39
+ }
40
+
41
+ const USAGE = {
42
+ '/workflow': 'Usage: /workflow <name | workflow id | run id>',
43
+ '/crystal': 'Usage: /crystal <workflow name or id>',
44
+ '/memory': 'Usage: /memory <query>',
45
+ '/agents': 'Usage: /agents <name>'
46
+ };
47
+
48
+ /**
49
+ * cmd: '/skills' (with a name), '/workflow', '/crystal', '/agents' (with a name), '/memory', '/rules',
50
+ * '/proof', '/reconcile'. ctx: { objects (createObjectsApi), rules, rulesOn, items (history + live
51
+ * blocks) }. -> { object: { type, data } } | { note: text, tone } | null (not ours).
52
+ */
53
+ export async function runObjectCommand(cmd, arg, ctx) {
54
+ const o = ctx.objects;
55
+ const a = String(arg || '').trim();
56
+ // A bare /skills or /agents is a list, not an object: leave it to its own handler.
57
+ if (!['/workflow', '/crystal', '/memory', '/rules', '/proof', '/reconcile', '/fleet', '/prove', '/replay', '/health', '/core'].includes(cmd) && !((cmd === '/skills' || cmd === '/agents') && a)) return null;
58
+ if (!o?.health && (cmd === '/health' || cmd === '/core')) return null; // no objects api (demo, local): app.js shows /status instead
59
+ if (!o) return cmd === '/rules' || cmd === '/skills' ? null : { note: 'Object views are not available in this mode.', tone: 'warn' };
60
+ const wrap = async (type, fn) => {
61
+ try {
62
+ const r = await fn();
63
+ if (r?.error) return { note: r.error, tone: r.tone || 'warn' };
64
+ return { object: { type, data: r.data } };
65
+ } catch (e) {
66
+ return { note: `${type}: ${e?.status ? `HTTP ${e.status}: ` : ''}${e?.message || 'failed'}`, tone: 'warn' };
67
+ }
68
+ };
69
+ switch (cmd) {
70
+ case '/skills': return a ? wrap('skill', () => o.skill(a)) : null;
71
+ case '/agents': return a ? wrap('agent', () => o.agent(a)) : null;
72
+ case '/workflow': return a ? wrap('workflow', () => o.workflowRun(a)) : { note: USAGE['/workflow'], tone: 'warn' };
73
+ case '/crystal': return a ? wrap('crystal', () => o.crystal(a)) : { note: USAGE['/crystal'], tone: 'warn' };
74
+ case '/memory': return a ? wrap('memory', () => o.memory(a)) : { note: USAGE['/memory'], tone: 'warn' };
75
+ case '/replay': {
76
+ const { ref, page } = parseReplayArg(a);
77
+ if (!ref && !ctx.conversationId && !toolCalls(ctx.items).length) return { note: 'Nothing to replay yet: no turn in this conversation. /replay <run or conversation id> replays an earlier one.' };
78
+ return wrap('replay', () => o.replay({ ref, page, conversationId: ctx.conversationId || null, calls: lastTurnCalls(ctx.items) }));
79
+ }
80
+ case '/prove': {
81
+ const calls = lastTurnCalls(ctx.items);
82
+ if (!calls.length) return { note: 'No tool calls in the last turn: nothing to prove.' };
83
+ return wrap('prove', () => o.prove(calls));
84
+ }
85
+ case '/fleet': return wrap('fleet', () => o.fleet(a));
86
+ case '/health': case '/core': return wrap('health', () => o.health()); // the Core dashboard summary (objects/health.js)
87
+ case '/rules': {
88
+ return wrap('rules', async () => {
89
+ const r = await o.rules();
90
+ return { data: { ...r.data, quoxmd: ctx.rules || null, enabled: ctx.rulesOn !== false } };
91
+ });
92
+ }
93
+ case '/proof': {
94
+ const calls = toolCalls(ctx.items).filter(b => b.envelopeId);
95
+ const t = a ? calls.find(b => b.envelopeId === a || b.callId === a) : calls[calls.length - 1];
96
+ if (!t) return { note: a ? `No tool call "${a}" with an envelope in this session.` : 'No tool call with an envelope id in this session yet.', tone: 'warn' };
97
+ return wrap('proof', () => o.proof({ tool: t.tool, status: t.status, envelopeId: t.envelopeId, callId: t.callId }));
98
+ }
99
+ case '/reconcile': {
100
+ const unk = toolCalls(ctx.items).filter(b => b.status === 'effect_unknown');
101
+ if (!unk.length) return { note: 'Nothing to reconcile: no tool call in this session ended with effect unknown.' };
102
+ return wrap('reconcile', () => o.reconcile(unk.map(b => ({ tool: b.tool, envelopeId: b.envelopeId }))));
103
+ }
104
+ default: return null;
105
+ }
106
+ }