@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,18 +1,24 @@
|
|
|
1
|
+
import { performance } from "node:perf_hooks";
|
|
1
2
|
import type { ClioSettings } from "../core/config.js";
|
|
2
3
|
import type { SafeEventBus } from "../core/event-bus.js";
|
|
3
4
|
import type { ContextState } from "../domains/context/index.js";
|
|
4
5
|
import type { DispatchContract } from "../domains/dispatch/contract.js";
|
|
5
6
|
import type { TaskMemoryOperatorStatus } from "../domains/memory/index.js";
|
|
6
|
-
import type {
|
|
7
|
+
import type {
|
|
8
|
+
ObservabilityContract,
|
|
9
|
+
ObservabilitySnapshot,
|
|
10
|
+
TokenThroughputSnapshot,
|
|
11
|
+
} from "../domains/observability/index.js";
|
|
7
12
|
import { type ProvidersContract, resolveModelRuntimeCapabilitiesForProviders } from "../domains/providers/index.js";
|
|
8
13
|
import type { ResourcesContract } from "../domains/resources/index.js";
|
|
9
14
|
import { getMarketplaceSkills } from "../domains/resources/skills/marketplace.js";
|
|
15
|
+
import { ceilChars, contentChars } from "../domains/session/context-accounting.js";
|
|
10
16
|
import type { SessionContract, TaskBoardSnapshot } from "../domains/session/index.js";
|
|
11
17
|
import type { Component, TUI } from "../engine/tui.js";
|
|
12
|
-
import type { ChatLoop } from "./chat-loop.js";
|
|
18
|
+
import type { ChatLoop, ChatLoopEvent } from "./chat-loop.js";
|
|
13
19
|
import { type ChatPanel, createChatPanel } from "./chat-panel.js";
|
|
14
20
|
import { type CoalescingChatRenderer, createCoalescingChatRenderer } from "./chat-renderer.js";
|
|
15
|
-
import { ClioEditor } from "./clio-editor.js";
|
|
21
|
+
import { ClioEditor, type EditorChrome } from "./clio-editor.js";
|
|
16
22
|
import { createCommandOutputRunIo } from "./command-output.js";
|
|
17
23
|
import { createContextActivityStore } from "./context-activity.js";
|
|
18
24
|
import { createDispatchBoardStore, createDispatchBoardView, type DispatchBoardView } from "./dispatch-board.js";
|
|
@@ -29,6 +35,8 @@ import type { SessionTranscript } from "./session-transcript.js";
|
|
|
29
35
|
import { createSlashCommandAutocompleteProvider } from "./slash-autocomplete.js";
|
|
30
36
|
import { parseSlashCommand, type RunIo } from "./slash-commands.js";
|
|
31
37
|
import { createStatusController, type StatusController, type TurnSummary } from "./status/index.js";
|
|
38
|
+
import type { SmoothStreamingMode } from "./stream-pacer.js";
|
|
39
|
+
import { processAutoPacingAllowed, resolveSmoothStreamingMode } from "./stream-pacing-policy.js";
|
|
32
40
|
import { formatTargetLabel } from "./theme/index.js";
|
|
33
41
|
import { createWelcomeDashboard, type WelcomeDashboardComponent } from "./welcome-dashboard.js";
|
|
34
42
|
import type { WorkspaceFacts } from "./workspace-facts.js";
|
|
@@ -69,7 +77,13 @@ export interface InteractivePresentationDeps {
|
|
|
69
77
|
sessionTranscript: Pick<SessionTranscript, "liveSessionTurns">;
|
|
70
78
|
tui: TUI;
|
|
71
79
|
terminal: { readonly columns: number };
|
|
72
|
-
mount
|
|
80
|
+
mount?: (root: Component, editor: Component) => void;
|
|
81
|
+
/** Stage 0's exact editor; when present no replacement editor is constructed. */
|
|
82
|
+
editor?: ClioEditor;
|
|
83
|
+
/** Stage 0's already-installed keybinding manager and pi-tui global. */
|
|
84
|
+
keybindings?: ClioKeybindingManager;
|
|
85
|
+
/** Pending boot submissions remain visible until serial admission removes them. */
|
|
86
|
+
bootPending?: Component;
|
|
73
87
|
getSettings?: () => Readonly<ClioSettings>;
|
|
74
88
|
resources?: Pick<ResourcesContract, "skills">;
|
|
75
89
|
session?: Pick<SessionContract, "current">;
|
|
@@ -80,9 +94,19 @@ export interface InteractivePresentationDeps {
|
|
|
80
94
|
getContextState?: (cwd?: string) => ContextState;
|
|
81
95
|
/** Whether the Ctrl+G leader is armed and waiting for its next key. */
|
|
82
96
|
getLeaderArmed?: () => boolean;
|
|
97
|
+
/** Whether a Ctrl+C armed the double tap and its window is still open. */
|
|
98
|
+
getShutdownArmed?: () => boolean;
|
|
83
99
|
getCwd?: () => string;
|
|
100
|
+
resolveVisibleEventSequence?: (event: ChatLoopEvent) => number | null;
|
|
101
|
+
resolveStreamIngress?: (
|
|
102
|
+
event: ChatLoopEvent,
|
|
103
|
+
) => { sequence: number; generation: string | number; ingressAt: number } | null;
|
|
104
|
+
commitFrame?: (reason?: string) => Promise<unknown>;
|
|
105
|
+
hasObservedBackpressure?: () => boolean;
|
|
106
|
+
onSmoothStreamingMode?: (mode: SmoothStreamingMode, pacingActive: boolean) => void;
|
|
84
107
|
scheduleInterval?: (callback: () => void, intervalMs: number) => PresentationTickerHandle;
|
|
85
108
|
clearScheduledInterval?: (handle: PresentationTickerHandle) => void;
|
|
109
|
+
now?: () => number;
|
|
86
110
|
factories?: Partial<InteractivePresentationFactories>;
|
|
87
111
|
}
|
|
88
112
|
|
|
@@ -107,11 +131,14 @@ export interface InteractivePresentation {
|
|
|
107
131
|
announceTaskMemorySeedOffer(): void;
|
|
108
132
|
collapseWelcomeDashboard(): void;
|
|
109
133
|
editor: ClioEditor;
|
|
134
|
+
editorChrome: EditorChrome;
|
|
110
135
|
dispatchBoard: DispatchBoardView;
|
|
111
136
|
chatRenderer: CoalescingChatRenderer;
|
|
112
137
|
io: RunIo;
|
|
113
138
|
root: Component;
|
|
114
139
|
getObservabilitySnapshot(): ObservabilitySnapshot;
|
|
140
|
+
/** Fold one raw chat event into the ephemeral throughput shown only while this turn is active. */
|
|
141
|
+
recordChatEvent(event: ChatLoopEvent): void;
|
|
115
142
|
recordToolStart(toolCallId: string, toolName: string): void;
|
|
116
143
|
recordToolEnd(result: PresentationToolEnd): void;
|
|
117
144
|
setLastTurnSummary(summary: TurnSummary | null): void;
|
|
@@ -175,9 +202,10 @@ function willEnterSteerActiveWork(deps: InteractivePresentationDeps, text: strin
|
|
|
175
202
|
export function createInteractivePresentation(deps: InteractivePresentationDeps): InteractivePresentation {
|
|
176
203
|
const factories = { ...DEFAULT_FACTORIES, ...deps.factories };
|
|
177
204
|
const getCwd = deps.getCwd ?? (() => process.cwd());
|
|
205
|
+
const now = deps.now ?? performance.now.bind(performance);
|
|
178
206
|
const requestRender = (): void => deps.tui.requestRender();
|
|
179
207
|
const settings = deps.getSettings?.() ?? ({ keybindings: {} } as ClioSettings);
|
|
180
|
-
const keybindings = factories.createKeybindings(settings);
|
|
208
|
+
const keybindings = deps.keybindings ?? factories.createKeybindings(settings);
|
|
181
209
|
const { getExtensionStats, getLiveWorkspaceSnapshot, getWorkspaceSnapshot, refreshLiveWorkspaceGit } =
|
|
182
210
|
deps.workspaceFacts;
|
|
183
211
|
|
|
@@ -223,6 +251,69 @@ export function createInteractivePresentation(deps: InteractivePresentationDeps)
|
|
|
223
251
|
let footerToolTruncatedResults = 0;
|
|
224
252
|
let lastTurnSummary: TurnSummary | null = null;
|
|
225
253
|
let observabilitySnapshot = deps.observability.snapshot();
|
|
254
|
+
let liveThroughput: {
|
|
255
|
+
startedAt: number;
|
|
256
|
+
firstDeltaAt: number | null;
|
|
257
|
+
settledOutputTokens: number;
|
|
258
|
+
partialOutputTokens: number;
|
|
259
|
+
} | null = null;
|
|
260
|
+
const recordChatEvent = (event: ChatLoopEvent): void => {
|
|
261
|
+
if (event.type === "agent_start") {
|
|
262
|
+
liveThroughput = {
|
|
263
|
+
startedAt: now(),
|
|
264
|
+
firstDeltaAt: null,
|
|
265
|
+
settledOutputTokens: 0,
|
|
266
|
+
partialOutputTokens: 0,
|
|
267
|
+
};
|
|
268
|
+
return;
|
|
269
|
+
}
|
|
270
|
+
if (event.type === "agent_end") {
|
|
271
|
+
liveThroughput = null;
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
if (!liveThroughput) return;
|
|
275
|
+
if (event.type === "message_start" && event.message?.role === "assistant") {
|
|
276
|
+
liveThroughput.partialOutputTokens = 0;
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
if (event.type === "message_update") {
|
|
280
|
+
const update = event.assistantMessageEvent as { type?: unknown; partial?: { content?: unknown; payload?: unknown } };
|
|
281
|
+
if (
|
|
282
|
+
update.type !== "text_delta" &&
|
|
283
|
+
update.type !== "thinking_delta" &&
|
|
284
|
+
update.type !== "toolcall_start" &&
|
|
285
|
+
update.type !== "toolcall_delta"
|
|
286
|
+
) {
|
|
287
|
+
return;
|
|
288
|
+
}
|
|
289
|
+
liveThroughput.firstDeltaAt ??= now();
|
|
290
|
+
liveThroughput.partialOutputTokens = ceilChars(contentChars(update.partial?.payload ?? update.partial?.content));
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
293
|
+
if (event.type === "message_end" && event.message?.role === "assistant") {
|
|
294
|
+
const output = (event.message as { usage?: { output?: unknown } }).usage?.output;
|
|
295
|
+
const reported = typeof output === "number" && Number.isFinite(output) && output > 0 ? output : null;
|
|
296
|
+
liveThroughput.settledOutputTokens += reported ?? liveThroughput.partialOutputTokens;
|
|
297
|
+
liveThroughput.partialOutputTokens = 0;
|
|
298
|
+
}
|
|
299
|
+
};
|
|
300
|
+
const currentLiveThroughput = (): TokenThroughputSnapshot | null => {
|
|
301
|
+
if (!liveThroughput || liveThroughput.firstDeltaAt === null) return null;
|
|
302
|
+
const outputTokens = liveThroughput.settledOutputTokens + liveThroughput.partialOutputTokens;
|
|
303
|
+
if (outputTokens <= 0) return null;
|
|
304
|
+
const at = now();
|
|
305
|
+
const durationMs = Math.max(1, at - liveThroughput.firstDeltaAt);
|
|
306
|
+
const settings = deps.getSettings?.();
|
|
307
|
+
return {
|
|
308
|
+
tokensPerSecond: outputTokens / (durationMs / 1000),
|
|
309
|
+
outputTokens,
|
|
310
|
+
durationMs,
|
|
311
|
+
ttftMs: Math.max(0, liveThroughput.firstDeltaAt - liveThroughput.startedAt),
|
|
312
|
+
providerId: settings?.orchestrator?.target ?? "",
|
|
313
|
+
modelId: settings?.orchestrator?.model ?? "",
|
|
314
|
+
recordedAt: Date.now(),
|
|
315
|
+
};
|
|
316
|
+
};
|
|
226
317
|
let footer: FooterDashboardPanel;
|
|
227
318
|
const notifications = factories.createNotificationCenter({
|
|
228
319
|
onChange: () => {
|
|
@@ -256,7 +347,8 @@ export function createInteractivePresentation(deps: InteractivePresentationDeps)
|
|
|
256
347
|
getAgentStatus: () => statusController.current(),
|
|
257
348
|
getTerminalColumns: () => deps.terminal.columns,
|
|
258
349
|
getSessionTokens: () => observabilitySnapshot.session.tokens,
|
|
259
|
-
getTokenThroughput: () =>
|
|
350
|
+
getTokenThroughput: () =>
|
|
351
|
+
liveThroughput === null ? observabilitySnapshot.session.latestThroughput : currentLiveThroughput(),
|
|
260
352
|
getSessionCost: () => observabilitySnapshot.session.cost,
|
|
261
353
|
getContextUsage: () => deps.chat.contextUsage(),
|
|
262
354
|
getContextLedger: () => deps.chat.contextLedger(),
|
|
@@ -265,6 +357,7 @@ export function createInteractivePresentation(deps: InteractivePresentationDeps)
|
|
|
265
357
|
...(deps.getTaskMemoryStatus ? { getTaskMemoryStatus: deps.getTaskMemoryStatus } : {}),
|
|
266
358
|
getContextActivity: () => contextActivityStore.current(),
|
|
267
359
|
...(deps.getLeaderArmed ? { getLeaderArmed: deps.getLeaderArmed } : {}),
|
|
360
|
+
...(deps.getShutdownArmed ? { getShutdownArmed: deps.getShutdownArmed } : {}),
|
|
268
361
|
getToolCounts: () => ({
|
|
269
362
|
tools: Object.fromEntries(footerToolCounts),
|
|
270
363
|
errors: footerToolErrors,
|
|
@@ -295,7 +388,7 @@ export function createInteractivePresentation(deps: InteractivePresentationDeps)
|
|
|
295
388
|
requestRender();
|
|
296
389
|
});
|
|
297
390
|
|
|
298
|
-
const
|
|
391
|
+
const editorChrome: EditorChrome = {
|
|
299
392
|
getModelLabel: () => {
|
|
300
393
|
const current = deps.getSettings?.();
|
|
301
394
|
// The rail is the narrowest of the three, so it drops the spaces.
|
|
@@ -318,7 +411,8 @@ export function createInteractivePresentation(deps: InteractivePresentationDeps)
|
|
|
318
411
|
willEnterSteer: (text) => willEnterSteerActiveWork(deps, text),
|
|
319
412
|
getSubmitKeyLabel: () => formatKeyLabel(keybindings.getKeys("tui.input.submit")[0], "Enter"),
|
|
320
413
|
getNewlineKeyLabel: () => formatKeyLabel(keybindings.getKeys("tui.input.newLine")[0], "Shift+Enter"),
|
|
321
|
-
}
|
|
414
|
+
};
|
|
415
|
+
const editor = deps.editor ?? factories.createEditor(deps.tui, editorChrome);
|
|
322
416
|
editor.focused = true;
|
|
323
417
|
const autocomplete: AutocompleteProvider = factories.createAutocomplete({
|
|
324
418
|
listSkills: () => ({
|
|
@@ -335,20 +429,55 @@ export function createInteractivePresentation(deps: InteractivePresentationDeps)
|
|
|
335
429
|
const chatRenderer = factories.createChatRenderer({
|
|
336
430
|
chatPanel,
|
|
337
431
|
requestRender,
|
|
338
|
-
...(
|
|
432
|
+
...(deps.resolveStreamIngress && deps.getSettings
|
|
433
|
+
? {
|
|
434
|
+
streamIngress: deps.resolveStreamIngress,
|
|
435
|
+
getSmoothStreamingMode: () => {
|
|
436
|
+
const mode = resolveSmoothStreamingMode(deps.getSettings?.().terminal.smoothStreaming ?? "off");
|
|
437
|
+
const autoAllowed = processAutoPacingAllowed(deps.hasObservedBackpressure?.() ?? false);
|
|
438
|
+
deps.onSmoothStreamingMode?.(mode, mode === "on" || (mode === "auto" && autoAllowed));
|
|
439
|
+
return mode;
|
|
440
|
+
},
|
|
441
|
+
isAutoPacingAllowed: () => processAutoPacingAllowed(deps.hasObservedBackpressure?.() ?? false),
|
|
442
|
+
...(deps.commitFrame ? { commitFrame: deps.commitFrame } : {}),
|
|
443
|
+
}
|
|
444
|
+
: {}),
|
|
445
|
+
...(renderTrace
|
|
446
|
+
? {
|
|
447
|
+
visibleEventSequence: (event) => deps.resolveVisibleEventSequence?.(event) ?? null,
|
|
448
|
+
onQueue: (eventSeq, action) => renderTrace.recordQueue(eventSeq, action),
|
|
449
|
+
onPanelApplied: (eventSeq) => renderTrace.recordPanelApplied(eventSeq),
|
|
450
|
+
}
|
|
451
|
+
: {}),
|
|
339
452
|
});
|
|
340
453
|
const io = factories.createIo({
|
|
341
|
-
appendReplayBlock: (renderBlock) =>
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
const root = factories.buildLayout({
|
|
345
|
-
banner,
|
|
346
|
-
chat: chatPanel,
|
|
347
|
-
pending: followUpQueuePanel,
|
|
348
|
-
editor,
|
|
349
|
-
footer: footer.view,
|
|
454
|
+
appendReplayBlock: (renderBlock) =>
|
|
455
|
+
chatRenderer.mutate(() => chatPanel.appendReplayBlock(renderBlock), "command-output"),
|
|
456
|
+
requestRender: () => {},
|
|
350
457
|
});
|
|
351
|
-
deps.
|
|
458
|
+
const pending: Component = deps.bootPending
|
|
459
|
+
? {
|
|
460
|
+
render: (width) => [...(deps.bootPending?.render(width) ?? []), ...followUpQueuePanel.render(width)],
|
|
461
|
+
invalidate: () => {
|
|
462
|
+
deps.bootPending?.invalidate();
|
|
463
|
+
followUpQueuePanel.invalidate();
|
|
464
|
+
},
|
|
465
|
+
}
|
|
466
|
+
: followUpQueuePanel;
|
|
467
|
+
const root = factories.buildLayout(
|
|
468
|
+
{
|
|
469
|
+
banner,
|
|
470
|
+
chat: chatPanel,
|
|
471
|
+
pending,
|
|
472
|
+
editor,
|
|
473
|
+
footer: footer.view,
|
|
474
|
+
},
|
|
475
|
+
{
|
|
476
|
+
mode: settings.terminal?.tuiMode ?? "regular",
|
|
477
|
+
fullscreenScrollbar: settings.terminal?.fullscreenScrollbar ?? "auto",
|
|
478
|
+
},
|
|
479
|
+
);
|
|
480
|
+
deps.mount?.(root, editor);
|
|
352
481
|
|
|
353
482
|
const scheduleInterval = deps.scheduleInterval ?? ((callback, intervalMs) => setInterval(callback, intervalMs));
|
|
354
483
|
const clearScheduledInterval =
|
|
@@ -414,11 +543,13 @@ export function createInteractivePresentation(deps: InteractivePresentationDeps)
|
|
|
414
543
|
if (banner.collapseToSessionHeader()) requestRender();
|
|
415
544
|
},
|
|
416
545
|
editor,
|
|
546
|
+
editorChrome,
|
|
417
547
|
dispatchBoard,
|
|
418
548
|
chatRenderer,
|
|
419
549
|
io,
|
|
420
550
|
root,
|
|
421
551
|
getObservabilitySnapshot: () => observabilitySnapshot,
|
|
552
|
+
recordChatEvent,
|
|
422
553
|
recordToolStart: (toolCallId, toolName) => {
|
|
423
554
|
footerActiveTools.add(toolCallId);
|
|
424
555
|
footerToolCounts.set(toolName, (footerToolCounts.get(toolName) ?? 0) + 1);
|
|
@@ -438,6 +569,7 @@ export function createInteractivePresentation(deps: InteractivePresentationDeps)
|
|
|
438
569
|
footerToolErrors = 0;
|
|
439
570
|
footerToolTruncatedResults = 0;
|
|
440
571
|
lastTurnSummary = null;
|
|
572
|
+
liveThroughput = null;
|
|
441
573
|
statusController.reset();
|
|
442
574
|
},
|
|
443
575
|
stopTickers,
|
|
@@ -1,13 +1,25 @@
|
|
|
1
|
-
import type { Component, Terminal } from "../engine/tui.js";
|
|
2
|
-
import { ProcessTerminal, TUI } from "../engine/tui.js";
|
|
3
|
-
import {
|
|
1
|
+
import type { Component, Terminal, TuiMode, TuiRenderObserver } from "../engine/tui.js";
|
|
2
|
+
import { InstrumentedTuiAltScreen, InstrumentedTuiMainScreen, ProcessTerminal, type TUI } from "../engine/tui.js";
|
|
3
|
+
import {
|
|
4
|
+
createRenderTrace,
|
|
5
|
+
type RenderTrace,
|
|
6
|
+
renderTracePath,
|
|
7
|
+
traceComponentRenders,
|
|
8
|
+
traceProcessStdout,
|
|
9
|
+
} from "./render-trace.js";
|
|
10
|
+
import type { StdoutBackpressureGate } from "./stdout-backpressure.js";
|
|
11
|
+
import { installStdoutBackpressureGate } from "./stdout-backpressure.js";
|
|
4
12
|
|
|
5
13
|
export interface InteractiveShellTui {
|
|
14
|
+
readonly mode?: TuiMode;
|
|
6
15
|
addChild(component: Component): void;
|
|
16
|
+
removeChild?(component: Component): void;
|
|
17
|
+
setLayoutRoot?(component: Component | undefined): void;
|
|
7
18
|
setFocus(component: Component): void;
|
|
8
19
|
start(): void;
|
|
9
20
|
stop(): void;
|
|
10
21
|
requestRender(): void;
|
|
22
|
+
renderNow?(force?: boolean): void;
|
|
11
23
|
}
|
|
12
24
|
|
|
13
25
|
export interface InteractiveShellInterval {
|
|
@@ -22,6 +34,8 @@ export interface InteractiveShellDeps<
|
|
|
22
34
|
createTui: (terminal: TTerminal) => TTui;
|
|
23
35
|
scheduleInterval?: (callback: () => void, intervalMs: number) => InteractiveShellInterval;
|
|
24
36
|
clearScheduledInterval?: (handle: InteractiveShellInterval) => void;
|
|
37
|
+
prepareRoot?: (root: Component) => void;
|
|
38
|
+
onStop?: () => void | Promise<void>;
|
|
25
39
|
}
|
|
26
40
|
|
|
27
41
|
export interface InteractiveShell<
|
|
@@ -34,6 +48,16 @@ export interface InteractiveShell<
|
|
|
34
48
|
anchor(): Promise<number>;
|
|
35
49
|
releaseAnchor(): void;
|
|
36
50
|
stop(): void;
|
|
51
|
+
/** Issue the latest model frame and wait a finite bound for stdout drain. */
|
|
52
|
+
commitCurrentFrame(timeoutMs?: number): Promise<number | null>;
|
|
53
|
+
/** True after this process has observed stdout saturation at least once. */
|
|
54
|
+
hasObservedBackpressure(): boolean;
|
|
55
|
+
/** Enable admission control only while presentation pacing is actually active. */
|
|
56
|
+
setStreamPacingActive(active: boolean): void;
|
|
57
|
+
/** Await asynchronous teardown work started by stop(), including trace-file settlement. */
|
|
58
|
+
settle(): Promise<void>;
|
|
59
|
+
/** Resolve after the next render transaction that reaches terminal commit. */
|
|
60
|
+
nextCommittedFrame(): Promise<number | null>;
|
|
37
61
|
complete(code: number): void;
|
|
38
62
|
}
|
|
39
63
|
|
|
@@ -62,6 +86,8 @@ export function createInteractiveShell<TTerminal extends Terminal, TTui extends
|
|
|
62
86
|
let resolveRun: ((code: number) => void) | null = null;
|
|
63
87
|
let run: Promise<number> | null = null;
|
|
64
88
|
let completedCode: number | null = null;
|
|
89
|
+
let stopped = false;
|
|
90
|
+
let stopSettlement: Promise<void> | null = null;
|
|
65
91
|
|
|
66
92
|
return {
|
|
67
93
|
terminal,
|
|
@@ -69,7 +95,9 @@ export function createInteractiveShell<TTerminal extends Terminal, TTui extends
|
|
|
69
95
|
mount(root, focus): void {
|
|
70
96
|
if (mounted) return;
|
|
71
97
|
mounted = true;
|
|
98
|
+
deps.prepareRoot?.(root);
|
|
72
99
|
tui.addChild(root);
|
|
100
|
+
if (tui.mode === "fullscreen") tui.setLayoutRoot?.(root);
|
|
73
101
|
tui.setFocus(focus);
|
|
74
102
|
tui.start();
|
|
75
103
|
},
|
|
@@ -90,12 +118,37 @@ export function createInteractiveShell<TTerminal extends Terminal, TTui extends
|
|
|
90
118
|
keepAlive = null;
|
|
91
119
|
},
|
|
92
120
|
stop(): void {
|
|
121
|
+
if (stopped) return;
|
|
122
|
+
stopped = true;
|
|
93
123
|
try {
|
|
94
124
|
tui.stop();
|
|
95
125
|
} catch {
|
|
96
126
|
// TUI may already be stopped by a closed input stream.
|
|
127
|
+
} finally {
|
|
128
|
+
try {
|
|
129
|
+
stopSettlement = Promise.resolve(deps.onStop?.()).then(() => undefined);
|
|
130
|
+
} catch {
|
|
131
|
+
// Teardown is best effort, like a terminal that already closed.
|
|
132
|
+
stopSettlement = Promise.resolve();
|
|
133
|
+
}
|
|
97
134
|
}
|
|
98
135
|
},
|
|
136
|
+
async commitCurrentFrame(): Promise<number | null> {
|
|
137
|
+
if (!tui.renderNow) {
|
|
138
|
+
tui.requestRender();
|
|
139
|
+
return null;
|
|
140
|
+
}
|
|
141
|
+
tui.renderNow(false);
|
|
142
|
+
return null;
|
|
143
|
+
},
|
|
144
|
+
hasObservedBackpressure: () => false,
|
|
145
|
+
setStreamPacingActive: () => {},
|
|
146
|
+
settle(): Promise<void> {
|
|
147
|
+
return stopSettlement ?? Promise.resolve();
|
|
148
|
+
},
|
|
149
|
+
nextCommittedFrame(): Promise<number | null> {
|
|
150
|
+
return Promise.resolve(null);
|
|
151
|
+
},
|
|
99
152
|
complete(code): void {
|
|
100
153
|
if (completedCode !== null) return;
|
|
101
154
|
completedCode = code;
|
|
@@ -115,20 +168,221 @@ export function getActiveRenderTrace(): RenderTrace | null {
|
|
|
115
168
|
return activeRenderTrace;
|
|
116
169
|
}
|
|
117
170
|
|
|
171
|
+
/**
|
|
172
|
+
* Wait for ordinary admission, but never let a missing drain erase the final
|
|
173
|
+
* model state. After the finite pre-render bound, exactly one caller-supplied
|
|
174
|
+
* final frame is still issued; a post-render drain wait is likewise bounded.
|
|
175
|
+
*/
|
|
176
|
+
export async function settleLatestInteractiveFrame(
|
|
177
|
+
gate: Pick<StdoutBackpressureGate, "whenWritable"> | null,
|
|
178
|
+
timeoutMs: number,
|
|
179
|
+
renderFrame: () => Promise<number>,
|
|
180
|
+
): Promise<number> {
|
|
181
|
+
const writableBeforeRender = gate ? await gate.whenWritable(timeoutMs) : true;
|
|
182
|
+
const frameId = await renderFrame();
|
|
183
|
+
if (writableBeforeRender && gate) await gate.whenWritable(timeoutMs);
|
|
184
|
+
return frameId;
|
|
185
|
+
}
|
|
186
|
+
|
|
118
187
|
/** Production factories stay here so the composition root does not own them. */
|
|
119
|
-
export function createProcessInteractiveShell(
|
|
188
|
+
export function createProcessInteractiveShell(
|
|
189
|
+
options: {
|
|
190
|
+
tuiMode?: TuiMode;
|
|
191
|
+
onFirstFrameCommit?: (frameId: number) => void;
|
|
192
|
+
streamPacingActive?: boolean;
|
|
193
|
+
/** Construction fault seams for process-global rollback contracts. */
|
|
194
|
+
testing?: {
|
|
195
|
+
createTerminal?: () => ProcessTerminal;
|
|
196
|
+
createTui?: (terminal: ProcessTerminal) => TUI;
|
|
197
|
+
};
|
|
198
|
+
} = {},
|
|
199
|
+
): InteractiveShell<ProcessTerminal, TUI> {
|
|
120
200
|
const tracePath = renderTracePath();
|
|
201
|
+
let restoreStdout: (() => void) | null = null;
|
|
202
|
+
let restoreFirstFrameStdout: (() => void) | null = null;
|
|
203
|
+
let restoreRoot: (() => void) | null = null;
|
|
204
|
+
let backpressure: StdoutBackpressureGate | null = null;
|
|
205
|
+
let observedBackpressure = false;
|
|
121
206
|
if (tracePath) {
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
207
|
+
let candidate: RenderTrace | null = null;
|
|
208
|
+
try {
|
|
209
|
+
candidate = createRenderTrace(tracePath);
|
|
210
|
+
restoreStdout = traceProcessStdout(candidate);
|
|
211
|
+
activeRenderTrace = candidate;
|
|
212
|
+
} catch {
|
|
213
|
+
// A diagnostics path must never prevent the interactive application from starting.
|
|
214
|
+
restoreStdout?.();
|
|
215
|
+
restoreStdout = null;
|
|
216
|
+
void candidate?.close().catch(() => {});
|
|
217
|
+
activeRenderTrace = null;
|
|
218
|
+
}
|
|
219
|
+
} else activeRenderTrace = null;
|
|
126
220
|
const trace = activeRenderTrace;
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
221
|
+
if (trace && options.onFirstFrameCommit) trace.onFirstFrameCommit(options.onFirstFrameCommit);
|
|
222
|
+
let firstFrameDelivered = false;
|
|
223
|
+
let firstFrameSeq = 0;
|
|
224
|
+
let firstFrameActive = false;
|
|
225
|
+
let firstFrameWrote = false;
|
|
226
|
+
if (!trace && options.onFirstFrameCommit) {
|
|
227
|
+
const stdout = process.stdout;
|
|
228
|
+
const original = stdout.write;
|
|
229
|
+
const wrapped = function (this: typeof stdout, ...args: unknown[]): boolean {
|
|
230
|
+
const returned = Reflect.apply(original, this, args) as boolean;
|
|
231
|
+
if (firstFrameActive) firstFrameWrote = true;
|
|
232
|
+
return returned;
|
|
233
|
+
} as typeof stdout.write;
|
|
234
|
+
stdout.write = wrapped;
|
|
235
|
+
restoreFirstFrameStdout = () => {
|
|
236
|
+
if (stdout.write === wrapped) stdout.write = original;
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
const firstFrameOnlyObserver: TuiRenderObserver = {
|
|
240
|
+
isEnabled: () => !firstFrameDelivered,
|
|
241
|
+
beginFrame: () => {
|
|
242
|
+
firstFrameSeq += 1;
|
|
243
|
+
firstFrameActive = true;
|
|
244
|
+
firstFrameWrote = false;
|
|
245
|
+
return firstFrameSeq;
|
|
246
|
+
},
|
|
247
|
+
endFrame: (frame) => {
|
|
248
|
+
firstFrameActive = false;
|
|
249
|
+
if (firstFrameDelivered || !firstFrameWrote) return;
|
|
250
|
+
firstFrameDelivered = true;
|
|
251
|
+
options.onFirstFrameCommit?.(frame as number);
|
|
252
|
+
restoreFirstFrameStdout?.();
|
|
253
|
+
restoreFirstFrameStdout = null;
|
|
254
|
+
},
|
|
255
|
+
beginPhase: () => null,
|
|
256
|
+
endPhase: () => {},
|
|
257
|
+
};
|
|
258
|
+
const primaryObserver = trace ?? (options.onFirstFrameCommit ? firstFrameOnlyObserver : null);
|
|
259
|
+
let committedFrameSequence = 0;
|
|
260
|
+
const frameWaiters: Array<{ resolve: (frameId: number) => void }> = [];
|
|
261
|
+
const renderObserver: TuiRenderObserver = {
|
|
262
|
+
isEnabled: () => frameWaiters.length > 0 || (primaryObserver !== null && (primaryObserver.isEnabled?.() ?? true)),
|
|
263
|
+
beginFrame: (fields) => ({
|
|
264
|
+
primary: primaryObserver?.beginFrame(fields),
|
|
265
|
+
primaryActive: primaryObserver !== null && (primaryObserver.isEnabled?.() ?? true),
|
|
266
|
+
frameId: ++committedFrameSequence,
|
|
267
|
+
}),
|
|
268
|
+
endFrame: (token) => {
|
|
269
|
+
const frame = token as { primary: unknown; primaryActive: boolean; frameId: number };
|
|
270
|
+
if (frame.primaryActive) primaryObserver?.endFrame(frame.primary);
|
|
271
|
+
for (const waiter of frameWaiters.splice(0)) waiter.resolve(frame.frameId);
|
|
272
|
+
},
|
|
273
|
+
beginPhase: (token, phase) => {
|
|
274
|
+
const frame = token as { primary: unknown; primaryActive: boolean };
|
|
275
|
+
return frame.primaryActive ? primaryObserver?.beginPhase(frame.primary, phase) : null;
|
|
131
276
|
},
|
|
132
|
-
|
|
133
|
-
|
|
277
|
+
endPhase: (token, phase, phaseToken) => {
|
|
278
|
+
const frame = token as { primary: unknown; primaryActive: boolean };
|
|
279
|
+
if (frame.primaryActive) primaryObserver?.endPhase(frame.primary, phase, phaseToken);
|
|
280
|
+
},
|
|
281
|
+
};
|
|
282
|
+
const renderAdmission = {
|
|
283
|
+
get blocked() {
|
|
284
|
+
return backpressure?.blocked ?? false;
|
|
285
|
+
},
|
|
286
|
+
onWritable(listener: () => void) {
|
|
287
|
+
if (backpressure) return backpressure.onWritable(listener);
|
|
288
|
+
queueMicrotask(listener);
|
|
289
|
+
return () => {};
|
|
290
|
+
},
|
|
291
|
+
};
|
|
292
|
+
const setStreamPacingActive = (active: boolean): void => {
|
|
293
|
+
if (active) {
|
|
294
|
+
backpressure ??= installStdoutBackpressureGate();
|
|
295
|
+
return;
|
|
296
|
+
}
|
|
297
|
+
if (!backpressure) return;
|
|
298
|
+
observedBackpressure ||= backpressure.observed;
|
|
299
|
+
backpressure.restore();
|
|
300
|
+
backpressure = null;
|
|
301
|
+
};
|
|
302
|
+
let instrumentationCleanupStarted = false;
|
|
303
|
+
let instrumentationCleanupPromise: Promise<void> = Promise.resolve();
|
|
304
|
+
const cleanupInstrumentation = (): Promise<void> => {
|
|
305
|
+
if (instrumentationCleanupStarted) return instrumentationCleanupPromise;
|
|
306
|
+
instrumentationCleanupStarted = true;
|
|
307
|
+
const errors: unknown[] = [];
|
|
308
|
+
const attempt = (operation: () => void): void => {
|
|
309
|
+
try {
|
|
310
|
+
operation();
|
|
311
|
+
} catch (error) {
|
|
312
|
+
errors.push(error);
|
|
313
|
+
}
|
|
314
|
+
};
|
|
315
|
+
attempt(() => setStreamPacingActive(false));
|
|
316
|
+
attempt(() => restoreRoot?.());
|
|
317
|
+
restoreRoot = null;
|
|
318
|
+
attempt(() => restoreStdout?.());
|
|
319
|
+
restoreStdout = null;
|
|
320
|
+
attempt(() => restoreFirstFrameStdout?.());
|
|
321
|
+
restoreFirstFrameStdout = null;
|
|
322
|
+
if (activeRenderTrace === trace) activeRenderTrace = null;
|
|
323
|
+
instrumentationCleanupPromise = (async () => {
|
|
324
|
+
if (trace) {
|
|
325
|
+
try {
|
|
326
|
+
await trace.close();
|
|
327
|
+
} catch (error) {
|
|
328
|
+
errors.push(error);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
if (errors.length > 0) throw new AggregateError(errors, "interactive shell instrumentation cleanup failed");
|
|
332
|
+
})();
|
|
333
|
+
return instrumentationCleanupPromise;
|
|
334
|
+
};
|
|
335
|
+
let shell: InteractiveShell<ProcessTerminal, TUI>;
|
|
336
|
+
try {
|
|
337
|
+
setStreamPacingActive(options.streamPacingActive === true);
|
|
338
|
+
shell = createInteractiveShell({
|
|
339
|
+
createTerminal: options.testing?.createTerminal ?? (() => new ProcessTerminal()),
|
|
340
|
+
createTui: (terminal) =>
|
|
341
|
+
options.testing?.createTui?.(terminal) ??
|
|
342
|
+
(options.tuiMode === "fullscreen"
|
|
343
|
+
? new InstrumentedTuiAltScreen(terminal, renderObserver, undefined, undefined, undefined, renderAdmission)
|
|
344
|
+
: new InstrumentedTuiMainScreen(terminal, renderObserver, undefined, undefined, renderAdmission)),
|
|
345
|
+
prepareRoot: (root) => {
|
|
346
|
+
if (trace) restoreRoot = traceComponentRenders(root, trace);
|
|
347
|
+
},
|
|
348
|
+
onStop: cleanupInstrumentation,
|
|
349
|
+
});
|
|
350
|
+
} catch (error) {
|
|
351
|
+
void cleanupInstrumentation().catch(() => {});
|
|
352
|
+
throw error;
|
|
353
|
+
}
|
|
354
|
+
return {
|
|
355
|
+
...shell,
|
|
356
|
+
nextCommittedFrame(): Promise<number | null> {
|
|
357
|
+
return new Promise<number>((resolve) => {
|
|
358
|
+
frameWaiters.push({ resolve });
|
|
359
|
+
});
|
|
360
|
+
},
|
|
361
|
+
async commitCurrentFrame(timeoutMs = 30_000): Promise<number | null> {
|
|
362
|
+
return await settleLatestInteractiveFrame(backpressure, timeoutMs, async () => {
|
|
363
|
+
const tui = shell.tui as TUI & { renderNow(force?: boolean): void };
|
|
364
|
+
const waiter: { resolve: (frameId: number) => void } = { resolve: () => {} };
|
|
365
|
+
const frame = new Promise<number>((resolve) => {
|
|
366
|
+
waiter.resolve = resolve;
|
|
367
|
+
frameWaiters.push(waiter);
|
|
368
|
+
});
|
|
369
|
+
try {
|
|
370
|
+
// Even when the writable never drains, issue exactly one bounded
|
|
371
|
+
// final frame. Preserve the renderer's cursor/history state: forcing
|
|
372
|
+
// a reset here makes TuiMainScreen repaint from the current physical
|
|
373
|
+
// column and can concatenate the full frame onto the footer. A direct
|
|
374
|
+
// differential render is still synchronous and commits every newest
|
|
375
|
+
// component mutation without reopening ordinary frame production.
|
|
376
|
+
tui.renderNow(false);
|
|
377
|
+
} catch (error) {
|
|
378
|
+
const index = frameWaiters.indexOf(waiter);
|
|
379
|
+
if (index >= 0) frameWaiters.splice(index, 1);
|
|
380
|
+
throw error;
|
|
381
|
+
}
|
|
382
|
+
return await frame;
|
|
383
|
+
});
|
|
384
|
+
},
|
|
385
|
+
hasObservedBackpressure: () => observedBackpressure || backpressure?.observed === true,
|
|
386
|
+
setStreamPacingActive,
|
|
387
|
+
};
|
|
134
388
|
}
|