quoxcli 0.2.0 → 0.4.0

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 (442) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +2 -0
  3. package/bin/quox.js +99 -126
  4. package/lib/api/endpoints/actions.js +15 -0
  5. package/lib/api/endpoints/admin.js +46 -0
  6. package/lib/api/endpoints/agent-schedules.js +26 -0
  7. package/lib/api/endpoints/agents.js +7 -0
  8. package/lib/api/endpoints/assistants.js +12 -0
  9. package/lib/api/endpoints/away.js +15 -0
  10. package/lib/api/endpoints/blog.js +16 -0
  11. package/lib/api/endpoints/chat.js +14 -0
  12. package/lib/api/endpoints/contactsq.js +6 -0
  13. package/lib/api/endpoints/conversations.js +14 -0
  14. package/lib/api/endpoints/devServerRegistry.js +25 -0
  15. package/lib/api/endpoints/engagement.js +26 -0
  16. package/lib/api/endpoints/evidence.js +20 -0
  17. package/lib/api/endpoints/executions.js +13 -0
  18. package/lib/api/endpoints/fetchAllowlist.js +27 -0
  19. package/lib/api/endpoints/files.js +14 -0
  20. package/lib/api/endpoints/hat.js +44 -0
  21. package/lib/api/endpoints/inbox.js +20 -0
  22. package/lib/api/endpoints/index.js +26 -0
  23. package/lib/api/endpoints/loops.js +26 -0
  24. package/lib/api/endpoints/memory.js +19 -0
  25. package/lib/api/endpoints/mind.js +13 -0
  26. package/lib/api/endpoints/mon.js +179 -0
  27. package/lib/api/endpoints/objectives.js +12 -0
  28. package/lib/api/endpoints/plugins.js +18 -0
  29. package/lib/api/endpoints/presence.js +33 -0
  30. package/lib/api/endpoints/quoxplan.js +7 -0
  31. package/lib/api/endpoints/quoxseo.js +12 -0
  32. package/lib/api/endpoints/router.js +17 -0
  33. package/lib/api/endpoints/safety.js +7 -0
  34. package/lib/api/endpoints/server.js +21 -0
  35. package/lib/api/endpoints/setup.js +6 -0
  36. package/lib/api/endpoints/skills.js +20 -0
  37. package/lib/api/endpoints/stepup.js +20 -0
  38. package/lib/api/endpoints/teams.js +2 -2
  39. package/lib/api/endpoints/triggers.js +26 -0
  40. package/lib/api/endpoints/v1.js +120 -0
  41. package/lib/api/endpoints/ward.js +7 -0
  42. package/lib/api/endpoints/workflows.js +7 -0
  43. package/lib/api/endpoints/x.js +8 -0
  44. package/lib/commands/actions.js +131 -0
  45. package/lib/commands/admin.js +16 -0
  46. package/lib/commands/agent.js +170 -27
  47. package/lib/commands/agentAttach.js +140 -13
  48. package/lib/commands/approvals.js +78 -1
  49. package/lib/commands/aside.js +24 -0
  50. package/lib/commands/ask.js +146 -0
  51. package/lib/commands/assistant.js +59 -4
  52. package/lib/commands/auth.js +8 -2
  53. package/lib/commands/backup.js +8 -4
  54. package/lib/commands/blog.js +110 -0
  55. package/lib/commands/brain.js +105 -14
  56. package/lib/commands/build.js +19 -5
  57. package/lib/commands/chat.js +180 -26
  58. package/lib/commands/chatCompanion.js +27 -0
  59. package/lib/commands/chatState.js +45 -0
  60. package/lib/commands/claude.js +35 -38
  61. package/lib/commands/contacts.js +134 -4
  62. package/lib/commands/contactsSendAt.js +21 -0
  63. package/lib/commands/conversation.js +35 -4
  64. package/lib/commands/dashboard.js +43 -0
  65. package/lib/commands/department.js +28 -7
  66. package/lib/commands/devResident.js +15 -3
  67. package/lib/commands/devSupervisor.js +13 -1
  68. package/lib/commands/discord.js +75 -39
  69. package/lib/commands/done.js +98 -28
  70. package/lib/commands/engagement.js +107 -6
  71. package/lib/commands/evidence.js +154 -0
  72. package/lib/commands/ext.js +23 -0
  73. package/lib/commands/fetchAllowlist.js +71 -0
  74. package/lib/commands/file.js +38 -1
  75. package/lib/commands/fleet.js +336 -4
  76. package/lib/commands/governance.js +12 -3
  77. package/lib/commands/gripe.js +44 -13
  78. package/lib/commands/hat.js +254 -9
  79. package/lib/commands/helpers.js +18 -1
  80. package/lib/commands/hyperion.js +58 -0
  81. package/lib/commands/image.js +68 -0
  82. package/lib/commands/inbox.js +74 -23
  83. package/lib/commands/kuma.js +1050 -0
  84. package/lib/commands/kumaSla.js +174 -0
  85. package/lib/commands/licence.js +52 -155
  86. package/lib/commands/loop.js +291 -0
  87. package/lib/commands/lucid.js +10 -4
  88. package/lib/commands/memory.js +85 -8
  89. package/lib/commands/mind.js +71 -0
  90. package/lib/commands/mon.js +69 -2
  91. package/lib/commands/monitoring.js +1 -1
  92. package/lib/commands/motion.js +2 -2
  93. package/lib/commands/nucleus.js +48 -17
  94. package/lib/commands/objective.js +59 -1
  95. package/lib/commands/offload.js +89 -0
  96. package/lib/commands/onboard.js +2 -1
  97. package/lib/commands/org.js +30 -3
  98. package/lib/commands/peek.js +28 -0
  99. package/lib/commands/plan.js +38 -0
  100. package/lib/commands/plugin.js +110 -0
  101. package/lib/commands/presence.js +89 -0
  102. package/lib/commands/provider.js +217 -0
  103. package/lib/commands/qlarity.js +19 -3
  104. package/lib/commands/quoxchat.js +13 -4
  105. package/lib/commands/quoxseo.js +69 -0
  106. package/lib/commands/reach.js +2 -1
  107. package/lib/commands/research.js +79 -0
  108. package/lib/commands/router.js +77 -0
  109. package/lib/commands/rows.js +367 -0
  110. package/lib/commands/run.js +82 -10
  111. package/lib/commands/scope.js +2 -2
  112. package/lib/commands/server.js +405 -0
  113. package/lib/commands/setup.js +33 -7
  114. package/lib/commands/shortcut.js +41 -0
  115. package/lib/commands/skills.js +68 -9
  116. package/lib/commands/slot.js +260 -7
  117. package/lib/commands/status.js +1 -1
  118. package/lib/commands/team.js +3 -1
  119. package/lib/commands/tips.js +23 -0
  120. package/lib/commands/tool.js +133 -45
  121. package/lib/commands/trace.js +12 -7
  122. package/lib/commands/trigger.js +95 -0
  123. package/lib/commands/update.js +46 -0
  124. package/lib/commands/vault.js +31 -8
  125. package/lib/commands/vm.js +237 -0
  126. package/lib/commands/voice.js +34 -3
  127. package/lib/commands/volt.js +45 -3
  128. package/lib/commands/walkthrough.js +32 -0
  129. package/lib/commands/watch.js +73 -21
  130. package/lib/commands/welcome.js +14 -0
  131. package/lib/commands/workflow.js +189 -32
  132. package/lib/commands/x.js +13 -4
  133. package/lib/commands/youtube.js +172 -0
  134. package/lib/core/actingAs.js +2 -2
  135. package/lib/core/actionItems.js +115 -0
  136. package/lib/core/activeSummary.js +186 -0
  137. package/lib/core/agentAlias.js +2 -0
  138. package/lib/core/agentFamilies.js +7 -0
  139. package/lib/core/aside.js +54 -0
  140. package/lib/core/askDecision.js +60 -0
  141. package/lib/core/auth.js +164 -13
  142. package/lib/core/callerSource.js +1 -1
  143. package/lib/core/cliBuild.js +62 -0
  144. package/lib/core/client.js +152 -35
  145. package/lib/core/commandRegistrars.js +130 -0
  146. package/lib/core/config.js +143 -25
  147. package/lib/core/customHats.js +168 -0
  148. package/lib/core/doneEngineFetch.js +8 -0
  149. package/lib/core/errors.js +329 -20
  150. package/lib/core/findingReconcile.js +90 -0
  151. package/lib/core/global-flags.js +105 -5
  152. package/lib/core/governedSession.js +1 -3
  153. package/lib/core/hyperion.js +102 -0
  154. package/lib/core/inboxResolution.js +65 -0
  155. package/lib/core/lazyCommands.js +4 -1
  156. package/lib/core/liveSessionsReport.js +1 -1
  157. package/lib/core/loopGlyph.js +97 -0
  158. package/lib/core/offload.js +533 -0
  159. package/lib/core/org-override.js +1 -1
  160. package/lib/core/orgResolve.js +70 -0
  161. package/lib/core/output.js +11 -11
  162. package/lib/core/peek.js +126 -0
  163. package/lib/core/profileUsers.js +51 -0
  164. package/lib/core/promptCancel.js +18 -0
  165. package/lib/core/repoPath.js +11 -0
  166. package/lib/core/residentSeed.js +3 -1
  167. package/lib/core/rootOptions.js +39 -0
  168. package/lib/core/router.js +168 -0
  169. package/lib/core/selfUpdate.js +188 -0
  170. package/lib/core/sessionHeartbeat.js +12 -8
  171. package/lib/core/sessionsOverview.js +64 -0
  172. package/lib/core/shortcut.js +83 -0
  173. package/lib/core/slotKeeper.js +248 -3
  174. package/lib/core/slotWake.js +120 -0
  175. package/lib/core/supervisorEngine.js +71 -2
  176. package/lib/core/version.js +1 -1
  177. package/lib/core/vm.js +366 -0
  178. package/lib/core/vmTui.js +86 -0
  179. package/lib/core/walkthrough.js +35 -0
  180. package/lib/dragon/companionView.js +34 -0
  181. package/lib/dragon/frames.js +118 -0
  182. package/lib/dragon/jobs.js +123 -0
  183. package/lib/dragon/renderWorker.js +15 -0
  184. package/lib/dragon/select.js +72 -0
  185. package/lib/evidence/bundleExport.js +47 -0
  186. package/lib/evidence/bundleVerify.js +77 -0
  187. package/lib/hyperion/deck.js +29 -0
  188. package/lib/lucid/LucidCard.jsx +68 -0
  189. package/lib/lucid/LucidIntro.jsx +45 -58
  190. package/lib/lucid/cards.js +86 -0
  191. package/lib/lucid/markdown.js +81 -0
  192. package/lib/lucid/motion.js +56 -0
  193. package/lib/quoxon/EXTENSIONS.md +23 -0
  194. package/lib/quoxon/activity.js +14 -2
  195. package/lib/quoxon/aocl.js +117 -0
  196. package/lib/quoxon/api.js +690 -25
  197. package/lib/quoxon/app.js +3586 -250
  198. package/lib/quoxon/approvalFacts.js +96 -0
  199. package/lib/quoxon/approvalSentence.js +44 -0
  200. package/lib/quoxon/approvalsView.js +384 -0
  201. package/lib/quoxon/asideView.js +40 -0
  202. package/lib/quoxon/ask.js +121 -0
  203. package/lib/quoxon/away.js +52 -0
  204. package/lib/quoxon/bang.js +224 -0
  205. package/lib/quoxon/bulkRisk.js +17 -0
  206. package/lib/quoxon/capabilities.js +13 -6
  207. package/lib/quoxon/cells.js +53 -0
  208. package/lib/quoxon/commandShort.js +124 -0
  209. package/lib/quoxon/commands.js +429 -39
  210. package/lib/quoxon/connect.js +210 -23
  211. package/lib/quoxon/connectCard.js +19 -2
  212. package/lib/quoxon/consent.js +86 -0
  213. package/lib/quoxon/copy.js +4 -3
  214. package/lib/quoxon/countdownLine.js +20 -0
  215. package/lib/quoxon/deck.js +30 -0
  216. package/lib/quoxon/demo.autoplay.js +29 -0
  217. package/lib/quoxon/demo.fixtures.js +1 -1
  218. package/lib/quoxon/demo.js +46 -3
  219. package/lib/quoxon/devObserver.js +20 -0
  220. package/lib/quoxon/dividerAocl.js +192 -0
  221. package/lib/quoxon/dividerRule.js +57 -0
  222. package/lib/quoxon/dragonCompanion.js +255 -0
  223. package/lib/quoxon/dragonModes.js +151 -0
  224. package/lib/quoxon/dragonMoments.js +82 -0
  225. package/lib/quoxon/dragonReads.js +68 -0
  226. package/lib/quoxon/dragonView.js +41 -0
  227. package/lib/quoxon/earlyInput.js +40 -0
  228. package/lib/quoxon/echo.js +15 -0
  229. package/lib/quoxon/egg.js +2 -2
  230. package/lib/quoxon/events.js +266 -26
  231. package/lib/quoxon/extensions.js +276 -0
  232. package/lib/quoxon/feedback.js +50 -0
  233. package/lib/quoxon/gallery.js +21 -7
  234. package/lib/quoxon/handoffOffer.js +78 -0
  235. package/lib/quoxon/hatSwitch.js +37 -0
  236. package/lib/quoxon/headless.js +161 -0
  237. package/lib/quoxon/hostUrls.js +41 -0
  238. package/lib/quoxon/inboxView.js +79 -0
  239. package/lib/quoxon/indicator.js +6 -2
  240. package/lib/quoxon/installCli.js +79 -0
  241. package/lib/quoxon/intent.js +12 -1
  242. package/lib/quoxon/keys.js +51 -8
  243. package/lib/quoxon/launcher.js +103 -0
  244. package/lib/quoxon/loopCard.js +456 -0
  245. package/lib/quoxon/loopCards.js +180 -0
  246. package/lib/quoxon/loopStream.js +87 -0
  247. package/lib/quoxon/main.js +101 -160
  248. package/lib/quoxon/markdown.js +45 -21
  249. package/lib/quoxon/markdownSettle.js +19 -0
  250. package/lib/quoxon/matrixDomains.json +46 -0
  251. package/lib/quoxon/mentions.js +90 -0
  252. package/lib/quoxon/mind.js +103 -0
  253. package/lib/quoxon/mode.js +46 -0
  254. package/lib/quoxon/model.js +132 -26
  255. package/lib/quoxon/modelPrefs.js +345 -0
  256. package/lib/quoxon/motion/clock.js +3 -2
  257. package/lib/quoxon/motion/level.js +91 -0
  258. package/lib/quoxon/mouse.js +222 -0
  259. package/lib/quoxon/noai.js +57 -0
  260. package/lib/quoxon/objectiveOffer.js +82 -0
  261. package/lib/quoxon/objects/away.js +72 -0
  262. package/lib/quoxon/objects/fetch.js +17 -5
  263. package/lib/quoxon/objects/fleet.js +149 -0
  264. package/lib/quoxon/objects/health.js +186 -0
  265. package/lib/quoxon/objects/index.js +46 -7
  266. package/lib/quoxon/objects/mirror.js +137 -0
  267. package/lib/quoxon/objects/model.js +33 -0
  268. package/lib/quoxon/objects/peek.js +17 -0
  269. package/lib/quoxon/objects/proof.js +12 -4
  270. package/lib/quoxon/objects/prove.js +130 -0
  271. package/lib/quoxon/objects/replay.js +125 -0
  272. package/lib/quoxon/objects/sitrep.js +58 -0
  273. package/lib/quoxon/objects/view.js +11 -0
  274. package/lib/quoxon/onboarding/copy.js +32 -4
  275. package/lib/quoxon/onboarding/credential.js +17 -4
  276. package/lib/quoxon/onboarding/dockerOffer.js +45 -0
  277. package/lib/quoxon/onboarding/failureCause.js +33 -0
  278. package/lib/quoxon/onboarding/finish.js +15 -0
  279. package/lib/quoxon/onboarding/index.js +34 -7
  280. package/lib/quoxon/onboarding/installRunner.js +64 -5
  281. package/lib/quoxon/onboarding/preflight.js +17 -3
  282. package/lib/quoxon/onboarding/probe.js +65 -0
  283. package/lib/quoxon/onboarding/shortcutOffer.js +28 -0
  284. package/lib/quoxon/onboarding/view.js +76 -19
  285. package/lib/quoxon/orgLabel.js +10 -0
  286. package/lib/quoxon/orgSwitch.js +59 -0
  287. package/lib/quoxon/ownBroadcast.js +22 -0
  288. package/lib/quoxon/palette.js +43 -0
  289. package/lib/quoxon/planSteps.js +51 -0
  290. package/lib/quoxon/print.js +12 -5
  291. package/lib/quoxon/profileSwitch.js +53 -0
  292. package/lib/quoxon/promptHistory.js +41 -0
  293. package/lib/quoxon/providers.js +48 -0
  294. package/lib/quoxon/qart.js +20 -51
  295. package/lib/quoxon/qdragon.js +410 -0
  296. package/lib/quoxon/qdragonFly.js +62 -0
  297. package/lib/quoxon/qdragonScenes.js +282 -0
  298. package/lib/quoxon/qeyes.js +213 -0
  299. package/lib/quoxon/qmotion.js +75 -37
  300. package/lib/quoxon/render.js +740 -124
  301. package/lib/quoxon/resend.js +72 -0
  302. package/lib/quoxon/roster.js +117 -17
  303. package/lib/quoxon/route.js +6 -5
  304. package/lib/quoxon/rows.js +954 -0
  305. package/lib/quoxon/rowsStore.js +80 -0
  306. package/lib/quoxon/screenContext.js +150 -0
  307. package/lib/quoxon/screenFrames.js +254 -0
  308. package/lib/quoxon/serverChip.js +42 -0
  309. package/lib/quoxon/session.js +182 -2
  310. package/lib/quoxon/sessionDead.js +17 -0
  311. package/lib/quoxon/signin.js +125 -0
  312. package/lib/quoxon/slash/agents.js +112 -0
  313. package/lib/quoxon/slash/argSources.js +65 -0
  314. package/lib/quoxon/slash/args.js +65 -0
  315. package/lib/quoxon/slash/automate.js +89 -0
  316. package/lib/quoxon/slash/broadcast.js +140 -0
  317. package/lib/quoxon/slash/broadcastRun.js +108 -0
  318. package/lib/quoxon/slash/card.js +30 -0
  319. package/lib/quoxon/slash/challenge.js +114 -0
  320. package/lib/quoxon/slash/cliCommand.js +94 -0
  321. package/lib/quoxon/slash/cliLeaves.json +1023 -0
  322. package/lib/quoxon/slash/compact.js +1 -1
  323. package/lib/quoxon/slash/confirm.js +30 -0
  324. package/lib/quoxon/slash/crystallize.js +69 -0
  325. package/lib/quoxon/slash/dashboard.js +136 -0
  326. package/lib/quoxon/slash/draft.js +54 -0
  327. package/lib/quoxon/slash/evidenceCmd.js +34 -0
  328. package/lib/quoxon/slash/hatWalk.js +206 -0
  329. package/lib/quoxon/slash/inverses.js +77 -0
  330. package/lib/quoxon/slash/killer.js +24 -0
  331. package/lib/quoxon/slash/killerApi.js +16 -0
  332. package/lib/quoxon/slash/ledger.js +13 -8
  333. package/lib/quoxon/slash/listView.js +3 -1
  334. package/lib/quoxon/slash/modelCmd.js +261 -0
  335. package/lib/quoxon/slash/palette.js +22 -8
  336. package/lib/quoxon/slash/paletteController.js +117 -7
  337. package/lib/quoxon/slash/panels.js +21 -6
  338. package/lib/quoxon/slash/picker.js +20 -2
  339. package/lib/quoxon/slash/qpeCmd.js +35 -0
  340. package/lib/quoxon/slash/restart.js +95 -13
  341. package/lib/quoxon/slash/resume.js +18 -1
  342. package/lib/quoxon/slash/rowCmd.js +157 -0
  343. package/lib/quoxon/slash/rowWalk.js +175 -0
  344. package/lib/quoxon/slash/settings.js +16 -6
  345. package/lib/quoxon/slash/spawn.js +177 -0
  346. package/lib/quoxon/slash/stepUp.js +274 -0
  347. package/lib/quoxon/slash/stepUpCard.js +60 -0
  348. package/lib/quoxon/slash/stepUpCmds.js +78 -0
  349. package/lib/quoxon/slash/todoCmd.js +122 -0
  350. package/lib/quoxon/slash/undoApi.js +38 -0
  351. package/lib/quoxon/slash/undoCmd.js +49 -0
  352. package/lib/quoxon/slash/undoWish.js +15 -0
  353. package/lib/quoxon/slash/watch.js +164 -0
  354. package/lib/quoxon/slash/wish.js +23 -0
  355. package/lib/quoxon/slash/wishCmd.js +32 -0
  356. package/lib/quoxon/slotChat.js +300 -0
  357. package/lib/quoxon/slotFormat.js +195 -0
  358. package/lib/quoxon/slotRun.js +131 -0
  359. package/lib/quoxon/sound/mapping.js +2 -1
  360. package/lib/quoxon/stray.js +22 -0
  361. package/lib/quoxon/suggestCommand.js +90 -0
  362. package/lib/quoxon/term.js +46 -11
  363. package/lib/quoxon/textBuffer.js +176 -2
  364. package/lib/quoxon/theme.js +58 -25
  365. package/lib/quoxon/tips.js +433 -0
  366. package/lib/quoxon/toolCards.js +30 -0
  367. package/lib/quoxon/toolError.js +41 -0
  368. package/lib/quoxon/transcript.js +42 -4
  369. package/lib/quoxon/web/qface.js +18 -10
  370. package/lib/quoxon/welcome.js +1 -1
  371. package/lib/quoxon/whatsnew.js +136 -0
  372. package/lib/quoxon/whatsnew.jsonl +134 -0
  373. package/lib/quoxon/windowOrg.js +123 -0
  374. package/lib/server/devServers.js +137 -0
  375. package/lib/server/diag.js +129 -0
  376. package/lib/server/doctor.js +71 -0
  377. package/lib/server/install.js +149 -0
  378. package/lib/server/pluginEnable.js +161 -0
  379. package/lib/server/skew.js +56 -0
  380. package/lib/server/snapshot.js +131 -0
  381. package/lib/server/status.js +128 -0
  382. package/lib/server/sys.js +65 -0
  383. package/lib/server/uninstall.js +63 -0
  384. package/lib/server/update.js +234 -0
  385. package/lib/toolOutputShape.js +315 -0
  386. package/lib/tui/views/HyperionDeck.jsx +79 -0
  387. package/lib/tui/views/LucidDeck.jsx +209 -217
  388. package/package.json +5 -1
  389. package/vendor/dragonlab/SOURCE +4 -0
  390. package/vendor/dragonlab/design/cipher/v1/cipher-master.svg +46 -0
  391. package/vendor/dragonlab/design/cipher/v2/character.mjs +49 -0
  392. package/vendor/dragonlab/design/cipher/v2/review.mjs +33 -0
  393. package/vendor/dragonlab/design/cipher/v2/watch.mjs +56 -0
  394. package/vendor/dragonlab/design/drago/v1/character.mjs +19 -0
  395. package/vendor/dragonlab/design/drago/v1/drago-master.svg +56 -0
  396. package/vendor/dragonlab/design/drago/v2/character.mjs +87 -0
  397. package/vendor/dragonlab/design/drago/v4/character.mjs +67 -0
  398. package/vendor/dragonlab/design/drago/v4/profile.mjs +35 -0
  399. package/vendor/dragonlab/design/drago/v4/review.mjs +33 -0
  400. package/vendor/dragonlab/design/drago/v4/watch.mjs +56 -0
  401. package/vendor/dragonlab/design/hyperion/v1/hyperion-master.svg +56 -0
  402. package/vendor/dragonlab/design/hyperion/v2/character.mjs +79 -0
  403. package/vendor/dragonlab/design/hyperion/v2/review.mjs +33 -0
  404. package/vendor/dragonlab/design/hyperion/v2/watch.mjs +56 -0
  405. package/vendor/dragonlab/design/lucid/recovery/arrival.mjs +22 -0
  406. package/vendor/dragonlab/design/lucid/recovery/character.mjs +106 -0
  407. package/vendor/dragonlab/design/lucid/recovery/layout.mjs +50 -0
  408. package/vendor/dragonlab/design/lucid/recovery/lucid-master.svg +78 -0
  409. package/vendor/dragonlab/design/lucid/recovery/motion.mjs +42 -0
  410. package/vendor/dragonlab/design/lucid/recovery/render.mjs +121 -0
  411. package/vendor/dragonlab/design/lucid/recovery/review.mjs +68 -0
  412. package/vendor/dragonlab/design/lucid/recovery/verify.mjs +84 -0
  413. package/vendor/dragonlab/design/lucid/recovery/watch.mjs +56 -0
  414. package/vendor/dragonlab/design/seer/v1/seer-master.svg +53 -0
  415. package/vendor/dragonlab/design/seer/v2/character.mjs +88 -0
  416. package/vendor/dragonlab/design/seer/v3/character.mjs +33 -0
  417. package/vendor/dragonlab/design/seer/v4/character.mjs +66 -0
  418. package/vendor/dragonlab/design/seer/v4/review.mjs +33 -0
  419. package/vendor/dragonlab/design/seer/v4/watch.mjs +56 -0
  420. package/vendor/dragonlab/design/stage3/companion-review.mjs +28 -0
  421. package/vendor/dragonlab/design/stage3/sentinel-art.js +39 -0
  422. package/vendor/dragonlab/design/stage3/sentinel-braille.js +216 -0
  423. package/vendor/dragonlab/design/stage3/sentinel-character.js +257 -0
  424. package/vendor/dragonlab/design/stage3/sentinel-icon.js +103 -0
  425. package/vendor/dragonlab/design/stage3/sentinel-warden-eyes.js +95 -0
  426. package/vendor/dragonlab/design/stage3/svg-coverage.js +148 -0
  427. package/vendor/dragonlab/factory/svg-rig.mjs +63 -0
  428. package/vendor/dragonlab/integration/companions-v1/characters.mjs +88 -0
  429. package/vendor/dragonlab/integration/companions-v1/cipher.mjs +2 -0
  430. package/vendor/dragonlab/integration/companions-v1/companion.mjs +63 -0
  431. package/vendor/dragonlab/integration/companions-v1/drago.mjs +2 -0
  432. package/vendor/dragonlab/integration/companions-v1/hyperion.mjs +2 -0
  433. package/vendor/dragonlab/integration/companions-v1/lucid.mjs +2 -0
  434. package/vendor/dragonlab/integration/companions-v1/seer.mjs +2 -0
  435. package/vendor/dragonlab/integration/companions-v1/sentinel.mjs +2 -0
  436. package/vendor/dragonlab/integration/companions-v1/view.mjs +28 -0
  437. package/vendor/dragonlab/integration/hyperion-v3/activity.mjs +76 -0
  438. package/vendor/dragonlab/lib/power-effects.js +294 -0
  439. package/vendor/dragonlab/lib/power-registry.js +74 -0
  440. package/vendor/dragonlab/vendor/quox-dragon/qart.js +348 -0
  441. package/vendor/dragonlab/vendor/quox-dragon/qeyes.js +213 -0
  442. package/lib/core/websiteSession.js +0 -148
