@iowarp/clio-coder 0.3.1 → 0.3.3
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/CHANGELOG.md +233 -373
- package/CONTRIBUTING.md +23 -23
- package/README.md +284 -613
- package/dist/{acp-FPR54DGL.js → acp-P2AQILE2.js} +43 -53
- package/dist/{agents-OGPIHPJH.js → agents-72W3BI7I.js} +43 -26
- package/dist/assets/codewiki.json +1 -1
- package/dist/{auth-IC3K6NIZ.js → auth-5TWEIYDN.js} +20 -12
- package/dist/chunk-2DJ2KNFG.js +2095 -0
- package/dist/{chunk-IS3ONKU3.js → chunk-2IR2NMPA.js} +6 -4
- package/dist/chunk-2SFS6XQE.js +122 -0
- package/dist/{chunk-PV4JUBVJ.js → chunk-2TLUCQVG.js} +40 -21
- package/dist/chunk-2VTFPG5O.js +48 -0
- package/dist/chunk-4BJ5BYCE.js +61 -0
- package/dist/{chunk-474KN5II.js → chunk-4BPJXDWC.js} +111 -181
- package/dist/chunk-4VP4KH3K.js +962 -0
- package/dist/chunk-4XUGQOHA.js +797 -0
- package/dist/chunk-4ZG3XFUR.js +77 -0
- package/dist/chunk-5B2AEOW5.js +5407 -0
- package/dist/{chunk-K2ITRMHZ.js → chunk-5TSRNF4G.js} +6 -138
- package/dist/{chunk-4QKXUHSR.js → chunk-5UFT4SUX.js} +70 -20
- package/dist/{chunk-OLBBMFRD.js → chunk-5UUP6MWO.js} +24 -62
- package/dist/chunk-65DEGPJ6.js +52 -0
- package/dist/chunk-6EJMN2Y3.js +17 -0
- package/dist/chunk-6N5PTWMY.js +136 -0
- package/dist/chunk-6SGHMWE3.js +277 -0
- package/dist/chunk-6XLNIQDB.js +27 -0
- package/dist/chunk-7CR24IG7.js +242 -0
- package/dist/chunk-7MNJORFF.js +22 -0
- package/dist/{chunk-KY56HMHH.js → chunk-A3CYT5EX.js} +125 -31
- package/dist/chunk-AGYYIBLL.js +1069 -0
- package/dist/{chunk-GB6QRBXN.js → chunk-APJ265NV.js} +54 -1187
- package/dist/{chunk-673JJUWJ.js → chunk-BMEMKKIT.js} +2 -2
- package/dist/chunk-CBCAPZAA.js +229 -0
- package/dist/chunk-CMZWFGD2.js +352 -0
- package/dist/chunk-COU2UHX6.js +400 -0
- package/dist/chunk-DSELYM6W.js +1077 -0
- package/dist/chunk-DUYJ5IO6.js +644 -0
- package/dist/chunk-ECH6PKUQ.js +39 -0
- package/dist/chunk-ED4KHGC3.js +143 -0
- package/dist/chunk-EKMEHE4H.js +340 -0
- package/dist/chunk-FCSXB6T2.js +338 -0
- package/dist/chunk-FJ3H4MN5.js +48 -0
- package/dist/{chunk-RPTR2H26.js → chunk-FNTMWMX5.js} +21 -15
- package/dist/chunk-FQ4SKYE4.js +29 -0
- package/dist/chunk-G4BMMOKF.js +182 -0
- package/dist/{chunk-ZPY3JZ5E.js → chunk-GGXXDWE4.js} +183 -1233
- package/dist/chunk-HC4CLZ2Y.js +68 -0
- package/dist/{chunk-LU4TK2PR.js → chunk-HFSBBKSQ.js} +5 -56
- package/dist/{chunk-PIUMUEMV.js → chunk-HKIYEGME.js} +10 -6
- package/dist/chunk-I4HZDVNP.js +73 -0
- package/dist/chunk-IKCO5N3L.js +162 -0
- package/dist/chunk-IR4CFBFN.js +56 -0
- package/dist/{chunk-R5KLMSBV.js → chunk-J5Q24KAG.js} +2 -2
- package/dist/chunk-J7CWMCQD.js +255 -0
- package/dist/{chunk-K5XEMXTI.js → chunk-JVCV3ICN.js} +1 -1
- package/dist/chunk-KZWTDYJF.js +217 -0
- package/dist/chunk-LBMZMYH2.js +285 -0
- package/dist/{chunk-G34LV2PF.js → chunk-LM5TQCJZ.js} +84 -170
- package/dist/chunk-LW6DSM3M.js +5135 -0
- package/dist/chunk-LWLEKMDQ.js +3482 -0
- package/dist/{chunk-H6F6BYOH.js → chunk-LZSJBIVT.js} +7003 -7434
- package/dist/{chunk-HQQID6OA.js → chunk-M6SHUN7Q.js} +5 -5
- package/dist/{chunk-FST4FYJB.js → chunk-MFFY33HR.js} +99 -140
- package/dist/{chunk-BSU2YIWB.js → chunk-MVVUPGPW.js} +131 -136
- package/dist/chunk-OAO4GE4M.js +619 -0
- package/dist/{chunk-Q3RUPKEJ.js → chunk-OC7FIQPC.js} +58 -189
- package/dist/chunk-OKGUZO2U.js +34 -0
- package/dist/{chunk-GAEBEQVI.js → chunk-OOJYHWRB.js} +32 -346
- package/dist/{chunk-Q5WJOSJ7.js → chunk-OQ33BKR3.js} +2 -1
- package/dist/chunk-OQE5J4C6.js +73 -0
- package/dist/{chunk-KKNLWXI6.js → chunk-ORBHGJC5.js} +8 -8
- package/dist/{chunk-MAR7Y6HW.js → chunk-PAJK6MAQ.js} +23 -16
- package/dist/{chunk-M5T5VO65.js → chunk-PIWWS5BL.js} +837 -635
- package/dist/chunk-POHLU5DW.js +1186 -0
- package/dist/chunk-QKMUKYO7.js +4961 -0
- package/dist/chunk-SRDMMSEP.js +16405 -0
- package/dist/chunk-SST6Z5JA.js +80 -0
- package/dist/chunk-STBPMHSX.js +2456 -0
- package/dist/chunk-T6YILFSB.js +80 -0
- package/dist/chunk-TZK7PACC.js +174 -0
- package/dist/chunk-TZTZS7QK.js +227 -0
- package/dist/{chunk-ASND7OZK.js → chunk-UFIIWP2H.js} +13 -13
- package/dist/chunk-UOV2BYIW.js +107 -0
- package/dist/{chunk-PFEFKVGL.js → chunk-V6RTAOC2.js} +13 -11
- package/dist/chunk-VAKQQHWR.js +434 -0
- package/dist/chunk-VG7TBQIY.js +128 -0
- package/dist/chunk-VJWL6YS5.js +244 -0
- package/dist/{chunk-EYOKLTMF.js → chunk-VPAYEGVX.js} +17 -3
- package/dist/chunk-WEH5XRJQ.js +32 -0
- package/dist/chunk-X4RCMKVQ.js +641 -0
- package/dist/{chunk-TEKV33Q5.js → chunk-X6IAEBZR.js} +65 -33
- package/dist/chunk-XBXAASKX.js +18 -0
- package/dist/chunk-XN3L4EYL.js +46 -0
- package/dist/{chunk-RDLVBZEO.js → chunk-YCWGATWI.js} +6 -4
- package/dist/chunk-YHZX5GEU.js +193 -0
- package/dist/chunk-YXLYO42X.js +91 -0
- package/dist/{chunk-NMOX6HFD.js → chunk-ZDOOVTXZ.js} +29 -77
- package/dist/chunk-ZI647VB5.js +37 -0
- package/dist/{chunk-C4PTHK7P.js → chunk-ZWLZP4ZT.js} +5 -5
- package/dist/chunk-ZWMF7253.js +1882 -0
- package/dist/cli/index.js +62 -54
- package/dist/clio-JOU4FXVA.js +25 -0
- package/dist/code-nav-7AX6FYE6.js +600 -0
- package/dist/codewiki/build-worker.js +66 -0
- package/dist/compile-cache-CVJMMODC.js +18 -0
- package/dist/{components-DMAOEKFB.js → components-KELWS457.js} +11 -6
- package/dist/{config-IRUQ7SE4.js → config-XCDVKR23.js} +92 -55
- package/dist/configure-4GAP54ZW.js +42 -0
- package/dist/{context-5RADCKTR.js → context-4UOGGLQ5.js} +71 -35
- package/dist/context-5VKGUVJJ.js +866 -0
- package/dist/{context-3KWFLHJG.js → context-77FM5DV5.js} +15 -13
- package/dist/{context-clear-7TSNPAAI.js → context-clear-XXJRLCJJ.js} +54 -28
- package/dist/{context-index-W4RLWOQH.js → context-index-BZ4UYMTC.js} +30 -24
- package/dist/dispatch-runner-QPRDDBDX.js +1997 -0
- package/dist/{docs-5AWSPS37.js → docs-2C2LTVT2.js} +23 -10
- package/dist/{doctor-UC5NAJYQ.js → doctor-HR46URBJ.js} +27 -17
- package/dist/{eval-U6TJHRLX.js → eval-XSSNATB4.js} +29 -16
- package/dist/{evidence-YEGUW4L3.js → evidence-6HG2PY2B.js} +46 -26
- package/dist/{evolve-TXARCTPG.js → evolve-K7YU3NCY.js} +45 -25
- package/dist/{extensions-OZFJ3A3G.js → extensions-QVDOHDGJ.js} +16 -7
- package/dist/{fleet-6G3DHNYE.js → fleet-VY3HHKN6.js} +163 -54
- package/dist/{fleet-preflight-DSNT37JK.js → fleet-preflight-DDN536IT.js} +7 -4
- package/dist/{init-KZ5QTF6M.js → init-JYGXI3FK.js} +69 -32
- package/dist/{memory-73ESV5YC.js → memory-WFZMGYHX.js} +48 -27
- package/dist/{models-A4PVNWJK.js → models-I5QWSEOM.js} +39 -25
- package/dist/monitor-GE4ID3IA.js +661 -0
- package/dist/{chunk-FCIH3BIZ.js → orchestrator-EM5MC3HM.js} +15979 -12407
- package/dist/{paths-C4H6IV77.js → paths-UXLN5YYZ.js} +10 -5
- package/dist/{preload-6WVMHX3A.js → preload-P6DGH2PZ.js} +2 -2
- package/dist/{reset-BGW6OGMV.js → reset-L2FQEE3E.js} +16 -10
- package/dist/{run-YTPEYQOH.js → run-ZU3QMZPZ.js} +101 -61
- package/dist/{share-YIFFV4NQ.js → share-S5BZQC5I.js} +15 -8
- package/dist/{skills-2V6RA3OQ.js → skills-X5VXCRNQ.js} +34 -14
- package/dist/{skills-eval-S2TVJO4F.js → skills-eval-WKIHWTHR.js} +70 -34
- package/dist/steer-GGWFUJUD.js +77 -0
- package/dist/{targets-TYXLPB23.js → targets-SNCPI2NR.js} +43 -27
- package/dist/terminal-lease-BNAHVHBS.js +395 -0
- package/dist/{trace-GGOJ6Q6Z.js → trace-PNCASAXC.js} +41 -16
- package/dist/{chunk-N6F52NLF.js → tree-sitter-HGKH6LG4.js} +28 -2306
- package/dist/{uninstall-LLLT4F4W.js → uninstall-FZCQCDKC.js} +10 -5
- package/dist/{upgrade-33G2LMM5.js → upgrade-JQHHPQ4K.js} +45 -25
- package/dist/{usage-ZAFSXKKG.js → usage-OR4O5SMZ.js} +62 -31
- package/dist/verify-375KUB3Y.js +716 -0
- package/dist/web-fetch-2YHJ3KTG.js +638 -0
- package/dist/{wiki-generate-NUQCVOQ3.js → wiki-generate-UEXP2ARI.js} +74 -34
- package/dist/worker/entry.js +221 -36
- package/dist/workspace-G4ZWUIPR.js +22 -0
- package/docs/README.md +22 -17
- package/docs/acp.md +168 -16
- package/docs/alcf-provider.md +1 -1
- package/docs/architecture.md +136 -7
- package/docs/artifact-versions.md +1 -1
- package/docs/built-in-agents.md +1 -1
- package/docs/capacity-and-scheduling.md +1 -1
- package/docs/commands-and-modes.md +114 -71
- package/docs/config-knobs-audit.md +1 -3
- package/docs/configuration-and-targets.md +174 -46
- package/docs/context-engine.md +29 -6
- package/docs/development-pipeline.md +26 -1
- package/docs/dispatch-architecture-rationale.md +1 -1
- package/docs/documentation-coverage.md +2 -2
- package/docs/documentation-guide.md +1 -1
- package/docs/environment-variables.md +13 -5
- package/docs/eval-runner.md +1 -1
- package/docs/evals-internal.md +1 -1
- package/docs/evidence-and-memory.md +6 -2
- package/docs/evolution.md +2 -2
- package/docs/exit-codes-and-output.md +15 -9
- package/docs/extensions-and-sharing.md +9 -9
- package/docs/fleet-dispatch.md +7 -5
- package/docs/git-commit-provenance.md +120 -0
- package/docs/glossary.md +1 -1
- package/docs/installation-and-lifecycle.md +34 -27
- package/docs/middleware-and-components.md +1 -1
- package/docs/model-catalog.md +45 -14
- package/docs/observability.md +8 -5
- package/docs/performance-methodology.md +491 -0
- package/docs/pi-boundary.md +72 -0
- package/docs/proactive-memory.md +3 -3
- package/docs/prompt-envelope-and-tools.md +24 -3
- package/docs/provider-adapter-cookbook.md +57 -4
- package/docs/release-cut-checklist.md +129 -115
- package/docs/safety-model.md +9 -5
- package/docs/scientific-validation.md +3 -3
- package/docs/session-lifecycle.md +55 -12
- package/docs/skills-marketplace.md +12 -8
- package/docs/time-conventions.md +1 -1
- package/docs/tool-usage.md +3 -3
- package/docs/trace-store.md +1 -1
- package/docs/troubleshooting.md +10 -7
- package/docs/tui-design.md +47 -10
- package/docs/worker-dispatch-mechanics.md +1 -1
- package/package.json +19 -22
- package/skills/coding/ast-grep/SKILL.md +136 -0
- package/skills/coding/ast-grep/evals.md +56 -0
- package/skills/coding/ast-grep/references/rule_reference.md +297 -0
- package/skills/coding/coding-standards/SKILL.md +113 -0
- package/skills/coding/coding-standards/evals.md +34 -0
- package/skills/coding/prototype/SKILL.md +86 -0
- package/skills/coding/prototype/evals.md +42 -0
- package/skills/coding/prototype/references/LOGIC.md +67 -0
- package/skills/coding/prototype/references/UI.md +112 -0
- package/skills/coding/tdd/SKILL.md +101 -0
- package/skills/coding/tdd/evals.md +41 -0
- package/skills/coding/tdd/references/mocking.md +59 -0
- package/skills/coding/tdd/references/tests.md +77 -0
- package/skills/context/context-handoff/SKILL.md +126 -0
- package/skills/context/context-handoff/evals.md +57 -0
- package/skills/context/context-handoff/scripts/new-handoff.sh +26 -0
- package/skills/context/context-prime/SKILL.md +95 -0
- package/skills/context/context-prime/evals.md +54 -0
- package/skills/meta/clio-dev/SKILL.md +91 -0
- package/skills/meta/clio-dev/evals.md +45 -0
- package/skills/meta/clio-test/SKILL.md +130 -0
- package/skills/meta/clio-test/evals.md +43 -0
- package/skills/meta/clio-test/references/harness.md +97 -0
- package/skills/meta/clio-test/references/test-map.md +59 -0
- package/skills/meta/credentials/SKILL.md +125 -0
- package/skills/meta/credentials/evals.md +104 -0
- package/skills/meta/find-skills/SKILL.md +72 -0
- package/skills/meta/find-skills/evals.md +47 -0
- package/skills/meta/herdr/SKILL.md +127 -0
- package/skills/meta/herdr/evals.md +38 -0
- package/skills/meta/skill-craft/SKILL.md +102 -0
- package/skills/meta/skill-craft/evals.md +41 -0
- package/skills/planning/architecture/SKILL.md +129 -0
- package/skills/planning/architecture/evals.md +36 -0
- package/skills/planning/backlog/SKILL.md +90 -0
- package/skills/planning/backlog/evals.md +43 -0
- package/skills/planning/prd/SKILL.md +82 -0
- package/skills/planning/prd/evals.md +49 -0
- package/skills/planning/product-intent/SKILL.md +112 -0
- package/skills/planning/product-intent/evals.md +36 -0
- package/skills/planning/tech-spec/SKILL.md +115 -0
- package/skills/planning/tech-spec/evals.md +47 -0
- package/skills/registry.yaml +136 -0
- package/skills/research/arxiv-literature/SKILL.md +104 -0
- package/skills/research/arxiv-literature/evals.md +58 -0
- package/skills/research/experiment-protocol/SKILL.md +122 -0
- package/skills/research/experiment-protocol/evals.md +91 -0
- package/skills/research/scientific-debugging/SKILL.md +119 -0
- package/skills/research/scientific-debugging/evals.md +138 -0
- package/skills/research/scientific-modernization/SKILL.md +138 -0
- package/skills/research/scientific-modernization/evals.md +84 -0
- package/skills/workflow/design-council/SKILL.md +139 -0
- package/skills/workflow/design-council/evals.md +97 -0
- package/skills/workflow/grill-me/SKILL.md +186 -0
- package/skills/workflow/grill-me/evals.md +78 -0
- package/skills/workflow/workflow-distiller/SKILL.md +136 -0
- package/skills/workflow/workflow-distiller/evals.md +107 -0
- package/src/cli/acp.ts +31 -4
- package/src/cli/clio.ts +68 -6
- package/src/cli/config-inspect.ts +28 -22
- package/src/cli/configure.ts +47 -9
- package/src/cli/context-clear.ts +2 -2
- package/src/cli/context-index.ts +21 -23
- package/src/cli/context.ts +13 -8
- package/src/cli/default-target.ts +9 -17
- package/src/cli/docs.ts +11 -5
- package/src/cli/evidence.ts +4 -1
- package/src/cli/extensions.ts +10 -1
- package/src/cli/fleet.ts +47 -6
- package/src/cli/index.ts +55 -26
- package/src/cli/memory.ts +3 -1
- package/src/cli/models.ts +1 -1
- package/src/cli/modes/json-stream.ts +37 -1
- package/src/cli/modes/print.ts +24 -9
- package/src/cli/run.ts +2 -2
- package/src/cli/skills-eval.ts +23 -8
- package/src/cli/skills.ts +19 -4
- package/src/cli/targets.ts +4 -0
- package/src/cli/text-layout.ts +15 -5
- package/src/cli/trace.ts +62 -14
- package/src/cli/upgrade.ts +18 -2
- package/src/cli/usage.ts +10 -3
- package/src/cli/wiki-generate.ts +2 -1
- package/src/core/agent-environment.ts +7 -0
- package/src/core/bash-exec.ts +72 -1
- package/src/core/boot-trace.ts +9 -4
- package/src/core/bus-events.ts +20 -4
- package/src/core/commit-attribution.ts +157 -0
- package/src/core/compile-cache.ts +159 -0
- package/src/core/config.ts +131 -2
- package/src/core/defaults.ts +39 -5
- package/src/core/domain-loader.ts +12 -5
- package/src/core/git-commit-attribution.ts +387 -0
- package/src/core/incomplete-installation.ts +45 -0
- package/src/core/response-schema.ts +1 -1
- package/src/core/safe-exec.ts +13 -1
- package/src/core/settings-layers.ts +155 -21
- package/src/core/skill-activation.ts +1 -1
- package/src/core/startup-timer.ts +3 -3
- package/src/core/state-file-lock.ts +13 -1
- package/src/core/termination.ts +78 -5
- package/src/domains/config/classify.ts +15 -3
- package/src/domains/config/extension.ts +19 -13
- package/src/domains/config/index.ts +10 -0
- package/src/domains/config/keybindings.ts +45 -9
- package/src/domains/context/bootstrap-prompt.ts +1 -1
- package/src/domains/context/bootstrap.ts +111 -18
- package/src/domains/context/clear.ts +16 -11
- package/src/domains/context/clio-md.ts +111 -9
- package/src/domains/context/codewiki/artifact.ts +400 -0
- package/src/domains/context/codewiki/build-worker-protocol.ts +24 -0
- package/src/domains/context/codewiki/build-worker.ts +54 -0
- package/src/domains/context/codewiki/coordinator.ts +182 -0
- package/src/domains/context/codewiki/indexer.ts +59 -144
- package/src/domains/context/codewiki/paths.ts +67 -0
- package/src/domains/context/codewiki/schema.ts +80 -0
- package/src/domains/context/codewiki/tree-sitter.ts +1 -1
- package/src/domains/context/contract.ts +11 -5
- package/src/domains/context/extension.ts +94 -143
- package/src/domains/context/fingerprint.ts +3 -1
- package/src/domains/context/index.ts +12 -22
- package/src/domains/context/project-metadata.ts +19 -0
- package/src/domains/context/prompt-context.ts +9 -10
- package/src/domains/context/refresh.ts +29 -21
- package/src/domains/context/runtime.ts +17 -0
- package/src/domains/context/wiki/generate.ts +39 -34
- package/src/domains/context/wiki/plan.ts +1 -1
- package/src/domains/context/wiki/prompts.ts +21 -8
- package/src/domains/dispatch/code-step.ts +20 -1
- package/src/domains/dispatch/extension.ts +158 -21
- package/src/domains/dispatch/failure-classification.ts +6 -0
- package/src/domains/dispatch/fleet-commit-attribution.ts +56 -0
- package/src/domains/dispatch/orphan-recovery.ts +50 -8
- package/src/domains/dispatch/receipt-integrity.ts +5 -0
- package/src/domains/dispatch/state.ts +31 -6
- package/src/domains/dispatch/transport.ts +2 -1
- package/src/domains/dispatch/types.ts +14 -0
- package/src/domains/dispatch/worker-spawn.ts +21 -2
- package/src/domains/eval/metrics/context.ts +1 -1
- package/src/domains/eval/types.ts +0 -1
- package/src/domains/evidence/build.ts +41 -1
- package/src/domains/lifecycle/migrations/2026-08-18-lmstudio-runtime-id.ts +52 -0
- package/src/domains/lifecycle/migrations/index.ts +24 -4
- package/src/domains/middleware/hooks-io.ts +12 -0
- package/src/domains/middleware/skills-reminder.ts +30 -15
- package/src/domains/prompts/compiler.ts +142 -84
- package/src/domains/prompts/contract.ts +18 -2
- package/src/domains/prompts/extension.ts +39 -7
- package/src/domains/prompts/fragment-loader.ts +0 -1
- package/src/domains/prompts/fragments/identity/clio.md +2 -4
- package/src/domains/prompts/fragments/identity/docs-routing.md +10 -0
- package/src/domains/prompts/fragments/identity/self-awareness.md +1 -45
- package/src/domains/prompts/fragments/operating/contract.md +4 -50
- package/src/domains/prompts/fragments/operating/delegation.md +42 -0
- package/src/domains/prompts/fragments/operating/skills.md +26 -0
- package/src/domains/prompts/fragments/operating/worker.md +16 -0
- package/src/domains/prompts/fragments/safety/auto-edit.md +5 -5
- package/src/domains/prompts/fragments/safety/full-auto.md +3 -3
- package/src/domains/prompts/fragments/safety/read-only.md +4 -4
- package/src/domains/prompts/fragments/safety/suggest.md +2 -2
- package/src/domains/prompts/fragments/wiki/page.md +10 -0
- package/src/domains/prompts/fragments/wiki/plan.md +10 -0
- package/src/domains/prompts/preload.ts +3 -3
- package/src/domains/providers/auth/api-key.ts +1 -1
- package/src/domains/providers/auth/backend-file.ts +20 -10
- package/src/domains/providers/auth/backend-memory.ts +59 -4
- package/src/domains/providers/auth/boot-status.ts +65 -0
- package/src/domains/providers/auth/oauth.ts +2 -1
- package/src/domains/providers/auth/storage.ts +97 -38
- package/src/domains/providers/capabilities.ts +12 -4
- package/src/domains/providers/contract.ts +15 -4
- package/src/domains/providers/extension.ts +18 -6
- package/src/domains/providers/model-runtime-capabilities.ts +15 -4
- package/src/domains/providers/models/local-models/clio-local-coding-targets.yaml +118 -35
- package/src/domains/providers/plugins.ts +5 -3
- package/src/domains/providers/probe/fingerprint.ts +25 -5
- package/src/domains/providers/registry.ts +31 -10
- package/src/domains/providers/runtimes/boot-manifest.ts +55 -0
- package/src/domains/providers/runtimes/builtins.ts +2 -2
- package/src/domains/providers/runtimes/common/lmstudio-http.ts +423 -0
- package/src/domains/providers/runtimes/common/local-synth.ts +6 -7
- package/src/domains/providers/runtimes/local-native/lmstudio.ts +241 -0
- package/src/domains/providers/support.ts +6 -3
- package/src/domains/providers/types/local-model-quirks.ts +7 -9
- package/src/domains/providers/types/runtime-descriptor.ts +12 -1
- package/src/domains/providers/types/target-descriptor.ts +22 -0
- package/src/domains/resources/contract.ts +0 -1
- package/src/domains/resources/extension.ts +1 -3
- package/src/domains/resources/loader.ts +3 -4
- package/src/domains/resources/prompts/loader.ts +16 -2
- package/src/domains/resources/prompts/substitute.ts +1 -65
- package/src/domains/resources/skills/content-hash.ts +2 -0
- package/src/domains/resources/skills/install.ts +17 -0
- package/src/domains/resources/skills/loader.ts +17 -10
- package/src/domains/resources/skills/marketplace.ts +55 -9
- package/src/domains/safety/action-classifier.ts +4 -2
- package/src/domains/safety/audit.ts +8 -2
- package/src/domains/safety/extension.ts +1 -1
- package/src/domains/session/compaction/branch-summary.ts +3 -2
- package/src/domains/session/compaction/cut-point.ts +2 -1
- package/src/domains/session/compaction/tokens.ts +2 -1
- package/src/domains/session/context-ledger.ts +14 -0
- package/src/domains/session/contract.ts +15 -0
- package/src/domains/session/decision-board.ts +190 -0
- package/src/domains/session/entries.ts +66 -3
- package/src/domains/session/extension.ts +93 -12
- package/src/domains/session/retry.ts +10 -18
- package/src/domains/session/session-artifacts.ts +107 -0
- package/src/domains/session/task-board.ts +207 -13
- package/src/domains/session/tree/active-path.ts +44 -5
- package/src/domains/session/tree/fork.ts +26 -27
- package/src/domains/session/tree/preview.ts +2 -2
- package/src/domains/session/workspace/git-probe.ts +17 -11
- package/src/domains/user-tasks/store.ts +297 -0
- package/src/engine/acp/errors.ts +96 -0
- package/src/engine/acp/server.ts +1728 -146
- package/src/engine/acp/transport.ts +135 -14
- package/src/engine/acp/types.ts +26 -0
- package/src/engine/agent.ts +3 -3
- package/src/engine/ai.ts +32 -27
- package/src/engine/alcf-oauth.ts +26 -19
- package/src/engine/api-registry.ts +223 -0
- package/src/engine/apis/index.ts +3 -7
- package/src/engine/apis/llamacpp-residency.ts +49 -9
- package/src/engine/apis/lmstudio-residency.ts +5 -21
- package/src/engine/apis/lmstudio.ts +243 -0
- package/src/engine/apis/ollama-native.ts +24 -3
- package/src/engine/apis/openai-completions.ts +170 -91
- package/src/engine/apis/residency.ts +139 -3
- package/src/engine/apis/types.ts +16 -0
- package/src/engine/env-api-keys.ts +98 -0
- package/src/engine/gemma-channel-filter.ts +223 -0
- package/src/engine/instrumented-tui.ts +192 -0
- package/src/engine/messages.ts +14 -0
- package/src/engine/models.ts +42 -0
- package/src/engine/oauth.ts +16 -12
- package/src/engine/prompt-templates.ts +1 -0
- package/src/engine/provider-payload.ts +16 -59
- package/src/engine/strip-tokenizer-sentinels.ts +1 -1
- package/src/engine/truncate.ts +9 -0
- package/src/engine/tui.ts +17 -9
- package/src/engine/types.ts +3 -6
- package/src/engine/worker-runtime-capabilities.ts +5 -0
- package/src/engine/worker-runtime.ts +1 -1
- package/src/engine/worker-tools.ts +9 -4
- package/src/entry/boot-options.ts +50 -0
- package/src/entry/orchestrator.ts +288 -150
- package/src/interactive/application-controller.ts +89 -2
- package/src/interactive/chat-loop.ts +266 -41
- package/src/interactive/chat-panel.ts +715 -278
- package/src/interactive/chat-renderer.ts +306 -85
- package/src/interactive/clio-editor.ts +3 -8
- package/src/interactive/command-fallbacks.ts +2 -2
- package/src/interactive/context-overlay.ts +27 -1
- package/src/interactive/editor-submit.ts +253 -24
- package/src/interactive/export-html/ansi-to-html.ts +161 -0
- package/src/interactive/export-html/index.ts +51 -0
- package/src/interactive/export-html/template.ts +45 -0
- package/src/interactive/export-html/tool-renderer.ts +54 -0
- package/src/interactive/footer/dashboard.ts +4 -0
- package/src/interactive/footer/notifications.ts +1 -1
- package/src/interactive/footer/widgets.ts +42 -22
- package/src/interactive/footer-panel.ts +8 -3
- package/src/interactive/format-time.ts +14 -2
- package/src/interactive/interactive-application.ts +203 -17
- package/src/interactive/interactive-event-projection.ts +18 -1
- package/src/interactive/interactive-input-runtime.ts +50 -4
- package/src/interactive/interactive-presentation.ts +151 -19
- package/src/interactive/interactive-shell.ts +268 -14
- package/src/interactive/interactive-slash-runtime.ts +184 -117
- package/src/interactive/interactive-tickers.ts +38 -7
- package/src/interactive/keybinding-manager.ts +1 -1
- package/src/interactive/layout.ts +40 -3
- package/src/interactive/overlay-frame.ts +1 -1
- package/src/interactive/overlay-general-openers.ts +58 -1
- package/src/interactive/overlay-key-routing.ts +3 -0
- package/src/interactive/overlay-lifecycle.ts +13 -0
- package/src/interactive/overlay-permission-lifecycle.ts +2 -1
- package/src/interactive/overlay-session-lifecycle.ts +69 -12
- package/src/interactive/overlays/ask-user.ts +146 -24
- package/src/interactive/overlays/decisions.ts +300 -0
- package/src/interactive/overlays/help-reference.ts +15 -10
- package/src/interactive/overlays/model-selector.ts +34 -16
- package/src/interactive/overlays/session-selector.ts +18 -0
- package/src/interactive/overlays/settings.ts +105 -17
- package/src/interactive/overlays/skills-hub.ts +4 -4
- package/src/interactive/overlays/tree-selector.ts +41 -6
- package/src/interactive/render-trace.ts +499 -90
- package/src/interactive/renderers/compaction-summary.ts +2 -2
- package/src/interactive/renderers/diff.ts +115 -104
- package/src/interactive/renderers/mermaid.ts +53 -0
- package/src/interactive/renderers/tool-execution.ts +516 -168
- package/src/interactive/renderers/worker-entry.ts +20 -4
- package/src/interactive/session-switch-settlement.ts +10 -0
- package/src/interactive/slash-autocomplete.ts +6 -114
- package/src/interactive/slash-commands.ts +135 -47
- package/src/interactive/slash-spec.ts +9 -38
- package/src/interactive/status/controller.ts +5 -1
- package/src/interactive/status/index.ts +12 -1
- package/src/interactive/status/reasoning.ts +87 -0
- package/src/interactive/status/summary.ts +13 -2
- package/src/interactive/stdout-backpressure.ts +99 -0
- package/src/interactive/stream-pacer.ts +530 -0
- package/src/interactive/stream-pacing-policy.ts +66 -0
- package/src/interactive/tasks-overlay.ts +368 -14
- package/src/interactive/terminal-lease.ts +485 -0
- package/src/interactive/theme/tokens.ts +1 -1
- package/src/interactive/transcript-detail.ts +120 -0
- package/src/interactive/turn-context.ts +4 -3
- package/src/interactive/turn-persistence.ts +30 -13
- package/src/interactive/turn-queues.ts +12 -0
- package/src/interactive/turn-recovery.ts +25 -8
- package/src/interactive/turn-runtime.ts +79 -12
- package/src/interactive/turn-state.ts +10 -0
- package/src/interactive/view/artifacts.ts +114 -4
- package/src/interactive/view/view-overlay.ts +3 -0
- package/src/interactive/welcome-dashboard.ts +17 -16
- package/src/interactive/worker-receipts.ts +52 -3
- package/src/interactive/worker-stream.ts +5 -1
- package/src/tools/agent-tools.ts +23 -3
- package/src/tools/artifact.ts +2 -2
- package/src/tools/ask-user.ts +23 -13
- package/src/tools/bash.ts +30 -2
- package/src/tools/bootstrap.ts +34 -431
- package/src/tools/builtin-tool-catalog.ts +271 -0
- package/src/tools/codewiki/code-nav-surface.ts +29 -0
- package/src/tools/codewiki/code-nav.ts +8 -22
- package/src/tools/codewiki/shared.ts +41 -38
- package/src/tools/context/docs-engine.ts +14 -3
- package/src/tools/context/index.ts +107 -28
- package/src/tools/context/surface.ts +19 -0
- package/src/tools/core-bootstrap.ts +168 -0
- package/src/tools/credential-present.ts +5 -5
- package/src/tools/dispatch-admission.ts +533 -0
- package/src/tools/dispatch-background.ts +54 -0
- package/src/tools/dispatch-event-text.ts +6 -0
- package/src/tools/dispatch-plan.ts +9 -4
- package/src/tools/dispatch-run-events.ts +238 -0
- package/src/tools/dispatch-runner.ts +2370 -0
- package/src/tools/dispatch-scout-admission.ts +295 -0
- package/src/tools/dispatch-types.ts +77 -0
- package/src/tools/dispatch.ts +67 -3161
- package/src/tools/find.ts +4 -2
- package/src/tools/grep.ts +2 -2
- package/src/tools/lazy-tool.ts +60 -0
- package/src/tools/ledger.ts +3 -3
- package/src/tools/monitor-surface.ts +36 -0
- package/src/tools/monitor.ts +2 -32
- package/src/tools/observers.ts +2 -2
- package/src/tools/presentation.ts +107 -0
- package/src/tools/registry.ts +45 -27
- package/src/tools/safe-exec.ts +2 -2
- package/src/tools/steer-surface.ts +17 -0
- package/src/tools/steer.ts +2 -13
- package/src/tools/tasks.ts +108 -11
- package/src/tools/truncate.ts +25 -184
- package/src/tools/verify/frontend.ts +3 -1
- package/src/tools/verify/index.ts +3 -38
- package/src/tools/verify/surface.ts +46 -0
- package/src/tools/web-fetch-surface.ts +23 -0
- package/src/tools/web-fetch.ts +2 -20
- package/src/tools/write.ts +7 -2
- package/src/worker/entry.ts +39 -2
- package/src/worker/spec-contract.ts +26 -5
- package/dist/chunk-7SS2CTV2.js +0 -61361
- package/dist/chunk-DKGKUHFA.js +0 -924
- package/dist/chunk-GEP36Y4X.js +0 -12796
- package/dist/chunk-XYWBQRDM.js +0 -137
- package/dist/clio-BZVGEUFJ.js +0 -58
- package/dist/configure-S7S6F6CL.js +0 -32
- package/docs/html/agents_blueprint.html +0 -936
- package/docs/html/alcf_blueprint.html +0 -324
- package/docs/html/architecture_blueprint.html +0 -850
- package/docs/html/commands_blueprint.html +0 -939
- package/docs/html/config_knobs_audit_blueprint.html +0 -178
- package/docs/html/configuration_blueprint.html +0 -1080
- package/docs/html/context_blueprint.html +0 -603
- package/docs/html/documentation_blueprint.html +0 -832
- package/docs/html/environment_blueprint.html +0 -404
- package/docs/html/eval_blueprint.html +0 -743
- package/docs/html/evals_internal_blueprint.html +0 -190
- package/docs/html/evolution_blueprint.html +0 -674
- package/docs/html/extensions_blueprint.html +0 -2065
- package/docs/html/fleet_dispatch_blueprint.html +0 -286
- package/docs/html/index.html +0 -919
- package/docs/html/lifecycle_blueprint.html +0 -723
- package/docs/html/memory_blueprint.html +0 -699
- package/docs/html/middleware_blueprint.html +0 -664
- package/docs/html/models_blueprint.html +0 -2366
- package/docs/html/observability_blueprint.html +0 -683
- package/docs/html/provider_adapter_blueprint.html +0 -245
- package/docs/html/safety_blueprint.html +0 -1386
- package/docs/html/shared.css +0 -571
- package/docs/html/shared.js +0 -143
- package/docs/html/skills_blueprint.html +0 -671
- package/docs/html/soak_blueprint.html +0 -182
- package/docs/html/tool_usage_blueprint.html +0 -350
- package/docs/html/tools_blueprint.html +0 -2249
- package/docs/html/trace_blueprint.html +0 -235
- package/docs/html/tui_design_blueprint.html +0 -374
- package/docs/html/validation_blueprint.html +0 -961
- package/docs/html/worker_dispatch_blueprint.html +0 -231
- package/src/core/release.ts +0 -2
- package/src/domains/providers/runtimes/common/lmstudio-logger.ts +0 -32
- package/src/domains/providers/runtimes/local-native/lmstudio-native.ts +0 -491
- package/src/engine/apis/lmstudio-native.ts +0 -1438
- package/src/engine/apis/thinking-replay.ts +0 -11
- package/src/tools/string-enum.ts +0 -15
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
import { runBashCommand } from "../core/bash-exec.js";
|
|
1
|
+
import { combineBashOutput, runBashCommand } from "../core/bash-exec.js";
|
|
2
|
+
import type { PendingSkillRequest } from "../core/skill-activation.js";
|
|
3
|
+
import { ToolNames } from "../core/tool-names.js";
|
|
2
4
|
import type { DispatchContract } from "../domains/dispatch/contract.js";
|
|
3
5
|
import type { SessionContract, SessionEntry } from "../domains/session/index.js";
|
|
6
|
+
import { toolPresentationPolicy } from "../tools/presentation.js";
|
|
4
7
|
import type { ChatLoop } from "./chat-loop.js";
|
|
5
8
|
import type { ChatPanel } from "./chat-panel.js";
|
|
6
|
-
import { renderBashExecutionEntry } from "./chat-renderer.js";
|
|
7
9
|
import { bashExecutionEntryInput, parseEditorBashCommand } from "./editor-bash.js";
|
|
8
10
|
import {
|
|
9
11
|
formatSteerCandidates,
|
|
@@ -12,7 +14,15 @@ import {
|
|
|
12
14
|
resolveSteerTarget,
|
|
13
15
|
} from "./editor-steer.js";
|
|
14
16
|
import { type ExternalEditResult, editTextExternally, resolveExternalEditor } from "./external-editor.js";
|
|
15
|
-
import {
|
|
17
|
+
import { type BashTranscriptExecution, renderBashTranscriptExecution } from "./renderers/tool-execution.js";
|
|
18
|
+
import { parseSlashCommand, type RunIo, type SlashCommand, type SlashCommandDispatchResult } from "./slash-commands.js";
|
|
19
|
+
import {
|
|
20
|
+
type FoldOverride,
|
|
21
|
+
policyRunningToolFold,
|
|
22
|
+
policyToolFold,
|
|
23
|
+
resolveFold,
|
|
24
|
+
type TranscriptDetailPolicy,
|
|
25
|
+
} from "./transcript-detail.js";
|
|
16
26
|
|
|
17
27
|
const EDITOR_BASH_TIMEOUT_MS = 300_000;
|
|
18
28
|
|
|
@@ -26,13 +36,8 @@ const EDITOR_BASH_TIMEOUT_MS = 300_000;
|
|
|
26
36
|
* operator can see which flag the usage line is complaining about and fix that
|
|
27
37
|
* one token.
|
|
28
38
|
*
|
|
29
|
-
* `unknown-command`
|
|
30
|
-
*
|
|
31
|
-
* against, and the restored text has no cursor placement of its own: the next
|
|
32
|
-
* keystrokes land in front of the leftover `/token`, which no longer parses as
|
|
33
|
-
* a command, so the whole concatenation goes to the model as a chat message the
|
|
34
|
-
* operator never wrote. An empty line after "is not a command" costs a retype
|
|
35
|
-
* and says exactly what happened.
|
|
39
|
+
* `unknown-command` cannot be decided here: a prompt template can still claim
|
|
40
|
+
* it during dispatch. Its post-dispatch verdict is handled at the call site.
|
|
36
41
|
*
|
|
37
42
|
* A command that ran and failed has done work, and chat text belongs to the
|
|
38
43
|
* transcript, so both also leave the line empty.
|
|
@@ -44,6 +49,10 @@ function isRejectedCommand(command: SlashCommand): boolean {
|
|
|
44
49
|
export interface EditorSubmitExpansion {
|
|
45
50
|
text: string;
|
|
46
51
|
images: ReadonlyArray<unknown>;
|
|
52
|
+
/** Paths the draft referenced inline; the idle path hands them to the chat loop for rule scoping. */
|
|
53
|
+
workingContextPaths?: ReadonlyArray<string>;
|
|
54
|
+
/** Skill requests parsed out of the draft; the idle path hands them to the chat loop as the pending-skill policy. */
|
|
55
|
+
pendingSkillRequests?: ReadonlyArray<PendingSkillRequest>;
|
|
47
56
|
}
|
|
48
57
|
|
|
49
58
|
export interface EditorSubmitEditor {
|
|
@@ -58,13 +67,18 @@ export interface EditorSubmitUi {
|
|
|
58
67
|
requestRender(force?: boolean): void;
|
|
59
68
|
}
|
|
60
69
|
|
|
61
|
-
type EditorSubmitChat = Pick<
|
|
70
|
+
type EditorSubmitChat = Pick<
|
|
71
|
+
ChatLoop,
|
|
72
|
+
"clearQueuedFollowUps" | "interruptRefusal" | "isStreaming" | "queueFollowUp" | "submit" | "whenSettled"
|
|
73
|
+
>;
|
|
62
74
|
type EditorSubmitDispatch = Pick<DispatchContract, "snapshot" | "steer">;
|
|
63
75
|
type EditorSubmitSession = Pick<SessionContract, "appendEntry" | "current" | "tree">;
|
|
64
76
|
|
|
65
77
|
export interface EditorSubmitSessionTranscript {
|
|
66
78
|
ensureSessionForLocalEntry(): void;
|
|
67
79
|
refreshChatContextFromSession(leafTurnId: string | null): void;
|
|
80
|
+
/** Count a prompt the operator submitted; the idle path does this through the slash runtime. */
|
|
81
|
+
recordSubmittedTurn(): void;
|
|
68
82
|
}
|
|
69
83
|
|
|
70
84
|
export interface EditorSubmitDeps {
|
|
@@ -76,7 +90,10 @@ export interface EditorSubmitDeps {
|
|
|
76
90
|
session?: EditorSubmitSession;
|
|
77
91
|
sessionTranscript: EditorSubmitSessionTranscript;
|
|
78
92
|
chatPanel: Pick<ChatPanel, "appendReplayBlock">;
|
|
79
|
-
|
|
93
|
+
beforeSemanticBoundary?: (reason: string) => void;
|
|
94
|
+
settleVisibleFrame?: (reason: string) => Promise<void>;
|
|
95
|
+
dispatchCommand: (text: string) => SlashCommandDispatchResult;
|
|
96
|
+
dispatchCommandAsync?: (text: string, signal?: AbortSignal) => Promise<void>;
|
|
80
97
|
/** Idempotently collapses a fresh-session launchpad before any handler can append output. */
|
|
81
98
|
collapseLaunchpadBeforeSubmit?: () => void;
|
|
82
99
|
expandSubmit: (text: string) => Promise<EditorSubmitExpansion>;
|
|
@@ -93,15 +110,27 @@ export interface EditorSubmitController {
|
|
|
93
110
|
openExternalEditorForInput(): void;
|
|
94
111
|
handleEditorSteerMention(mention: { target: string; text: string }): boolean;
|
|
95
112
|
submitEditorText(text: string): void;
|
|
113
|
+
/** Admit an immutable boot record without reading or mutating the live draft. */
|
|
114
|
+
admitCapturedText(text: string, signal?: AbortSignal): Promise<void>;
|
|
96
115
|
queueFollowUpFromEditor(): void;
|
|
116
|
+
/**
|
|
117
|
+
* Interrupt mode: cancel the active run and deliver the draft now. Idle, it
|
|
118
|
+
* is a plain send. The chat loop owns cancel → settle → submit and the two
|
|
119
|
+
* refusals (attached dispatch, parked permission ask), which degrade the
|
|
120
|
+
* message to next-slot delivery with a notice.
|
|
121
|
+
*/
|
|
122
|
+
interruptFromEditor(): void;
|
|
97
123
|
restoreQueuedFollowUpsToEditor(): void;
|
|
98
124
|
hasActiveEditorBash(): boolean;
|
|
99
125
|
cancelActiveEditorBash(): boolean;
|
|
100
126
|
}
|
|
101
127
|
|
|
128
|
+
type EditorSteerSubmission = "unhandled" | "accepted" | "rejected";
|
|
129
|
+
|
|
102
130
|
/** Owns editor submission and the one local bash process attached to it. */
|
|
103
131
|
export function createEditorSubmitController(deps: EditorSubmitDeps): EditorSubmitController {
|
|
104
132
|
let activeEditorBash: AbortController | null = null;
|
|
133
|
+
let activeEditorBashSettlement: Promise<void> | null = null;
|
|
105
134
|
|
|
106
135
|
const runEditorBash = (text: string): boolean => {
|
|
107
136
|
const parsed = parseEditorBashCommand(text);
|
|
@@ -126,13 +155,55 @@ export function createEditorSubmitController(deps: EditorSubmitDeps): EditorSubm
|
|
|
126
155
|
activeEditorBash = null;
|
|
127
156
|
return true;
|
|
128
157
|
}
|
|
158
|
+
const startedAt = performance.now();
|
|
159
|
+
const execution: BashTranscriptExecution = {
|
|
160
|
+
command: parsed.command,
|
|
161
|
+
output: "",
|
|
162
|
+
running: true,
|
|
163
|
+
totalBytes: 0,
|
|
164
|
+
excludeFromContext: parsed.excludeFromContext,
|
|
165
|
+
};
|
|
166
|
+
// The operator's bash row follows the same rule as a model bash call: the
|
|
167
|
+
// transcript detail policy (through bash's presentation once settled)
|
|
168
|
+
// unless the operator overrode this one block with the expand key.
|
|
169
|
+
let fold: FoldOverride;
|
|
170
|
+
const bashPresentation = toolPresentationPolicy(ToolNames.Bash, undefined);
|
|
171
|
+
const policyFold = (detail: TranscriptDetailPolicy) =>
|
|
172
|
+
execution.running ? policyRunningToolFold(detail) : policyToolFold(detail, bashPresentation);
|
|
173
|
+
deps.chatPanel.appendReplayBlock(
|
|
174
|
+
(width, detail) =>
|
|
175
|
+
renderBashTranscriptExecution(
|
|
176
|
+
{
|
|
177
|
+
...execution,
|
|
178
|
+
folded: resolveFold(fold, policyFold(detail)) === "folded",
|
|
179
|
+
...(execution.running ? { elapsedMs: Math.max(0, performance.now() - startedAt) } : {}),
|
|
180
|
+
},
|
|
181
|
+
width,
|
|
182
|
+
),
|
|
183
|
+
() => execution.running,
|
|
184
|
+
{
|
|
185
|
+
policyFold,
|
|
186
|
+
fold: () => fold,
|
|
187
|
+
setFold: (next: FoldOverride) => {
|
|
188
|
+
fold = next;
|
|
189
|
+
deps.ui.requestRender();
|
|
190
|
+
},
|
|
191
|
+
},
|
|
192
|
+
);
|
|
193
|
+
deps.ui.requestRender();
|
|
129
194
|
|
|
130
|
-
|
|
195
|
+
let settlement!: Promise<void>;
|
|
196
|
+
settlement = (async () => {
|
|
131
197
|
try {
|
|
132
198
|
const result = await (deps.runBash ?? runBashCommand)(parsed.command, {
|
|
133
199
|
cwd: deps.getCwd?.() ?? process.cwd(),
|
|
134
200
|
timeoutMs: EDITOR_BASH_TIMEOUT_MS,
|
|
135
201
|
signal: abort.signal,
|
|
202
|
+
onUpdate: (progress) => {
|
|
203
|
+
execution.output = combineBashOutput(progress);
|
|
204
|
+
execution.totalBytes = progress.outputBytes;
|
|
205
|
+
deps.ui.requestRender();
|
|
206
|
+
},
|
|
136
207
|
});
|
|
137
208
|
const input = bashExecutionEntryInput({
|
|
138
209
|
command: parsed.command,
|
|
@@ -149,17 +220,34 @@ export function createEditorSubmitController(deps: EditorSubmitDeps): EditorSubm
|
|
|
149
220
|
timestamp: deps.nowIso?.() ?? new Date().toISOString(),
|
|
150
221
|
} as SessionEntry);
|
|
151
222
|
if (entry.kind === "bashExecution") {
|
|
152
|
-
|
|
223
|
+
execution.output = entry.output;
|
|
224
|
+
execution.running = false;
|
|
225
|
+
execution.exitCode = entry.exitCode;
|
|
226
|
+
execution.cancelled = entry.cancelled;
|
|
227
|
+
execution.truncated = entry.truncated;
|
|
228
|
+
execution.fullOutputPath = entry.fullOutputPath;
|
|
229
|
+
execution.totalBytes = Math.max(execution.totalBytes ?? 0, Buffer.byteLength(combineBashOutput(result), "utf8"));
|
|
153
230
|
}
|
|
154
|
-
|
|
231
|
+
// `parentTurnId` was the leaf when the command started and stays the
|
|
232
|
+
// entry's anchor. The chat leaf is a different question: a prompt
|
|
233
|
+
// may have landed while the command ran, so restore the leaf the
|
|
234
|
+
// session has now, not the one captured then. Restoring the stale
|
|
235
|
+
// one wedged every later submit on a parent that was no longer
|
|
236
|
+
// the leaf.
|
|
237
|
+
deps.sessionTranscript.refreshChatContextFromSession(deps.session?.tree().leafId ?? parentTurnId);
|
|
155
238
|
} catch (err) {
|
|
156
239
|
const msg = err instanceof Error ? err.message : String(err);
|
|
240
|
+
execution.running = false;
|
|
241
|
+
execution.error = msg;
|
|
157
242
|
deps.io.stderr(`[bash] ${msg}\n`);
|
|
158
243
|
} finally {
|
|
159
244
|
if (activeEditorBash === abort) activeEditorBash = null;
|
|
245
|
+
if (activeEditorBashSettlement === settlement) activeEditorBashSettlement = null;
|
|
160
246
|
deps.ui.requestRender();
|
|
161
247
|
}
|
|
162
248
|
})();
|
|
249
|
+
activeEditorBashSettlement = settlement;
|
|
250
|
+
void settlement;
|
|
163
251
|
return true;
|
|
164
252
|
};
|
|
165
253
|
|
|
@@ -186,14 +274,14 @@ export function createEditorSubmitController(deps: EditorSubmitDeps): EditorSubm
|
|
|
186
274
|
deps.ui.requestRender(true);
|
|
187
275
|
};
|
|
188
276
|
|
|
189
|
-
const
|
|
277
|
+
const submitEditorSteerMention = (mention: { target: string; text: string }): EditorSteerSubmission => {
|
|
190
278
|
let running: RunningDispatchRef[] = [];
|
|
191
279
|
try {
|
|
192
280
|
running = deps.dispatch.snapshot().running.map((run) => ({ runId: run.runId, agentId: run.agentId }));
|
|
193
281
|
} catch {
|
|
194
282
|
running = [];
|
|
195
283
|
}
|
|
196
|
-
if (running.length === 0) return
|
|
284
|
+
if (running.length === 0) return "unhandled";
|
|
197
285
|
const resolution = resolveSteerTarget(mention.target, running);
|
|
198
286
|
if (resolution.kind === "match") {
|
|
199
287
|
try {
|
|
@@ -203,11 +291,12 @@ export function createEditorSubmitController(deps: EditorSubmitDeps): EditorSubm
|
|
|
203
291
|
`steer queued for ${resolution.run.agentId} (${resolution.run.runId}); awaiting worker acknowledgement`,
|
|
204
292
|
`steer:${resolution.run.runId}`,
|
|
205
293
|
);
|
|
294
|
+
return "accepted";
|
|
206
295
|
} catch (err) {
|
|
207
296
|
const msg = err instanceof Error ? err.message : String(err);
|
|
208
297
|
deps.notify("error", `steer to @${mention.target} failed: ${msg}`, `steer:${mention.target}`);
|
|
298
|
+
return "rejected";
|
|
209
299
|
}
|
|
210
|
-
return true;
|
|
211
300
|
}
|
|
212
301
|
if (resolution.kind === "ambiguous") {
|
|
213
302
|
deps.notify(
|
|
@@ -215,34 +304,127 @@ export function createEditorSubmitController(deps: EditorSubmitDeps): EditorSubm
|
|
|
215
304
|
`@${mention.target} matches ${resolution.candidates.length} runs: ${formatSteerCandidates(resolution.candidates)}; use a runId prefix`,
|
|
216
305
|
`steer:${mention.target}`,
|
|
217
306
|
);
|
|
218
|
-
return
|
|
307
|
+
return "rejected";
|
|
219
308
|
}
|
|
220
309
|
deps.notify(
|
|
221
310
|
"warning",
|
|
222
311
|
`no running dispatch matches @${mention.target}; running: ${formatSteerCandidates(running)}`,
|
|
223
312
|
`steer:${mention.target}`,
|
|
224
313
|
);
|
|
225
|
-
return
|
|
314
|
+
return "rejected";
|
|
226
315
|
};
|
|
227
316
|
|
|
317
|
+
const handleEditorSteerMention = (mention: { target: string; text: string }): boolean =>
|
|
318
|
+
submitEditorSteerMention(mention) !== "unhandled";
|
|
319
|
+
|
|
228
320
|
const submitEditorText = (text: string): void => {
|
|
229
321
|
const trimmed = text.trim();
|
|
230
322
|
if (trimmed.length === 0) return;
|
|
231
323
|
deps.collapseLaunchpadBeforeSubmit?.();
|
|
232
324
|
if (parseEditorBashCommand(text)) {
|
|
233
|
-
if (!deps.chat.isStreaming() && !activeEditorBash)
|
|
325
|
+
if (!deps.chat.isStreaming() && !activeEditorBash) {
|
|
326
|
+
deps.editor.addToHistory(text);
|
|
327
|
+
deps.editor.setText("");
|
|
328
|
+
} else {
|
|
329
|
+
// Pi Editor clears the buffer before invoking onSubmit. A command
|
|
330
|
+
// refused by either admission guard is still a draft, so put it back
|
|
331
|
+
// for the operator instead of silently discarding it.
|
|
332
|
+
deps.editor.setText(text);
|
|
333
|
+
}
|
|
234
334
|
if (runEditorBash(text)) deps.ui.requestRender();
|
|
235
335
|
return;
|
|
236
336
|
}
|
|
237
337
|
const steerMention = parseEditorSteerMention(trimmed);
|
|
238
|
-
if (steerMention
|
|
338
|
+
if (steerMention) {
|
|
339
|
+
const submission = submitEditorSteerMention(steerMention);
|
|
340
|
+
if (submission !== "unhandled") {
|
|
341
|
+
if (submission === "accepted") {
|
|
342
|
+
deps.editor.addToHistory(text);
|
|
343
|
+
deps.editor.setText("");
|
|
344
|
+
} else {
|
|
345
|
+
// Resolution and dispatch failures are correctable rejections. Pi
|
|
346
|
+
// has already cleared the editor, so explicitly restore the draft.
|
|
347
|
+
deps.editor.setText(text);
|
|
348
|
+
}
|
|
349
|
+
deps.ui.requestRender();
|
|
350
|
+
return;
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
const command = parseSlashCommand(trimmed);
|
|
354
|
+
if (isRejectedCommand(command)) {
|
|
355
|
+
deps.editor.setText(text);
|
|
356
|
+
deps.dispatchCommand(trimmed);
|
|
357
|
+
} else if (command.kind === "unknown-command") {
|
|
358
|
+
const result = deps.dispatchCommand(trimmed);
|
|
359
|
+
if (result === "rejected") {
|
|
360
|
+
deps.editor.setText(text);
|
|
361
|
+
} else {
|
|
362
|
+
deps.editor.addToHistory(text);
|
|
363
|
+
deps.editor.setText("");
|
|
364
|
+
}
|
|
365
|
+
} else {
|
|
239
366
|
deps.editor.addToHistory(text);
|
|
240
367
|
deps.editor.setText("");
|
|
368
|
+
deps.dispatchCommand(trimmed);
|
|
369
|
+
}
|
|
370
|
+
deps.ui.requestRender();
|
|
371
|
+
};
|
|
372
|
+
|
|
373
|
+
const awaitWithAbort = async (promise: Promise<void>, signal?: AbortSignal): Promise<void> => {
|
|
374
|
+
if (!signal) return await promise;
|
|
375
|
+
signal.throwIfAborted();
|
|
376
|
+
let abort: (() => void) | null = null;
|
|
377
|
+
try {
|
|
378
|
+
await Promise.race([
|
|
379
|
+
promise,
|
|
380
|
+
new Promise<never>((_resolve, reject) => {
|
|
381
|
+
abort = () => reject(signal.reason ?? new DOMException("aborted", "AbortError"));
|
|
382
|
+
signal.addEventListener("abort", abort, { once: true });
|
|
383
|
+
}),
|
|
384
|
+
]);
|
|
385
|
+
} finally {
|
|
386
|
+
if (abort) signal.removeEventListener("abort", abort);
|
|
387
|
+
}
|
|
388
|
+
};
|
|
389
|
+
|
|
390
|
+
const admitCapturedText = async (text: string, signal?: AbortSignal): Promise<void> => {
|
|
391
|
+
const trimmed = text.trim();
|
|
392
|
+
if (trimmed.length === 0) return;
|
|
393
|
+
signal?.throwIfAborted();
|
|
394
|
+
deps.collapseLaunchpadBeforeSubmit?.();
|
|
395
|
+
if (parseEditorBashCommand(text)) {
|
|
396
|
+
while (deps.chat.isStreaming()) await awaitWithAbort(deps.chat.whenSettled(), signal);
|
|
397
|
+
while (activeEditorBashSettlement) await awaitWithAbort(activeEditorBashSettlement, signal);
|
|
398
|
+
signal?.throwIfAborted();
|
|
399
|
+
deps.editor.addToHistory(text);
|
|
400
|
+
runEditorBash(text);
|
|
241
401
|
deps.ui.requestRender();
|
|
242
402
|
return;
|
|
243
403
|
}
|
|
244
|
-
|
|
245
|
-
|
|
404
|
+
const steerMention = parseEditorSteerMention(trimmed);
|
|
405
|
+
if (steerMention) {
|
|
406
|
+
const submission = submitEditorSteerMention(steerMention);
|
|
407
|
+
if (submission !== "unhandled") {
|
|
408
|
+
if (submission === "rejected") {
|
|
409
|
+
throw new Error("queued boot steer was not admitted; preserving it for recovery");
|
|
410
|
+
}
|
|
411
|
+
deps.editor.addToHistory(text);
|
|
412
|
+
deps.ui.requestRender();
|
|
413
|
+
return;
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
const command = parseSlashCommand(trimmed);
|
|
417
|
+
if (isRejectedCommand(command)) {
|
|
418
|
+
signal?.throwIfAborted();
|
|
419
|
+
if (deps.dispatchCommandAsync) await deps.dispatchCommandAsync(trimmed, signal);
|
|
420
|
+
else deps.dispatchCommand(trimmed);
|
|
421
|
+
deps.ui.requestRender();
|
|
422
|
+
throw new Error("queued boot command needs correction; preserving it for recovery");
|
|
423
|
+
}
|
|
424
|
+
deps.editor.addToHistory(text);
|
|
425
|
+
signal?.throwIfAborted();
|
|
426
|
+
if (deps.dispatchCommandAsync) await deps.dispatchCommandAsync(trimmed, signal);
|
|
427
|
+
else deps.dispatchCommand(trimmed);
|
|
246
428
|
deps.ui.requestRender();
|
|
247
429
|
};
|
|
248
430
|
|
|
@@ -261,6 +443,7 @@ export function createEditorSubmitController(deps: EditorSubmitDeps): EditorSubm
|
|
|
261
443
|
deps.io.stderr("[follow-up] image references cannot be queued while a response is streaming\n");
|
|
262
444
|
return;
|
|
263
445
|
}
|
|
446
|
+
deps.beforeSemanticBoundary?.("follow-up-submit");
|
|
264
447
|
if (!deps.chat.queueFollowUp(submitted.text)) {
|
|
265
448
|
deps.io.stderr("[follow-up] no active response to queue against\n");
|
|
266
449
|
return;
|
|
@@ -274,6 +457,50 @@ export function createEditorSubmitController(deps: EditorSubmitDeps): EditorSubm
|
|
|
274
457
|
});
|
|
275
458
|
};
|
|
276
459
|
|
|
460
|
+
const interruptFromEditor = (): void => {
|
|
461
|
+
const text = deps.editor.getText().trim();
|
|
462
|
+
if (text.length === 0) return;
|
|
463
|
+
if (!deps.chat.isStreaming()) {
|
|
464
|
+
deps.editor.setText("");
|
|
465
|
+
submitEditorText(text);
|
|
466
|
+
deps.ui.requestRender();
|
|
467
|
+
return;
|
|
468
|
+
}
|
|
469
|
+
void (async () => {
|
|
470
|
+
const submitted = await deps.expandSubmit(text);
|
|
471
|
+
if (submitted.images.length > 0) {
|
|
472
|
+
deps.io.stderr("[interrupt] image references cannot be sent while a response is streaming\n");
|
|
473
|
+
return;
|
|
474
|
+
}
|
|
475
|
+
deps.editor.addToHistory(text);
|
|
476
|
+
// Same restore Esc performs: when the interrupt will really cancel the
|
|
477
|
+
// run, the queued steers and follow-ups come back to the editor rather
|
|
478
|
+
// than vanishing with the cancelled run. A refused interrupt cancels
|
|
479
|
+
// nothing, so the queue stays put.
|
|
480
|
+
const restored = deps.chat.interruptRefusal() === null ? deps.chat.clearQueuedFollowUps() : [];
|
|
481
|
+
deps.editor.setText(restored.join("\n\n"));
|
|
482
|
+
deps.ui.requestRender();
|
|
483
|
+
// An interrupt is a fresh prompt, so it carries what the idle path
|
|
484
|
+
// carries: the launchpad collapse, the submitted-turn count, and the
|
|
485
|
+
// expansion's working-context paths and pending skill requests. Only
|
|
486
|
+
// images stay behind, rejected above, as they are for a follow-up.
|
|
487
|
+
deps.collapseLaunchpadBeforeSubmit?.();
|
|
488
|
+
deps.sessionTranscript.recordSubmittedTurn();
|
|
489
|
+
const paths = submitted.workingContextPaths ?? [];
|
|
490
|
+
const skillRequests = submitted.pendingSkillRequests ?? [];
|
|
491
|
+
deps.beforeSemanticBoundary?.("interrupt-submit");
|
|
492
|
+
await deps.chat.submit(submitted.text, {
|
|
493
|
+
steering: "interrupt",
|
|
494
|
+
...(paths.length > 0 ? { workingContextPaths: paths } : {}),
|
|
495
|
+
...(skillRequests.length > 0 ? { pendingSkillRequests: skillRequests } : {}),
|
|
496
|
+
});
|
|
497
|
+
await deps.settleVisibleFrame?.("interrupt-submit-return");
|
|
498
|
+
})().catch((err) => {
|
|
499
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
500
|
+
deps.io.stderr(`[interrupt] ${msg}\n`);
|
|
501
|
+
});
|
|
502
|
+
};
|
|
503
|
+
|
|
277
504
|
const restoreQueuedFollowUpsToEditor = (): void => {
|
|
278
505
|
const restored = deps.chat.clearQueuedFollowUps();
|
|
279
506
|
if (restored.length === 0) {
|
|
@@ -291,7 +518,9 @@ export function createEditorSubmitController(deps: EditorSubmitDeps): EditorSubm
|
|
|
291
518
|
openExternalEditorForInput,
|
|
292
519
|
handleEditorSteerMention,
|
|
293
520
|
submitEditorText,
|
|
521
|
+
admitCapturedText,
|
|
294
522
|
queueFollowUpFromEditor,
|
|
523
|
+
interruptFromEditor,
|
|
295
524
|
restoreQueuedFollowUpsToEditor,
|
|
296
525
|
hasActiveEditorBash: () => activeEditorBash !== null,
|
|
297
526
|
cancelActiveEditorBash: () => {
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Terminal ANSI to HTML conversion adapted from pi-coding-agent 0.84.0's
|
|
3
|
+
* `dist/core/export-html/ansi-to-html.js`.
|
|
4
|
+
*
|
|
5
|
+
* Clio's transcript also contains OSC 133 shell-integration markers and may
|
|
6
|
+
* contain other non-SGR terminal controls. Those controls are discarded here;
|
|
7
|
+
* only SGR presentation survives as inline HTML styles.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
const ANSI_COLORS = [
|
|
11
|
+
"rgb(0,0,0)",
|
|
12
|
+
"rgb(128,0,0)",
|
|
13
|
+
"rgb(0,128,0)",
|
|
14
|
+
"rgb(128,128,0)",
|
|
15
|
+
"rgb(0,0,128)",
|
|
16
|
+
"rgb(128,0,128)",
|
|
17
|
+
"rgb(0,128,128)",
|
|
18
|
+
"rgb(192,192,192)",
|
|
19
|
+
"rgb(128,128,128)",
|
|
20
|
+
"rgb(255,0,0)",
|
|
21
|
+
"rgb(0,255,0)",
|
|
22
|
+
"rgb(255,255,0)",
|
|
23
|
+
"rgb(0,0,255)",
|
|
24
|
+
"rgb(255,0,255)",
|
|
25
|
+
"rgb(0,255,255)",
|
|
26
|
+
"rgb(255,255,255)",
|
|
27
|
+
] as const;
|
|
28
|
+
|
|
29
|
+
interface TextStyle {
|
|
30
|
+
fg: string | null;
|
|
31
|
+
bg: string | null;
|
|
32
|
+
bold: boolean;
|
|
33
|
+
dim: boolean;
|
|
34
|
+
italic: boolean;
|
|
35
|
+
underline: boolean;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function color256ToHex(index: number): string {
|
|
39
|
+
const bounded = Math.max(0, Math.min(255, index));
|
|
40
|
+
if (bounded < 16) return ANSI_COLORS[bounded] ?? ANSI_COLORS[0];
|
|
41
|
+
if (bounded < 232) {
|
|
42
|
+
const cubeIndex = bounded - 16;
|
|
43
|
+
const component = (value: number): number => (value === 0 ? 0 : 55 + value * 40);
|
|
44
|
+
return `rgb(${component(Math.floor(cubeIndex / 36))},${component(Math.floor((cubeIndex % 36) / 6))},${component(cubeIndex % 6)})`;
|
|
45
|
+
}
|
|
46
|
+
const gray = 8 + (bounded - 232) * 10;
|
|
47
|
+
return `rgb(${gray},${gray},${gray})`;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function escapeHtml(text: string): string {
|
|
51
|
+
return text
|
|
52
|
+
.replace(/&/gu, "&")
|
|
53
|
+
.replace(/</gu, "<")
|
|
54
|
+
.replace(/>/gu, ">")
|
|
55
|
+
.replace(/"/gu, """)
|
|
56
|
+
.replace(/'/gu, "'");
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function createEmptyStyle(): TextStyle {
|
|
60
|
+
return { fg: null, bg: null, bold: false, dim: false, italic: false, underline: false };
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function styleToInlineCss(style: TextStyle): string {
|
|
64
|
+
const parts: string[] = [];
|
|
65
|
+
if (style.fg) parts.push(`color:${style.fg}`);
|
|
66
|
+
if (style.bg) parts.push(`background-color:${style.bg}`);
|
|
67
|
+
if (style.bold) parts.push("font-weight:bold");
|
|
68
|
+
if (style.dim) parts.push("opacity:0.6");
|
|
69
|
+
if (style.italic) parts.push("font-style:italic");
|
|
70
|
+
if (style.underline) parts.push("text-decoration:underline");
|
|
71
|
+
return parts.join(";");
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function hasStyle(style: TextStyle): boolean {
|
|
75
|
+
return style.fg !== null || style.bg !== null || style.bold || style.dim || style.italic || style.underline;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function applySgrCode(params: number[], style: TextStyle): void {
|
|
79
|
+
let index = 0;
|
|
80
|
+
while (index < params.length) {
|
|
81
|
+
const code = params[index] ?? 0;
|
|
82
|
+
if (code === 0) Object.assign(style, createEmptyStyle());
|
|
83
|
+
else if (code === 1) style.bold = true;
|
|
84
|
+
else if (code === 2) style.dim = true;
|
|
85
|
+
else if (code === 3) style.italic = true;
|
|
86
|
+
else if (code === 4) style.underline = true;
|
|
87
|
+
else if (code === 22) {
|
|
88
|
+
style.bold = false;
|
|
89
|
+
style.dim = false;
|
|
90
|
+
} else if (code === 23) style.italic = false;
|
|
91
|
+
else if (code === 24) style.underline = false;
|
|
92
|
+
else if (code >= 30 && code <= 37) style.fg = ANSI_COLORS[code - 30] ?? null;
|
|
93
|
+
else if (code === 38) {
|
|
94
|
+
if (params[index + 1] === 5 && params[index + 2] !== undefined) {
|
|
95
|
+
style.fg = color256ToHex(params[index + 2] ?? 0);
|
|
96
|
+
index += 2;
|
|
97
|
+
} else if (params[index + 1] === 2 && params[index + 4] !== undefined) {
|
|
98
|
+
style.fg = `rgb(${params[index + 2]},${params[index + 3]},${params[index + 4]})`;
|
|
99
|
+
index += 4;
|
|
100
|
+
}
|
|
101
|
+
} else if (code === 39) style.fg = null;
|
|
102
|
+
else if (code >= 40 && code <= 47) style.bg = ANSI_COLORS[code - 40] ?? null;
|
|
103
|
+
else if (code === 48) {
|
|
104
|
+
if (params[index + 1] === 5 && params[index + 2] !== undefined) {
|
|
105
|
+
style.bg = color256ToHex(params[index + 2] ?? 0);
|
|
106
|
+
index += 2;
|
|
107
|
+
} else if (params[index + 1] === 2 && params[index + 4] !== undefined) {
|
|
108
|
+
style.bg = `rgb(${params[index + 2]},${params[index + 3]},${params[index + 4]})`;
|
|
109
|
+
index += 4;
|
|
110
|
+
}
|
|
111
|
+
} else if (code === 49) style.bg = null;
|
|
112
|
+
else if (code >= 90 && code <= 97) style.fg = ANSI_COLORS[code - 90 + 8] ?? null;
|
|
113
|
+
else if (code >= 100 && code <= 107) style.bg = ANSI_COLORS[code - 100 + 8] ?? null;
|
|
114
|
+
index += 1;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// CSI, OSC, DCS/SOS/PM/APC, and single-character ESC sequences. SGR CSI
|
|
119
|
+
// sequences are interpreted; every other terminal control is removed.
|
|
120
|
+
const ESC = String.fromCharCode(27);
|
|
121
|
+
const BEL = String.fromCharCode(7);
|
|
122
|
+
const TERMINAL_SEQUENCE = new RegExp(
|
|
123
|
+
`${ESC}(?:\\[([0-?]*[ -/]*)([@-~])|\\][^${BEL}${ESC}]*(?:${BEL}|${ESC}\\\\)|[PX^_][\\s\\S]*?${ESC}\\\\|[@-_])`,
|
|
124
|
+
"gu",
|
|
125
|
+
);
|
|
126
|
+
|
|
127
|
+
export function ansiToHtml(text: string): string {
|
|
128
|
+
const style = createEmptyStyle();
|
|
129
|
+
let result = "";
|
|
130
|
+
let lastIndex = 0;
|
|
131
|
+
let spanOpen = false;
|
|
132
|
+
TERMINAL_SEQUENCE.lastIndex = 0;
|
|
133
|
+
let match = TERMINAL_SEQUENCE.exec(text);
|
|
134
|
+
while (match !== null) {
|
|
135
|
+
result += escapeHtml(text.slice(lastIndex, match.index));
|
|
136
|
+
if (match[2] === "m") {
|
|
137
|
+
if (spanOpen) result += "</span>";
|
|
138
|
+
const raw = match[1] ?? "";
|
|
139
|
+
const params = raw.length > 0 ? raw.split(";").map((part) => Number.parseInt(part, 10) || 0) : [0];
|
|
140
|
+
applySgrCode(params, style);
|
|
141
|
+
spanOpen = hasStyle(style);
|
|
142
|
+
if (spanOpen) result += `<span style="${styleToInlineCss(style)}">`;
|
|
143
|
+
}
|
|
144
|
+
lastIndex = match.index + match[0].length;
|
|
145
|
+
match = TERMINAL_SEQUENCE.exec(text);
|
|
146
|
+
}
|
|
147
|
+
result += escapeHtml(text.slice(lastIndex));
|
|
148
|
+
if (spanOpen) result += "</span>";
|
|
149
|
+
// A raw C0 control is never meaningful inside the exported document. Tabs
|
|
150
|
+
// remain useful in preformatted tool output and are safe in HTML text.
|
|
151
|
+
return Array.from(result)
|
|
152
|
+
.filter((character) => {
|
|
153
|
+
const code = character.charCodeAt(0);
|
|
154
|
+
return code === 9 || (code >= 32 && code !== 127);
|
|
155
|
+
})
|
|
156
|
+
.join("");
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
export function ansiLinesToHtml(lines: ReadonlyArray<string>): string {
|
|
160
|
+
return lines.map((line) => `<div class="ansi-line">${ansiToHtml(line) || " "}</div>`).join("\n");
|
|
161
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { htmlTemplate } from "./template.js";
|
|
2
|
+
import { renderTranscriptHtml } from "./tool-renderer.js";
|
|
3
|
+
|
|
4
|
+
export const MAX_HTML_EXPORT_BYTES = 2 * 1024 * 1024;
|
|
5
|
+
const TEMPLATE_RESERVE_BYTES = 8 * 1024;
|
|
6
|
+
|
|
7
|
+
export interface HtmlSessionExportInput {
|
|
8
|
+
sessionId: string;
|
|
9
|
+
exportedAt: string;
|
|
10
|
+
ansiLines: ReadonlyArray<string>;
|
|
11
|
+
maxBytes?: number;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Build the bounded, self-contained HTML document used by `/export`.
|
|
16
|
+
* Whole rendered rows are admitted until the byte budget is full, so the
|
|
17
|
+
* result never cuts an ANSI sequence, Unicode scalar, span, or tool section.
|
|
18
|
+
*/
|
|
19
|
+
export function renderSessionHtml(input: HtmlSessionExportInput): string {
|
|
20
|
+
const maxBytes = input.maxBytes ?? MAX_HTML_EXPORT_BYTES;
|
|
21
|
+
if (!Number.isSafeInteger(maxBytes) || maxBytes < TEMPLATE_RESERVE_BYTES * 2) {
|
|
22
|
+
throw new Error(`HTML export size limit must be at least ${TEMPLATE_RESERVE_BYTES * 2} bytes`);
|
|
23
|
+
}
|
|
24
|
+
const lineBudget = maxBytes - TEMPLATE_RESERVE_BYTES;
|
|
25
|
+
const selected: string[] = [];
|
|
26
|
+
let renderedBytes = 0;
|
|
27
|
+
let truncated = false;
|
|
28
|
+
for (const line of input.ansiLines) {
|
|
29
|
+
const rendered = renderTranscriptHtml([line]);
|
|
30
|
+
const bytes = Buffer.byteLength(rendered, "utf8") + 1;
|
|
31
|
+
if (renderedBytes + bytes > lineBudget) {
|
|
32
|
+
truncated = true;
|
|
33
|
+
break;
|
|
34
|
+
}
|
|
35
|
+
selected.push(line);
|
|
36
|
+
renderedBytes += bytes;
|
|
37
|
+
}
|
|
38
|
+
const html = htmlTemplate({
|
|
39
|
+
sessionId: input.sessionId,
|
|
40
|
+
exportedAt: input.exportedAt,
|
|
41
|
+
transcriptHtml: renderTranscriptHtml(selected),
|
|
42
|
+
truncated,
|
|
43
|
+
});
|
|
44
|
+
if (Buffer.byteLength(html, "utf8") > maxBytes) {
|
|
45
|
+
throw new Error(`HTML export exceeded its ${maxBytes}-byte size limit`);
|
|
46
|
+
}
|
|
47
|
+
return html;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export { ansiLinesToHtml, ansiToHtml } from "./ansi-to-html.js";
|
|
51
|
+
export { renderTranscriptHtml } from "./tool-renderer.js";
|