@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
|
@@ -13,11 +13,16 @@
|
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
15
|
import { sanitizeCallTargetText } from "../../domains/safety/call-target.js";
|
|
16
|
+
import { formatSize } from "../../engine/truncate.js";
|
|
16
17
|
import { visibleWidth, wrapTextWithAnsi } from "../../engine/tui.js";
|
|
18
|
+
import { classifyResourceRead, toolPresentationPolicy } from "../../tools/presentation.js";
|
|
19
|
+
import type { ApprovalRequestView } from "../permission-overlay.js";
|
|
17
20
|
import { clioTheme, formatCompactMs, GLYPH } from "../theme/index.js";
|
|
18
|
-
import {
|
|
21
|
+
import { renderDiffLines } from "./diff.js";
|
|
19
22
|
import { tryRenderJson, tryRenderXml } from "./structured.js";
|
|
20
23
|
|
|
24
|
+
export { classifyResourceRead };
|
|
25
|
+
|
|
21
26
|
const theme = clioTheme();
|
|
22
27
|
const dim = (text: string): string => theme.fg("dim", text);
|
|
23
28
|
const red = (text: string): string => theme.fg("error", text);
|
|
@@ -34,11 +39,12 @@ const BODY_INDENT_VISIBLE_WIDTH = 2;
|
|
|
34
39
|
const HEADER_PREFIX_PLAIN = "▸ ";
|
|
35
40
|
const ARG_PREVIEW_LIMIT = 60;
|
|
36
41
|
const WEB_FETCH_ARG_PREVIEW_LIMIT = 140;
|
|
37
|
-
const RESULT_PREVIEW_LIMIT = 4000;
|
|
38
42
|
const FULL_RESULT_PREVIEW_LIMIT = 60_000;
|
|
39
43
|
const FULL_RESULT_ROW_LIMIT = 120;
|
|
40
44
|
const STREAMING_RESULT_ROW_LIMIT = 20;
|
|
41
45
|
const ARGS_BODY_LINE_LIMIT = 24;
|
|
46
|
+
/** Rows of mutation diff a folded edit/write row keeps visible before it defers to the body. */
|
|
47
|
+
const FOLDED_DIFF_ROW_LIMIT = 24;
|
|
42
48
|
const STATUS_OK_GLYPH = GLYPH.ok;
|
|
43
49
|
const STATUS_ERROR_GLYPH = GLYPH.error;
|
|
44
50
|
|
|
@@ -54,6 +60,8 @@ export interface ToolExecutionStart {
|
|
|
54
60
|
args: unknown;
|
|
55
61
|
/** Live elapsed time supplied by the panel for running segments. */
|
|
56
62
|
elapsedMs?: number | undefined;
|
|
63
|
+
/** Pi may stream a tool call's arguments before execution starts. */
|
|
64
|
+
phase?: "forming" | "ready" | "running" | undefined;
|
|
57
65
|
}
|
|
58
66
|
|
|
59
67
|
export interface ToolExecutionFinished {
|
|
@@ -73,6 +81,10 @@ export interface ToolExecutionFinished {
|
|
|
73
81
|
* model reading the same transcript, to guess at the rule.
|
|
74
82
|
*/
|
|
75
83
|
blockReason?: string | undefined;
|
|
84
|
+
/** Structured exit status when the caller has one; text parsing is legacy fallback only. */
|
|
85
|
+
exitCode?: number | string | null | undefined;
|
|
86
|
+
/** Local `!!` bash output is visible to the operator but excluded from model context. */
|
|
87
|
+
excludeFromContext?: boolean | undefined;
|
|
76
88
|
}
|
|
77
89
|
|
|
78
90
|
export interface ToolBodyRenderOptions {
|
|
@@ -83,6 +95,8 @@ export interface ToolBodyRenderOptions {
|
|
|
83
95
|
* the complete tool output the model actually received.
|
|
84
96
|
*/
|
|
85
97
|
unbounded?: boolean;
|
|
98
|
+
/** Live rows color mutation diffs; replay and export deliberately use plain text. */
|
|
99
|
+
diffStyle?: "color" | "plain";
|
|
86
100
|
}
|
|
87
101
|
|
|
88
102
|
/** Row cap for a tool body: unbounded lifts both the row and char limits. */
|
|
@@ -218,10 +232,9 @@ function bashExitCodeFromResult(result: unknown): string | null {
|
|
|
218
232
|
|
|
219
233
|
/**
|
|
220
234
|
* Map of known tools to their canonical "primary" arg field. When the arg is
|
|
221
|
-
* a string the header summarises it directly and the
|
|
222
|
-
*
|
|
223
|
-
*
|
|
224
|
-
* to a JSON-dump summary plus the full args body.
|
|
235
|
+
* a string the header summarises it directly and the expanded argument list
|
|
236
|
+
* omits only that repeated field. Tools not in this map (or with an unexpected
|
|
237
|
+
* arg shape) fall back to a JSON summary plus their complete redacted fields.
|
|
225
238
|
*/
|
|
226
239
|
const PRIMARY_ARG_FIELD: Record<string, string> = {
|
|
227
240
|
read: "path",
|
|
@@ -244,8 +257,8 @@ const PRIMARY_ARG_FIELD: Record<string, string> = {
|
|
|
244
257
|
|
|
245
258
|
/**
|
|
246
259
|
* Returns the captured primary-arg string when the header successfully used a
|
|
247
|
-
* known tool's canonical arg, otherwise null.
|
|
248
|
-
*
|
|
260
|
+
* known tool's canonical arg, otherwise null. The argument renderer uses the
|
|
261
|
+
* same map to omit that one repeated field below `read(README.md)`.
|
|
249
262
|
*/
|
|
250
263
|
function capturedPrimaryArg(toolName: string, args: unknown): string | null {
|
|
251
264
|
const field = PRIMARY_ARG_FIELD[toolName];
|
|
@@ -278,24 +291,6 @@ function summarizeArgs(toolName: string, args: unknown): string {
|
|
|
278
291
|
return truncate(jsonStringifySafe(safeArgs), ARG_PREVIEW_LIMIT);
|
|
279
292
|
}
|
|
280
293
|
|
|
281
|
-
/**
|
|
282
|
-
* Compact resource-read classification. Reads of skill/handbook/agent
|
|
283
|
-
* instruction files and docs pages collapse to one labeled line and never
|
|
284
|
-
* auto-expand; their bodies are reference material, not task output.
|
|
285
|
-
*/
|
|
286
|
-
export function classifyResourceRead(toolName: string, args: unknown): string | null {
|
|
287
|
-
if (toolName !== "read") return null;
|
|
288
|
-
const path = readStringField(args, "path");
|
|
289
|
-
if (path === null) return null;
|
|
290
|
-
const normalized = path.replace(/\\/g, "/");
|
|
291
|
-
const base = normalized.split("/").pop() ?? "";
|
|
292
|
-
if (base === "SKILL.md") return "skill";
|
|
293
|
-
if (base === "CLIO-CODER.md") return "handbook";
|
|
294
|
-
if (base === "AGENTS.md") return "agents";
|
|
295
|
-
if (/(^|\/)docs\//.test(normalized)) return "docs";
|
|
296
|
-
return null;
|
|
297
|
-
}
|
|
298
|
-
|
|
299
294
|
function detailsOf(result: unknown): Record<string, unknown> | null {
|
|
300
295
|
if (!isPlainObject(result)) return null;
|
|
301
296
|
return isPlainObject(result.details) ? result.details : null;
|
|
@@ -318,12 +313,6 @@ function stringField(record: Record<string, unknown> | null, key: string): strin
|
|
|
318
313
|
return typeof value === "string" && value.length > 0 ? value : null;
|
|
319
314
|
}
|
|
320
315
|
|
|
321
|
-
function formatBytes(bytes: number): string {
|
|
322
|
-
if (bytes < 1024) return `${bytes}B`;
|
|
323
|
-
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)}KB`;
|
|
324
|
-
return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;
|
|
325
|
-
}
|
|
326
|
-
|
|
327
316
|
function countSummary(observation: Record<string, unknown>): string | null {
|
|
328
317
|
const unit = stringField(observation, "unit") ?? "results";
|
|
329
318
|
const shown = numberField(observation, "shownCount");
|
|
@@ -396,9 +385,46 @@ function shownBytesOf(finished: ToolExecutionFinished): number | null {
|
|
|
396
385
|
const observation = observationOf(finished);
|
|
397
386
|
const fromObservation = numberField(observation, "shownBytes");
|
|
398
387
|
if (fromObservation !== null) return fromObservation;
|
|
388
|
+
const resultSize = detailsOf(finished.result)?.resultSize;
|
|
389
|
+
const fromResultSize = isPlainObject(resultSize) ? numberField(resultSize, "shownBytes") : null;
|
|
390
|
+
if (fromResultSize !== null) return fromResultSize;
|
|
399
391
|
return numberField(finished.resultSummary ?? null, "bytes");
|
|
400
392
|
}
|
|
401
393
|
|
|
394
|
+
function totalBytesOf(finished: ToolExecutionFinished): number | null {
|
|
395
|
+
const observation = observationOf(finished);
|
|
396
|
+
const fromObservation = numberField(observation, "totalBytes");
|
|
397
|
+
if (fromObservation !== null) return fromObservation;
|
|
398
|
+
const resultSize = detailsOf(finished.result)?.resultSize;
|
|
399
|
+
if (isPlainObject(resultSize)) {
|
|
400
|
+
const total = numberField(resultSize, "bytes");
|
|
401
|
+
if (total !== null) return total;
|
|
402
|
+
}
|
|
403
|
+
return shownBytesOf(finished);
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
function resultSizeOf(finished: ToolExecutionFinished): Record<string, unknown> | null {
|
|
407
|
+
const value = detailsOf(finished.result)?.resultSize;
|
|
408
|
+
return isPlainObject(value) ? value : null;
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
function isTruncatedResult(finished: ToolExecutionFinished): boolean {
|
|
412
|
+
const observation = observationOf(finished);
|
|
413
|
+
if (observation?.truncated === true) return true;
|
|
414
|
+
if (resultSizeOf(finished)?.truncated === true) return true;
|
|
415
|
+
const truncation = detailsOf(finished.result)?.truncation;
|
|
416
|
+
if (isPlainObject(truncation) && truncation.truncated === true) return true;
|
|
417
|
+
return finished.resultSummary?.truncated === true;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
function structuredExitCode(finished: ToolExecutionFinished): string | null {
|
|
421
|
+
if (isNonExecutedOutcome(finished.outcome)) return null;
|
|
422
|
+
if (finished.exitCode !== undefined && finished.exitCode !== null) return String(finished.exitCode);
|
|
423
|
+
const exitCode = detailsOf(finished.result)?.exitCode;
|
|
424
|
+
if (typeof exitCode === "number" || typeof exitCode === "string") return String(exitCode);
|
|
425
|
+
return finished.toolName === "bash" && finished.isError ? bashExitCodeFromResult(finished.result) : null;
|
|
426
|
+
}
|
|
427
|
+
|
|
402
428
|
/**
|
|
403
429
|
* The dim ledger tail appended to a finished collapsed subline: outcome facts,
|
|
404
430
|
* then byte size (duration rides on the status glyph), then the offload path
|
|
@@ -409,15 +435,58 @@ function ledgerTail(finished: ToolExecutionFinished): { facts: string; offload:
|
|
|
409
435
|
const parts: string[] = [];
|
|
410
436
|
const outcome = outcomeSummary(finished);
|
|
411
437
|
if (outcome !== null) parts.push(outcome);
|
|
412
|
-
const
|
|
413
|
-
|
|
414
|
-
|
|
438
|
+
const executed = !isNonExecutedOutcome(finished.outcome);
|
|
439
|
+
// A folded bash row is the only view of the call the operator gets by
|
|
440
|
+
// default, so its settlement facts have to be here rather than only in the
|
|
441
|
+
// expanded body. A failed row already carries `(exit N)` on the status glyph.
|
|
442
|
+
if (executed && finished.toolName === "bash" && !finished.isError) {
|
|
443
|
+
parts.push(`exit ${structuredExitCode(finished) ?? "0"}`);
|
|
444
|
+
}
|
|
445
|
+
const bytes = executed ? shownBytesOf(finished) : null;
|
|
446
|
+
if (bytes !== null && bytes > 0) {
|
|
447
|
+
const total = totalBytesOf(finished);
|
|
448
|
+
parts.push(
|
|
449
|
+
total !== null && total > bytes ? `${formatSize(bytes)} shown / ${formatSize(total)} total` : formatSize(bytes),
|
|
450
|
+
);
|
|
451
|
+
}
|
|
452
|
+
if (executed) {
|
|
453
|
+
if (isTruncatedResult(finished)) parts.push("truncated");
|
|
454
|
+
const details = detailsOf(finished.result);
|
|
455
|
+
if (details?.timedOut === true) parts.push("timed out");
|
|
456
|
+
if (details?.outputCapped === true) parts.push("output capped");
|
|
457
|
+
}
|
|
458
|
+
if (finished.excludeFromContext === true) parts.push("excluded from context");
|
|
459
|
+
const offloadPath = executed ? offloadPathOf(finished) : null;
|
|
415
460
|
return {
|
|
416
461
|
facts: parts.length > 0 ? dim(` · ${parts.join(" · ")}`) : "",
|
|
417
462
|
offload: offloadPath !== null ? dim(` · full: ${offloadPath}`) : "",
|
|
418
463
|
};
|
|
419
464
|
}
|
|
420
465
|
|
|
466
|
+
/** Longest diagnostic excerpt a folded failure row may carry. */
|
|
467
|
+
const FAILURE_EXCERPT_LIMIT = 80;
|
|
468
|
+
|
|
469
|
+
/**
|
|
470
|
+
* Last non-empty output line of a failed call, bounded so the folded row stays
|
|
471
|
+
* diagnostically useful without opening the body. Sanitized to one line: the
|
|
472
|
+
* source is raw tool output. The tool's presentation policy decides whether
|
|
473
|
+
* its failures carry one; the renderer never names a tool here.
|
|
474
|
+
*/
|
|
475
|
+
function failureExcerpt(finished: ToolExecutionFinished, width: number): string {
|
|
476
|
+
if (!finished.isError || !toolPresentationPolicy(finished.toolName, finished.args).failureExcerpt) return "";
|
|
477
|
+
if (isNonExecutedOutcome(finished.outcome)) return "";
|
|
478
|
+
const text = unwrapResultEnvelope(finished.result);
|
|
479
|
+
if (typeof text !== "string") return "";
|
|
480
|
+
let excerpt: string | undefined;
|
|
481
|
+
for (const raw of text.split("\n")) {
|
|
482
|
+
const line = sanitizeCallTargetText(raw).trim();
|
|
483
|
+
if (line.length > 0) excerpt = line;
|
|
484
|
+
}
|
|
485
|
+
if (excerpt === undefined) return "";
|
|
486
|
+
const limit = Math.min(FAILURE_EXCERPT_LIMIT, Math.max(20, width - 20));
|
|
487
|
+
return dim(` · ${truncate(excerpt, limit)}`);
|
|
488
|
+
}
|
|
489
|
+
|
|
421
490
|
/**
|
|
422
491
|
* Marker for a call parked at admission awaiting operator approval. Rendered
|
|
423
492
|
* in place of the elapsed counter so a parked call never reads as executing
|
|
@@ -430,24 +499,40 @@ const AWAITING_APPROVAL_TAIL = ` ${yellow(GLYPH.phaseBlocked)}${dim(" awaiting a
|
|
|
430
499
|
* No elapsed counter (nothing is running) and no status glyph (nothing has
|
|
431
500
|
* finished): the awaiting-approval tail is the segment's whole state.
|
|
432
501
|
*/
|
|
433
|
-
export function renderToolAwaitingApproval(
|
|
502
|
+
export function renderToolAwaitingApproval(
|
|
503
|
+
call: ToolExecutionStart,
|
|
504
|
+
width: number,
|
|
505
|
+
view?: ApprovalRequestView,
|
|
506
|
+
): string[] {
|
|
434
507
|
const parts = sublineParts({ toolCallId: call.toolCallId, toolName: call.toolName, args: call.args }, undefined, {});
|
|
435
|
-
|
|
508
|
+
const lines = wrapSublineWithTail(parts.lead, AWAITING_APPROVAL_TAIL, width);
|
|
509
|
+
if (view === undefined) return lines;
|
|
510
|
+
const axis = view.axis.kind === "net" ? `safety-net rail ${view.axis.ruleId}` : `autonomy level ${view.axis.level}`;
|
|
511
|
+
const facts = [
|
|
512
|
+
["action", view.actionClass],
|
|
513
|
+
["axis", axis],
|
|
514
|
+
...(view.target !== undefined && view.target.length > 0 ? [["target", view.target]] : []),
|
|
515
|
+
] as const;
|
|
516
|
+
for (const [label, value] of facts) {
|
|
517
|
+
lines.push(...indentAndWrap(`${dim(`${label} ·`)} ${value}`, width, false));
|
|
518
|
+
}
|
|
519
|
+
return lines;
|
|
436
520
|
}
|
|
437
521
|
|
|
438
522
|
/**
|
|
439
|
-
* Header status
|
|
440
|
-
* `"ok"`
|
|
523
|
+
* Header status follows Pi's call lifecycle before and during execution, then
|
|
524
|
+
* becomes `"ok"` or `"error"` at settlement. The
|
|
441
525
|
* glyph hangs off the right of the header line so the tool name + args read
|
|
442
526
|
* left-to-right without extra punctuation.
|
|
443
527
|
*/
|
|
444
|
-
type HeaderStatus = "ok" | "error" | undefined;
|
|
528
|
+
type HeaderStatus = "forming" | "ready" | "running" | "ok" | "error" | undefined;
|
|
445
529
|
|
|
446
530
|
/** Keeps a refusal reason to one scannable clause on the status tail. */
|
|
447
531
|
const BLOCK_REASON_LIMIT = 72;
|
|
448
532
|
|
|
449
533
|
interface StatusMeta {
|
|
450
534
|
durationMs?: number | undefined;
|
|
535
|
+
elapsedMs?: number | undefined;
|
|
451
536
|
exitCode?: string | null;
|
|
452
537
|
outcome?: ToolExecutionFinished["outcome"];
|
|
453
538
|
/** Refusal reason, rendered only alongside a non-executed outcome. */
|
|
@@ -456,6 +541,12 @@ interface StatusMeta {
|
|
|
456
541
|
|
|
457
542
|
function statusGlyph(status: HeaderStatus, meta: StatusMeta = {}): string {
|
|
458
543
|
if (status === undefined) return "";
|
|
544
|
+
if (status === "forming") return ` ${dim(GLYPH.queued)}${dim(" forming call")}`;
|
|
545
|
+
if (status === "ready") return ` ${dim(GLYPH.queued)}${dim(" ready")}`;
|
|
546
|
+
if (status === "running") {
|
|
547
|
+
const elapsed = optionalCompactMs(meta.elapsedMs);
|
|
548
|
+
return ` ${cyan(GLYPH.running)}${dim(elapsed === null ? " running" : ` running · ${elapsed}`)}`;
|
|
549
|
+
}
|
|
459
550
|
const duration = optionalCompactMs(meta.durationMs);
|
|
460
551
|
const durationSuffix = duration ? dim(` · ${duration}`) : "";
|
|
461
552
|
if (status === "ok") return ` ${green(STATUS_OK_GLYPH)}${durationSuffix}`;
|
|
@@ -470,8 +561,8 @@ function statusGlyph(status: HeaderStatus, meta: StatusMeta = {}): string {
|
|
|
470
561
|
}
|
|
471
562
|
|
|
472
563
|
function headerLine(toolName: string, args: unknown, status: HeaderStatus, meta: StatusMeta = {}): string {
|
|
473
|
-
const
|
|
474
|
-
const head = `${dim(HEADER_PREFIX_PLAIN)}${
|
|
564
|
+
const body = styleSublineBody(buildSublineBody(toolName, args, status, undefined, meta.outcome));
|
|
565
|
+
const head = `${dim(HEADER_PREFIX_PLAIN)}${body}`;
|
|
475
566
|
return `${head}${statusGlyph(status, meta)}`;
|
|
476
567
|
}
|
|
477
568
|
|
|
@@ -485,8 +576,9 @@ function styleSublineBody(body: string): string {
|
|
|
485
576
|
return sublineLead(match.groups.lead, match.groups.rest);
|
|
486
577
|
}
|
|
487
578
|
|
|
488
|
-
function
|
|
489
|
-
|
|
579
|
+
function buildGenericToolBody(toolName: string, args: unknown): string {
|
|
580
|
+
const summary = summarizeArgs(toolName, args);
|
|
581
|
+
return summary.length > 0 ? `tool action ${summary}` : "tool action";
|
|
490
582
|
}
|
|
491
583
|
|
|
492
584
|
function buildFieldSublineBody(
|
|
@@ -543,6 +635,7 @@ const SUBLINE_BODY_BUILDERS: Readonly<Record<string, (args: unknown) => string |
|
|
|
543
635
|
bash: (args) => buildFieldSublineBody(args, "command", "running ", { wrapInBackticks: true }),
|
|
544
636
|
grep: (args) => buildFieldSublineBody(args, "pattern", "searching for ", { wrapInBackticks: true }),
|
|
545
637
|
find: (args) => buildFieldSublineBody(args, "pattern", "finding ", { wrapInBackticks: true }),
|
|
638
|
+
web_fetch: (args) => buildFieldSublineBody(args, "url", "fetching "),
|
|
546
639
|
git: (args) => buildFieldSublineBody(args, "op", "git "),
|
|
547
640
|
verify: (args) => buildFieldSublineBody(args, "check", "verifying "),
|
|
548
641
|
code_nav: (args) => {
|
|
@@ -580,7 +673,7 @@ const SUBLINE_BODY_BUILDERS: Readonly<Record<string, (args: unknown) => string |
|
|
|
580
673
|
/**
|
|
581
674
|
* Per-tool subline templates. Maps a tool name to a function that builds the
|
|
582
675
|
* verb-led subline body without the leading glyph and without the trailing
|
|
583
|
-
* status glyph. Unknown tools fall back to
|
|
676
|
+
* status glyph. Unknown tools fall back to a tool-neutral action summary.
|
|
584
677
|
*/
|
|
585
678
|
function webFetchMeta(result: unknown): string | null {
|
|
586
679
|
if (!isPlainObject(result) || !isPlainObject(result.details)) return null;
|
|
@@ -597,11 +690,10 @@ function webFetchMeta(result: unknown): string | null {
|
|
|
597
690
|
|
|
598
691
|
/**
|
|
599
692
|
* A call the permission gate blocked never executed, so the collapsed row must
|
|
600
|
-
* not claim it did.
|
|
601
|
-
*
|
|
602
|
-
*
|
|
603
|
-
*
|
|
604
|
-
* output.
|
|
693
|
+
* not claim it did. Blocked calls keep the ordinary operator-facing action
|
|
694
|
+
* description but use a neutral noun for commands; the status tail supplies the
|
|
695
|
+
* blocked outcome. The ledger byte count is suppressed elsewhere because those
|
|
696
|
+
* bytes are the denial text, not output.
|
|
605
697
|
*/
|
|
606
698
|
function isNonExecutedOutcome(outcome: ToolExecutionFinished["outcome"]): boolean {
|
|
607
699
|
return outcome === "blocked";
|
|
@@ -614,20 +706,29 @@ function buildSublineBody(
|
|
|
614
706
|
result?: unknown,
|
|
615
707
|
outcome?: ToolExecutionFinished["outcome"],
|
|
616
708
|
): string {
|
|
617
|
-
if (isNonExecutedOutcome(outcome))
|
|
709
|
+
if (isNonExecutedOutcome(outcome)) {
|
|
710
|
+
if (toolName === "bash") {
|
|
711
|
+
return (
|
|
712
|
+
buildFieldSublineBody(args, "command", "command ", { wrapInBackticks: true }) ??
|
|
713
|
+
buildGenericToolBody(toolName, args)
|
|
714
|
+
);
|
|
715
|
+
}
|
|
716
|
+
return SUBLINE_BODY_BUILDERS[toolName]?.(args) ?? buildGenericToolBody(toolName, args);
|
|
717
|
+
}
|
|
618
718
|
if (toolName === "web_fetch") {
|
|
619
719
|
const meta = status === undefined ? null : webFetchMeta(result);
|
|
620
|
-
|
|
720
|
+
const body = SUBLINE_BODY_BUILDERS.web_fetch?.(args) ?? buildGenericToolBody(toolName, args);
|
|
721
|
+
return `${body}${meta ? dim(` · ${meta}`) : ""}`;
|
|
621
722
|
}
|
|
622
723
|
if (toolName === "bash") {
|
|
623
|
-
const lead = status ===
|
|
724
|
+
const lead = status === "ok" || status === "error" ? "ran " : "running ";
|
|
624
725
|
return (
|
|
625
|
-
buildFieldSublineBody(args, "command", lead, { wrapInBackticks: true }) ??
|
|
726
|
+
buildFieldSublineBody(args, "command", lead, { wrapInBackticks: true }) ?? buildGenericToolBody(toolName, args)
|
|
626
727
|
);
|
|
627
728
|
}
|
|
628
729
|
const body = SUBLINE_BODY_BUILDERS[toolName]?.(args);
|
|
629
730
|
if (body !== null && body !== undefined) return body;
|
|
630
|
-
return
|
|
731
|
+
return buildGenericToolBody(toolName, args);
|
|
631
732
|
}
|
|
632
733
|
|
|
633
734
|
interface SublineParts {
|
|
@@ -660,9 +761,7 @@ function sublineParts(
|
|
|
660
761
|
tail: `${statusGlyph(status, meta)}${ledger.offload}`,
|
|
661
762
|
};
|
|
662
763
|
}
|
|
663
|
-
|
|
664
|
-
const running = elapsed !== null ? dim(` · ${elapsed}`) : "";
|
|
665
|
-
return { lead: `${dim(HEADER_PREFIX_PLAIN)}${body}${resource}${running}`, tail: "" };
|
|
764
|
+
return { lead: `${dim(HEADER_PREFIX_PLAIN)}${body}${resource}`, tail: statusGlyph(status, meta) };
|
|
666
765
|
}
|
|
667
766
|
|
|
668
767
|
/**
|
|
@@ -708,33 +807,69 @@ function indentAndWrap(line: string, width: number, isError: boolean): string[]
|
|
|
708
807
|
return out;
|
|
709
808
|
}
|
|
710
809
|
|
|
810
|
+
function scalarArgValue(value: unknown): string | null {
|
|
811
|
+
if (typeof value === "string") {
|
|
812
|
+
const lines = value.split("\n").length;
|
|
813
|
+
const bytes = Buffer.byteLength(value, "utf8");
|
|
814
|
+
if (lines > 1 || value.length > 160) return dim(`<${lines} lines · ${formatSize(bytes)} text>`);
|
|
815
|
+
return green(JSON.stringify(value));
|
|
816
|
+
}
|
|
817
|
+
if (typeof value === "number") return cyan(String(value));
|
|
818
|
+
if (typeof value === "boolean") return yellow(String(value));
|
|
819
|
+
if (value === null) return dim("null");
|
|
820
|
+
return null;
|
|
821
|
+
}
|
|
822
|
+
|
|
711
823
|
/**
|
|
712
|
-
* Render
|
|
713
|
-
*
|
|
714
|
-
*
|
|
715
|
-
*
|
|
716
|
-
*
|
|
824
|
+
* Render secondary arguments as a compact typed field list. The primary path,
|
|
825
|
+
* command, pattern, or query already lives in the call signature; keeping the
|
|
826
|
+
* rest means `cwd`, timeout, range, glob, and flags no longer disappear merely
|
|
827
|
+
* because one field was important enough for the header. Nested values retain
|
|
828
|
+
* the structured JSON renderer, while large strings become byte/line facts
|
|
829
|
+
* instead of flooding the transcript.
|
|
717
830
|
*/
|
|
718
|
-
function renderArgsBody(args: unknown, width: number, isError: boolean): string[] {
|
|
831
|
+
function renderArgsBody(toolName: string, args: unknown, width: number, isError: boolean): string[] {
|
|
719
832
|
if (isEmptyArgs(args)) return [];
|
|
833
|
+
const safeArgs = redactToolArgs(args);
|
|
834
|
+
if (!isPlainObject(safeArgs)) {
|
|
835
|
+
const bodyWidth = Math.max(1, width - BODY_INDENT_VISIBLE_WIDTH);
|
|
836
|
+
const lines = tryRenderJson(safeArgs, bodyWidth, { lineLimit: ARGS_BODY_LINE_LIMIT });
|
|
837
|
+
return lines?.flatMap((line) => indentAndWrap(line, width, isError)) ?? [];
|
|
838
|
+
}
|
|
839
|
+
const primary = PRIMARY_ARG_FIELD[toolName];
|
|
840
|
+
const entries = Object.entries(safeArgs).filter(([key]) => key !== primary);
|
|
841
|
+
if (entries.length === 0) return [];
|
|
720
842
|
const out: string[] = [];
|
|
721
843
|
const bodyWidth = Math.max(1, width - BODY_INDENT_VISIBLE_WIDTH);
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
for (const
|
|
725
|
-
|
|
844
|
+
out.push(...indentAndWrap(`${cyanBold("args")}${dim(` · ${entries.length}`)}`, width, isError));
|
|
845
|
+
const keyWidth = Math.min(18, Math.max(...entries.map(([key]) => visibleWidth(key))));
|
|
846
|
+
for (const [key, value] of entries) {
|
|
847
|
+
const label = `${cyan(key.padEnd(keyWidth))} `;
|
|
848
|
+
const scalar = scalarArgValue(value);
|
|
849
|
+
if (scalar !== null) {
|
|
850
|
+
out.push(...indentAndWrap(`${label}${scalar}`, width, isError));
|
|
851
|
+
continue;
|
|
852
|
+
}
|
|
853
|
+
out.push(...indentAndWrap(cyan(key), width, isError));
|
|
854
|
+
const lines = tryRenderJson(value, Math.max(1, bodyWidth - 2), { lineLimit: ARGS_BODY_LINE_LIMIT });
|
|
855
|
+
for (const line of lines ?? [jsonStringifySafe(value)]) {
|
|
856
|
+
out.push(...indentAndWrap(` ${line}`, width, isError));
|
|
857
|
+
if (out.length >= ARGS_BODY_LINE_LIMIT) break;
|
|
858
|
+
}
|
|
859
|
+
if (out.length >= ARGS_BODY_LINE_LIMIT) break;
|
|
726
860
|
}
|
|
861
|
+
if (out.length >= ARGS_BODY_LINE_LIMIT) out.push(...indentAndWrap(dim("… more arguments hidden"), width, isError));
|
|
727
862
|
return out;
|
|
728
863
|
}
|
|
729
864
|
|
|
730
865
|
/**
|
|
731
866
|
* pi-agent-core wraps tool results in `{ content: [{ type: "text", text }, ...] }`
|
|
732
|
-
* envelopes. Rendering that JSON verbatim hides the actual
|
|
733
|
-
*
|
|
734
|
-
*
|
|
735
|
-
*
|
|
867
|
+
* envelopes. Rendering that JSON verbatim hides the actual output and, for a
|
|
868
|
+
* mixed result, can dump a base64 image into the terminal. Text blocks are
|
|
869
|
+
* joined, image blocks become compact MIME/size placeholders, and unknown
|
|
870
|
+
* content blocks are named without serializing their payload.
|
|
736
871
|
*/
|
|
737
|
-
|
|
872
|
+
function unwrapResultEnvelope(result: unknown): unknown {
|
|
738
873
|
if (typeof result === "string" || result === null || result === undefined) return result;
|
|
739
874
|
const blocks = Array.isArray(result)
|
|
740
875
|
? result
|
|
@@ -745,16 +880,25 @@ export function unwrapResultEnvelope(result: unknown): unknown {
|
|
|
745
880
|
const parts: string[] = [];
|
|
746
881
|
for (const block of blocks) {
|
|
747
882
|
if (!isPlainObject(block)) return result;
|
|
748
|
-
if (block.type
|
|
749
|
-
|
|
883
|
+
if (block.type === "text" && typeof block.text === "string") {
|
|
884
|
+
parts.push(block.text);
|
|
885
|
+
continue;
|
|
886
|
+
}
|
|
887
|
+
if (block.type === "image" && typeof block.data === "string") {
|
|
888
|
+
const mimeType = typeof block.mimeType === "string" ? block.mimeType : "image/unknown";
|
|
889
|
+
const padding = block.data.endsWith("==") ? 2 : block.data.endsWith("=") ? 1 : 0;
|
|
890
|
+
const bytes = Math.max(0, Math.floor((block.data.length * 3) / 4) - padding);
|
|
891
|
+
parts.push(`[image ${mimeType} · ${formatSize(bytes)}]`);
|
|
892
|
+
continue;
|
|
893
|
+
}
|
|
894
|
+
if (typeof block.type === "string") {
|
|
895
|
+
parts.push(`[${block.type} content]`);
|
|
896
|
+
continue;
|
|
897
|
+
}
|
|
898
|
+
return result;
|
|
750
899
|
}
|
|
751
900
|
if (parts.length === 0) return result;
|
|
752
|
-
return parts.join("");
|
|
753
|
-
}
|
|
754
|
-
|
|
755
|
-
export function previewResult(result: unknown): string {
|
|
756
|
-
if (typeof result === "string") return truncate(result, RESULT_PREVIEW_LIMIT);
|
|
757
|
-
return truncate(jsonStringifySafe(result), RESULT_PREVIEW_LIMIT);
|
|
901
|
+
return parts.join("\n");
|
|
758
902
|
}
|
|
759
903
|
|
|
760
904
|
function isEmptyResult(result: unknown): boolean {
|
|
@@ -822,50 +966,14 @@ function highlightBashCommand(command: string): string {
|
|
|
822
966
|
.join("");
|
|
823
967
|
}
|
|
824
968
|
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
new_string: string;
|
|
829
|
-
}
|
|
830
|
-
|
|
831
|
-
/**
|
|
832
|
-
* Defensive shape check: edit-tool args must carry both `old_string` and
|
|
833
|
-
* `new_string` strings before we can render a diff. `path` is optional; the
|
|
834
|
-
* diff renderer falls back to `"file"` when absent. Anything else falls
|
|
835
|
-
* through to the standard result block so the dispatch is opportunistic and
|
|
836
|
-
* never throws.
|
|
837
|
-
*/
|
|
838
|
-
function asEditDiffArgs(args: unknown): EditDiffArgs | null {
|
|
839
|
-
if (!isPlainObject(args)) return null;
|
|
840
|
-
const oldString = args.old_string;
|
|
841
|
-
const newString = args.new_string;
|
|
842
|
-
if (typeof oldString !== "string" || typeof newString !== "string") return null;
|
|
843
|
-
const out: EditDiffArgs = { old_string: oldString, new_string: newString };
|
|
844
|
-
if (typeof args.path === "string") out.path = args.path;
|
|
845
|
-
return out;
|
|
846
|
-
}
|
|
847
|
-
|
|
848
|
-
// The `diff` library appends a `` sentinel row when a
|
|
849
|
-
// side of the comparison lacks a trailing newline. It is transcript noise, so
|
|
850
|
-
// the edit diff block drops it. The marker text carries no ANSI, so a substring
|
|
851
|
-
// check against the styled row is reliable and keeps this module free of raw
|
|
852
|
-
// escape literals.
|
|
853
|
-
const NO_NEWLINE_MARKER = "\";
|
|
854
|
-
|
|
855
|
-
function isNoNewlineMarkerRow(row: string): boolean {
|
|
856
|
-
return row.includes(NO_NEWLINE_MARKER);
|
|
969
|
+
function resultDiff(result: unknown): string | null {
|
|
970
|
+
const value = detailsOf(result)?.diff;
|
|
971
|
+
return typeof value === "string" && value.length > 0 ? value : null;
|
|
857
972
|
}
|
|
858
973
|
|
|
859
|
-
function
|
|
974
|
+
function renderMutationDiffBlock(diff: string, width: number, color: boolean): string[] {
|
|
860
975
|
const bodyWidth = Math.max(1, width - BODY_INDENT_VISIBLE_WIDTH);
|
|
861
|
-
|
|
862
|
-
if (args.path !== undefined) input.filename = args.path;
|
|
863
|
-
const out: string[] = [];
|
|
864
|
-
for (const line of renderUnifiedDiff(input, bodyWidth)) {
|
|
865
|
-
if (isNoNewlineMarkerRow(line)) continue;
|
|
866
|
-
out.push(`${RAIL_DIM}${line}`);
|
|
867
|
-
}
|
|
868
|
-
return out;
|
|
976
|
+
return renderDiffLines(diff, bodyWidth, { color }).map((line) => `${RAIL_DIM}${line}`);
|
|
869
977
|
}
|
|
870
978
|
|
|
871
979
|
interface BashArgs {
|
|
@@ -884,6 +992,79 @@ function asBashArgs(args: unknown): BashArgs | null {
|
|
|
884
992
|
return { command: redactSecretString(command) };
|
|
885
993
|
}
|
|
886
994
|
|
|
995
|
+
function resultLineCount(result: unknown): number {
|
|
996
|
+
const unwrapped = unwrapResultEnvelope(result);
|
|
997
|
+
if (typeof unwrapped !== "string" || unwrapped.length === 0) return 0;
|
|
998
|
+
const normalized = unwrapped.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
999
|
+
const withoutTerminator = normalized.endsWith("\n") ? normalized.slice(0, -1) : normalized;
|
|
1000
|
+
return withoutTerminator.split("\n").length;
|
|
1001
|
+
}
|
|
1002
|
+
|
|
1003
|
+
function toolUsageFact(result: unknown): string | null {
|
|
1004
|
+
if (!isPlainObject(result) || !isPlainObject(result.usage)) return null;
|
|
1005
|
+
const total = numberField(result.usage, "totalTokens");
|
|
1006
|
+
if (total === null || total <= 0) return null;
|
|
1007
|
+
return `${total} tool token${total === 1 ? "" : "s"}`;
|
|
1008
|
+
}
|
|
1009
|
+
|
|
1010
|
+
function outputFacts(finished: ToolExecutionFinished): string[] {
|
|
1011
|
+
const parts: string[] = [];
|
|
1012
|
+
if (isNonExecutedOutcome(finished.outcome)) {
|
|
1013
|
+
if (finished.excludeFromContext === true) parts.push("excluded from context");
|
|
1014
|
+
return parts;
|
|
1015
|
+
}
|
|
1016
|
+
const exitCode = structuredExitCode(finished) ?? (finished.toolName === "bash" && !finished.isError ? "0" : null);
|
|
1017
|
+
if (exitCode !== null) parts.push(`exit ${exitCode}`);
|
|
1018
|
+
const observation = observationOf(finished);
|
|
1019
|
+
const count = observation === null ? null : countSummary(observation);
|
|
1020
|
+
if (count !== null) parts.push(count);
|
|
1021
|
+
const lines = resultLineCount(finished.result);
|
|
1022
|
+
if (count === null && lines > 0) parts.push(`${lines} line${lines === 1 ? "" : "s"}`);
|
|
1023
|
+
const shownBytes = shownBytesOf(finished);
|
|
1024
|
+
const totalBytes = totalBytesOf(finished);
|
|
1025
|
+
if (shownBytes !== null && shownBytes > 0) {
|
|
1026
|
+
parts.push(
|
|
1027
|
+
totalBytes !== null && totalBytes > shownBytes
|
|
1028
|
+
? `${formatSize(shownBytes)} shown / ${formatSize(totalBytes)} total`
|
|
1029
|
+
: formatSize(shownBytes),
|
|
1030
|
+
);
|
|
1031
|
+
}
|
|
1032
|
+
if (isTruncatedResult(finished)) parts.push("truncated");
|
|
1033
|
+
const details = detailsOf(finished.result);
|
|
1034
|
+
if (details?.timedOut === true) parts.push("timed out");
|
|
1035
|
+
if (details?.outputCapped === true) parts.push("output capped");
|
|
1036
|
+
const usage = toolUsageFact(finished.result);
|
|
1037
|
+
if (usage !== null) parts.push(usage);
|
|
1038
|
+
if (isPlainObject(finished.result) && Array.isArray(finished.result.addedToolNames)) {
|
|
1039
|
+
const added = finished.result.addedToolNames.filter((name): name is string => typeof name === "string");
|
|
1040
|
+
if (added.length > 0) parts.push(`added ${added.join(", ")}`);
|
|
1041
|
+
}
|
|
1042
|
+
if (isPlainObject(finished.result) && finished.result.terminate === true) parts.push("terminal result");
|
|
1043
|
+
if (finished.excludeFromContext === true) parts.push("excluded from context");
|
|
1044
|
+
return parts;
|
|
1045
|
+
}
|
|
1046
|
+
|
|
1047
|
+
function renderOutputMeta(
|
|
1048
|
+
finished: ToolExecutionFinished,
|
|
1049
|
+
width: number,
|
|
1050
|
+
isError: boolean,
|
|
1051
|
+
label = "output",
|
|
1052
|
+
): string[] {
|
|
1053
|
+
const facts = outputFacts(finished);
|
|
1054
|
+
const suffix = facts.length > 0 ? dim(` · ${facts.join(" · ")}`) : "";
|
|
1055
|
+
return indentAndWrap(`${cyanBold(label)}${suffix}`, width, isError);
|
|
1056
|
+
}
|
|
1057
|
+
|
|
1058
|
+
function renderOutputFooter(finished: ToolExecutionFinished, width: number, isError: boolean): string[] {
|
|
1059
|
+
const out: string[] = [];
|
|
1060
|
+
const offloadPath = isNonExecutedOutcome(finished.outcome) ? null : offloadPathOf(finished);
|
|
1061
|
+
if (offloadPath !== null) out.push(...indentAndWrap(`${yellow("full output")} ${offloadPath}`, width, isError));
|
|
1062
|
+
const hint =
|
|
1063
|
+
stringField(resultSizeOf(finished), "followUpHint") ?? stringField(finished.resultSummary ?? null, "followUpHint");
|
|
1064
|
+
if (hint !== null) out.push(...indentAndWrap(`${dim("next")} ${hint}`, width, isError));
|
|
1065
|
+
return out;
|
|
1066
|
+
}
|
|
1067
|
+
|
|
887
1068
|
/**
|
|
888
1069
|
* Bash subrenderer: emits `$ <cmd>` (full command) on its own line under the
|
|
889
1070
|
* rail, then the unwrapped output via the same chain as `renderResultBlock`.
|
|
@@ -927,11 +1108,17 @@ function renderResultBlock(
|
|
|
927
1108
|
|
|
928
1109
|
/**
|
|
929
1110
|
* Header-only render for a tool call that has not yet finished. Used by the
|
|
930
|
-
* live chat panel
|
|
931
|
-
*
|
|
1111
|
+
* live chat panel from streamed argument formation through execution. The
|
|
1112
|
+
* lifecycle tail distinguishes a forming call, a ready call, and a running
|
|
1113
|
+
* call without inventing execution time before Pi starts the tool.
|
|
932
1114
|
*/
|
|
933
1115
|
export function renderToolCallHeader(call: ToolExecutionStart, width: number): string[] {
|
|
934
|
-
return wrap(
|
|
1116
|
+
return wrap(
|
|
1117
|
+
headerLine(call.toolName, call.args, call.phase ?? "running", {
|
|
1118
|
+
elapsedMs: call.elapsedMs,
|
|
1119
|
+
}),
|
|
1120
|
+
width,
|
|
1121
|
+
);
|
|
935
1122
|
}
|
|
936
1123
|
|
|
937
1124
|
/** Running-only footer used when an operator pauses live output; execution continues. */
|
|
@@ -939,11 +1126,7 @@ export function renderToolRunningStatus(call: ToolExecutionStart, width: number)
|
|
|
939
1126
|
const elapsed = optionalCompactMs(call.elapsedMs);
|
|
940
1127
|
return [
|
|
941
1128
|
...renderToolCallHeader(call, width),
|
|
942
|
-
...indentAndWrap(
|
|
943
|
-
dim(elapsed ? `(running... ${elapsed}; live output hidden)` : "(running; live output hidden)"),
|
|
944
|
-
width,
|
|
945
|
-
false,
|
|
946
|
-
),
|
|
1129
|
+
...indentAndWrap(dim(elapsed ? `live output paused · ${elapsed}` : "live output paused"), width, false),
|
|
947
1130
|
];
|
|
948
1131
|
}
|
|
949
1132
|
|
|
@@ -952,7 +1135,7 @@ function sublineStatus(call: ToolExecutionStart | ToolExecutionFinished): Header
|
|
|
952
1135
|
// carries a `result` field, so a `ToolExecutionStart` with a stray
|
|
953
1136
|
// `isError: false` (e.g. from a future event-shape change) cannot trip the
|
|
954
1137
|
// finished path. `result` is the type's load-bearing field.
|
|
955
|
-
if (!("result" in call)) return
|
|
1138
|
+
if (!("result" in call)) return call.phase ?? "running";
|
|
956
1139
|
return call.isError ? "error" : "ok";
|
|
957
1140
|
}
|
|
958
1141
|
|
|
@@ -972,25 +1155,58 @@ function sublineStatus(call: ToolExecutionStart | ToolExecutionFinished): Header
|
|
|
972
1155
|
* imports the keybindings manager directly; the caller resolves the key string
|
|
973
1156
|
* and passes it in to keep this module pure.
|
|
974
1157
|
*/
|
|
1158
|
+
export interface ToolSublineRenderOptions {
|
|
1159
|
+
/** Live rows color the folded mutation diff; replay and export request plain rows. */
|
|
1160
|
+
diffStyle?: "color" | "plain";
|
|
1161
|
+
/**
|
|
1162
|
+
* Whether the folded row carries the extras its tool's presentation asks
|
|
1163
|
+
* for (today the bounded mutation diff). The bare subline level drops them;
|
|
1164
|
+
* the failure excerpt is not one of them and always rides the row.
|
|
1165
|
+
*/
|
|
1166
|
+
foldedExtras?: "per-tool" | "none";
|
|
1167
|
+
}
|
|
1168
|
+
|
|
1169
|
+
/**
|
|
1170
|
+
* The bounded diff a folded mutation row keeps under itself, when the tool's
|
|
1171
|
+
* presentation asks for one and the result carries one. A folded `edit` that
|
|
1172
|
+
* hid its change told the operator nothing they could act on.
|
|
1173
|
+
*/
|
|
1174
|
+
function foldedDiffRows(finished: ToolExecutionFinished, width: number, opts: ToolSublineRenderOptions): string[] {
|
|
1175
|
+
if (opts.foldedExtras === "none") return [];
|
|
1176
|
+
if (finished.isError || isNonExecutedOutcome(finished.outcome)) return [];
|
|
1177
|
+
if (!toolPresentationPolicy(finished.toolName, finished.args).showDiffWhenFolded) return [];
|
|
1178
|
+
const diff = resultDiff(finished.result);
|
|
1179
|
+
if (diff === null) return [];
|
|
1180
|
+
return truncateRowsMiddle(
|
|
1181
|
+
renderMutationDiffBlock(diff, width, opts.diffStyle !== "plain"),
|
|
1182
|
+
FOLDED_DIFF_ROW_LIMIT,
|
|
1183
|
+
false,
|
|
1184
|
+
);
|
|
1185
|
+
}
|
|
1186
|
+
|
|
975
1187
|
export function renderToolSubline(
|
|
976
1188
|
call: ToolExecutionStart | ToolExecutionFinished,
|
|
977
1189
|
width: number,
|
|
978
1190
|
expandKey?: string,
|
|
1191
|
+
opts: ToolSublineRenderOptions = {},
|
|
979
1192
|
): string[] {
|
|
980
1193
|
const status = sublineStatus(call);
|
|
981
1194
|
const meta: StatusMeta =
|
|
982
1195
|
"result" in call
|
|
983
1196
|
? {
|
|
984
1197
|
durationMs: call.durationMs,
|
|
985
|
-
exitCode:
|
|
1198
|
+
exitCode: structuredExitCode(call),
|
|
986
1199
|
outcome: call.outcome,
|
|
987
1200
|
blockReason: call.blockReason,
|
|
988
1201
|
}
|
|
989
|
-
: {};
|
|
1202
|
+
: { elapsedMs: call.elapsedMs };
|
|
990
1203
|
const parts = sublineParts(call, status, meta);
|
|
991
|
-
const
|
|
1204
|
+
const excerpt = "result" in call ? failureExcerpt(call, width) : "";
|
|
1205
|
+
const showHint = "result" in call && expandKey !== undefined && expandKey.length > 0;
|
|
992
1206
|
const tail = showHint ? `${parts.tail}${dim(` (${expandKey})`)}` : parts.tail;
|
|
993
|
-
|
|
1207
|
+
const lines = wrapSublineWithTail(`${parts.lead}${excerpt}`, tail, width);
|
|
1208
|
+
if ("result" in call) lines.push(...foldedDiffRows(call, width, opts));
|
|
1209
|
+
return lines;
|
|
994
1210
|
}
|
|
995
1211
|
|
|
996
1212
|
/**
|
|
@@ -1008,22 +1224,23 @@ export function renderToolExecution(
|
|
|
1008
1224
|
const status: HeaderStatus = finished.isError ? "error" : "ok";
|
|
1009
1225
|
const statusMeta: StatusMeta = {
|
|
1010
1226
|
durationMs: finished.durationMs,
|
|
1011
|
-
exitCode:
|
|
1227
|
+
exitCode: structuredExitCode(finished),
|
|
1012
1228
|
outcome: finished.outcome,
|
|
1013
1229
|
blockReason: finished.blockReason,
|
|
1014
1230
|
};
|
|
1015
1231
|
const out: string[] = [];
|
|
1016
1232
|
out.push(...wrap(headerLine(finished.toolName, finished.args, status, statusMeta), width));
|
|
1017
1233
|
|
|
1018
|
-
// Edit
|
|
1019
|
-
//
|
|
1020
|
-
//
|
|
1021
|
-
//
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
out.push(...
|
|
1234
|
+
// Edit and write tools produce one bounded numbered diff on result.details.
|
|
1235
|
+
// It is the authority because canonical edit args can contain multiple
|
|
1236
|
+
// replacements and fuzzy matching can change the actual base text. Live rows
|
|
1237
|
+
// receive Pi's word-level styling; replay and export request plain rows.
|
|
1238
|
+
if ((finished.toolName === "edit" || finished.toolName === "write") && finished.isError === false) {
|
|
1239
|
+
const diff = resultDiff(finished.result);
|
|
1240
|
+
if (diff !== null) {
|
|
1241
|
+
out.push(...renderOutputMeta(finished, width, false, "change"));
|
|
1242
|
+
out.push(...renderMutationDiffBlock(diff, width, opts.diffStyle !== "plain"));
|
|
1243
|
+
out.push(...renderOutputFooter(finished, width, false));
|
|
1027
1244
|
return out;
|
|
1028
1245
|
}
|
|
1029
1246
|
}
|
|
@@ -1035,20 +1252,35 @@ export function renderToolExecution(
|
|
|
1035
1252
|
if (finished.toolName === "bash") {
|
|
1036
1253
|
const bashArgs = asBashArgs(redactToolArgs(finished.args));
|
|
1037
1254
|
if (bashArgs !== null) {
|
|
1255
|
+
out.push(...renderArgsBody(finished.toolName, finished.args, width, finished.isError));
|
|
1256
|
+
out.push(
|
|
1257
|
+
...renderOutputMeta(
|
|
1258
|
+
finished,
|
|
1259
|
+
width,
|
|
1260
|
+
finished.isError,
|
|
1261
|
+
isNonExecutedOutcome(finished.outcome) ? "decision" : "output",
|
|
1262
|
+
),
|
|
1263
|
+
);
|
|
1038
1264
|
out.push(...renderBashResultBlock(bashArgs, finished.result, width, finished.isError, opts));
|
|
1265
|
+
out.push(...renderOutputFooter(finished, width, finished.isError));
|
|
1039
1266
|
return out;
|
|
1040
1267
|
}
|
|
1041
1268
|
}
|
|
1042
1269
|
|
|
1043
|
-
//
|
|
1044
|
-
//
|
|
1045
|
-
//
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1270
|
+
// The primary argument already lives in the signature. Keep the secondary
|
|
1271
|
+
// fields below it so flags, ranges, working directories, and timeouts remain
|
|
1272
|
+
// inspectable without repeating the primary value.
|
|
1273
|
+
out.push(...renderArgsBody(finished.toolName, finished.args, width, finished.isError));
|
|
1274
|
+
out.push(
|
|
1275
|
+
...renderOutputMeta(
|
|
1276
|
+
finished,
|
|
1277
|
+
width,
|
|
1278
|
+
finished.isError,
|
|
1279
|
+
isNonExecutedOutcome(finished.outcome) ? "decision" : "output",
|
|
1280
|
+
),
|
|
1281
|
+
);
|
|
1051
1282
|
out.push(...renderResultBlock(finished.result, finished.isError, width, opts));
|
|
1283
|
+
out.push(...renderOutputFooter(finished, width, finished.isError));
|
|
1052
1284
|
return out;
|
|
1053
1285
|
}
|
|
1054
1286
|
|
|
@@ -1065,13 +1297,15 @@ export function renderToolResultOnly(
|
|
|
1065
1297
|
const status: HeaderStatus = finished.isError ? "error" : "ok";
|
|
1066
1298
|
const statusMeta: StatusMeta = {
|
|
1067
1299
|
durationMs: finished.durationMs,
|
|
1068
|
-
exitCode:
|
|
1300
|
+
exitCode: structuredExitCode(finished),
|
|
1069
1301
|
outcome: finished.outcome,
|
|
1070
1302
|
blockReason: finished.blockReason,
|
|
1071
1303
|
};
|
|
1072
1304
|
const out: string[] = [];
|
|
1073
1305
|
out.push(...wrap(headerLine(finished.toolName, undefined, status, statusMeta), width));
|
|
1306
|
+
out.push(...renderOutputMeta(finished, width, finished.isError));
|
|
1074
1307
|
out.push(...renderResultBlock(finished.result, finished.isError, width, opts));
|
|
1308
|
+
out.push(...renderOutputFooter(finished, width, finished.isError));
|
|
1075
1309
|
return out;
|
|
1076
1310
|
}
|
|
1077
1311
|
|
|
@@ -1079,26 +1313,140 @@ export function renderToolResultOnly(
|
|
|
1079
1313
|
* Streaming render for an in-flight tool call whose expanded block should
|
|
1080
1314
|
* surface the latest partial output. Used by the chat panel between
|
|
1081
1315
|
* `tool_execution_start` and `tool_execution_end` when the user has expanded
|
|
1082
|
-
* the tool segment. The header carries
|
|
1083
|
-
*
|
|
1084
|
-
*
|
|
1085
|
-
* and a dim `(running...)` marker on the trailing line communicates that the
|
|
1086
|
-
* block is still being written. An empty `partialOutput` renders
|
|
1316
|
+
* the tool segment. The header carries the running lifecycle tail, secondary
|
|
1317
|
+
* arguments remain visible, and the latest cumulative Pi result renders under
|
|
1318
|
+
* a labeled live-output rail capped at the streaming row limit. An empty result renders
|
|
1087
1319
|
* `(no output yet)` so the user can distinguish a slow start from a stalled
|
|
1088
1320
|
* call.
|
|
1089
1321
|
*/
|
|
1090
|
-
export function renderToolStreamingExecution(
|
|
1322
|
+
export function renderToolStreamingExecution(
|
|
1323
|
+
call: ToolExecutionStart,
|
|
1324
|
+
width: number,
|
|
1325
|
+
partialResult: unknown,
|
|
1326
|
+
): string[] {
|
|
1091
1327
|
const out: string[] = [];
|
|
1092
|
-
out.push(...
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1328
|
+
out.push(...renderToolCallHeader({ ...call, phase: "running" }, width));
|
|
1329
|
+
out.push(...renderArgsBody(call.toolName, call.args, width, false));
|
|
1330
|
+
const partial: ToolExecutionFinished = {
|
|
1331
|
+
toolCallId: call.toolCallId,
|
|
1332
|
+
toolName: call.toolName,
|
|
1333
|
+
args: call.args,
|
|
1334
|
+
result: partialResult,
|
|
1335
|
+
isError: false,
|
|
1336
|
+
};
|
|
1337
|
+
out.push(...renderOutputMeta(partial, width, false, "live output"));
|
|
1338
|
+
const partialOutput = unwrapResultEnvelope(partialResult);
|
|
1339
|
+
if (isEmptyResult(partialOutput)) {
|
|
1097
1340
|
out.push(...indentAndWrap(dim("(no output yet)"), width, false));
|
|
1098
1341
|
} else {
|
|
1099
|
-
|
|
1342
|
+
if (call.toolName === "bash") {
|
|
1343
|
+
const bashArgs = asBashArgs(redactToolArgs(call.args));
|
|
1344
|
+
if (bashArgs !== null) {
|
|
1345
|
+
const commandLine = `${cyanBold("$")} ${highlightBashCommand(stripShellWrapperForDisplay(bashArgs.command))}`;
|
|
1346
|
+
out.push(...indentAndWrap(commandLine, width, false));
|
|
1347
|
+
}
|
|
1348
|
+
}
|
|
1349
|
+
out.push(
|
|
1350
|
+
...renderOutputRows(resultText(partialOutput, FULL_RESULT_PREVIEW_LIMIT), width, false, STREAMING_RESULT_ROW_LIMIT),
|
|
1351
|
+
);
|
|
1100
1352
|
}
|
|
1101
|
-
const elapsed = optionalCompactMs(call.elapsedMs);
|
|
1102
|
-
out.push(...indentAndWrap(dim(elapsed !== null ? `(running... ${elapsed})` : "(running...)"), width, false));
|
|
1103
1353
|
return out;
|
|
1104
1354
|
}
|
|
1355
|
+
|
|
1356
|
+
/** Display-only lifecycle for operator-issued `!` and `!!` bash commands. */
|
|
1357
|
+
export interface BashTranscriptExecution {
|
|
1358
|
+
command: string;
|
|
1359
|
+
output: string;
|
|
1360
|
+
running: boolean;
|
|
1361
|
+
elapsedMs?: number | undefined;
|
|
1362
|
+
totalBytes?: number | undefined;
|
|
1363
|
+
exitCode?: number | null | undefined;
|
|
1364
|
+
cancelled?: boolean | undefined;
|
|
1365
|
+
truncated?: boolean | undefined;
|
|
1366
|
+
fullOutputPath?: string | undefined;
|
|
1367
|
+
excludeFromContext?: boolean | undefined;
|
|
1368
|
+
error?: string | undefined;
|
|
1369
|
+
/**
|
|
1370
|
+
* Whether the block draws its one-line row instead of the full body. The
|
|
1371
|
+
* caller resolves this from the transcript detail policy and the operator's
|
|
1372
|
+
* override, the same way the panel resolves a model bash call. Omitted means
|
|
1373
|
+
* folded.
|
|
1374
|
+
*/
|
|
1375
|
+
folded?: boolean | undefined;
|
|
1376
|
+
}
|
|
1377
|
+
|
|
1378
|
+
/**
|
|
1379
|
+
* Render local bash with the same call, argument, output, and settlement grammar
|
|
1380
|
+
* as model-initiated bash. This is a view projection only; callers keep Clio's
|
|
1381
|
+
* existing immutable `bashExecution` ledger entry.
|
|
1382
|
+
*/
|
|
1383
|
+
export function renderBashTranscriptExecution(
|
|
1384
|
+
execution: BashTranscriptExecution,
|
|
1385
|
+
width: number,
|
|
1386
|
+
expandKey?: string,
|
|
1387
|
+
bodyOptions: ToolBodyRenderOptions = {},
|
|
1388
|
+
): string[] {
|
|
1389
|
+
const shownBytes = Buffer.byteLength(execution.output, "utf8");
|
|
1390
|
+
const totalBytes = execution.totalBytes ?? shownBytes;
|
|
1391
|
+
const args: Record<string, unknown> = { command: execution.command };
|
|
1392
|
+
if (execution.excludeFromContext === true) args.context = "excluded from model context";
|
|
1393
|
+
const details = {
|
|
1394
|
+
resultSize: {
|
|
1395
|
+
bytes: totalBytes,
|
|
1396
|
+
shownBytes,
|
|
1397
|
+
truncated: execution.truncated === true,
|
|
1398
|
+
policy: "tail",
|
|
1399
|
+
...(execution.fullOutputPath !== undefined ? { offloadPath: execution.fullOutputPath } : {}),
|
|
1400
|
+
},
|
|
1401
|
+
};
|
|
1402
|
+
const result = {
|
|
1403
|
+
content: [{ type: "text", text: execution.output }],
|
|
1404
|
+
details,
|
|
1405
|
+
};
|
|
1406
|
+
const folded = execution.folded !== false;
|
|
1407
|
+
if (execution.running) {
|
|
1408
|
+
if (folded) {
|
|
1409
|
+
return renderToolSubline(
|
|
1410
|
+
{
|
|
1411
|
+
toolCallId: "local-bash",
|
|
1412
|
+
toolName: "bash",
|
|
1413
|
+
args,
|
|
1414
|
+
elapsedMs: execution.elapsedMs,
|
|
1415
|
+
phase: "running",
|
|
1416
|
+
},
|
|
1417
|
+
width,
|
|
1418
|
+
);
|
|
1419
|
+
}
|
|
1420
|
+
return renderToolStreamingExecution(
|
|
1421
|
+
{
|
|
1422
|
+
toolCallId: "local-bash",
|
|
1423
|
+
toolName: "bash",
|
|
1424
|
+
args,
|
|
1425
|
+
elapsedMs: execution.elapsedMs,
|
|
1426
|
+
phase: "running",
|
|
1427
|
+
},
|
|
1428
|
+
width,
|
|
1429
|
+
result,
|
|
1430
|
+
);
|
|
1431
|
+
}
|
|
1432
|
+
const message = execution.error?.trim();
|
|
1433
|
+
const output = message
|
|
1434
|
+
? `${execution.output}${execution.output.length > 0 ? "\n\n" : ""}${message}`
|
|
1435
|
+
: execution.output;
|
|
1436
|
+
const finished: ToolExecutionFinished = {
|
|
1437
|
+
toolCallId: "local-bash",
|
|
1438
|
+
toolName: "bash",
|
|
1439
|
+
args,
|
|
1440
|
+
result: { ...result, content: [{ type: "text", text: output }] },
|
|
1441
|
+
isError: execution.cancelled === true || execution.error !== undefined || (execution.exitCode ?? 0) !== 0,
|
|
1442
|
+
exitCode: execution.exitCode,
|
|
1443
|
+
...(execution.cancelled === true ? { outcome: "aborted" as const } : {}),
|
|
1444
|
+
excludeFromContext: execution.excludeFromContext,
|
|
1445
|
+
resultSummary: {
|
|
1446
|
+
bytes: shownBytes,
|
|
1447
|
+
truncated: execution.truncated === true,
|
|
1448
|
+
...(execution.fullOutputPath !== undefined ? { offloadPath: execution.fullOutputPath } : {}),
|
|
1449
|
+
},
|
|
1450
|
+
};
|
|
1451
|
+
return folded ? renderToolSubline(finished, width, expandKey) : renderToolExecution(finished, width, bodyOptions);
|
|
1452
|
+
}
|