@@ -0,0 +1,122 @@
1
+ /**
2
+ * /todo <text> adds an Action Tracker item; /todo alone and /todos list the board; /todo move do5 done moves one
3
+ * (owner typed /todo, 2026-10-20). The writes and reads are core/actionItems.js, the same core as `quox actions`.
4
+ * Items get per-listing short ids by column: td1.. (to do), do1.. (doing), dn1.. (done). They are positions in the
5
+ * last list, mapped to real item ids; a move re-reads the board and says so when the list has changed.
6
+ * Pure helpers here: parse, short ids, wording.
7
+ */
8
+ export const DONE_SHOWN = 10;
9
+ const PREFIX = { backlog: 'td', doing: 'do', done: 'dn' };
10
+ const COLUMN_NAME = { backlog: 'To do', doing: 'Doing', done: 'Done' };
11
+ const REF = /^(td|do|dn)(\d+)$/i;
12
+ const STATUS_WORD = { todo: 'todo', 'to-do': 'todo', td: 'todo', doing: 'doing', do: 'doing', wip: 'doing', progress: 'doing', 'in-progress': 'doing', done: 'done', dn: 'done', complete: 'done', completed: 'done', finished: 'done' };
13
+ const USAGE = 'Usage: /todo <text> adds. /todos lists. /todo move do5 done (or /todo do5 done, /todo mark do2 done, /todo td3 doing) moves one.';
14
+
15
+ /** A column word -> 'todo' | 'doing' | 'done' | null. Accepts "to do" and "in progress" as two words. */
16
+ export function statusWord(words) {
17
+ const w = (Array.isArray(words) ? words.join('-') : String(words || '')).trim().toLowerCase();
18
+ return STATUS_WORD[w] || null;
19
+ }
20
+
21
+ /** Leading short ids from words, comma and/or space separated ("td1,td2", "td1 td2", "td1, td2") -> { refs, used } (used = words consumed). */
22
+ export function takeRefs(words) {
23
+ const refs = [];
24
+ let used = 0;
25
+ for (const w of words) {
26
+ const parts = String(w).split(',').filter(Boolean);
27
+ if (!parts.length || !parts.every((p) => REF.test(p))) break;
28
+ refs.push(...parts.map((p) => p.toLowerCase()));
29
+ used += 1;
30
+ }
31
+ return { refs: [...new Set(refs)], used };
32
+ }
33
+
34
+ /** "/done td1,td2" argument -> { kind: 'done', refs } | { kind: 'usage', text }. Nothing but short ids is accepted. */
35
+ export function parseDone(arg) {
36
+ const words = String(arg || '').trim().split(/\s+/).filter(Boolean);
37
+ const { refs, used } = takeRefs(words);
38
+ if (!refs.length || used !== words.length) return { kind: 'usage', text: 'Usage: /done td1,td2 (or /done td1 td2) marks those items done. /todos lists the ids.' };
39
+ return { kind: 'done', refs };
40
+ }
41
+
42
+ export function todoDoneLine(title) {
43
+ return `\u2714 Done: ${title}`;
44
+ }
45
+
46
+ /**
47
+ * "/todo ..." or "/todos ..." + its argument ->
48
+ * { kind: 'list' } | { kind: 'add', text } | { kind: 'move', ref, to } | { kind: 'usage', text }.
49
+ * Only /todo with free text adds. A short id plus a column word moves; an id with a bad column is a usage error, never an add.
50
+ */
51
+ export function parseTodo(command, arg) {
52
+ const text = String(arg || '').trim();
53
+ if (String(command || '').toLowerCase() === '/todos' || !text) return { kind: 'list' };
54
+ const words = text.split(/\s+/);
55
+ const verb = /^(move|mv|mark|set)$/i.test(words[0]);
56
+ const rest = verb ? words.slice(1) : words;
57
+ const lead = takeRefs(rest);
58
+ if (lead.refs.length) {
59
+ const to = statusWord(rest.slice(lead.used));
60
+ if (to) return lead.refs.length > 1 ? { kind: 'move', ref: lead.refs[0], refs: lead.refs, to } : { kind: 'move', ref: lead.refs[0], to };
61
+ return { kind: 'usage', text: USAGE };
62
+ }
63
+ if (verb) return { kind: 'usage', text: USAGE };
64
+ return { kind: 'add', text };
65
+ }
66
+
67
+ /** board {backlog,doing,done} (backlog = the to-do column) -> { map: { td1: id, ... }, shown: { todo, doing, done } } (done is capped at DONE_SHOWN). */
68
+ export function numberBoard(board, doneShown = DONE_SHOWN) {
69
+ const shown = { backlog: board.backlog || [], doing: board.doing || [], done: (board.done || []).slice(0, doneShown) };
70
+ const map = {};
71
+ for (const col of Object.keys(PREFIX)) shown[col].forEach((it, n) => { map[`${PREFIX[col]}${n + 1}`] = it.id; });
72
+ return { map, shown };
73
+ }
74
+
75
+ /** Confirmation after an add: the item id plus where to see the list. */
76
+ export function todoAddedLine(item) {
77
+ return `Added to your Action Tracker: ${item.id} ${item.title}. /todos lists them.`;
78
+ }
79
+
80
+ /** The board as short numbered lines, per column, with short ids. -> string. */
81
+ export function todoBoardText(board, numbered = numberBoard(board)) {
82
+ const total = (board.backlog || []).length + (board.doing || []).length + (board.done || []).length;
83
+ if (!total) return 'Nothing in your Action Tracker. /todo <text> adds an item.';
84
+ const out = [`Your Action Tracker (${(board.backlog || []).length} to do, ${(board.doing || []).length} doing, ${(board.done || []).length} done). /todo <text> adds, /todo move do2 done moves:`];
85
+ for (const col of ['backlog', 'doing', 'done']) {
86
+ const items = numbered.shown[col];
87
+ const all = (board[col] || []).length;
88
+ if (!all) continue;
89
+ out.push(`${COLUMN_NAME[col]}:`);
90
+ items.forEach((i, n) => out.push(` ${PREFIX[col]}${n + 1} ${i.title}${i.due_date ? ` due ${String(i.due_date).slice(0, 10)}` : ''}`));
91
+ if (all > items.length) out.push(` ... and ${all - items.length} more ${col === 'done' ? 'done (quox actions list --status done)' : ''}`.trimEnd());
92
+ }
93
+ return out.join('\n');
94
+ }
95
+
96
+ /**
97
+ * Resolve a short id for a move. oldMap is the map from the last /todos (or null if none yet); fresh is the board
98
+ * read just now. The item is found by its REAL id from the old list, so a list that shifted still moves the item
99
+ * you saw. -> { id, title, note? } | { error }.
100
+ */
101
+ export function resolveRef(ref, oldMap, board) {
102
+ const fresh = numberBoard(board, Infinity);
103
+ const byId = {};
104
+ for (const [short, id] of Object.entries(fresh.map)) byId[id] = short;
105
+ const titleOf = (id) => [...(board.backlog || []), ...(board.doing || []), ...(board.done || [])].find((i) => i.id === id)?.title || '';
106
+ if (!oldMap || !oldMap[ref]) {
107
+ const id = fresh.map[ref];
108
+ if (!id) return { error: `No ${ref} on your board. /todos lists the current ids.` };
109
+ return { id, title: titleOf(id), note: oldMap ? undefined : `No list shown yet in this window, so ${ref} is read from the board as it is now.` };
110
+ }
111
+ const id = oldMap[ref];
112
+ if (!byId[id]) return { error: `${ref} is gone from your board (done elsewhere or deleted). /todos lists the current ids.` };
113
+ const nowRef = byId[id];
114
+ const shownNow = numberBoard(board).map[nowRef] === id; // the id is one the user could see in a fresh listing
115
+ return nowRef === ref
116
+ ? { id, title: titleOf(id) }
117
+ : { id, title: titleOf(id), note: `The list changed since /todos: "${titleOf(id)}" is ${nowRef} now${shownNow ? '' : ' (beyond the short list)'}. Moving that one.` };
118
+ }
119
+
120
+ export function todoMovedLine(item) {
121
+ return `Moved ${item.title} to ${item.status}.`;
122
+ }
@@ -0,0 +1,38 @@
1
+ /** Server calls behind /undo. Each throws on a non-2xx (never reads an error body as data). */
2
+ import { resolveEndpoint } from '../../api/endpoints.js';
3
+
4
+ const listOf = (d, ...keys) => { for (const k of keys) if (Array.isArray(d?.[k])) return d[k]; return Array.isArray(d) ? d : []; };
5
+ const receiptOf = (d) => d?.envelope_id || d?.envelopeId || d?.receipt?.envelope_id || d?.receipt?.id || null;
6
+
7
+ export function createUndoOps({ client, orgId = () => null }) {
8
+ return {
9
+ /** The call's envelope, read back: { ok, env } | { ok:false, error }. */
10
+ async envelope(id) {
11
+ try { const d = await client.get(`/aee/${encodeURIComponent(id)}`, { service: 'collector', retries: 0, timeout: 10000 }); return { ok: true, env: d?.envelope || d }; }
12
+ catch (e) { return { ok: false, error: e?.status ? `HTTP ${e.status}` : (e?.message || 'failed') }; }
13
+ },
14
+ async recentMoves() {
15
+ const ep = resolveEndpoint('inboxq.moves.recent');
16
+ return listOf(await client.get(ep.path, { service: ep.service, retries: 0, query: { limit: 20 } }), 'moves');
17
+ },
18
+ async undoMove(moveId) {
19
+ const ep = resolveEndpoint('inboxq.moves.undo');
20
+ return { receipt: receiptOf(await client.post(ep.path, { service: ep.service, retries: 0, body: { moveId } })) };
21
+ },
22
+ async releaseSlot(name) {
23
+ const ep = resolveEndpoint('v1.slots.release', { name });
24
+ const data = await client.post(ep.path, { service: ep.service, retries: 0, body: { force: false, org_id: orgId() || undefined } });
25
+ const after = data?.slot;
26
+ if (after && after.state !== 'free' && !data.promoted) throw new Error(`slot ${name} was not released: the server still shows it ${after.state}${after.holder_session ? ` by ${after.holder_session}` : ''}`);
27
+ return { receipt: receiptOf(data) };
28
+ },
29
+ async listNotes() {
30
+ const ep = resolveEndpoint('notesq.notes.list');
31
+ return listOf(await client.get(ep.path, { service: ep.service, retries: 0 }), 'notes', 'items', 'data');
32
+ },
33
+ async deleteNote(id) {
34
+ const ep = resolveEndpoint('notesq.notes.delete', { id });
35
+ return { receipt: receiptOf(await client.delete(ep.path, { service: ep.service, retries: 0 })) };
36
+ }
37
+ };
38
+ }
@@ -0,0 +1,49 @@
1
+ /** /undo last: find the last receipt-backed state change, explain it, and (when a known inverse binds) reverse it on y. */
2
+ import { lastStateChange, INVERSES, BY_HAND } from './inverses.js';
3
+
4
+ const ago = (ms) => { const s = Math.max(0, Math.round(ms / 1000)); return s < 60 ? `${s}s ago` : s < 3600 ? `${Math.round(s / 60)}m ago` : `${Math.round(s / 3600)}h ago`; };
5
+ const clip = (s, n) => { const t = String(s || '').replace(/\s+/g, ' ').trim(); return t.length > n ? `${t.slice(0, n - 1)}…` : t; };
6
+
7
+ export function createUndoCmd({ api, say, getItems, card, now = () => Date.now() }) {
8
+ return async function undo(arg) {
9
+ const a = String(arg || '').trim().toLowerCase();
10
+ if (a && a !== 'last') return say('Usage: /undo last (bare /undo does the same; Ctrl+_ undoes composer typing)', 'warn');
11
+ const ops = api.undoOps;
12
+ if (!ops) return say('/undo is not available in this mode.', 'warn');
13
+ const call = lastStateChange(getItems());
14
+ if (!call) return say('No Quox action in this conversation has a receipt to reverse yet.', 'dim');
15
+ const when = Number.isFinite(call.startedAt) ? ago(now() - call.startedAt) : 'earlier';
16
+ // The receipt is the evidence of what ran: read it back before offering to reverse anything.
17
+ const rec = await ops.envelope(call.envelopeId);
18
+ if (rec.ok) {
19
+ const p = rec.env?.payload || {};
20
+ if (p.tool_name && p.tool_name !== call.tool) return say(`The receipt ${call.envelopeId} is for ${p.tool_name}, not ${call.tool}, so nothing was offered.`, 'warn');
21
+ if (p.success === false) return say(`The receipt says ${call.tool} did not succeed, so there is nothing to undo.`, 'warn');
22
+ }
23
+ const head = `undo │ ${call.tool} · ${when} · receipt ${call.envelopeId}${rec.ok ? '' : ` (receipt not read (${rec.error}))`}`;
24
+ const inv = INVERSES[call.tool];
25
+ if (!inv) {
26
+ say(head);
27
+ say(`Quox can't reverse ${call.tool} automatically.`, 'warn');
28
+ say(`It did: ${clip(call.resultSummary || call.summary || call.tool, 100)}. By hand: ${BY_HAND[call.tool] || 'check what it changed with /proof and undo that yourself'}.`, 'dim');
29
+ return undefined;
30
+ }
31
+ let bound;
32
+ try { bound = await inv.bind(call, ops); } catch (e) { return say(`Could not work out what to reverse: ${e?.message || e}. Nothing ran.`, 'warn'); }
33
+ if (!bound.ok) {
34
+ say(head);
35
+ say(`Quox can't reverse ${call.tool} automatically here: ${bound.why}.`, 'warn');
36
+ say(`By hand: ${bound.byHand}.`, 'dim');
37
+ return undefined;
38
+ }
39
+ card.ask([head, `It ${inv.did}: ${clip(call.resultSummary || call.summary, 100)}.`, `Undoing it will ${bound.reverse}.`],
40
+ async () => {
41
+ let r;
42
+ try { r = await bound.run(ops); } catch (e) { return say(`NOT undone: ${e?.message || e}`, 'warn'); }
43
+ say(`Undone: ${bound.reverse}.`, 'ok');
44
+ say(r?.receipt ? `new receipt ${r.receipt} (/proof ${r.receipt})` : 'The server returned no receipt id for this reversal, so there is nothing to /proof for it.', 'dim');
45
+ return undefined;
46
+ }, 'Cancelled; nothing was undone.', { question: 'Undo it?' });
47
+ return undefined;
48
+ };
49
+ }
@@ -0,0 +1,15 @@
1
+ /** /undo and /wish factory app.js wires: switch cases plus one answer hook. They share one card (one y/n at a time). */
2
+ import { createCard } from './card.js';
3
+ import { createUndoCmd } from './undoCmd.js';
4
+ import { createWishCmd } from './wishCmd.js';
5
+
6
+ export function createUndoWish({ api, say, getItems, runTurn, draft, now }) {
7
+ const card = createCard({ say, now });
8
+ return {
9
+ undo: createUndoCmd({ api, say, getItems, card, now }),
10
+ wish: createWishCmd({ api, say, card, runTurn, draft }),
11
+ answer: (text) => card.answer(text),
12
+ pending: () => card.pending(),
13
+ touch: () => card.touch()
14
+ };
15
+ }
@@ -0,0 +1,164 @@
1
+ /**
2
+ * /watch <anything>: turn a site, repo, server, competitor page, metric or condition into an ongoing observer.
3
+ * Backend (real): an agent schedule on the tasks service (POST /api/agent-schedules). Each tick the scheduler runs
4
+ * the watch prompt as an objective and escalates to the owner's Approvals inbox per the escalation policy.
5
+ */
6
+ const DAY = 1440;
7
+ const PAGE_WORDS = /\b(competitor|competitors|pricing|price|prices|plans?|changelog|blog|docs|landing)\b/i;
8
+ const SERVER_WORDS = /\b(server|host|box|vm|node|gitea|nginx|postgres|redis|db|database|service|container|docker|disk|cpu|memory|ram|load|health|healthy|status)\b/i;
9
+ const METRIC_WORDS = /\b(metric|signups?|sign-ups?|revenue|mrr|arr|traffic|errors?|latency|conversion|sales|users?|churn|orders?|visits?)\b/i;
10
+ const URL_RE = /\bhttps?:\/\/[^\s]+/i;
11
+ const GITHUB_RE = /\b(?:https?:\/\/)?github\.com\/[\w.-]+\/[\w.-]+/i;
12
+ const DOMAIN_RE = /\b(?:[a-z0-9-]+\.)+[a-z]{2,}(?:\/[^\s]*)?/i;
13
+
14
+ const DEFAULT_CONDITION = {
15
+ site: 'it is down, returns an error status, or responds very slowly',
16
+ server: 'it is unhealthy or unreachable',
17
+ page: 'the page changes in a way that matters (prices, plans, wording, new sections)',
18
+ repo: 'something needs attention: failing CI, new issues or security alerts'
19
+ };
20
+ const unitMin = (n, u) => { const x = u.toLowerCase(); return x.startsWith('h') ? n * 60 : x.startsWith('d') ? n * DAY : n; };
21
+ const strip = (s) => s.replace(/[),.;]+$/, '');
22
+
23
+ /** "quox.ai for downtime every 5 minutes" -> { kind, target, condition, everyMin|null } */
24
+ export function parseWatch(text) {
25
+ let t = String(text || '').trim();
26
+ let everyMin = null;
27
+ const ev = t.match(/\b(?:every|each)\s+(\d+)\s*(minutes?|mins?|m|hours?|hrs?|h|days?|d)\b/i);
28
+ if (ev) { everyMin = unitMin(Number(ev[1]), ev[2]); t = t.replace(ev[0], ' '); }
29
+ else {
30
+ const w = t.match(/\b(hourly|daily)\b/i);
31
+ if (w) { everyMin = w[1].toLowerCase() === 'hourly' ? 60 : DAY; t = t.replace(w[0], ' '); }
32
+ }
33
+ t = t.replace(/\s+/g, ' ').trim();
34
+ if (!t) return { kind: 'none', target: '', condition: '', everyMin };
35
+
36
+ let left = t, cond = '';
37
+ const m = t.match(/^(.*?)\s+(?:for|when|whenever|if)\s+(.+)$/i);
38
+ if (m && m[1].trim()) { left = m[1].trim(); cond = m[2].trim(); }
39
+
40
+ const url = left.match(URL_RE)?.[0];
41
+ const gh = left.match(GITHUB_RE)?.[0];
42
+ const dom = !url && !gh ? left.match(DOMAIN_RE)?.[0] : null;
43
+ const out = (kind, target, condition) => ({ kind, target, condition, everyMin });
44
+
45
+ if (gh || /\brepo(sitory)?\b/i.test(left)) {
46
+ return out('repo', gh ? strip(gh).replace(/^https?:\/\//, '') : (left.replace(/\brepo(sitory)?\b/i, '').trim() || left), cond || DEFAULT_CONDITION.repo);
47
+ }
48
+ if (url || dom) {
49
+ const target = strip(url || dom);
50
+ const pageish = PAGE_WORDS.test(left) && !/\b(down|downtime|uptime|outage)\b/i.test(cond);
51
+ return pageish ? out('page', target, cond || DEFAULT_CONDITION.page) : out('site', target, cond || DEFAULT_CONDITION.site);
52
+ }
53
+ if (PAGE_WORDS.test(left) && !METRIC_WORDS.test(left)) return out('page', left, cond || DEFAULT_CONDITION.page);
54
+ if (METRIC_WORDS.test(left)) return out('metric', left, cond || left);
55
+ if (SERVER_WORDS.test(left) && left.split(' ').length <= 3) {
56
+ const target = left.replace(/\b(health|healthy|status)\b/gi, '').replace(/\s+/g, ' ').trim() || left;
57
+ return out('server', target, cond || DEFAULT_CONDITION.server);
58
+ }
59
+ return out('condition', cond ? left : t, cond || t);
60
+ }
61
+
62
+ /** Cron-friendly interval in minutes (floor 5, whole hours above an hour, cap one day). */
63
+ export function normalizeEvery(min) {
64
+ const n = Number(min);
65
+ if (!Number.isFinite(n) || n <= 0) return 15;
66
+ if (n >= DAY) return DAY;
67
+ if (n < 5) return 5;
68
+ if (n < 60) return [5, 10, 15, 20, 30, 60].reduce((a, b) => (Math.abs(b - n) < Math.abs(a - n) ? b : a));
69
+ return Math.min(23, Math.max(1, Math.round(n / 60))) * 60;
70
+ }
71
+ export function everyToCron(min) {
72
+ const n = normalizeEvery(min);
73
+ if (n >= DAY) return '0 9 * * *';
74
+ if (n === 60) return '0 * * * *';
75
+ if (n > 60) return `0 */${n / 60} * * *`;
76
+ return `*/${n} * * * *`;
77
+ }
78
+ export const everyLabel = (min) => { const n = normalizeEvery(min); return n >= DAY ? 'day' : n === 60 ? 'hour' : n > 60 ? `${n / 60} h` : `${n} min`; };
79
+
80
+ const KIND = { site: 'website', server: 'server', page: 'web page', repo: 'repository', metric: 'metric', condition: 'condition' };
81
+ const slug = (s) => { const x = String(s).replace(/^https?:\/\//i, '').replace(/\/+$/, ''); return x.length > 60 ? `${x.slice(0, 59)}…` : x; };
82
+
83
+ const watchPrompt = (name, w) => [
84
+ `You are running a scheduled watch named "${name}".`,
85
+ `Target (${KIND[w.kind] || w.kind}): ${w.target}.`,
86
+ `Condition to detect: ${w.condition}.`,
87
+ 'Check the target now using the read-only tools you have. Change nothing.',
88
+ 'If the condition is NOT met, finish with the single line "ok" and raise nothing: stay quiet.',
89
+ 'If it IS met, raise it to the owner as a notification or inbox item: what you saw, when, and the evidence, in 3 lines or fewer.',
90
+ 'If you cannot check it at all (no tool, no access), say exactly that once; do not pretend it is fine.'
91
+ ].join('\n');
92
+
93
+ /** -> { body (POST /api/agent-schedules), card[] , every } */
94
+ export function buildWatchPlan(w) {
95
+ const every = normalizeEvery(w.everyMin ?? 15);
96
+ const cron = everyToCron(every);
97
+ const name = `watch:${slug(w.target)}`;
98
+ const budget = { maxTokensPerRun: 20000, maxToolCallsPerRun: 10, maxDurationMs: 120000 };
99
+ const body = {
100
+ agentId: 'quox', name, cronExpression: cron, timezone: 'UTC',
101
+ taskTemplate: { title: name, prompt: watchPrompt(name, w) },
102
+ escalationPolicy: { onFailure: 'ESCALATE', escalateTo: null },
103
+ budget, maxConsecutiveFailures: 5
104
+ };
105
+ const card = [
106
+ ['Watch preview (nothing is created until you answer):', 'accent'],
107
+ ` Watching ${w.target} (${KIND[w.kind] || w.kind})`,
108
+ ` Triggers ${w.condition}`,
109
+ ` Checks every ${everyLabel(every)} (cron ${cron}, UTC)`,
110
+ ' Notifies you, in your Approvals inbox, only when it triggers or the watch keeps failing',
111
+ ` Runs as agent quox, read-only by instruction, ${budget.maxToolCallsPerRun} tool calls per check`
112
+ ];
113
+ return { body, card, every };
114
+ }
115
+
116
+ const USAGE = 'Usage: /watch <what> [for <condition>] [every 5 min] e.g. /watch quox.ai for downtime, /watch gitea health. Also /watch list, /watch stop <id>.';
117
+ const why = (e) => `${e?.status ? `HTTP ${e.status}: ` : ''}${e?.message || 'failed'}`;
118
+
119
+ export function createWatchCmd({ api, say, confirm }) {
120
+ const listed = async () => {
121
+ const rows = await api.watchList();
122
+ return (Array.isArray(rows) ? rows : rows?.schedules || []).filter((s) => String(s.name || '').startsWith('watch:'));
123
+ };
124
+ async function list() {
125
+ let rows;
126
+ try { rows = await listed(); } catch (e) { return say(`Could not list watches: ${why(e)}`, 'warn'); }
127
+ if (!rows.length) return say('No watches yet. /watch quox.ai for downtime sets one up.');
128
+ say(`Watches (${rows.length}):`);
129
+ for (const s of rows) say(` ${s.id} ${s.name.slice(6)} cron ${s.cron_expression} ${Number(s.enabled) === 0 ? 'stopped' : (s.last_status || 'no check yet')}`);
130
+ return say('Stop one with /watch stop <id>.', 'dim');
131
+ }
132
+ async function stop(idArg) {
133
+ if (!idArg) return say('Usage: /watch stop <id> (/watch list shows ids)', 'warn');
134
+ let rows;
135
+ try { rows = await listed(); } catch (e) { return say(`Could not read watches: ${why(e)}`, 'warn'); }
136
+ const hits = rows.filter((s) => s.id === idArg || s.id.toLowerCase().startsWith(idArg.toLowerCase()));
137
+ if (hits.length !== 1) return say(hits.length ? `"${idArg}" matches ${hits.length} watches; use more of the id.` : `No watch "${idArg}". /watch list shows them.`, 'warn');
138
+ try { await api.watchStop(hits[0].id); } catch (e) { return say(`Could not stop ${hits[0].id}: ${why(e)}`, 'warn'); }
139
+ return say(`✔ Stopped watch ${hits[0].id} (${hits[0].name.slice(6)}).`, 'ok');
140
+ }
141
+ function create(text) {
142
+ const w = parseWatch(text);
143
+ if (!w.target) return say(USAGE, 'warn');
144
+ const plan = buildWatchPlan(w);
145
+ confirm.ask(plan.card, async () => {
146
+ let r;
147
+ try { r = await api.watchCreate(plan.body); } catch (e) { return say(`Could not create the watch: ${why(e)}. Nothing is watching.`, 'warn'); }
148
+ if (!r?.id) return say('The server returned no watch id, so I cannot confirm it exists. /watch list shows what is there.', 'warn');
149
+ say(`✔ Watching ${w.target} (id ${r.id}). First check within ${everyLabel(plan.every)}.`, 'ok');
150
+ say(` Stop it: /watch stop ${r.id} See all: /watch list`);
151
+ }, { prompt: 'Create this watch?' });
152
+ return undefined;
153
+ }
154
+ return {
155
+ handle(arg) {
156
+ const a = String(arg || '').trim();
157
+ if (!a) return say(USAGE);
158
+ if (!api.watchCreate) return say('Watches are not available in this mode.', 'warn');
159
+ if (/^list$/i.test(a)) return list();
160
+ const s = a.match(/^(?:stop|rm)\b\s*(.*)$/i);
161
+ return s ? stop(s[1].trim()) : create(a);
162
+ }
163
+ };
164
+ }
@@ -0,0 +1,23 @@
1
+ /** /wish: the prompt that makes Quox draft a spec, reading its shape back, and the follow-up prompts. */
2
+ export const SHAPE_LABEL = { skill: 'a skill', workflow: 'a workflow', power: 'a power from a repo', code: 'needs code' };
3
+
4
+ export const wishPrompt = (wish) => 'The user wishes Quox could do something it cannot do today. Do NOT build or install anything and do not call any state-changing tool. '
5
+ + 'Reply with a SHORT design spec, plain lines, no preamble, using exactly these labels:\n'
6
+ + 'What it does: one or two sentences.\n'
7
+ + 'Uses: which existing Quox tools, CLI commands or APIs it would call.\n'
8
+ + 'Hat: which hat and permissions it needs.\n'
9
+ + 'Tests: what would prove it works.\n'
10
+ + 'Shape: exactly one of skill | workflow | power | code (skill = a procedure an agent follows; workflow = a scheduled or triggered sequence of existing steps; power = packaged from a repo; code = needs new code).\n\n'
11
+ + `Wish: ${String(wish).trim().slice(0, 1500)}`;
12
+
13
+ /** -> 'skill' | 'workflow' | 'power' | 'code' | null (no readable Shape line). */
14
+ export function parseShape(spec) {
15
+ const m = /^\s*shape\s*:\s*(skill|workflow|power|code)\b/im.exec(String(spec || ''));
16
+ return m ? m[1].toLowerCase() : null;
17
+ }
18
+
19
+ export const creationPrompt = (shape, wish, spec) => (shape === 'skill'
20
+ ? `The user approved this spec. Create it now as a skill with skill_manage (op=create; it lands experimental and queued for review, which is expected). Use only what the spec says.\n\nWish: ${wish}\n\n${spec}`
21
+ : `The user approved this spec. Create it now as a workflow with your workflow tool, left inactive: do not activate it or deploy it, and do not schedule it. Use only what the spec says.\n\nWish: ${wish}\n\n${spec}`);
22
+
23
+ export const requestText = (wish, spec) => `Feature request from /wish: ${wish}\n\nDrafted spec:\n${String(spec).trim()}\n\nNo shape of skill or workflow fit, so this needs the normal build and review path.`;
@@ -0,0 +1,32 @@
1
+ /** /wish: draft a governed spec, show it as one card, and on y create (skill, workflow) or file (power, code). Never installs code. */
2
+ import { wishPrompt, parseShape, creationPrompt, requestText, SHAPE_LABEL } from './wish.js';
3
+
4
+ const clip = (s, n) => { const t = String(s || '').replace(/\s+/g, ' ').trim(); return t.length > n ? `${t.slice(0, n - 1)}…` : t; };
5
+
6
+ export function createWishCmd({ api, say, card, runTurn, draft }) {
7
+ return async function wish(arg) {
8
+ const text = String(arg || '').trim();
9
+ if (!text) return say('Usage: /wish <what you wish Quox could do>', 'warn');
10
+ if (!draft) return say('/wish is not available in this mode.', 'warn');
11
+ say('Drafting a spec for that…', 'dim');
12
+ let spec;
13
+ try { spec = await draft(wishPrompt(text)); } catch (e) { spec = null; say(`Draft failed: ${e?.message || e}`, 'warn'); }
14
+ if (!spec || !String(spec).trim()) return say('Quox could not draft a spec for that, so nothing was proposed. Try /wish again.', 'warn');
15
+ const shape = parseShape(spec);
16
+ const body = String(spec).trim().split('\n').slice(0, 14).map(l => clip(l, 110));
17
+ const plan = shape === 'skill' || shape === 'workflow'
18
+ ? `On y: Quox creates it as ${shape === 'skill' ? 'an experimental skill queued for human review' : 'an inactive workflow'} through the normal governed path (you will see its tool call and receipt).`
19
+ : `On y: the spec is filed as a feature request (${shape ? SHAPE_LABEL[shape] : 'shape unclear, treated as needing code'}). Nothing is installed; code goes through the normal build and review path.`;
20
+ card.ask([`wish │ ${clip(text, 80)}`, ...body], // the plan is the card's "do" row
21
+ async () => {
22
+ if (shape === 'skill' || shape === 'workflow') { say(`Creating the ${shape}…`, 'dim'); return runTurn(creationPrompt(shape, text, spec)); }
23
+ if (!api.gripe) return say('Filing is not available in this mode; the spec is above.', 'warn');
24
+ const g = await api.gripe(requestText(text, spec).slice(0, 4000), { yes: true });
25
+ if (!g.ok) return say(`Not filed: ${g.message}`, 'warn');
26
+ const url = (g.notes || []).find(n => n.kind === 'created')?.url;
27
+ say(url ? `Filed as a feature request: ${url}. Nothing was installed.` : 'Filed as a feature request. Nothing was installed.', 'ok');
28
+ return undefined;
29
+ }, 'Cancelled; nothing was created or filed.', { who: 'Quox', question: shape === 'skill' || shape === 'workflow' ? `Create the ${shape}?` : 'File it as a governed spec?', action: plan.replace(/^On y: /, '') });
30
+ return undefined;
31
+ };
32
+ }