@cleocode/cleo 2026.10.3 → 2026.10.4
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.
- package/bin/cleo.js +11 -1
- package/dist/cli/adapter-LVXHFBC4.js +158 -0
- package/dist/cli/add-WUAV7LDT.js +443 -0
- package/dist/cli/add-batch-U2DLKAQC.js +163 -0
- package/dist/cli/admin-I7BQYVZD.js +340 -0
- package/dist/cli/adr-K2THMQBS.js +171 -0
- package/dist/cli/agent-WQ6XY2DW.js +2366 -0
- package/dist/cli/agent-outputs-BJIYLVTU.js +84 -0
- package/dist/cli/analyze-PGQZWGOC.js +48 -0
- package/dist/cli/archive-5LZPF7C3.js +64 -0
- package/dist/cli/archive-stats-U6CYC6JM.js +100 -0
- package/dist/cli/attention-SOURWCNI.js +167 -0
- package/dist/cli/audit-FO2Y4LH2.js +122 -0
- package/dist/cli/auth-ED7TAIXI.js +491 -0
- package/dist/cli/backfill-32TRAYRD.js +156 -0
- package/dist/cli/backup-LEJMZJKL.js +587 -0
- package/dist/cli/backup-inspect-6HPLUEI2.js +26 -0
- package/dist/cli/backup-recover-2BTYBZU2.js +29 -0
- package/dist/cli/blockers-5JULUJTV.js +54 -0
- package/dist/cli/brain-273N3FW4.js +400 -0
- package/dist/cli/briefing-7H6OLECX.js +212 -0
- package/dist/cli/caamp-MFQVN6VU.js +181 -0
- package/dist/cli/cancel-SCMJTXZB.js +84 -0
- package/dist/cli/canon-NPF5RODM.js +142 -0
- package/dist/cli/canon-docs-2GTOLF7Y.js +26 -0
- package/dist/cli/cant-46XCUP4P.js +239 -0
- package/dist/cli/changeset-32NMBGG2.js +248 -0
- package/dist/cli/check-RWJLBCI2.js +907 -0
- package/dist/cli/checkpoint-37HMMKD7.js +128 -0
- package/dist/cli/chunk-2JIJD2I7.js +108 -0
- package/dist/cli/chunk-37NU2XDP.js +171 -0
- package/dist/cli/chunk-3IOQVUO7.js +17308 -0
- package/dist/cli/chunk-3PGH67MT.js +175 -0
- package/dist/cli/chunk-3ZO3M37V.js +1002 -0
- package/dist/cli/chunk-47JYZAMS.js +30 -0
- package/dist/cli/chunk-5J2VH3BC.js +66 -0
- package/dist/cli/chunk-5ZFFUFH7.js +92 -0
- package/dist/cli/chunk-6JSJNYH2.js +114 -0
- package/dist/cli/chunk-7INMKEAD.js +85 -0
- package/dist/cli/chunk-A2IUEIM5.js +278 -0
- package/dist/cli/chunk-AWCQH2W5.js +35 -0
- package/dist/cli/chunk-AYA6F4ZT.js +56 -0
- package/dist/cli/chunk-BCEXRFA2.js +76 -0
- package/dist/cli/chunk-BPEVD37G.js +124 -0
- package/dist/cli/chunk-C3B7C43W.js +16 -0
- package/dist/cli/chunk-DVTPIZJM.js +72 -0
- package/dist/cli/chunk-DYABOIHB.js +96 -0
- package/dist/cli/chunk-EBRZ76HS.js +51 -0
- package/dist/cli/chunk-EGOTK2HA.js +57 -0
- package/dist/cli/chunk-EOPQFCSR.js +148 -0
- package/dist/cli/chunk-FORFDPP5.js +288 -0
- package/dist/cli/chunk-GFGLLDXX.js +110 -0
- package/dist/cli/chunk-GH37QXW5.js +280 -0
- package/dist/cli/chunk-GZFVDR44.js +320 -0
- package/dist/cli/chunk-I3CRQQAD.js +225 -0
- package/dist/cli/chunk-J3ZFM3UQ.js +754 -0
- package/dist/cli/chunk-JNZJPIPJ.js +90 -0
- package/dist/cli/chunk-KHB52JNB.js +209 -0
- package/dist/cli/chunk-KJDWWQFY.js +46 -0
- package/dist/cli/chunk-LKNUA3SB.js +83 -0
- package/dist/cli/chunk-LVGIFMCV.js +163 -0
- package/dist/cli/chunk-LWQBJQSE.js +67 -0
- package/dist/cli/chunk-MNJRLSEQ.js +107 -0
- package/dist/cli/chunk-NRKWJLMS.js +91 -0
- package/dist/cli/chunk-NSHV2JNM.js +48 -0
- package/dist/cli/chunk-NWTATTEQ.js +210 -0
- package/dist/cli/chunk-OAPN46TC.js +89 -0
- package/dist/cli/chunk-OGV57L4J.js +59 -0
- package/dist/cli/chunk-OILHT47L.js +252 -0
- package/dist/cli/chunk-OPTEQKBB.js +258 -0
- package/dist/cli/chunk-PKKZPOOP.js +352 -0
- package/dist/cli/chunk-QA6T2LQ5.js +71 -0
- package/dist/cli/chunk-QFFQSKRC.js +4497 -0
- package/dist/cli/chunk-QPUY2HQZ.js +74 -0
- package/dist/cli/chunk-REUTEW3O.js +258 -0
- package/dist/cli/chunk-S24YI723.js +88 -0
- package/dist/cli/chunk-SXXOC6KZ.js +209 -0
- package/dist/cli/chunk-ULN4OKQQ.js +259 -0
- package/dist/cli/chunk-V5GBGOGM.js +46 -0
- package/dist/cli/chunk-VLEYOOPH.js +31 -0
- package/dist/cli/chunk-W33Q3FBH.js +66 -0
- package/dist/cli/chunk-W3JLYKKY.js +140 -0
- package/dist/cli/chunk-XRAX6XFP.js +48 -0
- package/dist/cli/chunk-YGKEECTI.js +78 -0
- package/dist/cli/chunk-YUZJI67I.js +108 -0
- package/dist/cli/chunk-YY66LFZF.js +29 -0
- package/dist/cli/chunk-ZBISIPCK.js +78 -0
- package/dist/cli/chunk-ZZTHTMQP.js +77 -0
- package/dist/cli/claim-KPENYHIQ.js +96 -0
- package/dist/cli/classify-DRVMCFQU.js +117 -0
- package/dist/cli/cli-T3CR7J57.js +48 -0
- package/dist/cli/cloud-PPQ4O5TX.js +565 -0
- package/dist/cli/cockpit-RZKLGYPN.js +790 -0
- package/dist/cli/code-Z5CTMVTD.js +178 -0
- package/dist/cli/complete-UBOCOBRB.js +34 -0
- package/dist/cli/complexity-BV2AGQRZ.js +56 -0
- package/dist/cli/compliance-32PD5Y47.js +276 -0
- package/dist/cli/conduit-VDKCH33F.js +307 -0
- package/dist/cli/config-I72JAXK4.js +516 -0
- package/dist/cli/consensus-LFILLSTK.js +121 -0
- package/dist/cli/context-XUUVFVTP.js +141 -0
- package/dist/cli/contribution-37NQ4N5R.js +111 -0
- package/dist/cli/curator-TFDXU2EX.js +139 -0
- package/dist/cli/current-C4SN5BWV.js +42 -0
- package/dist/cli/daemon-DV25JQ62.js +451 -0
- package/dist/cli/dash-TFU4RLQW.js +70 -0
- package/dist/cli/decide-5VPMNTSI.js +419 -0
- package/dist/cli/decompose-KOYEZNJL.js +77 -0
- package/dist/cli/decomposition-7OHUFIQN.js +121 -0
- package/dist/cli/delete-Q7YCAFY5.js +68 -0
- package/dist/cli/deps-6UZKLDGJ.js +463 -0
- package/dist/cli/detect-FERY35UL.js +45 -0
- package/dist/cli/detect-drift-UL2JTPUK.js +408 -0
- package/dist/cli/diagnostics-TI5QAZXR.js +132 -0
- package/dist/cli/docs-QI2PRN3T.js +3095 -0
- package/dist/cli/doctor-AX5TICQO.js +1253 -0
- package/dist/cli/doctor-ac-bindings-YPMYHU2G.js +26 -0
- package/dist/cli/doctor-acceptance-drift-PYNFGMKB.js +26 -0
- package/dist/cli/doctor-credentials-UZRIADKM.js +26 -0
- package/dist/cli/doctor-db-substrate-Q2TOYM2S.js +27 -0
- package/dist/cli/doctor-dep-cycles-GCVYZY6F.js +26 -0
- package/dist/cli/doctor-exodus-RO5SUTC2.js +26 -0
- package/dist/cli/doctor-exodus-residue-EM2AWQXP.js +26 -0
- package/dist/cli/doctor-fk-check-Q3FOLECE.js +26 -0
- package/dist/cli/doctor-global-delivery-TNOAQ3NP.js +26 -0
- package/dist/cli/doctor-heavy-command-hook-IO3QAQLG.js +26 -0
- package/dist/cli/doctor-legacy-backups-O2YH5VLS.js +26 -0
- package/dist/cli/doctor-legacy-reaper-VSEJEIFA.js +26 -0
- package/dist/cli/doctor-malformed-ids-LQ766V5K.js +26 -0
- package/dist/cli/doctor-manifest-rows-6FQDNHLH.js +26 -0
- package/dist/cli/doctor-memory-guard-J4PSEKB5.js +26 -0
- package/dist/cli/doctor-migrations-ONOH56YM.js +26 -0
- package/dist/cli/doctor-nexus-residency-FUQAX7PV.js +26 -0
- package/dist/cli/doctor-project-identity-GUDK3HYX.js +26 -0
- package/dist/cli/doctor-projects-7L3BNL4O.js +30 -0
- package/dist/cli/doctor-projects-registry-TEAVHFQU.js +26 -0
- package/dist/cli/doctor-release-readiness-IEGHX6SL.js +26 -0
- package/dist/cli/doctor-repair-NBONOSZU.js +26 -0
- package/dist/cli/doctor-skill-fixtures-7Y6L34A3.js +26 -0
- package/dist/cli/doctor-split-brain-TUKIGVHF.js +26 -0
- package/dist/cli/doctor-superseded-store-BHZY2B2L.js +26 -0
- package/dist/cli/doctor-tool-locks-REQMIVYK.js +26 -0
- package/dist/cli/doctor-twin-collapse-222GOSPE.js +26 -0
- package/dist/cli/doctor-worktree-stores-J7TCRVJ3.js +26 -0
- package/dist/cli/done-V3AOO65B.js +195 -0
- package/dist/cli/dynamic-RR4HB7BB.js +29 -0
- package/dist/cli/event-EGNPGE5A.js +372 -0
- package/dist/cli/exists-H4SDCBPL.js +65 -0
- package/dist/cli/exodus-KALO3B3X.js +401 -0
- package/dist/cli/export-ROFOCG4M.js +92 -0
- package/dist/cli/export-tasks-US3WBIEQ.js +96 -0
- package/dist/cli/federation-SUIB5QWT.js +145 -0
- package/dist/cli/find-YICG4BG6.js +177 -0
- package/dist/cli/focus-TKCZPKOM.js +55 -0
- package/dist/cli/gateway-H4HFDC3E.js +77 -0
- package/dist/cli/gateway-auto-start-EDK7XI6E.js +36 -0
- package/dist/cli/gc-5R2TUY5T.js +291 -0
- package/dist/cli/go-PRQFK5YG.js +206 -0
- package/dist/cli/goal-7CZRMLHC.js +212 -0
- package/dist/cli/grade-PY2YRPUS.js +56 -0
- package/dist/cli/graph-XIXMCFKG.js +878 -0
- package/dist/cli/history-EIXADPAD.js +137 -0
- package/dist/cli/hook-UF7J7R6D.js +57 -0
- package/dist/cli/hook-entry.js +244 -19
- package/dist/cli/hygiene-3QZ2NI7P.js +55 -0
- package/dist/cli/import-R73SO444.js +88 -0
- package/dist/cli/import-tasks-O22FZJ4U.js +108 -0
- package/dist/cli/index.js +419 -94612
- package/dist/cli/init-IHEJDQWU.js +40 -0
- package/dist/cli/inject-LSRVWNCP.js +82 -0
- package/dist/cli/install-global-4AZUCH6U.js +95 -0
- package/dist/cli/intelligence-2OSFOGD2.js +181 -0
- package/dist/cli/issue-IIWEDNFC.js +158 -0
- package/dist/cli/janitor-GPMC7VOR.js +111 -0
- package/dist/cli/labels-5NPOIQXN.js +87 -0
- package/dist/cli/lifecycle-4FFS2K2T.js +272 -0
- package/dist/cli/list-47KEUGPQ.js +108 -0
- package/dist/cli/llm-G5B3I6GD.js +703 -0
- package/dist/cli/llm-cost-S7RS6BVA.js +25 -0
- package/dist/cli/llm-stream-24A45NTS.js +27 -0
- package/dist/cli/log-XF6H2XSD.js +75 -0
- package/dist/cli/login-LBPLGHYG.js +43 -0
- package/dist/cli/logout-SX4JSJIV.js +74 -0
- package/dist/cli/manifest-NMCW4PIW.js +353 -0
- package/dist/cli/map-BU72KMGF.js +52 -0
- package/dist/cli/memory-UHYIVGVM.js +1956 -0
- package/dist/cli/migrate-agents-v2-OO7OILZK.js +33 -0
- package/dist/cli/migrate-claude-mem-EDNYUY3K.js +201 -0
- package/dist/cli/next-RZFRG5X7.js +56 -0
- package/dist/cli/nexus-4S4Z5EVU.js +2923 -0
- package/dist/cli/ops-KR7AWCG3.js +51 -0
- package/dist/cli/orchestrate-HOYZY3VX.js +948 -0
- package/dist/cli/otel-U7IIRBCT.js +188 -0
- package/dist/cli/phase-NYZFHUE5.js +220 -0
- package/dist/cli/pivot-FF2CVUZL.js +87 -0
- package/dist/cli/plan-3SL2NTRV.js +48 -0
- package/dist/cli/playbook-2FCBV7N3.js +229 -0
- package/dist/cli/project-WDX2TGMC.js +330 -0
- package/dist/cli/promote-YINYFBZY.js +52 -0
- package/dist/cli/provenance-C7AYD7WG.js +128 -0
- package/dist/cli/provider-QLJEDQBR.js +212 -0
- package/dist/cli/reason-JF5BHBM5.js +137 -0
- package/dist/cli/reconcile-NMISHDGX.js +127 -0
- package/dist/cli/refresh-memory-EY5YNICV.js +45 -0
- package/dist/cli/relates-R3ZPICAY.js +259 -0
- package/dist/cli/release-4ZJTMUUT.js +524 -0
- package/dist/cli/remote-QSONJDIK.js +279 -0
- package/dist/cli/renderers-64OR3IWX.js +37 -0
- package/dist/cli/reorder-J3DOE7ST.js +86 -0
- package/dist/cli/reparent-2OUMKEZX.js +58 -0
- package/dist/cli/req-TZB7OFKO.js +129 -0
- package/dist/cli/research-MTD7EX45.js +365 -0
- package/dist/cli/restore-VEUOX7NF.js +423 -0
- package/dist/cli/revert-3YF2IL5G.js +240 -0
- package/dist/cli/roadmap-7OOQLXKG.js +61 -0
- package/dist/cli/run-2U5NZV5Z.js +211 -0
- package/dist/cli/safestop-VR4VK56D.js +88 -0
- package/dist/cli/saga-SEWPIOX2.js +285 -0
- package/dist/cli/schema-C52WZ35V.js +195 -0
- package/dist/cli/self-update-GQIGUDPS.js +504 -0
- package/dist/cli/selfimprove-3Y5L4ECT.js +88 -0
- package/dist/cli/sentient-M4YMAVGV.js +1088 -0
- package/dist/cli/sequence-6UBMA4IF.js +93 -0
- package/dist/cli/service-5R7SILZ7.js +155 -0
- package/dist/cli/session-3C6AAC4Y.js +707 -0
- package/dist/cli/setup-BTUBW5PU.js +323 -0
- package/dist/cli/show-MXT2V7TF.js +122 -0
- package/dist/cli/skill-GFUZOU2C.js +84 -0
- package/dist/cli/skills-EDWLKAF3.js +928 -0
- package/dist/cli/smoke-provider-SKUFMZXU.js +218 -0
- package/dist/cli/snapshot-GUWMURCM.js +119 -0
- package/dist/cli/src-66GAKPXR.js +80 -0
- package/dist/cli/start-QFG56RGN.js +67 -0
- package/dist/cli/stats-GW55P7RR.js +95 -0
- package/dist/cli/status-46HTKNRR.js +157 -0
- package/dist/cli/sticky-2DUZOUGI.js +338 -0
- package/dist/cli/stop-J2QEUKHX.js +42 -0
- package/dist/cli/sync-GJP2QYT5.js +154 -0
- package/dist/cli/tasks-BNXTM7PB.js +174 -0
- package/dist/cli/telemetry-55Z2XJWL.js +120 -0
- package/dist/cli/templates-7O77TKPV.js +611 -0
- package/dist/cli/testing-37YTBNKP.js +146 -0
- package/dist/cli/token-UAVJMNUI.js +220 -0
- package/dist/cli/transcript-LORQTV5Z.js +440 -0
- package/dist/cli/tui-BPUFHYKK.js +51 -0
- package/dist/cli/update-NVCYV2FT.js +476 -0
- package/dist/cli/upgrade-OXJXOGEF.js +243 -0
- package/dist/cli/verify-LYLDHPT2.js +190 -0
- package/dist/cli/web-QP2RP266.js +275 -0
- package/dist/cli/workgraph-FXBSZDQE.js +232 -0
- package/dist/cli/worktree-6RXAJIST.js +370 -0
- package/package.json +13 -13
- package/studio-dist/client/_app/immutable/chunks/{DMj27Pxj.js → Btgeq_wq.js} +1 -1
- package/studio-dist/client/_app/immutable/chunks/{qq3pe1aT.js → CgBjxmu6.js} +1 -1
- package/studio-dist/client/_app/immutable/chunks/{Dc2owyvE.js → DgEKqO6r.js} +1 -1
- package/studio-dist/client/_app/immutable/chunks/t81h7afa.js +1 -0
- package/studio-dist/client/_app/immutable/entry/{app.CHWXLeE9.js → app.a02HWaRB.js} +2 -2
- package/studio-dist/client/_app/immutable/entry/start.BreMSngo.js +1 -0
- package/studio-dist/client/_app/immutable/nodes/{0.DmKQGvFh.js → 0.nTXyRfc-.js} +1 -1
- package/studio-dist/client/_app/immutable/nodes/{1.DqJk_REO.js → 1.4zrWeHtl.js} +1 -1
- package/studio-dist/client/_app/immutable/nodes/{15.GUy6kdW1.js → 15.D9mk4JyY.js} +1 -1
- package/studio-dist/client/_app/immutable/nodes/{16.CcnKZ8f9.js → 16._-wt-sQf.js} +1 -1
- package/studio-dist/client/_app/immutable/nodes/{17.DAlQF3lQ.js → 17.CUu6LQDj.js} +1 -1
- package/studio-dist/client/_app/immutable/nodes/{18.vQFr-vFj.js → 18.Dz4QRTkX.js} +1 -1
- package/studio-dist/client/_app/immutable/nodes/{20.GVOj5j_r.js → 20.CJ2_EB0U.js} +1 -1
- package/studio-dist/client/_app/immutable/nodes/{24.2-wC6DOh.js → 24.Igj2FS7k.js} +1 -1
- package/studio-dist/client/_app/immutable/nodes/{25.D1vYaH8g.js → 25.BnATjVGN.js} +2 -2
- package/studio-dist/client/_app/immutable/nodes/{26.C3rNqzZF.js → 26.6iPyjT44.js} +1 -1
- package/studio-dist/client/_app/immutable/nodes/{3.b-7pzc3M.js → 3.AA5GwNgP.js} +1 -1
- package/studio-dist/client/_app/version.json +1 -1
- package/studio-dist/server/chunks/{0-BaCce-O1.js → 0-DGmsoBYm.js} +3 -3
- package/studio-dist/server/chunks/1-8PfxPvlK.js +9 -0
- package/studio-dist/server/chunks/{15-DRMOSIC9.js → 15-Bg6YTndh.js} +3 -3
- package/studio-dist/server/chunks/{16-BulXhoZZ.js → 16-BObLwgyD.js} +3 -3
- package/studio-dist/server/chunks/{17-DUEOCM0H.js → 17-BNXGyAHX.js} +3 -3
- package/studio-dist/server/chunks/{18-DP7Q8zPs.js → 18-UqQFRIID.js} +3 -3
- package/studio-dist/server/chunks/{20-9ta6MI7q.js → 20-CMn8a_yP.js} +3 -3
- package/studio-dist/server/chunks/{24-DysdL1ab.js → 24-BuOTDzib.js} +3 -3
- package/studio-dist/server/chunks/{25-CYsps38R.js → 25-CIMSmjVx.js} +4 -4
- package/studio-dist/server/chunks/{26-Df4YXgg0.js → 26-DWGObn2T.js} +3 -3
- package/studio-dist/server/chunks/{3-BEhOhYpL.js → 3-CyiffdJZ.js} +3 -3
- package/studio-dist/server/chunks/{_layout.svelte-CnLcXYG-.js → _layout.svelte-DYtClaIk.js} +4 -4
- package/studio-dist/server/chunks/{_page.svelte-HUqTICJR.js → _page.svelte-1h9E6s_f.js} +3 -3
- package/studio-dist/server/chunks/{_page.svelte-DOl0DGOO.js → _page.svelte-BNNF62Nm.js} +3 -3
- package/studio-dist/server/chunks/{_page.svelte-DzcZljiy.js → _page.svelte-BT1EUadj.js} +5 -5
- package/studio-dist/server/chunks/{_page.svelte-Dv8tmDEC.js → _page.svelte-Bip079LT.js} +3 -3
- package/studio-dist/server/chunks/{_page.svelte-DGhXqeRc.js → _page.svelte-CEATWp_5.js} +3 -3
- package/studio-dist/server/chunks/{_page.svelte-C0qgUvzA.js → _page.svelte-CV3xiD1y.js} +4 -4
- package/studio-dist/server/chunks/{_page.svelte-CbyEPj2j.js → _page.svelte-Cv_KVJDV.js} +3 -3
- package/studio-dist/server/chunks/{_page.svelte-ui7LnWkL.js → _page.svelte-DSSy6LuK.js} +3 -3
- package/studio-dist/server/chunks/{_page.svelte-Da4q5l93.js → _page.svelte-TF795TAS.js} +3 -3
- package/studio-dist/server/chunks/{_server.ts-CnKVmf_s.js → _server.ts-BlhRFLY3.js} +2 -2
- package/studio-dist/server/chunks/{_server.ts-Cr57EKWf.js → _server.ts-C4w6UdU0.js} +3 -3
- package/studio-dist/server/chunks/{_server.ts-P4wVVksg.js → _server.ts-CzrwbhkQ.js} +3 -3
- package/studio-dist/server/chunks/{_server.ts-2BazvYRP.js → _server.ts-DWt8Dziu.js} +3 -3
- package/studio-dist/server/chunks/{_server.ts-C0evMKCk.js → _server.ts-Db6mEile.js} +3 -3
- package/studio-dist/server/chunks/{client-CPM4LrO2.js → client-D8f2k-H_.js} +2 -2
- package/studio-dist/server/chunks/{dist-CdoCt9zT.js → dist-B8xbIrdB.js} +3 -1
- package/studio-dist/server/chunks/{error.svelte-ShcZo43D.js → error.svelte-DbbOwIme.js} +3 -3
- package/studio-dist/server/chunks/{http-BiQjEmVU.js → http-1ftNGTs5.js} +2 -2
- package/studio-dist/server/chunks/{internal-Cgsrya1j.js → internal-CTULuLPB.js} +2 -2
- package/studio-dist/server/chunks/{stores-BGrpEDMK.js → stores-CS5XOReX.js} +2 -2
- package/studio-dist/server/index.js +1 -1
- package/studio-dist/server/manifest.js +17 -17
- package/studio-dist/client/_app/immutable/chunks/Bw6J8NDM.js +0 -1
- package/studio-dist/client/_app/immutable/entry/start.C9bwPpvc.js +0 -1
- package/studio-dist/server/chunks/1-CVo7Nk6d.js +0 -9
|
@@ -0,0 +1,790 @@
|
|
|
1
|
+
(() => {
|
|
2
|
+
const _installed = Symbol.for('cleocode.cli.sqliteWarningFilter');
|
|
3
|
+
if (globalThis[_installed]) return;
|
|
4
|
+
globalThis[_installed] = true;
|
|
5
|
+
const _origEmitWarning = process.emitWarning;
|
|
6
|
+
process.emitWarning = function(warning, type, code, ctor) {
|
|
7
|
+
if (typeof warning === 'object' && warning.name === 'ExperimentalWarning' && typeof warning.message === 'string' && /SQLite is an experimental feature/i.test(warning.message)) {
|
|
8
|
+
return;
|
|
9
|
+
}
|
|
10
|
+
if (typeof warning === 'string' && /SQLite is an experimental feature/i.test(warning)) {
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
return _origEmitWarning.call(process, warning, type, code, ctor);
|
|
14
|
+
};
|
|
15
|
+
})();
|
|
16
|
+
import {
|
|
17
|
+
spawnGatewayIfDown
|
|
18
|
+
} from "./chunk-LVGIFMCV.js";
|
|
19
|
+
|
|
20
|
+
// packages/cleo/src/cli/lib/tui/cockpit.ts
|
|
21
|
+
import { readFileSync } from "node:fs";
|
|
22
|
+
import { join } from "node:path";
|
|
23
|
+
import { createCleoClient as createCleoClient2 } from "@cleocode/core/gateway-client";
|
|
24
|
+
|
|
25
|
+
// packages/cleo/src/cli/lib/pi-tui-loader.ts
|
|
26
|
+
var PI_TUI_INSTALL_HINT = 'The `cleo tui` cockpit requires the optional "@earendil-works/pi-tui" package. Install it with `pnpm add @earendil-works/pi-tui` (or `npm i -g @earendil-works/pi-tui`) to enable the rich differential-rendered terminal board.';
|
|
27
|
+
var PI_TUI_SPECIFIER = "@earendil-works/pi-tui";
|
|
28
|
+
var realImporter = (specifier) => import(specifier);
|
|
29
|
+
var importer = realImporter;
|
|
30
|
+
function shapeCheck(candidate) {
|
|
31
|
+
if (candidate === null || typeof candidate !== "object") return null;
|
|
32
|
+
const mod = candidate;
|
|
33
|
+
const tuiOk = typeof mod.TUI === "function";
|
|
34
|
+
const terminalOk = typeof mod.ProcessTerminal === "function";
|
|
35
|
+
const textOk = typeof mod.Text === "function";
|
|
36
|
+
if (tuiOk && terminalOk && textOk) {
|
|
37
|
+
return candidate;
|
|
38
|
+
}
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
async function loadPiTui() {
|
|
42
|
+
try {
|
|
43
|
+
const mod = await importer(PI_TUI_SPECIFIER);
|
|
44
|
+
const candidate = mod.default ?? mod;
|
|
45
|
+
return shapeCheck(candidate);
|
|
46
|
+
} catch {
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
var cachedAvailable;
|
|
51
|
+
async function isPiTuiAvailable() {
|
|
52
|
+
if (cachedAvailable !== void 0) return cachedAvailable;
|
|
53
|
+
cachedAvailable = await loadPiTui() !== null;
|
|
54
|
+
return cachedAvailable;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// packages/cleo/src/cli/lib/tui/dispatch.ts
|
|
58
|
+
import { createCleoClient } from "@cleocode/core/gateway-client";
|
|
59
|
+
function clampTier(raw) {
|
|
60
|
+
return raw === 0 || raw === 2 ? raw : 1;
|
|
61
|
+
}
|
|
62
|
+
async function dispatchWorker(baseUrl, taskId, tier = 1) {
|
|
63
|
+
try {
|
|
64
|
+
const client = createCleoClient({ baseUrl });
|
|
65
|
+
const spawn = client.orchestrate.spawn;
|
|
66
|
+
const res = await spawn({ body: { taskId, tier } });
|
|
67
|
+
if (res.response == null) {
|
|
68
|
+
return {
|
|
69
|
+
ok: false,
|
|
70
|
+
taskId,
|
|
71
|
+
code: "E_GATEWAY_UNREACHABLE",
|
|
72
|
+
message: "daemon gateway not reachable \u2014 start it with `cleo daemon serve`"
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
const envelope = res.data;
|
|
76
|
+
if (envelope && envelope.success === false) {
|
|
77
|
+
return {
|
|
78
|
+
ok: false,
|
|
79
|
+
taskId,
|
|
80
|
+
code: "E_SPAWN_REJECTED",
|
|
81
|
+
message: envelope.error?.message ?? "spawn rejected"
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
return { ok: true, taskId, tier, data: envelope?.data ?? {} };
|
|
85
|
+
} catch (e) {
|
|
86
|
+
const message = e instanceof Error ? e.message : "spawn failed";
|
|
87
|
+
return { ok: false, taskId, code: "E_SPAWN_ERROR", message };
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
function buildConductorLane(taskId, assignee) {
|
|
91
|
+
return [
|
|
92
|
+
{ label: "Orchestrator", value: "you", hint: "cockpit dispatcher" },
|
|
93
|
+
{ label: "Lead", value: "orchestrate", hint: "spawn pipeline" },
|
|
94
|
+
{
|
|
95
|
+
label: "Worker",
|
|
96
|
+
value: assignee && assignee.length > 0 ? assignee : "worktree",
|
|
97
|
+
hint: `isolated agent \xB7 ${taskId}`
|
|
98
|
+
}
|
|
99
|
+
];
|
|
100
|
+
}
|
|
101
|
+
function renderConductorLane(roles) {
|
|
102
|
+
const chain = roles.map((r) => `${r.label}(${r.value})`).join(" \u2192 ");
|
|
103
|
+
return `Conductor: ${chain}`;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// packages/cleo/src/cli/lib/tui/kanban-board.ts
|
|
107
|
+
import {
|
|
108
|
+
AGENT_LIFECYCLE_LANE_HINTS,
|
|
109
|
+
AGENT_LIFECYCLE_LANE_LABELS,
|
|
110
|
+
AGENT_LIFECYCLE_LANES,
|
|
111
|
+
resolveAgentLifecycleLane
|
|
112
|
+
} from "@cleocode/core/tasks";
|
|
113
|
+
var HIDDEN_STATUSES = /* @__PURE__ */ new Set(["archived", "proposed"]);
|
|
114
|
+
function toSignal(row) {
|
|
115
|
+
const gates = row.gates != null ? {
|
|
116
|
+
implemented: row.gates.implemented === true,
|
|
117
|
+
testsPassed: row.gates.testsPassed === true,
|
|
118
|
+
qaPassed: row.gates.qaPassed === true
|
|
119
|
+
} : null;
|
|
120
|
+
return {
|
|
121
|
+
status: row.status ?? "pending",
|
|
122
|
+
blockedBy: row.blockedBy ?? null,
|
|
123
|
+
depends: row.depends ?? null,
|
|
124
|
+
...typeof row.unmetDependsCount === "number" ? { unmetDependsCount: row.unmetDependsCount } : {},
|
|
125
|
+
gates,
|
|
126
|
+
readyToComplete: row.readyToComplete === true,
|
|
127
|
+
prAwaiting: row.prAwaiting === true,
|
|
128
|
+
hitlPending: row.hitlPending === true,
|
|
129
|
+
workerActive: row.workerActive === true,
|
|
130
|
+
...typeof row.nextAction === "string" ? { nextAction: row.nextAction } : {}
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
function toCard(row) {
|
|
134
|
+
return {
|
|
135
|
+
id: row.id ?? "(no-id)",
|
|
136
|
+
title: row.title ?? "",
|
|
137
|
+
epic: row.parentId ?? null,
|
|
138
|
+
assignee: row.assignee ?? null,
|
|
139
|
+
proof: row.proof ?? null
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
function buildKanbanBoard(rows) {
|
|
143
|
+
const buckets = /* @__PURE__ */ new Map();
|
|
144
|
+
for (const lane of AGENT_LIFECYCLE_LANES) buckets.set(lane, []);
|
|
145
|
+
let total = 0;
|
|
146
|
+
for (const row of rows) {
|
|
147
|
+
if (row.status != null && HIDDEN_STATUSES.has(row.status)) continue;
|
|
148
|
+
const lane = resolveAgentLifecycleLane(toSignal(row));
|
|
149
|
+
buckets.get(lane)?.push(toCard(row));
|
|
150
|
+
total += 1;
|
|
151
|
+
}
|
|
152
|
+
const columns = AGENT_LIFECYCLE_LANES.map((lane) => {
|
|
153
|
+
const cards = buckets.get(lane) ?? [];
|
|
154
|
+
return {
|
|
155
|
+
lane,
|
|
156
|
+
label: AGENT_LIFECYCLE_LANE_LABELS[lane],
|
|
157
|
+
hint: AGENT_LIFECYCLE_LANE_HINTS[lane],
|
|
158
|
+
cards,
|
|
159
|
+
count: cards.length
|
|
160
|
+
};
|
|
161
|
+
});
|
|
162
|
+
return { columns, total };
|
|
163
|
+
}
|
|
164
|
+
function formatCardLine(card) {
|
|
165
|
+
const parts = [` \u2022 ${card.id}`];
|
|
166
|
+
if (card.title) parts.push(truncate(card.title, 48));
|
|
167
|
+
const tags = [];
|
|
168
|
+
if (card.epic) tags.push(`epic:${card.epic}`);
|
|
169
|
+
if (card.assignee) tags.push(`@${card.assignee}`);
|
|
170
|
+
if (card.proof) tags.push(`proof:${card.proof}`);
|
|
171
|
+
const head = parts.join(" ");
|
|
172
|
+
return tags.length > 0 ? `${head} [${tags.join(" ")}]` : head;
|
|
173
|
+
}
|
|
174
|
+
function truncate(s, max) {
|
|
175
|
+
if (s.length <= max) return s;
|
|
176
|
+
return `${s.slice(0, Math.max(0, max - 1))}\u2026`;
|
|
177
|
+
}
|
|
178
|
+
function renderKanbanBoardText(board, options) {
|
|
179
|
+
const cap = options?.maxCardsPerLane ?? 12;
|
|
180
|
+
const lines = [];
|
|
181
|
+
lines.push(`CLEO Cockpit \u2014 Kanban (${board.total} task${board.total === 1 ? "" : "s"})`);
|
|
182
|
+
lines.push("");
|
|
183
|
+
for (const col of board.columns) {
|
|
184
|
+
lines.push(`\u25B8 ${col.label} (${col.count})`);
|
|
185
|
+
if (col.cards.length === 0) {
|
|
186
|
+
lines.push(` ${col.hint}`);
|
|
187
|
+
} else {
|
|
188
|
+
for (const card of col.cards.slice(0, cap)) {
|
|
189
|
+
lines.push(formatCardLine(card));
|
|
190
|
+
}
|
|
191
|
+
if (col.cards.length > cap) {
|
|
192
|
+
lines.push(` \u2026 and ${col.cards.length - cap} more`);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
lines.push("");
|
|
196
|
+
}
|
|
197
|
+
return lines;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// packages/cleo/src/cli/lib/tui/sse-client.ts
|
|
201
|
+
import http from "node:http";
|
|
202
|
+
import https from "node:https";
|
|
203
|
+
var NOOP_SUBSCRIPTION = { unsubscribe: () => {
|
|
204
|
+
} };
|
|
205
|
+
function decodeSseRecord(record) {
|
|
206
|
+
const dataLines = [];
|
|
207
|
+
for (const rawLine of record.split("\n")) {
|
|
208
|
+
const line = rawLine.replace(/\r$/, "");
|
|
209
|
+
if (line.startsWith(":")) continue;
|
|
210
|
+
if (line.startsWith("data:")) {
|
|
211
|
+
dataLines.push(line.slice(5).replace(/^ /, ""));
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
if (dataLines.length === 0) return null;
|
|
215
|
+
try {
|
|
216
|
+
const parsed = JSON.parse(dataLines.join("\n"));
|
|
217
|
+
if (parsed === null || typeof parsed !== "object") return null;
|
|
218
|
+
const obj = parsed;
|
|
219
|
+
if (obj.kind !== "data" && obj.kind !== "done" && obj.kind !== "error") return null;
|
|
220
|
+
if (typeof obj.seq !== "number") return null;
|
|
221
|
+
return parsed;
|
|
222
|
+
} catch {
|
|
223
|
+
return null;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
function subscribeOrchestrateEvents(options, handlers) {
|
|
227
|
+
let url;
|
|
228
|
+
try {
|
|
229
|
+
url = new URL("/v1/orchestrate/events", options.baseUrl);
|
|
230
|
+
} catch {
|
|
231
|
+
handlers.onError?.("invalid gateway base URL");
|
|
232
|
+
return NOOP_SUBSCRIPTION;
|
|
233
|
+
}
|
|
234
|
+
if (typeof options.taskId === "string" && options.taskId.length > 0) {
|
|
235
|
+
url.searchParams.set("taskId", options.taskId);
|
|
236
|
+
}
|
|
237
|
+
const transport = url.protocol === "https:" ? https : http;
|
|
238
|
+
let buffer = "";
|
|
239
|
+
let closed = false;
|
|
240
|
+
let request = null;
|
|
241
|
+
const teardown = (fireClose) => {
|
|
242
|
+
if (closed) return;
|
|
243
|
+
closed = true;
|
|
244
|
+
if (request !== null) {
|
|
245
|
+
request.removeAllListeners();
|
|
246
|
+
request.destroy();
|
|
247
|
+
request = null;
|
|
248
|
+
}
|
|
249
|
+
if (fireClose) handlers.onClose?.();
|
|
250
|
+
};
|
|
251
|
+
request = transport.get(
|
|
252
|
+
url,
|
|
253
|
+
{
|
|
254
|
+
headers: {
|
|
255
|
+
Accept: "text/event-stream",
|
|
256
|
+
...options.headers ?? {}
|
|
257
|
+
}
|
|
258
|
+
},
|
|
259
|
+
(res) => {
|
|
260
|
+
const status = res.statusCode ?? 0;
|
|
261
|
+
if (status < 200 || status >= 300) {
|
|
262
|
+
res.resume();
|
|
263
|
+
handlers.onError?.(`gateway stream returned HTTP ${status}`);
|
|
264
|
+
teardown(true);
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
267
|
+
res.setEncoding("utf8");
|
|
268
|
+
res.on("data", (chunk) => {
|
|
269
|
+
if (closed) return;
|
|
270
|
+
buffer += chunk;
|
|
271
|
+
let sep = buffer.indexOf("\n\n");
|
|
272
|
+
while (sep !== -1) {
|
|
273
|
+
const record = buffer.slice(0, sep);
|
|
274
|
+
buffer = buffer.slice(sep + 2);
|
|
275
|
+
const frame = decodeSseRecord(record);
|
|
276
|
+
if (frame !== null) {
|
|
277
|
+
handlers.onFrame(frame);
|
|
278
|
+
if (frame.kind === "done" || frame.kind === "error") {
|
|
279
|
+
teardown(true);
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
sep = buffer.indexOf("\n\n");
|
|
284
|
+
}
|
|
285
|
+
});
|
|
286
|
+
res.on("end", () => teardown(true));
|
|
287
|
+
res.on("error", (e) => {
|
|
288
|
+
handlers.onError?.(e.message);
|
|
289
|
+
teardown(true);
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
);
|
|
293
|
+
request.on("error", (e) => {
|
|
294
|
+
handlers.onError?.(e.message);
|
|
295
|
+
teardown(true);
|
|
296
|
+
});
|
|
297
|
+
return {
|
|
298
|
+
unsubscribe: () => teardown(false)
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
// packages/cleo/src/cli/lib/tui/worker-stream.ts
|
|
303
|
+
var DEFAULT_OUTPUT_TAIL = 200;
|
|
304
|
+
function emptyWorkerStreamView() {
|
|
305
|
+
return {
|
|
306
|
+
status: "connecting",
|
|
307
|
+
outputTail: [],
|
|
308
|
+
usage: null,
|
|
309
|
+
checkpoints: [],
|
|
310
|
+
lastFrameTs: null,
|
|
311
|
+
error: null
|
|
312
|
+
};
|
|
313
|
+
}
|
|
314
|
+
function readString(payload, key) {
|
|
315
|
+
const v = payload[key];
|
|
316
|
+
return typeof v === "string" ? v : void 0;
|
|
317
|
+
}
|
|
318
|
+
function readNumber(payload, key) {
|
|
319
|
+
const v = payload[key];
|
|
320
|
+
return typeof v === "number" && Number.isFinite(v) ? v : 0;
|
|
321
|
+
}
|
|
322
|
+
function readUsage(payload) {
|
|
323
|
+
const source = payload.usage && typeof payload.usage === "object" ? payload.usage : payload;
|
|
324
|
+
const hasUsage = "inputTokens" in source || "outputTokens" in source || "totalTokens" in source || "records" in source;
|
|
325
|
+
if (!hasUsage) return null;
|
|
326
|
+
const inputTokens = readNumber(source, "inputTokens");
|
|
327
|
+
const outputTokens = readNumber(source, "outputTokens");
|
|
328
|
+
const totalTokens = "totalTokens" in source ? readNumber(source, "totalTokens") : inputTokens + outputTokens;
|
|
329
|
+
const records = "records" in source ? readNumber(source, "records") : 1;
|
|
330
|
+
return { inputTokens, outputTokens, totalTokens, records };
|
|
331
|
+
}
|
|
332
|
+
function readCheckpoint(payload) {
|
|
333
|
+
const cp = payload.checkpoint;
|
|
334
|
+
if (cp === null || typeof cp !== "object") return null;
|
|
335
|
+
const obj = cp;
|
|
336
|
+
const kind = obj.kind;
|
|
337
|
+
if (kind !== "commit" && kind !== "pr" && kind !== "test") return null;
|
|
338
|
+
const label = readString(obj, "label") ?? "";
|
|
339
|
+
return { kind, label };
|
|
340
|
+
}
|
|
341
|
+
function applyWorkerStreamFrame(view, frame, maxTail = DEFAULT_OUTPUT_TAIL) {
|
|
342
|
+
if (frame.kind === "error") {
|
|
343
|
+
return {
|
|
344
|
+
...view,
|
|
345
|
+
status: "error",
|
|
346
|
+
error: frame.error?.message ?? "stream error"
|
|
347
|
+
};
|
|
348
|
+
}
|
|
349
|
+
const payload = frame.data && typeof frame.data === "object" ? frame.data : {};
|
|
350
|
+
const lastFrameTs = readString(payload, "ts") ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
351
|
+
if (frame.kind === "done") {
|
|
352
|
+
return { ...view, status: "ended", lastFrameTs };
|
|
353
|
+
}
|
|
354
|
+
const usage = readUsage(payload);
|
|
355
|
+
if (usage !== null) {
|
|
356
|
+
return { ...view, status: "live", usage, lastFrameTs };
|
|
357
|
+
}
|
|
358
|
+
const checkpoint = readCheckpoint(payload);
|
|
359
|
+
if (checkpoint !== null) {
|
|
360
|
+
return {
|
|
361
|
+
...view,
|
|
362
|
+
status: "live",
|
|
363
|
+
checkpoints: [...view.checkpoints, checkpoint],
|
|
364
|
+
lastFrameTs
|
|
365
|
+
};
|
|
366
|
+
}
|
|
367
|
+
const line = readString(payload, "line") ?? readString(payload, "output");
|
|
368
|
+
if (line !== void 0) {
|
|
369
|
+
const next = [...view.outputTail, line];
|
|
370
|
+
const outputTail = next.length > maxTail ? next.slice(next.length - maxTail) : next;
|
|
371
|
+
return { ...view, status: "live", outputTail, lastFrameTs };
|
|
372
|
+
}
|
|
373
|
+
return { ...view, status: "live", lastFrameTs };
|
|
374
|
+
}
|
|
375
|
+
function formatUsageMeter(usage) {
|
|
376
|
+
if (!usage || usage.totalTokens === 0) return "\u2014 tokens";
|
|
377
|
+
const tok = usage.totalTokens >= 1e3 ? `${(usage.totalTokens / 1e3).toFixed(1)}k` : String(usage.totalTokens);
|
|
378
|
+
const calls = usage.records === 1 ? "1 call" : `${usage.records} calls`;
|
|
379
|
+
return `${tok} tok \xB7 ${calls}`;
|
|
380
|
+
}
|
|
381
|
+
function renderWorkerStreamPanel(taskId, view, options) {
|
|
382
|
+
const tailLines = options?.tailLines ?? 8;
|
|
383
|
+
const lines = [];
|
|
384
|
+
const statusDot = view.status === "live" ? "\u25CF" : view.status === "ended" ? "\u2713" : view.status === "error" ? "\u2717" : view.status === "stalled" ? "\u25CC" : "\u25CB";
|
|
385
|
+
lines.push(
|
|
386
|
+
`\u2500\u2500 Worker ${taskId} ${statusDot} ${view.status} \xB7 ${formatUsageMeter(view.usage)}`
|
|
387
|
+
);
|
|
388
|
+
if (view.checkpoints.length > 0) {
|
|
389
|
+
const chips = view.checkpoints.map((c) => `${c.kind}:${c.label}`).join(" ");
|
|
390
|
+
lines.push(` ${chips}`);
|
|
391
|
+
}
|
|
392
|
+
if (view.status === "error" && view.error) {
|
|
393
|
+
lines.push(` error: ${view.error}`);
|
|
394
|
+
}
|
|
395
|
+
const tail = view.outputTail.slice(Math.max(0, view.outputTail.length - tailLines));
|
|
396
|
+
if (tail.length === 0) {
|
|
397
|
+
lines.push(" (waiting for worker output\u2026)");
|
|
398
|
+
} else {
|
|
399
|
+
for (const out of tail) lines.push(` \u2502 ${out}`);
|
|
400
|
+
}
|
|
401
|
+
return lines;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
// packages/cleo/src/cli/lib/tui/cockpit.ts
|
|
405
|
+
var DEFAULT_TUI_BASE_URL = "http://127.0.0.1:7777";
|
|
406
|
+
async function fetchTaskRows(baseUrl) {
|
|
407
|
+
const client = createCleoClient2({ baseUrl });
|
|
408
|
+
try {
|
|
409
|
+
const res = await client.tasks.list({ body: { limit: 500 } });
|
|
410
|
+
if (res.response == null) return null;
|
|
411
|
+
const tasks = res.data?.data?.tasks;
|
|
412
|
+
if (!Array.isArray(tasks)) return [];
|
|
413
|
+
return tasks;
|
|
414
|
+
} catch {
|
|
415
|
+
return null;
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
var DISPATCHABLE_LANES = /* @__PURE__ */ new Set(["backlog", "ready"]);
|
|
419
|
+
var KanbanBoardComponent = class {
|
|
420
|
+
constructor(board, deps) {
|
|
421
|
+
this.board = board;
|
|
422
|
+
this.deps = deps;
|
|
423
|
+
}
|
|
424
|
+
board;
|
|
425
|
+
deps;
|
|
426
|
+
/** Index of the lane that currently holds keyboard focus. */
|
|
427
|
+
focusedLane = 0;
|
|
428
|
+
/** Index of the focused card WITHIN the focused lane. */
|
|
429
|
+
focusedCard = 0;
|
|
430
|
+
/** Two-step confirm latch — set on the first dispatch key, cleared on action/move. */
|
|
431
|
+
confirming = false;
|
|
432
|
+
/** Spawn tier for the next dispatch (cycled with `t`). */
|
|
433
|
+
tier = 1;
|
|
434
|
+
/** A transient single-line status message (dispatch result / hint). */
|
|
435
|
+
status = "";
|
|
436
|
+
/** The folded worker-stream view for the focused Running card, or null. */
|
|
437
|
+
workerView = null;
|
|
438
|
+
/** The task id the worker panel is currently bound to. */
|
|
439
|
+
workerTaskId = null;
|
|
440
|
+
/** The live SSE subscription for the worker panel, or null. */
|
|
441
|
+
workerSub = null;
|
|
442
|
+
/** Wire the render/refresh callbacks the loop owns. */
|
|
443
|
+
bind(requestRender, refresh) {
|
|
444
|
+
this.deps.requestRender = requestRender;
|
|
445
|
+
this.deps.refresh = refresh;
|
|
446
|
+
}
|
|
447
|
+
/** Replace the board model (e.g. after a refresh) and clamp focus. */
|
|
448
|
+
setBoard(board) {
|
|
449
|
+
this.board = board;
|
|
450
|
+
if (this.focusedLane >= board.columns.length) this.focusedLane = 0;
|
|
451
|
+
this.clampCardFocus();
|
|
452
|
+
this.reconcileWorkerPanel();
|
|
453
|
+
}
|
|
454
|
+
/** The currently-focused lane column, or undefined. */
|
|
455
|
+
currentLane() {
|
|
456
|
+
return this.board.columns[this.focusedLane];
|
|
457
|
+
}
|
|
458
|
+
/** The currently-focused card, or undefined. */
|
|
459
|
+
focusedCardModel() {
|
|
460
|
+
return this.currentLane()?.cards[this.focusedCard];
|
|
461
|
+
}
|
|
462
|
+
/** Keep {@link focusedCard} within the focused lane's card range. */
|
|
463
|
+
clampCardFocus() {
|
|
464
|
+
const count = this.currentLane()?.cards.length ?? 0;
|
|
465
|
+
if (count === 0) {
|
|
466
|
+
this.focusedCard = 0;
|
|
467
|
+
return;
|
|
468
|
+
}
|
|
469
|
+
if (this.focusedCard >= count) this.focusedCard = count - 1;
|
|
470
|
+
if (this.focusedCard < 0) this.focusedCard = 0;
|
|
471
|
+
}
|
|
472
|
+
/** Move keyboard focus one lane right (wraps), resetting card focus. */
|
|
473
|
+
focusNextLane() {
|
|
474
|
+
const n = this.board.columns.length || 1;
|
|
475
|
+
this.focusedLane = (this.focusedLane + 1) % n;
|
|
476
|
+
this.focusedCard = 0;
|
|
477
|
+
this.confirming = false;
|
|
478
|
+
this.clampCardFocus();
|
|
479
|
+
this.reconcileWorkerPanel();
|
|
480
|
+
}
|
|
481
|
+
/** Move keyboard focus one lane left (wraps), resetting card focus. */
|
|
482
|
+
focusPrevLane() {
|
|
483
|
+
const n = this.board.columns.length || 1;
|
|
484
|
+
this.focusedLane = (this.focusedLane - 1 + n) % n;
|
|
485
|
+
this.focusedCard = 0;
|
|
486
|
+
this.confirming = false;
|
|
487
|
+
this.clampCardFocus();
|
|
488
|
+
this.reconcileWorkerPanel();
|
|
489
|
+
}
|
|
490
|
+
/** Move card focus down within the lane (wraps). */
|
|
491
|
+
focusNextCard() {
|
|
492
|
+
const count = this.currentLane()?.cards.length ?? 0;
|
|
493
|
+
if (count === 0) return;
|
|
494
|
+
this.focusedCard = (this.focusedCard + 1) % count;
|
|
495
|
+
this.confirming = false;
|
|
496
|
+
this.reconcileWorkerPanel();
|
|
497
|
+
}
|
|
498
|
+
/** Move card focus up within the lane (wraps). */
|
|
499
|
+
focusPrevCard() {
|
|
500
|
+
const count = this.currentLane()?.cards.length ?? 0;
|
|
501
|
+
if (count === 0) return;
|
|
502
|
+
this.focusedCard = (this.focusedCard - 1 + count) % count;
|
|
503
|
+
this.confirming = false;
|
|
504
|
+
this.reconcileWorkerPanel();
|
|
505
|
+
}
|
|
506
|
+
/** The id of the currently-focused lane (for the status bar / tests). */
|
|
507
|
+
focusedLaneId() {
|
|
508
|
+
return this.currentLane()?.lane ?? "";
|
|
509
|
+
}
|
|
510
|
+
/** Cycle the spawn tier 1 → 2 → 0 → 1 (for the next dispatch). */
|
|
511
|
+
cycleTier() {
|
|
512
|
+
this.tier = clampTier((this.tier + 1) % 3);
|
|
513
|
+
}
|
|
514
|
+
/** The current spawn tier (for tests / status). */
|
|
515
|
+
currentTier() {
|
|
516
|
+
return this.tier;
|
|
517
|
+
}
|
|
518
|
+
/** The current transient status line (for tests). */
|
|
519
|
+
statusLine() {
|
|
520
|
+
return this.status;
|
|
521
|
+
}
|
|
522
|
+
/** Whether the component is awaiting a dispatch confirm (for tests). */
|
|
523
|
+
isConfirming() {
|
|
524
|
+
return this.confirming;
|
|
525
|
+
}
|
|
526
|
+
/**
|
|
527
|
+
* Handle the dispatch key (`d` / Enter) on the focused card.
|
|
528
|
+
*
|
|
529
|
+
* Two-step confirm — spawning is real + expensive. The first press latches
|
|
530
|
+
* `confirming` and shows the confirm prompt; the second press performs the
|
|
531
|
+
* spawn via the injected dispatch fn (SDK → gateway), surfaces the result
|
|
532
|
+
* inline, and (on success) re-fetches so the worker lands in the Running lane.
|
|
533
|
+
* NEVER throws — a failed dispatch sets the status line, never crashes.
|
|
534
|
+
*/
|
|
535
|
+
async requestDispatch() {
|
|
536
|
+
const lane = this.focusedLaneId();
|
|
537
|
+
const card = this.focusedCardModel();
|
|
538
|
+
if (card === void 0) {
|
|
539
|
+
this.status = "No card focused to dispatch.";
|
|
540
|
+
this.deps.requestRender?.();
|
|
541
|
+
return;
|
|
542
|
+
}
|
|
543
|
+
if (!DISPATCHABLE_LANES.has(lane)) {
|
|
544
|
+
this.status = `Dispatch is only available on Backlog/Ready cards (focused: ${lane}).`;
|
|
545
|
+
this.confirming = false;
|
|
546
|
+
this.deps.requestRender?.();
|
|
547
|
+
return;
|
|
548
|
+
}
|
|
549
|
+
if (!this.confirming) {
|
|
550
|
+
this.confirming = true;
|
|
551
|
+
this.status = `Spawn a real worker for ${card.id} (tier ${this.tier})? Press [d] again to confirm, [Esc] to cancel.`;
|
|
552
|
+
this.deps.requestRender?.();
|
|
553
|
+
return;
|
|
554
|
+
}
|
|
555
|
+
this.confirming = false;
|
|
556
|
+
this.status = `Dispatching ${card.id} (tier ${this.tier})\u2026`;
|
|
557
|
+
this.deps.requestRender?.();
|
|
558
|
+
const result = await this.deps.dispatch(this.deps.baseUrl, card.id, this.tier);
|
|
559
|
+
if (result.ok) {
|
|
560
|
+
this.status = `Dispatched ${result.taskId} \u2192 Running (tier ${result.tier}).`;
|
|
561
|
+
await this.deps.refresh?.();
|
|
562
|
+
} else {
|
|
563
|
+
this.status = `Dispatch failed for ${result.taskId}: ${result.code} \u2014 ${result.message}`;
|
|
564
|
+
}
|
|
565
|
+
this.deps.requestRender?.();
|
|
566
|
+
}
|
|
567
|
+
/** Clear the confirm latch (Esc) without dispatching. */
|
|
568
|
+
cancelConfirm() {
|
|
569
|
+
if (this.confirming) {
|
|
570
|
+
this.confirming = false;
|
|
571
|
+
this.status = "Dispatch cancelled.";
|
|
572
|
+
this.deps.requestRender?.();
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
/**
|
|
576
|
+
* Bind / rebind the live worker stream to the focused card when (and only
|
|
577
|
+
* when) it is a Running card, tearing down any prior subscription. Idempotent
|
|
578
|
+
* for the same task — re-focusing the same Running card does not churn the
|
|
579
|
+
* socket.
|
|
580
|
+
*/
|
|
581
|
+
reconcileWorkerPanel() {
|
|
582
|
+
const lane = this.focusedLaneId();
|
|
583
|
+
const card = this.focusedCardModel();
|
|
584
|
+
const targetId = lane === "running" && card !== void 0 ? card.id : null;
|
|
585
|
+
if (targetId === this.workerTaskId) return;
|
|
586
|
+
this.teardownWorkerPanel();
|
|
587
|
+
if (targetId === null) return;
|
|
588
|
+
this.workerTaskId = targetId;
|
|
589
|
+
this.workerView = emptyWorkerStreamView();
|
|
590
|
+
this.workerSub = this.deps.subscribe(
|
|
591
|
+
{ baseUrl: this.deps.baseUrl, taskId: targetId },
|
|
592
|
+
{
|
|
593
|
+
onFrame: (frame) => {
|
|
594
|
+
if (this.workerTaskId !== targetId || this.workerView === null) return;
|
|
595
|
+
this.workerView = applyWorkerStreamFrame(this.workerView, frame);
|
|
596
|
+
this.deps.requestRender?.();
|
|
597
|
+
},
|
|
598
|
+
onError: (reason) => {
|
|
599
|
+
if (this.workerTaskId !== targetId) return;
|
|
600
|
+
this.status = `Worker stream for ${targetId} unavailable: ${reason}`;
|
|
601
|
+
this.deps.requestRender?.();
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
);
|
|
605
|
+
}
|
|
606
|
+
/** Tear down the active worker subscription + panel state (leak-free). */
|
|
607
|
+
teardownWorkerPanel() {
|
|
608
|
+
if (this.workerSub !== null) {
|
|
609
|
+
this.workerSub.unsubscribe();
|
|
610
|
+
this.workerSub = null;
|
|
611
|
+
}
|
|
612
|
+
this.workerView = null;
|
|
613
|
+
this.workerTaskId = null;
|
|
614
|
+
}
|
|
615
|
+
/** No cached state to clear — render is pure over the current board. */
|
|
616
|
+
invalidate() {
|
|
617
|
+
}
|
|
618
|
+
/** Render the board body plus the focus indicator, dispatch affordances,
|
|
619
|
+
* conductor lane, status line, and (on a Running card) the worker panel. */
|
|
620
|
+
render(_width) {
|
|
621
|
+
const lines = renderKanbanBoardText(this.board);
|
|
622
|
+
const lane = this.currentLane();
|
|
623
|
+
const card = this.focusedCardModel();
|
|
624
|
+
const focusCard = card !== void 0 ? `${card.id}` : "\u2014";
|
|
625
|
+
lines.push(`Focus: ${lane?.label ?? "\u2014"} \u203A ${focusCard} (tier ${this.tier})`);
|
|
626
|
+
if (card !== void 0 && DISPATCHABLE_LANES.has(lane?.lane ?? "")) {
|
|
627
|
+
lines.push(renderConductorLane(buildConductorLane(card.id, card.assignee)));
|
|
628
|
+
}
|
|
629
|
+
if (this.workerView !== null && this.workerTaskId !== null) {
|
|
630
|
+
for (const l of renderWorkerStreamPanel(this.workerTaskId, this.workerView)) {
|
|
631
|
+
lines.push(l);
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
if (this.status.length > 0) lines.push(this.status);
|
|
635
|
+
lines.push(
|
|
636
|
+
"[\u2190/\u2192 h/l] lane [\u2191/\u2193 j/k] card [Tab] cycle lane [d/Enter] dispatch [t] tier [Esc] cancel [r] refresh [q] quit"
|
|
637
|
+
);
|
|
638
|
+
return lines;
|
|
639
|
+
}
|
|
640
|
+
};
|
|
641
|
+
function runInteractiveLoop(piTui, component, refresh) {
|
|
642
|
+
return new Promise((resolve) => {
|
|
643
|
+
const terminal = new piTui.ProcessTerminal();
|
|
644
|
+
const tui = new piTui.TUI(terminal);
|
|
645
|
+
tui.addChild(component);
|
|
646
|
+
component.bind(
|
|
647
|
+
() => tui.requestRender(),
|
|
648
|
+
async () => {
|
|
649
|
+
await refresh();
|
|
650
|
+
tui.requestRender(true);
|
|
651
|
+
}
|
|
652
|
+
);
|
|
653
|
+
const dispose = tui.addInputListener((data) => {
|
|
654
|
+
if (data === "q" || data === "") {
|
|
655
|
+
component.teardownWorkerPanel();
|
|
656
|
+
dispose();
|
|
657
|
+
tui.stop();
|
|
658
|
+
resolve();
|
|
659
|
+
return { consume: true };
|
|
660
|
+
}
|
|
661
|
+
if (data === "\x1B[C" || data === "l" || data === " ") {
|
|
662
|
+
component.focusNextLane();
|
|
663
|
+
tui.requestRender();
|
|
664
|
+
return { consume: true };
|
|
665
|
+
}
|
|
666
|
+
if (data === "\x1B[D" || data === "h") {
|
|
667
|
+
component.focusPrevLane();
|
|
668
|
+
tui.requestRender();
|
|
669
|
+
return { consume: true };
|
|
670
|
+
}
|
|
671
|
+
if (data === "\x1B[B" || data === "j") {
|
|
672
|
+
component.focusNextCard();
|
|
673
|
+
tui.requestRender();
|
|
674
|
+
return { consume: true };
|
|
675
|
+
}
|
|
676
|
+
if (data === "\x1B[A" || data === "k") {
|
|
677
|
+
component.focusPrevCard();
|
|
678
|
+
tui.requestRender();
|
|
679
|
+
return { consume: true };
|
|
680
|
+
}
|
|
681
|
+
if (data === "d" || data === "\r" || data === "\n") {
|
|
682
|
+
void component.requestDispatch();
|
|
683
|
+
return { consume: true };
|
|
684
|
+
}
|
|
685
|
+
if (data === "t") {
|
|
686
|
+
component.cycleTier();
|
|
687
|
+
tui.requestRender();
|
|
688
|
+
return { consume: true };
|
|
689
|
+
}
|
|
690
|
+
if (data === "\x1B") {
|
|
691
|
+
component.cancelConfirm();
|
|
692
|
+
tui.requestRender();
|
|
693
|
+
return { consume: true };
|
|
694
|
+
}
|
|
695
|
+
if (data === "r") {
|
|
696
|
+
void refresh().then(() => tui.requestRender(true));
|
|
697
|
+
return { consume: true };
|
|
698
|
+
}
|
|
699
|
+
return void 0;
|
|
700
|
+
});
|
|
701
|
+
tui.start();
|
|
702
|
+
tui.requestRender(true);
|
|
703
|
+
});
|
|
704
|
+
}
|
|
705
|
+
async function runCockpit(options = {}, sink = (line) => process.stdout.write(`${line}
|
|
706
|
+
`)) {
|
|
707
|
+
const baseUrl = options.baseUrl ?? DEFAULT_TUI_BASE_URL;
|
|
708
|
+
const dispatch = options.dispatch ?? dispatchWorker;
|
|
709
|
+
const subscribe = options.subscribe ?? subscribeOrchestrateEvents;
|
|
710
|
+
let gatewayAutoStarted = false;
|
|
711
|
+
const autoStart = options.autoStart !== false;
|
|
712
|
+
let autoStartFailReason;
|
|
713
|
+
let rows = await fetchTaskRows(baseUrl);
|
|
714
|
+
if (rows === null && autoStart) {
|
|
715
|
+
let port;
|
|
716
|
+
let host;
|
|
717
|
+
try {
|
|
718
|
+
const u = new URL(baseUrl);
|
|
719
|
+
const parsed = Number.parseInt(u.port, 10);
|
|
720
|
+
port = Number.isFinite(parsed) && parsed > 0 ? parsed : void 0;
|
|
721
|
+
host = u.hostname || void 0;
|
|
722
|
+
} catch {
|
|
723
|
+
}
|
|
724
|
+
const spawnResult = await spawnGatewayIfDown({
|
|
725
|
+
...options.spawnOpts ?? {},
|
|
726
|
+
...port !== void 0 ? { port } : {},
|
|
727
|
+
...host !== void 0 ? { host } : {}
|
|
728
|
+
});
|
|
729
|
+
if (spawnResult.reachable) {
|
|
730
|
+
gatewayAutoStarted = spawnResult.spawned;
|
|
731
|
+
rows = await fetchTaskRows(baseUrl);
|
|
732
|
+
} else {
|
|
733
|
+
autoStartFailReason = spawnResult.reason;
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
if (rows === null) {
|
|
737
|
+
sink("CLEO cockpit: the daemon gateway is not reachable.");
|
|
738
|
+
sink(` Tried: ${baseUrl}/v1`);
|
|
739
|
+
if (autoStartFailReason !== void 0) {
|
|
740
|
+
sink(` auto-start: ${autoStartFailReason}`);
|
|
741
|
+
}
|
|
742
|
+
try {
|
|
743
|
+
const { getCleoLogDir } = await import("@cleocode/core");
|
|
744
|
+
const errPath = join(getCleoLogDir(), "gateway.err");
|
|
745
|
+
const errContent = readFileSync(errPath, "utf8").trimEnd();
|
|
746
|
+
if (errContent.length > 0) {
|
|
747
|
+
const lastLine = errContent.split("\n").at(-1) ?? "";
|
|
748
|
+
if (lastLine.length > 0) {
|
|
749
|
+
sink(` gateway.err: ${lastLine}`);
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
} catch {
|
|
753
|
+
}
|
|
754
|
+
sink(" Start it with: cleo daemon serve");
|
|
755
|
+
sink(" (override the target with: cleo tui --base-url <url>)");
|
|
756
|
+
return { outcome: "daemon-down", baseUrl, piTui: false, gatewayAutoStarted };
|
|
757
|
+
}
|
|
758
|
+
const board = buildKanbanBoard(rows);
|
|
759
|
+
const piTuiOk = await isPiTuiAvailable();
|
|
760
|
+
const interactive = options.once !== true && process.stdout.isTTY === true;
|
|
761
|
+
if (!piTuiOk || !interactive) {
|
|
762
|
+
for (const line of renderKanbanBoardText(board)) sink(line);
|
|
763
|
+
if (!piTuiOk) {
|
|
764
|
+
sink("");
|
|
765
|
+
sink(PI_TUI_INSTALL_HINT);
|
|
766
|
+
return { outcome: "degraded-pi", baseUrl, piTui: false, gatewayAutoStarted };
|
|
767
|
+
}
|
|
768
|
+
return { outcome: "rendered", baseUrl, piTui: false, gatewayAutoStarted };
|
|
769
|
+
}
|
|
770
|
+
const piTui = await loadPiTui();
|
|
771
|
+
if (piTui === null) {
|
|
772
|
+
for (const line of renderKanbanBoardText(board)) sink(line);
|
|
773
|
+
sink("");
|
|
774
|
+
sink(PI_TUI_INSTALL_HINT);
|
|
775
|
+
return { outcome: "degraded-pi", baseUrl, piTui: false, gatewayAutoStarted };
|
|
776
|
+
}
|
|
777
|
+
const component = new KanbanBoardComponent(board, { baseUrl, dispatch, subscribe });
|
|
778
|
+
const refresh = async () => {
|
|
779
|
+
const fresh = await fetchTaskRows(baseUrl);
|
|
780
|
+
if (fresh !== null) component.setBoard(buildKanbanBoard(fresh));
|
|
781
|
+
};
|
|
782
|
+
await runInteractiveLoop(piTui, component, refresh);
|
|
783
|
+
return { outcome: "rendered", baseUrl, piTui: true, gatewayAutoStarted };
|
|
784
|
+
}
|
|
785
|
+
export {
|
|
786
|
+
DEFAULT_TUI_BASE_URL,
|
|
787
|
+
KanbanBoardComponent,
|
|
788
|
+
runCockpit
|
|
789
|
+
};
|
|
790
|
+
//# sourceMappingURL=cockpit-RZKLGYPN.js.map
|