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,71 @@
1
+ /**
2
+ * E7 rules precedence: three layers that are visibly different and never confused.
3
+ * advisory QUOX.md files this client found (sent as context; cannot grant or bypass anything)
4
+ * pack the signed core dev pack on this machine (~/.claude/skills/.pack-version and
5
+ * .pack-rights.json, written by the collector's skill-pack installer): team guidance for
6
+ * coding agents, still advisory
7
+ * enforced ARMED governance policies on the server (GET /orgs/:org/governance/policies): the only
8
+ * layer that can stop an action
9
+ * The effective layer is the highest one that has rules. An unreadable layer is reported, and never
10
+ * treated as empty when deciding what is effective.
11
+ */
12
+ import { seg, fit, plural } from './model.js';
13
+
14
+ /** Pure: read the pack marker files through an injected reader (fs.readFileSync-like, may throw). */
15
+ export function packFrom(read) {
16
+ let marker = null, rights = null;
17
+ try { marker = String(read('.pack-version')).trim(); } catch { /* absent */ }
18
+ try { rights = JSON.parse(read('.pack-rights.json')); } catch { /* absent */ }
19
+ if (!marker && !rights) return { state: 'none' };
20
+ let m = null;
21
+ try { m = marker ? JSON.parse(marker) : null; } catch { m = null; }
22
+ const version = rights?.version ?? m?.version ?? (marker && !m ? marker : null);
23
+ return { state: 'installed', version: version != null ? String(version) : null, packId: rights?.packId ?? m?.packId ?? null, skills: Array.isArray(rights?.rights) ? rights.rights.length : null };
24
+ }
25
+
26
+ /**
27
+ * d: { quoxmd: loadRules() result | null, enabled: boolean, pack: packFrom() result,
28
+ * policies: { ok: true, list } | { ok: false, error } }
29
+ */
30
+ export function rulesLadder(d, cols) {
31
+ const nw = cols < 66;
32
+ const rows = [];
33
+ const files = d.quoxmd?.files || [];
34
+ const pol = d.policies || { ok: false, error: 'not read' };
35
+ const armed = pol.ok ? (pol.list || []).filter(p => p.state === 'armed') : [];
36
+ const staged = pol.ok ? (pol.list || []).filter(p => p.state === 'draft') : [];
37
+ const layers = [
38
+ { tag: 'advisory', role: 'muted', has: files.length > 0 && d.enabled !== false,
39
+ src: !files.length ? 'no QUOX.md found' : d.enabled === false ? `QUOX.md (${files.length}) · off this session` : `QUOX.md (${plural(files.length, 'file')}${d.quoxmd?.truncated ? ', cut' : ''})`,
40
+ scope: nw ? 'local' : 'you, this machine · guides only' },
41
+ { tag: 'pack', role: 'teal', has: d.pack?.state === 'installed',
42
+ src: d.pack?.state === 'installed' ? `core dev pack${d.pack.version ? ` v${d.pack.version}` : ''}${d.pack.skills != null && !nw ? ` · ${d.pack.skills} skills` : ''}` : 'not installed here',
43
+ scope: nw ? 'team' : 'team, signed · guides only' },
44
+ { tag: 'enforced', role: 'indigo', has: armed.length > 0, unknown: !pol.ok,
45
+ src: pol.ok ? (armed.length ? `${plural(armed.length, 'governance policy', 'governance policies')} armed` : 'no armed policy') : `could not read (${fit(pol.error, 28)})`,
46
+ scope: nw ? 'server' : 'server, cannot be bypassed' }
47
+ ];
48
+ const top = pol.ok ? [...layers].reverse().find(l => l.has) : null;
49
+ rows.push([seg('rules ', 'muted'), seg(nw ? 'precedence, top wins' : 'precedence · the highest layer with rules wins', 'value', true)]);
50
+ for (const l of [...layers].reverse()) {
51
+ const on = top === l;
52
+ const lose = top && !on && l.has;
53
+ rows.push([
54
+ seg(on ? '▸ ' : ' ', on ? 'value' : 'faint', true),
55
+ seg(l.tag.padEnd(9), lose ? 'faint' : l.unknown ? 'warn' : l.role, on),
56
+ seg(fit(l.src, nw ? cols - 14 : 34).padEnd(nw ? 0 : 35), l.unknown ? 'warn' : lose ? 'muted' : 'value', on),
57
+ ...(nw ? [] : [seg(fit(l.scope, Math.max(0, cols - 50)), 'muted')])
58
+ ]);
59
+ }
60
+ for (const p of armed.slice(0, 4)) rows.push([seg(' · ', 'faint'), seg(fit(`"${p.rule_text}"`, cols - 24), 'value'), seg(` → ${p.policy?.effect || 'enforced'}`, 'indigo')]);
61
+ if (armed.length > 4) rows.push([seg(` … ${armed.length - 4} more armed`, 'muted')]);
62
+ if (staged.length) rows.push([seg(` ${plural(staged.length, 'draft')} not armed (enforce nothing until armed)`, 'muted')]);
63
+ let eff;
64
+ if (!pol.ok) eff = [seg(nw ? 'effective: unknown (policies unreadable)' : 'effective: unknown · the server\'s policies could not be read, so nothing here is called enforced', 'warn')];
65
+ else if (top?.tag === 'enforced') eff = [seg(nw ? 'effective: enforced (server wins)' : 'effective: enforced · server policy outranks pack and QUOX.md', 'indigo')];
66
+ else if (top) eff = [seg(nw ? `effective: ${top.tag} (advisory only)` : `effective: ${top.tag} · advisory, guides the agent but enforces nothing`, top.role === 'muted' ? 'value' : top.role)];
67
+ else eff = [seg('effective: none · no rules at any layer', 'muted')];
68
+ rows.push(eff);
69
+ rows.push([seg(nw ? '/rules files: the QUOX.md text' : '/rules files shows the QUOX.md text · /rules off|on', 'faint')]);
70
+ return { rows };
71
+ }
@@ -0,0 +1,44 @@
1
+ /**
2
+ * E6 memory facts with provenance, from GET /api/memory/search (memory service). Each fact shows what
3
+ * the record says about where it came from (provenance, type, source conversation or agent), how old
4
+ * and how trusted it is (confidence, verification, use), and any conflict state (superseded or
5
+ * invalid) in plain sight, never hidden.
6
+ */
7
+ import { seg, fit, ago, short, plural } from './model.js';
8
+
9
+ const PROVENANCE = {
10
+ model_inference: 'inferred by a model', user_stated: 'stated by a user', user_confirmed: 'confirmed by a user',
11
+ tool_output: 'from a tool result', document: 'from a document', imported: 'imported', system: 'system'
12
+ };
13
+ export const provenanceWord = (p) => (p ? PROVENANCE[p] || String(p).replace(/_/g, ' ') : null);
14
+
15
+ /** d: { query, results: [...], total?, now } */
16
+ export function memoryFacts(d, cols, { max = 5 } = {}) {
17
+ const now = d.now ?? Date.now();
18
+ const nw = cols < 70;
19
+ const inner = Math.max(20, cols - 6);
20
+ const rows = [];
21
+ const res = (d.results || []).slice(0, max);
22
+ if (!res.length) return { rows: [[seg(`No memory matches "${fit(d.query, 40)}".`, 'muted')]] };
23
+ rows.push([seg(`${plural((d.results || []).length, 'fact')} for "${fit(d.query, 40)}"${(d.results || []).length > max ? `, showing ${max}` : ''}`, 'muted')]);
24
+ const L = (label, text, role = 'value') => [seg(' '), seg(label.padEnd(7), 'muted'), seg(fit(text, inner - 9), role)];
25
+ for (const m of res) {
26
+ rows.push([seg(' ')]);
27
+ rows.push([seg('◆ ', 'indigo', true), seg(m.memory_role === 'fact' || !m.memory_role ? 'fact ' : `${m.memory_role} `, 'muted'), seg(fit(m.content, inner - 8), 'value', true)]);
28
+ const src = [provenanceWord(m.provenance), m.memory_type].filter(Boolean);
29
+ if (m.source_conversation_id) src.push(nw ? `chat ${short(m.source_conversation_id, 8)}` : `conversation ${short(m.source_conversation_id, 10)}`);
30
+ if (m.agent_id) src.push(`agent ${m.agent_id}`);
31
+ if (src.length) rows.push(L('source', src.join(' · ')));
32
+ const age = [];
33
+ const created = m.created_at || m.createdAt;
34
+ if (created) age.push(`${ago(created, now)} old`);
35
+ if (m.confidence != null) age.push(`confidence ${Math.round(Number(m.confidence) * 100)}%`);
36
+ if (m.verified_at) age.push(`verified${m.verified_by ? ` by ${short(m.verified_by, 10)}` : ''} ${ago(m.verified_at, now)} ago`);
37
+ else age.push('not verified');
38
+ if (m.access_count) age.push(`used ${plural(Number(m.access_count), 'time')}`);
39
+ rows.push(L('age', age.join(' · '), 'muted'));
40
+ if (m.superseded_by) rows.push(L('status', `superseded by ${short(m.superseded_by, 12)}`, 'warn'));
41
+ else if (m.valid === false || m.valid === 0) rows.push(L('status', 'marked invalid', 'error'));
42
+ }
43
+ return { rows };
44
+ }
@@ -0,0 +1,137 @@
1
+ /**
2
+ * /mirror: the Mirror, what CommanderQ sees about this org right now. Read from GET /api/v1/mind/mirror,
3
+ * the org-scoped object the collector builds from each owning service and injects into CommanderQ's
4
+ * [SELF-KNOWLEDGE]. Sectioned: identity, health, implants, capabilities, plugins, memory, codebase,
5
+ * then every unknown with its code, service and message. `/mirror agents` lists the agents.
6
+ * Text wraps to width, never clipped. No grey roles: 'value' text, 'sky' headings, 'ok'/'warn' state.
7
+ */
8
+ import { seg, boxWidth, len } from './model.js';
9
+
10
+ const age = (ms) => {
11
+ if (!Number.isFinite(ms)) return '';
12
+ const s = Math.max(0, Math.floor(ms / 1000));
13
+ if (s < 60) return `${s}s`;
14
+ const m = Math.floor(s / 60);
15
+ if (m < 60) return `${m}m`;
16
+ const h = Math.floor(m / 60);
17
+ return h < 48 ? `${h}h` : `${Math.floor(h / 24)}d`;
18
+ };
19
+
20
+ /** Word-wrap to n display chars; a word longer than n is hard-split. Nothing is dropped. */
21
+ export function wrapText(text, n) {
22
+ const out = [];
23
+ for (const para of String(text ?? '').split('\n')) {
24
+ let line = '';
25
+ for (let w of para.split(/\s+/).filter(Boolean)) {
26
+ while (len(w) > n) {
27
+ if (line) { out.push(line); line = ''; }
28
+ out.push([...w].slice(0, n).join('')); w = [...w].slice(n).join('');
29
+ }
30
+ if (!line) line = w;
31
+ else if (len(line) + 1 + len(w) <= n) line += ' ' + w;
32
+ else { out.push(line); line = w; }
33
+ }
34
+ out.push(line);
35
+ }
36
+ return out;
37
+ }
38
+
39
+ const ICON = { healthy: '✔', degraded: '⚠', weak: '⚠', collecting: '◐', 'license-required': '⛔', unreachable: '✖', 'not-reported': '◐' };
40
+ const unk = (u) => `unknown: ${u.code} (${u.service}: ${u.message})`;
41
+ const isUnk = (v) => v && typeof v === 'object' && v.unknown;
42
+
43
+ /** d: GET /api/v1/mind/mirror body (+ view: 'agents'). -> view { box, rows } */
44
+ export function mirrorCard(d, cols) {
45
+ const w = boxWidth(cols, 100), inner = w - 4;
46
+ const rows = [];
47
+ const put = (t, role = 'value', indent = 0) => { const pad = ' '.repeat(indent); for (const l of wrapText(t, inner - indent)) rows.push([seg(pad + l, role)]); };
48
+ const head = (t) => { if (rows.length) rows.push([seg(' ')]); rows.push([seg(t, 'sky', true)]); };
49
+ const m = d?.mirror;
50
+ const a = age(d?.age_ms);
51
+ const right = `${a ? `${a} old · ` : ''}${d?.fresh ? 'fresh' : 'stale'}`;
52
+ const box = (title) => ({ width: w, title, titleRole: 'value', right, rightRole: d?.fresh ? 'ok' : 'warn', border: d?.fresh ? 'indigo' : 'warn' });
53
+ if (!m) {
54
+ put(`The Mirror could not be read: ${d?.error || d?.reason || 'the server returned no mirror'}.`, 'warn'); // RESTORE-TUI: say the server's reason (an unbuilt mirror says why)
55
+ return { box: { ...box('The Mirror'), right: 'not available', rightRole: 'warn', border: 'warn' }, rows };
56
+ }
57
+
58
+ if (d.view === 'agents') {
59
+ const ag = m.capabilities?.agents;
60
+ if (isUnk(ag)) put(`Agents ${unk(ag.unknown)}`, 'warn');
61
+ else {
62
+ put(`${ag.count} agents, ${ag.entitled} entitled for this org.`);
63
+ rows.push([seg(' ')]);
64
+ for (const x of ag.list || []) put(`${x.entitled === false ? '⛔' : '✔'} ${x.name || x.id} (${x.id})${x.role ? ` · ${x.role}` : ''}${x.level != null ? ` · level ${x.level}` : ''}${x.entitled === false ? ' · not entitled' : ''}`, x.entitled === false ? 'warn' : 'value');
65
+ }
66
+ return { box: box('The Mirror · agents'), rows };
67
+ }
68
+
69
+ head('Identity');
70
+ put(`${m.identity?.name || 'CommanderQ'}: ${m.identity?.role || ''}. This is what CommanderQ is told about this org on every turn, built ${m.generatedAt || 'now'} from server reads.`);
71
+
72
+ head('Health');
73
+ if (isUnk(m.health)) put(unk(m.health.unknown), 'warn');
74
+ else {
75
+ const h = m.health;
76
+ put(`${h.score}% · ${h.activeServices}/${h.totalServices} services up${h.down?.length ? ` · down: ${h.down.join(', ')}` : ''}${h.degraded?.length ? ` · degraded: ${h.degraded.join(', ')}` : ''}`, h.score >= 90 ? 'ok' : 'warn');
77
+ }
78
+
79
+ head('Implants');
80
+ if (isUnk(m.implants)) put(unk(m.implants.unknown), 'warn');
81
+ else {
82
+ const s = m.implantSummary;
83
+ if (s) put(`${s.healthy}/${s.total} healthy (${Object.entries(s.by_status || {}).map(([k, v]) => `${v} ${k}`).join(', ')})`);
84
+ for (const i of m.implants || []) {
85
+ const bad = i.status !== 'healthy';
86
+ put(`${ICON[i.status] || '◐'} ${i.name}${i.tier ? ` [${i.tier}]` : ''} · ${i.status}${typeof i.health === 'number' ? ` ${i.health}` : ''}${i.metric ? ` · ${i.metric}` : ''}`, bad ? 'warn' : 'value', 1);
87
+ if (i.reason && bad) put(`${i.reason.code} (${i.reason.service}: ${i.reason.message})`, 'warn', 4);
88
+ }
89
+ }
90
+
91
+ head('Capabilities');
92
+ const c = m.capabilities || {};
93
+ put(isUnk(c.tools) ? `Tools ${unk(c.tools.unknown)}` : `Tools: ${c.tools.total} (${c.tools.platform} platform, ${c.tools.org} installed for this org)`, isUnk(c.tools) ? 'warn' : 'value');
94
+ put(isUnk(c.workflows) ? `Workflows ${unk(c.workflows.unknown)}` : `Workflows: ${c.workflows}`, isUnk(c.workflows) ? 'warn' : 'value');
95
+ put(isUnk(c.agents) ? `Agents ${unk(c.agents.unknown)}` : `Agents: ${c.agents.count} (${c.agents.entitled} entitled) · /mirror agents lists them`, isUnk(c.agents) ? 'warn' : 'value');
96
+
97
+ head('Plugins');
98
+ if (isUnk(m.plugins)) put(unk(m.plugins.unknown), 'warn');
99
+ else put(`${m.plugins.installed} installed, ${m.plugins.enabled} enabled${m.plugins.list?.length ? `: ${m.plugins.list.map((p) => p.id).join(', ')}` : ''}`);
100
+
101
+ head('Memory');
102
+ if (isUnk(m.memory)) put(unk(m.memory.unknown), 'warn');
103
+ else {
104
+ const mm = m.memory;
105
+ put(`${mm.total} memories, ${mm.entities} entities, ${mm.relations} relations, across ${mm.users} users of this org`);
106
+ const types = Object.entries(mm.by_type || {}).sort((x, y) => y[1] - x[1]);
107
+ if (types.length) put(types.map(([k, v]) => `${k} ${v}`).join(' · '), 'value', 1);
108
+ }
109
+
110
+ head('Codebase');
111
+ const f = m.codebaseFabric || {};
112
+ if (isUnk(f)) put(unk(f.unknown), 'warn');
113
+ else {
114
+ if (f.repobrain_unknown) put(`RepoBrain ${unk(f.repobrain_unknown)}`, 'warn');
115
+ else {
116
+ put(`RepoBrain: ${f.repos} repos indexed${f.indexedFiles != null ? `, ${f.indexedFiles} files` : ''}`);
117
+ if (f.indexedFiles_reason) put(`files ${f.indexedFiles_reason.code} (${f.indexedFiles_reason.service}: ${f.indexedFiles_reason.message})`, 'warn', 1);
118
+ }
119
+ if (f.projects_unknown) put(`Scans ${unk(f.projects_unknown)}`, 'warn');
120
+ else if (f.projectCount != null) put(`Scans: ${f.projectCount} projects, ${f.totalRoutes} routes, ${f.totalServices} services, invariants ${f.invariantStatus}${f.lastScan ? `, last ${f.lastScan}` : ''}`);
121
+ if (f.lastScan_reason) put(`${f.lastScan_reason.code} (${f.lastScan_reason.service}: ${f.lastScan_reason.message})`, 'warn', 1);
122
+ }
123
+
124
+ const un = m.unknowns || [];
125
+ head(`Unknown (${un.length})`);
126
+ if (!un.length) put('Every section above was read from its service.', 'ok');
127
+ for (const u of un) put(`${u.section}: ${u.code} (${u.service}: ${u.message})`, 'warn');
128
+ return { box: box('The Mirror'), rows };
129
+ }
130
+
131
+ /** A failed fetch as one plain line: the HTTP status, the error code and the server's own reason. */
132
+ export function mirrorErrorNote(e) {
133
+ const body = e?.body && typeof e.body === 'object' ? e.body : {};
134
+ const reason = body.error || body.message || e?.message || 'failed';
135
+ const code = body.code || (typeof e?.code === 'string' ? e.code : '');
136
+ return `mirror: could not read the Mirror (${e?.status ? `HTTP ${e.status}: ` : ''}${code ? `${code}: ` : ''}${reason}). Nothing is assumed.`;
137
+ }
@@ -0,0 +1,118 @@
1
+ /**
2
+ * Inline object views (QUOXON plan E2/E3, lab group E and D): shared, pure helpers.
3
+ *
4
+ * A view is { box?, rows } where a row is an array of segments { text, role, bold? }. Roles are theme
5
+ * roles ('value', 'muted', 'ok', 'warn', 'error', 'key', 'sky', 'teal', 'indigo', 'violet', 'faint') or
6
+ * 'agent:<name>', 'provider:<id>', 'proto:<aee|aocl|volt|ward>'. Nothing here does I/O or reads a clock:
7
+ * time arrives as `now`. Rule for every builder: a field the server did not supply is omitted, never
8
+ * invented, and an unreachable source is said plainly.
9
+ */
10
+ import { KANA } from '../qhello.js';
11
+
12
+ export const seg = (text, role = 'value', bold = false) => ({ text: String(text ?? ''), role, bold });
13
+ export const len = (s) => [...String(s ?? '')].length;
14
+ export const rowText = (row) => row.map(s => s.text).join('');
15
+ export const rowLen = (row) => len(rowText(row));
16
+
17
+ /** Clip a string to n display chars with an ellipsis (the lab's fit()). */
18
+ export const fit = (s, n) => {
19
+ const g = [...String(s ?? '').replace(/\s+/g, ' ').trim()];
20
+ if (n <= 0) return '';
21
+ return g.length > n ? g.slice(0, Math.max(0, n - 1)).join('') + '…' : g.join('');
22
+ };
23
+
24
+ /** Clip a row of segments to n chars total; later segments shrink first, the last one gets the ellipsis. */
25
+ export function fitRow(row, n) {
26
+ const out = [];
27
+ let used = 0;
28
+ for (const s of row) {
29
+ const room = n - used;
30
+ if (room <= 0) break;
31
+ const l = len(s.text);
32
+ if (l <= room) { out.push(s); used += l; continue; }
33
+ out.push({ ...s, text: fit(s.text, room) });
34
+ used = n;
35
+ break;
36
+ }
37
+ return out;
38
+ }
39
+
40
+ /** Pad a row to exactly n chars (clip first). */
41
+ export function padRow(row, n) {
42
+ const r = fitRow(row, n);
43
+ const l = rowLen(r);
44
+ return l < n ? [...r, seg(' '.repeat(n - l), 'muted')] : r;
45
+ }
46
+
47
+ /** Server timestamps: epoch ms, ISO, or SQLite "YYYY-MM-DD HH:MM:SS" (UTC). */
48
+ export function parseTs(v) {
49
+ if (v == null || v === '') return null;
50
+ if (typeof v === 'number') return v;
51
+ const s = String(v);
52
+ const t = Date.parse(/^\d{4}-\d\d-\d\d \d\d:\d\d(:\d\d)?$/.test(s) ? s.replace(' ', 'T') + 'Z' : s);
53
+ return Number.isFinite(t) ? t : null;
54
+ }
55
+
56
+ /** "45s", "3m", "2h", "28d" between two epoch ms. '' when unknown. */
57
+ export function ago(ts, now) {
58
+ const t = parseTs(ts);
59
+ if (t == null || !Number.isFinite(now)) return '';
60
+ const s = Math.max(0, Math.floor((now - t) / 1000));
61
+ if (s < 60) return `${s}s`;
62
+ const m = Math.floor(s / 60);
63
+ if (m < 60) return `${m}m`;
64
+ const h = Math.floor(m / 60);
65
+ if (h < 48) return `${h}h`;
66
+ return `${Math.floor(h / 24)}d`;
67
+ }
68
+
69
+ /** Duration in ms -> "0.4s", "3.4s", "2m05". */
70
+ export function dur(ms) {
71
+ if (ms == null || !Number.isFinite(ms)) return '';
72
+ if (ms < 60000) return `${(Math.max(0, ms) / 1000).toFixed(1)}s`;
73
+ const s = Math.round(ms / 1000);
74
+ return `${Math.floor(s / 60)}m${String(s % 60).padStart(2, '0')}`;
75
+ }
76
+
77
+ /** "21:20 UTC" from a timestamp (UTC on purpose: the box and the owner are in different zones). */
78
+ export function hhmm(ts) {
79
+ const t = parseTs(ts);
80
+ return t == null ? '' : `${new Date(t).toISOString().slice(11, 16)} UTC`;
81
+ }
82
+ export const day = (ts) => { const t = parseTs(ts); return t == null ? '' : new Date(t).toISOString().slice(0, 10); };
83
+ export const short = (id, n = 8) => { const s = String(id ?? ''); return s.length > n + 1 ? s.slice(0, n) + '…' : s; };
84
+ export const plural = (n, one, many = `${one}s`) => `${n} ${n === 1 ? one : many}`;
85
+
86
+ /** Box geometry the lab uses: the box is at most `max` wide and never wider than the terminal less 2. */
87
+ export const boxWidth = (cols, max) => Math.max(20, Math.min((cols || 80) - 2, max));
88
+
89
+ // ---- decode-in (the lab's text arrival) --------------------------------------------------------------
90
+ // Katakana flicker just ahead of the reveal edge; resolved letters keep their role. Pure: t and t0 in
91
+ // seconds, salt keeps rows distinct. The colour-only afterglow is left to the renderer (it maps `glow`).
92
+ const LEAD = 0.07, GLOW = 0.6, PER_CHAR = 0.012;
93
+ const hash = (a, b, c) => { let h = (a * 374761393 + b * 668265263 + c * 2147483647) | 0; h = Math.imul(h ^ (h >>> 13), 1274126177); return ((h ^ (h >>> 16)) >>> 0) / 4294967296; };
94
+
95
+ /**
96
+ * -> cells [{ ch, role, bold, glyph, glow }] for one row at time t (seconds since the object arrived).
97
+ * t = Infinity (or quiet) gives the settled row. A row starts at t0 and resolves left to right over dur.
98
+ */
99
+ export function decodeRow(row, t, t0 = 0, d = 0.25, salt = 1) {
100
+ const chars = [];
101
+ for (const s of row) for (const ch of s.text) chars.push({ ch, role: s.role, bold: Boolean(s.bold) });
102
+ if (!Number.isFinite(t)) return chars.map(c => ({ ...c, glyph: false, glow: 0 }));
103
+ const n = chars.length;
104
+ const span = Math.max(d, n * PER_CHAR);
105
+ return chars.map((c, i) => {
106
+ if (c.ch === ' ') return { ...c, glyph: false, glow: 0 };
107
+ const r = t0 + (n > 1 ? (i / (n - 1)) * span : 0), dt = t - r;
108
+ if (dt < -LEAD) return { ch: ' ', role: c.role, bold: false, glyph: false, glow: 0 };
109
+ if (dt < 0) return { ch: KANA[Math.floor(hash(i, Math.floor(t * 30), salt) * KANA.length)], role: 'sky', bold: false, glyph: true, glow: 0 };
110
+ return { ...c, bold: c.bold || dt < 0.05, glyph: false, glow: dt < GLOW ? (1 - dt / GLOW) ** 1.6 : 0 };
111
+ });
112
+ }
113
+
114
+ /** Seconds the arrival of a view takes: rows start 0.1 s apart and each resolves over 0.25 s. */
115
+ export function arrivalSeconds(view) {
116
+ const rows = view?.rows?.length || 0;
117
+ return rows ? 0.1 * (rows - 1) + Math.max(0.25, Math.max(...view.rows.map(r => rowLen(r))) * PER_CHAR) + GLOW : 0;
118
+ }
@@ -0,0 +1,17 @@
1
+ /**
2
+ * PEEK card: the hit of `/peek <id>` as an inline object (the box layout keeps the label column; a note would
3
+ * re-flow it). Fields come from core/peek.js ROWS, the same list `quox peek` prints. d: a peekId result.
4
+ */
5
+ import { seg, fit, boxWidth } from './model.js';
6
+ import { KIND_LABEL, ROWS, MORE } from '../../core/peek.js';
7
+
8
+ export function peekCard(d, cols) {
9
+ const w = boxWidth(cols, 84), inner = w - 4;
10
+ const { kind, data } = d.hit || {};
11
+ const rows = [];
12
+ const L = (label, value, role = 'value') => [seg(label.padEnd(10), 'muted'), seg(fit(value, inner - 10), role)];
13
+ for (const [k, v] of (ROWS[kind] ? ROWS[kind](data || {}) : [])) if (v) rows.push(L(k, v));
14
+ if (d.also?.length) rows.push(L('also', `an id of the same value: ${d.also.map(k => KIND_LABEL[k]).join(', ')}`, 'muted'));
15
+ if (MORE[kind]) rows.push(L('more', MORE[kind](d.id), 'muted'));
16
+ return { box: { width: w, title: `◇ ${KIND_LABEL[kind] || 'id'} ${d.id}`, titleRole: 'sky', right: 'read only', rightRole: 'muted', border: 'sky' }, rows };
17
+ }
@@ -0,0 +1,110 @@
1
+ /**
2
+ * D1 evidence integrity chain and D3 reconciliation for one tool call of this session.
3
+ * AEE the call's envelope, read back (GET /aee/:envelope_id)
4
+ * AOCL aocl.* envelopes on the same correlation id (GET /aee/query?corr=)
5
+ * TOOL what the server recorded for the call (payload.success / tool_name) vs what the stream said
6
+ * WARD the envelope's inclusion receipt (POST /ward/verify-receipt, server-verified, bounded)
7
+ * A link is drawn confirmed only when its read succeeded and said so. Nothing is recomputed locally,
8
+ * so the card says the server's WARD verified it, never "recomputed locally".
9
+ *
10
+ * D3: a tool that ended effect_unknown is reconciled against the server's own record of the call
11
+ * (the ops.tool envelope's payload.success). No envelope id means it cannot be reconciled from here.
12
+ */
13
+ import { seg, fit, short, plural } from './model.js';
14
+
15
+ const LINKS = ['AEE', 'AOCL', 'TOOL', 'WARD'];
16
+
17
+ /** -> [{ name, ok: true|false|null, sub }] in chain order. ok null = not confirmed (unknown). */
18
+ export function chainLinks(d) {
19
+ const t = d.tool || {};
20
+ const env = d.envelope?.ok ? d.envelope.env : null;
21
+ const out = [];
22
+ out.push(env ? { name: 'AEE', ok: true, sub: `envelope ${short(env.id || t.envelopeId, 14)}` }
23
+ : { name: 'AEE', ok: d.envelope?.status === 404 ? false : null, sub: d.envelope?.status === 404 ? 'envelope not found' : `envelope not read${d.envelope?.error ? ` (${fit(d.envelope.error, 24)})` : ''}` });
24
+ const aocl = d.aocl?.ok ? d.aocl.list || [] : null;
25
+ if (aocl && aocl.length) {
26
+ const has = (i) => aocl.some(e => e.intent === i);
27
+ const pol = aocl.filter(e => e.intent === 'aocl.policy.evaluated');
28
+ const polOk = pol.length ? pol.every(e => e.payload?.allPassed !== false) : null;
29
+ const bits = [];
30
+ if (has('aocl.identity.verified')) bits.push('identity');
31
+ if (polOk != null) bits.push(polOk ? 'policy ok' : 'policy blocked');
32
+ out.push({ name: 'AOCL', ok: polOk === false ? false : true, sub: bits.length ? bits.join(' + ') : plural(aocl.length, 'AOCL record') });
33
+ } else out.push({ name: 'AOCL', ok: null, sub: aocl ? 'no AOCL record on this corr' : `not read${d.aocl?.error ? ` (${fit(d.aocl.error, 20)})` : ''}` });
34
+ const rec = env?.payload || null;
35
+ if (rec && rec.success != null) {
36
+ const want = t.status === 'ok';
37
+ const match = Boolean(rec.success) === want || t.status === 'effect_unknown';
38
+ out.push({ name: 'TOOL', ok: match && Boolean(rec.success), sub: `${rec.tool_name || t.tool || 'tool'} ${rec.success ? 'succeeded' : 'failed'}${match ? '' : ` (stream said ${t.status})`}` });
39
+ } else out.push({ name: 'TOOL', ok: null, sub: `${t.tool || 'tool'} ${t.status || ''} (no server record)`.trim() });
40
+ const r = d.receipt?.ok ? d.receipt.result : null;
41
+ if (r?.status === 'WITNESSED') out.push({ name: 'WARD', ok: true, sub: `witnessed seq ${r.entry?.seq}` });
42
+ else if (r?.status === 'UNTIPPED') out.push({ name: 'WARD', ok: null, sub: `seq ${r.entry?.seq}, no signed tip yet` });
43
+ else if (r?.status === 'NOT_WITNESSED') out.push({ name: 'WARD', ok: null, sub: 'not witnessed yet' });
44
+ else if (r?.status) out.push({ name: 'WARD', ok: false, sub: `${r.status}${r.reason ? ` ${r.reason}` : ''}` });
45
+ else out.push({ name: 'WARD', ok: null, sub: d.receipt?.timeout ? `no answer in ${d.receipt.timeout}s` : `not checked${d.receipt?.error ? ` (${fit(d.receipt.error, 24)})` : ''}` });
46
+ return out;
47
+ }
48
+
49
+ const markOf = (ok) => (ok === true ? ['✔', 'ok'] : ok === false ? ['✖', 'error'] : ['○', 'faint']);
50
+
51
+ /** d: { tool, envelope, aocl, receipt } -> view { rows } (wide row at >= 90 cols, vertical below). */
52
+ export function proofChain(d, cols) {
53
+ const links = chainLinks(d);
54
+ const rows = [];
55
+ rows.push([seg('proof ', 'muted'), seg(fit(`${d.tool?.tool || 'tool call'}${d.tool?.envelopeId ? ` · ${short(d.tool.envelopeId, 18)}` : ''}`, cols - 10), 'value', true)]);
56
+ if (cols >= 90) {
57
+ const head = [], sub = [], cw = Math.max(23, Math.floor((cols - 4) / 4));
58
+ links.forEach((l, i) => {
59
+ const role = `proto:${l.name.toLowerCase() === 'tool' ? 'volt' : l.name.toLowerCase()}`;
60
+ head.push(seg(l.name, l.name === 'TOOL' ? 'value' : role, true));
61
+ sub.push(seg(fit(l.sub, cw - 1).padEnd(i < 3 ? cw : 0), l.ok === false ? 'error' : 'muted'));
62
+ if (i < 3) {
63
+ const linked = l.ok === true && links[i + 1].ok === true;
64
+ head.push(seg(' ' + (linked ? '━' : '╌').repeat(cw - 2 - l.name.length) + ' ', linked ? 'indigo' : 'faint'));
65
+ }
66
+ });
67
+ rows.push(head, sub);
68
+ } else {
69
+ links.forEach((l, i) => {
70
+ const role = `proto:${l.name.toLowerCase() === 'tool' ? 'volt' : l.name.toLowerCase()}`;
71
+ const [m, mr] = markOf(l.ok);
72
+ rows.push([seg(m, mr), seg(' '), seg(l.name.padEnd(5), l.name === 'TOOL' ? 'value' : role, true), seg(fit(l.sub, cols - 12), l.ok === false ? 'error' : 'muted')]);
73
+ if (i < 3) rows.push([seg(l.ok === true && links[i + 1].ok === true ? '┃' : '╎', l.ok === true && links[i + 1].ok === true ? 'indigo' : 'faint')]);
74
+ });
75
+ }
76
+ const n = links.filter(l => l.ok === true).length;
77
+ const bad = links.filter(l => l.ok === false).length;
78
+ if (n === 4) rows.push([seg('✔ ', 'ok'), seg(cols < 60 ? 'chain verified · 4 links' : 'chain verified · 4 links · WARD receipt checked by the server', 'value')]);
79
+ else rows.push([seg(bad ? '✖ ' : '◐ ', bad ? 'error' : 'warn'), seg(`${n} of 4 links confirmed${bad ? ` · ${bad} contradicted` : ''}`, bad ? 'error' : 'warn')]);
80
+ return { rows, links };
81
+ }
82
+
83
+ /** One effect_unknown call reconciled against the server's record of it. */
84
+ export function reconcileItem(it) {
85
+ if (!it.envelopeId) return { mark: '?', role: 'muted', state: 'unverified', why: 'no envelope id, cannot be checked from here' };
86
+ if (!it.record) return { mark: '?', role: 'muted', state: 'unverified', why: it.error ? `record not read (${fit(it.error, 30)})` : 'not checked' };
87
+ if (!it.record.ok) return { mark: '?', role: 'muted', state: 'unverified', why: it.record.status === 404 ? 'no server record of the call' : `record not read (${fit(it.record.error || '', 30)})` };
88
+ const ok = it.record.env?.payload?.success;
89
+ if (ok === true) return { mark: '✔', role: 'ok', state: 'confirmed', why: 'server recorded success' };
90
+ if (ok === false) return { mark: '✖', role: 'error', state: 'mismatch', why: 'server recorded a failure, not done' };
91
+ return { mark: '?', role: 'muted', state: 'unverified', why: 'server record has no outcome' };
92
+ }
93
+
94
+ /** d: { items: [{ tool, envelopeId, record }] } -> view { rows } */
95
+ export function reconcileView(d, cols) {
96
+ const nw = cols < 60;
97
+ const items = d.items || [];
98
+ const rows = [[seg(nw ? `reconcile · ${items.length} unknown` : `reconcile · ${plural(items.length, 'call')} ended with effect unknown, checking each`, 'muted')]];
99
+ let conf = 0, mis = 0;
100
+ for (const it of items) {
101
+ const r = reconcileItem(it);
102
+ if (r.state === 'confirmed') conf++; else if (r.state === 'mismatch') mis++;
103
+ const row = [seg(r.mark, r.role), seg(' '), seg(fit(it.tool || 'tool', 15).padEnd(16), 'value'), seg(r.state.padEnd(12), r.role === 'muted' ? 'muted' : r.role, r.state !== 'unverified')];
104
+ if (!nw) row.push(seg(fit(r.why, cols - 34), 'muted'));
105
+ rows.push(row);
106
+ }
107
+ const un = items.length - conf - mis;
108
+ rows.push([seg(`${conf} confirmed · ${mis} mismatch · ${un} unverified`, mis ? 'warn' : 'muted')]);
109
+ return { rows };
110
+ }
@@ -0,0 +1,130 @@
1
+ /**
2
+ * /prove: independently verify the last turn's tool calls. Two independent checks per call:
3
+ * 1. the receipt chain (the same reads as /proof: AEE envelope, the server's own record of the call,
4
+ * the WARD inclusion receipt), and
5
+ * 2. a TRUTH read: for a write whose effect we know how to read back (VERIFIERS below), read it back
6
+ * from the system of record and see whether it is really there.
7
+ * Per call: proven (chain agrees and, for a mapped write, the effect is there), unproven (cannot be shown:
8
+ * an unmapped write, a read that failed, no receipt) or contradicts (the stream said ok and the server or
9
+ * the truth read disagrees, or the call failed). An unmapped write is never called proven.
10
+ *
11
+ * Extending: push an entry on VERIFIERS: { id, tools: [tool names], keys: [arg names to find in the call
12
+ * summary], read: (reads, target) -> true | false | null, describe: (target, found) -> text }.
13
+ */
14
+ import { seg, fit, fitRow, short, boxWidth } from './model.js';
15
+ import { chainLinks } from './proof.js';
16
+
17
+ export const VERIFIERS = [
18
+ { id: 'slot_create', tools: ['slot_create'], keys: ['name', 'slot'], read: (r, t) => r.slotExists(t), describe: (t, f) => (f ? `slot "${t}" exists` : `slot "${t}" not found`) },
19
+ { id: 'memory_save', tools: ['memory_save'], keys: ['content', 'text', 'fact'], read: (r, t) => r.memoryFind(t), describe: (t, f) => (f ? `memory "${fit(t, 24)}" is stored` : `memory "${fit(t, 24)}" not found`) }
20
+ ];
21
+
22
+ export const verifierFor = (tool) => VERIFIERS.find(v => v.tools.includes(tool)) || null;
23
+
24
+ /** Tools that only read: their receipt chain is the whole proof (nothing changed to read back). */
25
+ const READ_RE = /_(list|read|get|search|stats|history|usage|brief|notes|roadmaps|streams|folders|zones|pending|accounts|blocked|proposals|latest|query|status|show)$/;
26
+ export const isReadTool = (tool) => READ_RE.test(String(tool || ''));
27
+
28
+ /** The thing to check, from the call summary: key=value, key: "value", else the first quoted string. */
29
+ export function targetOf(tool, summary) {
30
+ const s = String(summary || '');
31
+ const v = verifierFor(tool);
32
+ for (const k of v?.keys || ['name']) {
33
+ const m = new RegExp(`\\b${k}\\s*[=:]\\s*(?:"([^"]+)"|'([^']+)'|([\\w.\\-]+))`, 'i').exec(s);
34
+ if (m) return m[1] || m[2] || m[3];
35
+ }
36
+ const q = /["“]([^"”]+)["”]/.exec(s);
37
+ return q ? q[1] : null;
38
+ }
39
+
40
+ /** -> { mapped:false } | { mapped:true, found: true|false|null, what?, error?, noTarget? }. Never throws. */
41
+ export async function runTruth(call, reads) {
42
+ const v = verifierFor(call.tool);
43
+ if (!v) return { mapped: false };
44
+ const target = targetOf(call.tool, call.summary);
45
+ if (!target) return { mapped: true, found: null, noTarget: true };
46
+ try {
47
+ const found = await v.read(reads, target);
48
+ return { mapped: true, found: found === true ? true : found === false ? false : null, what: v.describe(target, found === true) };
49
+ } catch (e) {
50
+ return { mapped: true, found: null, error: e?.status ? `HTTP ${e.status}` : e?.message || 'failed' };
51
+ }
52
+ }
53
+
54
+ /** Settled tool calls after the last user message of `items` (history + live blocks). */
55
+ export function lastTurnCalls(items) {
56
+ const list = items || [];
57
+ let from = 0;
58
+ for (let i = list.length - 1; i >= 0; i--) if (list[i]?.kind === 'user' && !list[i].echo) { from = i + 1; break; }
59
+ return list.slice(from).filter(b => b && b.kind === 'tool' && b.status !== 'running');
60
+ }
61
+
62
+ const V = (state, why, call) => ({ state, mark: state === 'proven' ? '✔' : state === 'contradicts' ? '✖' : '⚠', why, envelopeId: call.envelopeId || null });
63
+
64
+ /** { call, proof, truth } -> { state, mark, why, envelopeId }. Pure. */
65
+ export function verdictFor({ call, proof, truth }) {
66
+ const bad = !['ok', 'effect_unknown'].includes(call.status);
67
+ if (bad) return V('contradicts', `the call ${call.status || 'did not finish'}, so the task did not get done`, call);
68
+ if (!call.envelopeId) return V('unproven', 'no receipt id on this call', call);
69
+ const links = proof ? chainLinks(proof) : [];
70
+ const by = Object.fromEntries(links.map(l => [l.name, l]));
71
+ if (by.TOOL?.ok === false) return V('contradicts', by.TOOL.sub, call);
72
+ if (by.WARD?.ok === false) return V('contradicts', `WARD: ${by.WARD.sub}`, call);
73
+ if (by.AEE?.ok !== true) return V('unproven', `receipt not confirmed (${by.AEE?.sub || 'not read'})`, call);
74
+ if (by.TOOL?.ok !== true) return V('unproven', 'no server record of the call outcome', call);
75
+ if (truth?.mapped) {
76
+ if (truth.found === true) return V('proven', `${truth.what || 'effect found'} · server recorded success`, call);
77
+ if (truth.found === false) return V('contradicts', `${truth.what || 'effect not found'}, though the call reported ok`, call);
78
+ return V('unproven', truth.noTarget ? 'could not tell which thing to check from the call' : `effect not read back (${truth.error || 'no answer'})`, call);
79
+ }
80
+ if (isReadTool(call.tool)) return V('proven', 'read call · receipt chain checked', call);
81
+ return V('unproven', `no read mapping for ${call.tool}: receipt checked, effect not independently read`, call);
82
+ }
83
+
84
+ /** d: { items: [{ call, proof, truth }] } -> view { box, rows } */
85
+ export function proveView(d, cols) {
86
+ const w = boxWidth(cols, 90), inner = w - 4, nw = w < 60;
87
+ const rows = [];
88
+ const tally = { proven: 0, unproven: 0, contradicts: 0 };
89
+ const items = d.items || [];
90
+ for (const it of items) {
91
+ const v = verdictFor(it);
92
+ tally[v.state]++;
93
+ const role = v.state === 'proven' ? 'ok' : v.state === 'contradicts' ? 'error' : 'warn';
94
+ rows.push([seg(v.mark, role, true), seg(' '), seg(fit(it.call.tool || 'tool', 14).padEnd(15), 'value', true), seg(v.state.padEnd(12), role, true), ...(nw ? [] : [seg(fit(v.why, inner - 30), 'muted')])]);
95
+ rows.push([seg(' '), ...(nw ? [seg(fit(v.why, inner - 2), 'muted')] : []), seg(v.envelopeId ? `${nw ? '' : ' '}receipt ${short(v.envelopeId, nw ? 12 : 22)}` : ' no receipt', 'muted')]);
96
+ }
97
+ if (!items.length) rows.push([seg('no tool calls to check', 'muted')]);
98
+ rows.push([seg(`${tally.proven} proven · ${tally.unproven} unproven · ${tally.contradicts} contradicts`, tally.contradicts ? 'error' : tally.unproven ? 'warn' : 'ok', true)]);
99
+ return { box: { width: w, title: 'Prove · last turn', titleRole: 'indigo', border: 'indigo' }, rows: rows.map(r => fitRow(r, inner)), tally };
100
+ }
101
+
102
+ /** Fetchers for createObjectsApi. deps: { self (the objects api, for proof), get, listOf, resolveEndpoint } */
103
+ export function proveFetchers({ self, get, listOf, resolveEndpoint }) {
104
+ const reads = {
105
+ async slotExists(name) {
106
+ const ep = resolveEndpoint('v1.slots.list');
107
+ const rows = listOf(await get('collector', ep.path, undefined, 10000), 'slots');
108
+ return rows.some(s => String(s.name || '').toLowerCase() === String(name).toLowerCase());
109
+ },
110
+ async memoryFind(text) {
111
+ const d = await get('memory', '/api/memory/search', { q: text, limit: 10 }, 10000);
112
+ const want = String(text).toLowerCase().slice(0, 60);
113
+ return listOf(d, 'results', 'memories', 'data').some(m => JSON.stringify(m).toLowerCase().includes(want));
114
+ }
115
+ };
116
+ return {
117
+ reads,
118
+ /** calls: tool blocks { tool, status, summary, envelopeId, callId } -> { data: { items } } */
119
+ async prove(calls) {
120
+ const items = await Promise.all((calls || []).slice(-12).map(async (call) => {
121
+ const [proof, truth] = await Promise.all([
122
+ call.envelopeId ? self.proof({ tool: call.tool, status: call.status, envelopeId: call.envelopeId, callId: call.callId }).then(r => r.data).catch(() => null) : null,
123
+ runTruth(call, reads)
124
+ ]);
125
+ return { call: { tool: call.tool, status: call.status, summary: call.summary, envelopeId: call.envelopeId || null }, proof, truth };
126
+ }));
127
+ return { data: { items } };
128
+ }
129
+ };
130
+ }