@iowarp/clio-coder 0.3.1 → 0.3.2
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 +90 -2
- package/CONTRIBUTING.md +23 -23
- package/README.md +284 -613
- package/dist/{acp-FPR54DGL.js → acp-BIYHVZIM.js} +43 -53
- package/dist/{agents-OGPIHPJH.js → agents-YT6SSRIT.js} +43 -26
- package/dist/assets/codewiki.json +1 -1
- package/dist/{auth-IC3K6NIZ.js → auth-5TWEIYDN.js} +20 -12
- package/dist/{chunk-PV4JUBVJ.js → chunk-2EHAIA3X.js} +40 -21
- package/dist/{chunk-IS3ONKU3.js → chunk-2IR2NMPA.js} +6 -4
- package/dist/chunk-2SFS6XQE.js +122 -0
- package/dist/chunk-2VTFPG5O.js +48 -0
- package/dist/{chunk-MAR7Y6HW.js → chunk-3ZXDFGR5.js} +23 -16
- package/dist/chunk-4BJ5BYCE.js +61 -0
- package/dist/{chunk-474KN5II.js → chunk-4BPJXDWC.js} +111 -181
- package/dist/chunk-4KLWL3UC.js +18 -0
- package/dist/chunk-4VP4KH3K.js +962 -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-OLBBMFRD.js → chunk-5UUP6MWO.js} +24 -62
- package/dist/chunk-65DEGPJ6.js +52 -0
- package/dist/chunk-6EJMN2Y3.js +17 -0
- package/dist/chunk-6EJV5X2W.js +16405 -0
- package/dist/chunk-6N5PTWMY.js +136 -0
- package/dist/chunk-6XLNIQDB.js +27 -0
- package/dist/{chunk-TEKV33Q5.js → chunk-77VKQEHF.js} +65 -33
- package/dist/chunk-7CR24IG7.js +242 -0
- package/dist/{chunk-M5T5VO65.js → chunk-7EYHLWU7.js} +837 -635
- 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-AO4RKG4M.js +277 -0
- package/dist/{chunk-GB6QRBXN.js → chunk-APJ265NV.js} +54 -1187
- package/dist/chunk-ARBGF5F7.js +174 -0
- 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-ECH6PKUQ.js +39 -0
- package/dist/chunk-ED4KHGC3.js +143 -0
- package/dist/chunk-EKMEHE4H.js +340 -0
- package/dist/{chunk-RPTR2H26.js → chunk-EPVUXGXG.js} +21 -15
- package/dist/chunk-FCSXB6T2.js +338 -0
- package/dist/chunk-FJ3H4MN5.js +48 -0
- package/dist/chunk-FQ4SKYE4.js +29 -0
- package/dist/chunk-G2DE3C7R.js +644 -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-4QKXUHSR.js → chunk-IGLFWIYI.js} +70 -20
- package/dist/chunk-IKCO5N3L.js +162 -0
- package/dist/chunk-IR4CFBFN.js +56 -0
- package/dist/{chunk-PFEFKVGL.js → chunk-J5HN4RYU.js} +13 -11
- package/dist/{chunk-R5KLMSBV.js → chunk-J5Q24KAG.js} +2 -2
- package/dist/{chunk-K5XEMXTI.js → chunk-JVCV3ICN.js} +1 -1
- package/dist/chunk-KJ5LWLOE.js +1077 -0
- package/dist/chunk-LBMZMYH2.js +285 -0
- package/dist/{chunk-G34LV2PF.js → chunk-LBNRH5WM.js} +84 -170
- package/dist/{chunk-H6F6BYOH.js → chunk-LZSJBIVT.js} +7003 -7434
- package/dist/{chunk-HQQID6OA.js → chunk-M6SHUN7Q.js} +5 -5
- package/dist/chunk-MAW544W2.js +1882 -0
- package/dist/chunk-MBS4V7ZP.js +217 -0
- package/dist/{chunk-FST4FYJB.js → chunk-MFFY33HR.js} +99 -140
- package/dist/chunk-MNA4JGU4.js +255 -0
- package/dist/chunk-MQSRRFWA.js +3428 -0
- package/dist/{chunk-BSU2YIWB.js → chunk-MVVUPGPW.js} +131 -136
- package/dist/chunk-OAO4GE4M.js +619 -0
- package/dist/chunk-OHHN2SO4.js +5135 -0
- 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-POHLU5DW.js +1186 -0
- package/dist/chunk-QKMUKYO7.js +4961 -0
- package/dist/{chunk-ASND7OZK.js → chunk-QTYWRVRA.js} +13 -13
- package/dist/{chunk-EYOKLTMF.js → chunk-SRF2PJNW.js} +17 -3
- package/dist/chunk-SST6Z5JA.js +80 -0
- package/dist/chunk-STBPMHSX.js +2456 -0
- package/dist/chunk-T6YILFSB.js +80 -0
- package/dist/chunk-TZTZS7QK.js +227 -0
- package/dist/chunk-UOV2BYIW.js +107 -0
- package/dist/{chunk-Q3RUPKEJ.js → chunk-V4RXGQ5Q.js} +58 -189
- package/dist/chunk-VAKQQHWR.js +434 -0
- package/dist/chunk-VG7TBQIY.js +128 -0
- package/dist/chunk-VJWL6YS5.js +244 -0
- package/dist/chunk-WEH5XRJQ.js +32 -0
- package/dist/chunk-WMSVI4G2.js +2095 -0
- package/dist/chunk-WVO7V2QY.js +797 -0
- package/dist/chunk-X4RCMKVQ.js +641 -0
- package/dist/chunk-X75S7HFS.js +374 -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/cli/index.js +62 -54
- package/dist/clio-4LY5K2AC.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-GTLUW2PR.js} +92 -55
- package/dist/configure-R6A64DHX.js +42 -0
- package/dist/context-5VKGUVJJ.js +866 -0
- package/dist/{context-3KWFLHJG.js → context-JFZEJ7W5.js} +15 -13
- package/dist/{context-5RADCKTR.js → context-RW5HC47S.js} +71 -35
- package/dist/{context-clear-7TSNPAAI.js → context-clear-6ZHBAZZT.js} +54 -28
- package/dist/{context-index-W4RLWOQH.js → context-index-BZ4UYMTC.js} +30 -24
- package/dist/dispatch-runner-VKBRCWQC.js +1997 -0
- package/dist/{docs-5AWSPS37.js → docs-2C2LTVT2.js} +23 -10
- package/dist/{doctor-UC5NAJYQ.js → doctor-KI767GSN.js} +27 -17
- package/dist/{eval-U6TJHRLX.js → eval-XSSNATB4.js} +29 -16
- package/dist/{evidence-YEGUW4L3.js → evidence-UA6AWDQQ.js} +46 -26
- package/dist/{evolve-TXARCTPG.js → evolve-QNTFGV6Z.js} +45 -25
- package/dist/{extensions-OZFJ3A3G.js → extensions-QVDOHDGJ.js} +16 -7
- package/dist/{fleet-6G3DHNYE.js → fleet-Q7UOMUSG.js} +163 -54
- package/dist/{fleet-preflight-DSNT37JK.js → fleet-preflight-DDN536IT.js} +7 -4
- package/dist/{init-KZ5QTF6M.js → init-WBB65ZHQ.js} +69 -32
- package/dist/{memory-73ESV5YC.js → memory-MD3O64RI.js} +48 -27
- package/dist/{models-A4PVNWJK.js → models-BZU34YWD.js} +39 -25
- package/dist/monitor-MEQA5C3I.js +661 -0
- package/dist/{chunk-FCIH3BIZ.js → orchestrator-CGFKEP27.js} +11832 -8687
- 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-IV4Q6RLN.js} +101 -61
- package/dist/{share-YIFFV4NQ.js → share-S5BZQC5I.js} +15 -8
- package/dist/{skills-2V6RA3OQ.js → skills-LQEKRDTN.js} +34 -14
- package/dist/{skills-eval-S2TVJO4F.js → skills-eval-3DC4HEWS.js} +70 -34
- package/dist/steer-GGWFUJUD.js +77 -0
- package/dist/{targets-TYXLPB23.js → targets-C4SSGQOB.js} +43 -27
- package/dist/terminal-lease-IT5JW2NR.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-7TT7SQ3G.js} +45 -25
- package/dist/{usage-ZAFSXKKG.js → usage-GV4PKT3M.js} +62 -31
- package/dist/verify-G6V4D2G7.js +716 -0
- package/dist/web-fetch-2YHJ3KTG.js +638 -0
- package/dist/{wiki-generate-NUQCVOQ3.js → wiki-generate-DQF6Z66B.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 +362 -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 +42 -6
- 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 +173 -47
- package/src/interactive/chat-renderer.ts +262 -72
- 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 +228 -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 +20 -2
- package/src/interactive/footer-panel.ts +2 -2
- package/src/interactive/format-time.ts +14 -2
- package/src/interactive/interactive-application.ts +201 -17
- package/src/interactive/interactive-event-projection.ts +6 -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 +176 -114
- 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/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 +386 -133
- 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/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/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 +265 -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/registry.ts +39 -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,4 +1,10 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import {
|
|
3
|
+
isSessionEntry,
|
|
4
|
+
type TaskLedgerGoal,
|
|
5
|
+
type TaskLedgerStatus,
|
|
6
|
+
type TaskLedgerValidationEvidence,
|
|
7
|
+
} from "./entries.js";
|
|
2
8
|
|
|
3
9
|
/**
|
|
4
10
|
* The session task board: the live state behind the `tasks` tool, the footer
|
|
@@ -15,11 +21,14 @@ import type { SessionEntry, TaskLedgerGoal, TaskLedgerStatus, TaskLedgerValidati
|
|
|
15
21
|
*/
|
|
16
22
|
|
|
17
23
|
const TASK_BOARD_GOAL_ID = "board";
|
|
24
|
+
export const LEGACY_TASK_BOARD_ID = "legacy";
|
|
18
25
|
|
|
19
26
|
export interface TaskBoardTask {
|
|
20
27
|
id: string;
|
|
21
28
|
title: string;
|
|
22
29
|
status: TaskLedgerStatus;
|
|
30
|
+
origin?: "agent" | "user";
|
|
31
|
+
userTaskId?: string;
|
|
23
32
|
/** Block or drop reason; empty for pending/active/completed tasks. */
|
|
24
33
|
reason?: string;
|
|
25
34
|
/** Evidence note recorded when the task was completed. */
|
|
@@ -27,6 +36,8 @@ export interface TaskBoardTask {
|
|
|
27
36
|
}
|
|
28
37
|
|
|
29
38
|
export interface TaskBoardSnapshot {
|
|
39
|
+
/** Stable identity for this plan generation; task display ids are reusable. */
|
|
40
|
+
boardId: string;
|
|
30
41
|
title: string;
|
|
31
42
|
tasks: ReadonlyArray<TaskBoardTask>;
|
|
32
43
|
/**
|
|
@@ -53,6 +64,7 @@ export interface TaskBoardCounts {
|
|
|
53
64
|
export type TaskBoardMutation =
|
|
54
65
|
| { op: "plan"; title: string; tasks: ReadonlyArray<string> }
|
|
55
66
|
| { op: "add"; tasks: ReadonlyArray<string> }
|
|
67
|
+
| { op: "pick"; title: string; userTaskId: string }
|
|
56
68
|
| { op: "start"; id: string }
|
|
57
69
|
| { op: "done"; id: string; evidence: string }
|
|
58
70
|
| { op: "block"; id: string; reason: string }
|
|
@@ -71,6 +83,7 @@ export type TaskBoardMutationResult =
|
|
|
71
83
|
export interface TaskLedgerEntryFields {
|
|
72
84
|
kind: "taskLedger";
|
|
73
85
|
parentTurnId: null;
|
|
86
|
+
boardId: string;
|
|
74
87
|
goals: TaskLedgerGoal[];
|
|
75
88
|
subgoals: TaskLedgerGoal[];
|
|
76
89
|
activeRunIds: string[];
|
|
@@ -88,18 +101,48 @@ export interface TaskBoardStoreDeps {
|
|
|
88
101
|
readEntries?: () => ReadonlyArray<unknown>;
|
|
89
102
|
/** Persist one full-snapshot taskLedger entry. Absent means in-memory only. */
|
|
90
103
|
appendEntry?: (entry: TaskLedgerEntryFields) => void;
|
|
104
|
+
/** Stable board-id source; injectable for deterministic contract tests. */
|
|
105
|
+
createBoardId?: () => string;
|
|
91
106
|
now?: () => Date;
|
|
92
107
|
}
|
|
93
108
|
|
|
109
|
+
export interface SessionTaskHistoryBoard {
|
|
110
|
+
boardId: string;
|
|
111
|
+
title: string;
|
|
112
|
+
tasks: ReadonlyArray<TaskBoardTask>;
|
|
113
|
+
lastSnapshotAt: string;
|
|
114
|
+
}
|
|
115
|
+
|
|
94
116
|
export interface TaskBoardStore {
|
|
95
117
|
/** Current board, refolded from the session ledger after a session switch. */
|
|
96
118
|
snapshot(): TaskBoardSnapshot | null;
|
|
119
|
+
/**
|
|
120
|
+
* Current in-memory projection only. Unlike snapshot(), this never reads or
|
|
121
|
+
* folds the session ledger and returns null rather than leaking a stale board
|
|
122
|
+
* when the session id changed or invalidate() has marked the cache dirty.
|
|
123
|
+
*/
|
|
124
|
+
cachedSnapshot(): TaskBoardSnapshot | null;
|
|
125
|
+
/** Durable board generations on the active session path, newest first. */
|
|
126
|
+
historySnapshot(): ReadonlyArray<SessionTaskHistoryBoard>;
|
|
97
127
|
/** Apply one mutation, persist the resulting snapshot, and return it. */
|
|
98
128
|
apply(mutation: TaskBoardMutation): TaskBoardMutationResult;
|
|
99
129
|
/** Link an in-flight dispatch run to the board; a no-op without a board. */
|
|
100
130
|
attachRun(runId: string): void;
|
|
101
131
|
/** Unlink a finished dispatch run; a no-op when it was never attached. */
|
|
102
132
|
detachRun(runId: string): void;
|
|
133
|
+
/**
|
|
134
|
+
* Force the next read to refold from the ledger even if `getSessionId()`
|
|
135
|
+
* reports the same id it did last time. A `/tree` switch moves the active
|
|
136
|
+
* append point without changing which session is open, so the id-keyed
|
|
137
|
+
* cache alone never noticed the branch change and kept showing the
|
|
138
|
+
* abandoned branch's board (issue #94). Callers invalidate on the bus
|
|
139
|
+
* signal that switch emits.
|
|
140
|
+
*/
|
|
141
|
+
invalidate(): void;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function isOpenUserTask(task: TaskBoardTask): boolean {
|
|
145
|
+
return task.origin === "user" && (task.status === "pending" || task.status === "active");
|
|
103
146
|
}
|
|
104
147
|
|
|
105
148
|
export function taskBoardCounts(board: Pick<TaskBoardSnapshot, "tasks">): TaskBoardCounts {
|
|
@@ -150,12 +193,15 @@ export function toTaskLedgerEntryFields(board: TaskBoardSnapshot, now: Date): Ta
|
|
|
150
193
|
status: task.status,
|
|
151
194
|
parentGoalId: TASK_BOARD_GOAL_ID,
|
|
152
195
|
};
|
|
196
|
+
if (task.origin) goal.origin = task.origin;
|
|
197
|
+
if (task.userTaskId) goal.userTaskId = task.userTaskId;
|
|
153
198
|
if (task.reason) goal.description = task.reason;
|
|
154
199
|
return goal;
|
|
155
200
|
});
|
|
156
201
|
return {
|
|
157
202
|
kind: "taskLedger",
|
|
158
203
|
parentTurnId: null,
|
|
204
|
+
boardId: board.boardId,
|
|
159
205
|
goals: [{ id: TASK_BOARD_GOAL_ID, title: board.title, status: boardStatus(board.tasks) }],
|
|
160
206
|
subgoals,
|
|
161
207
|
activeRunIds: [...board.activeRunIds],
|
|
@@ -165,13 +211,13 @@ export function toTaskLedgerEntryFields(board: TaskBoardSnapshot, now: Date): Ta
|
|
|
165
211
|
|
|
166
212
|
function isTaskLedgerShaped(value: unknown): value is {
|
|
167
213
|
kind: "taskLedger";
|
|
214
|
+
boardId?: string;
|
|
215
|
+
timestamp?: string;
|
|
168
216
|
goals: TaskLedgerGoal[];
|
|
169
217
|
subgoals: TaskLedgerGoal[];
|
|
170
218
|
requiredValidationEvidence: TaskLedgerValidationEvidence[];
|
|
171
219
|
} {
|
|
172
|
-
|
|
173
|
-
const entry = value as Partial<SessionEntry>;
|
|
174
|
-
return entry.kind === "taskLedger" && Array.isArray((entry as { goals?: unknown }).goals);
|
|
220
|
+
return isSessionEntry(value) && value.kind === "taskLedger";
|
|
175
221
|
}
|
|
176
222
|
|
|
177
223
|
/**
|
|
@@ -186,7 +232,60 @@ export function foldTaskBoard(entries: ReadonlyArray<unknown>): TaskBoardSnapsho
|
|
|
186
232
|
return last;
|
|
187
233
|
}
|
|
188
234
|
|
|
235
|
+
/**
|
|
236
|
+
* Fold every safely identifiable board generation in a session. New ledgers
|
|
237
|
+
* key generations by boardId; pre-boardId ledgers collapse to the newest
|
|
238
|
+
* legacy snapshot because reusable tN ids cannot safely distinguish their
|
|
239
|
+
* older plan generations.
|
|
240
|
+
*/
|
|
241
|
+
export function foldSessionTaskHistory(entries: ReadonlyArray<unknown>): SessionTaskHistoryBoard[] {
|
|
242
|
+
type MutableHistoryBoard = {
|
|
243
|
+
boardId: string;
|
|
244
|
+
title: string;
|
|
245
|
+
tasks: Map<string, TaskBoardTask>;
|
|
246
|
+
lastSnapshotAt: string;
|
|
247
|
+
lastIndex: number;
|
|
248
|
+
};
|
|
249
|
+
const boards = new Map<string, MutableHistoryBoard>();
|
|
250
|
+
for (const [index, raw] of entries.entries()) {
|
|
251
|
+
if (!isTaskLedgerShaped(raw)) continue;
|
|
252
|
+
const view = toEntryView(raw);
|
|
253
|
+
if (!view) continue;
|
|
254
|
+
const boardId = typeof raw.boardId === "string" && raw.boardId.length > 0 ? raw.boardId : LEGACY_TASK_BOARD_ID;
|
|
255
|
+
const timestamp = typeof raw.timestamp === "string" ? raw.timestamp : "";
|
|
256
|
+
if (boardId === LEGACY_TASK_BOARD_ID) {
|
|
257
|
+
boards.set(boardId, {
|
|
258
|
+
boardId,
|
|
259
|
+
title: view.title,
|
|
260
|
+
tasks: new Map(view.tasks.map((task) => [task.id, task])),
|
|
261
|
+
lastSnapshotAt: timestamp,
|
|
262
|
+
lastIndex: index,
|
|
263
|
+
});
|
|
264
|
+
continue;
|
|
265
|
+
}
|
|
266
|
+
const existing = boards.get(boardId);
|
|
267
|
+
if (!existing) {
|
|
268
|
+
boards.set(boardId, {
|
|
269
|
+
boardId,
|
|
270
|
+
title: view.title,
|
|
271
|
+
tasks: new Map(view.tasks.map((task) => [task.id, task])),
|
|
272
|
+
lastSnapshotAt: timestamp,
|
|
273
|
+
lastIndex: index,
|
|
274
|
+
});
|
|
275
|
+
continue;
|
|
276
|
+
}
|
|
277
|
+
existing.title = view.title;
|
|
278
|
+
for (const task of view.tasks) existing.tasks.set(task.id, task);
|
|
279
|
+
existing.lastSnapshotAt = timestamp;
|
|
280
|
+
existing.lastIndex = index;
|
|
281
|
+
}
|
|
282
|
+
return [...boards.values()]
|
|
283
|
+
.sort((left, right) => right.lastIndex - left.lastIndex)
|
|
284
|
+
.map(({ lastIndex: _lastIndex, tasks, ...board }) => ({ ...board, tasks: [...tasks.values()] }));
|
|
285
|
+
}
|
|
286
|
+
|
|
189
287
|
function toEntryView(entry: {
|
|
288
|
+
boardId?: string;
|
|
190
289
|
goals: TaskLedgerGoal[];
|
|
191
290
|
subgoals: TaskLedgerGoal[];
|
|
192
291
|
requiredValidationEvidence: TaskLedgerValidationEvidence[];
|
|
@@ -199,9 +298,16 @@ function toEntryView(entry: {
|
|
|
199
298
|
evidenceByTask.set(taskId, item.description);
|
|
200
299
|
}
|
|
201
300
|
return {
|
|
301
|
+
boardId: entry.boardId ?? LEGACY_TASK_BOARD_ID,
|
|
202
302
|
title: boardGoal.title,
|
|
203
303
|
tasks: entry.subgoals.map((goal) => {
|
|
204
|
-
const task: TaskBoardTask = {
|
|
304
|
+
const task: TaskBoardTask = {
|
|
305
|
+
id: goal.id,
|
|
306
|
+
title: goal.title,
|
|
307
|
+
status: goal.status,
|
|
308
|
+
origin: goal.origin ?? "agent",
|
|
309
|
+
};
|
|
310
|
+
if (goal.userTaskId) task.userTaskId = goal.userTaskId;
|
|
205
311
|
if (goal.description) task.reason = goal.description;
|
|
206
312
|
const evidence = evidenceByTask.get(goal.id);
|
|
207
313
|
if (evidence) task.evidence = evidence;
|
|
@@ -235,14 +341,27 @@ function applyMutation(
|
|
|
235
341
|
const titles = normalizeTitles(mutation.tasks);
|
|
236
342
|
if (mutation.title.trim().length === 0) return { error: "plan requires a non-empty title" };
|
|
237
343
|
if (titles.length === 0) return { error: "plan requires at least one task" };
|
|
344
|
+
const retained = board?.tasks.filter(isOpenUserTask) ?? [];
|
|
238
345
|
const notes: string[] = [];
|
|
239
|
-
|
|
240
|
-
|
|
346
|
+
const replacedOpen = board ? taskBoardCounts(board).open - retained.length : 0;
|
|
347
|
+
if (board && replacedOpen > 0) {
|
|
348
|
+
notes.push(`replaced board "${board.title}" with ${replacedOpen} agent task(s) still open`);
|
|
241
349
|
}
|
|
350
|
+
if (retained.length > 0) notes.push(`preserved ${retained.length} open operator task(s)`);
|
|
351
|
+
const start = nextTaskId(retained);
|
|
242
352
|
return {
|
|
243
353
|
board: {
|
|
354
|
+
boardId: "",
|
|
244
355
|
title: mutation.title.trim(),
|
|
245
|
-
tasks:
|
|
356
|
+
tasks: [
|
|
357
|
+
...retained,
|
|
358
|
+
...titles.map((title, index) => ({
|
|
359
|
+
id: `t${start + index}`,
|
|
360
|
+
title,
|
|
361
|
+
status: "pending" as const,
|
|
362
|
+
origin: "agent" as const,
|
|
363
|
+
})),
|
|
364
|
+
],
|
|
246
365
|
// Runs in flight outlive a board swap: they belong to the session,
|
|
247
366
|
// so the fresh board inherits the linkage until the runs finish.
|
|
248
367
|
activeRunIds: board?.activeRunIds ?? [],
|
|
@@ -250,12 +369,48 @@ function applyMutation(
|
|
|
250
369
|
notes,
|
|
251
370
|
};
|
|
252
371
|
}
|
|
372
|
+
if (mutation.op === "pick") {
|
|
373
|
+
const title = mutation.title.trim();
|
|
374
|
+
if (title.length === 0) return { error: "pick requires a non-empty operator task title" };
|
|
375
|
+
if (!/^u[1-9]\d*$/.test(mutation.userTaskId)) return { error: "pick requires an operator task id like u3" };
|
|
376
|
+
if (
|
|
377
|
+
board?.tasks.some(
|
|
378
|
+
(task) =>
|
|
379
|
+
task.userTaskId === mutation.userTaskId &&
|
|
380
|
+
(task.status === "pending" || task.status === "active" || task.status === "completed"),
|
|
381
|
+
)
|
|
382
|
+
) {
|
|
383
|
+
return { error: `operator task ${mutation.userTaskId} is already linked to durable board work` };
|
|
384
|
+
}
|
|
385
|
+
const tasks = board?.tasks ?? [];
|
|
386
|
+
const picked: TaskBoardTask = {
|
|
387
|
+
id: `t${nextTaskId(tasks)}`,
|
|
388
|
+
title,
|
|
389
|
+
status: "pending",
|
|
390
|
+
origin: "user",
|
|
391
|
+
userTaskId: mutation.userTaskId,
|
|
392
|
+
};
|
|
393
|
+
return {
|
|
394
|
+
board: {
|
|
395
|
+
boardId: board?.boardId ?? "",
|
|
396
|
+
title: board?.title ?? "Operator tasks",
|
|
397
|
+
tasks: [...tasks, picked],
|
|
398
|
+
activeRunIds: board?.activeRunIds ?? [],
|
|
399
|
+
},
|
|
400
|
+
notes: [],
|
|
401
|
+
};
|
|
402
|
+
}
|
|
253
403
|
if (board === null) return { error: 'no task board yet; declare one with action="plan" first' };
|
|
254
404
|
if (mutation.op === "add") {
|
|
255
405
|
const titles = normalizeTitles(mutation.tasks);
|
|
256
406
|
if (titles.length === 0) return { error: "add requires at least one task" };
|
|
257
407
|
const start = nextTaskId(board.tasks);
|
|
258
|
-
const added = titles.map((title, index) => ({
|
|
408
|
+
const added = titles.map((title, index) => ({
|
|
409
|
+
id: `t${start + index}`,
|
|
410
|
+
title,
|
|
411
|
+
status: "pending" as const,
|
|
412
|
+
origin: "agent" as const,
|
|
413
|
+
}));
|
|
259
414
|
return { board: { ...board, tasks: [...board.tasks, ...added] }, notes: [] };
|
|
260
415
|
}
|
|
261
416
|
const target = board.tasks.find((task) => task.id === mutation.id);
|
|
@@ -323,11 +478,13 @@ function applyStatusMutation(
|
|
|
323
478
|
|
|
324
479
|
export function createTaskBoardStore(deps: TaskBoardStoreDeps = {}): TaskBoardStore {
|
|
325
480
|
let cachedSessionId: string | null | undefined;
|
|
481
|
+
let dirty = true;
|
|
326
482
|
let board: TaskBoardSnapshot | null = null;
|
|
327
483
|
|
|
328
484
|
const syncToSession = (): void => {
|
|
329
485
|
const sessionId = deps.getSessionId?.() ?? null;
|
|
330
|
-
if (cachedSessionId === sessionId) return;
|
|
486
|
+
if (!dirty && cachedSessionId === sessionId) return;
|
|
487
|
+
dirty = false;
|
|
331
488
|
cachedSessionId = sessionId;
|
|
332
489
|
try {
|
|
333
490
|
board = deps.readEntries ? foldTaskBoard(deps.readEntries()) : null;
|
|
@@ -345,18 +502,52 @@ export function createTaskBoardStore(deps: TaskBoardStoreDeps = {}): TaskBoardSt
|
|
|
345
502
|
}
|
|
346
503
|
};
|
|
347
504
|
|
|
505
|
+
const mutationRequiresAcknowledgement = (current: TaskBoardSnapshot | null, mutation: TaskBoardMutation): boolean => {
|
|
506
|
+
if (mutation.op === "pick") return true;
|
|
507
|
+
if (mutation.op === "plan") return current?.tasks.some(isOpenUserTask) ?? false;
|
|
508
|
+
if (mutation.op !== "done") return false;
|
|
509
|
+
return current?.tasks.some((task) => task.id === mutation.id && task.origin === "user") ?? false;
|
|
510
|
+
};
|
|
511
|
+
|
|
348
512
|
return {
|
|
349
513
|
snapshot(): TaskBoardSnapshot | null {
|
|
350
514
|
syncToSession();
|
|
351
515
|
return board;
|
|
352
516
|
},
|
|
517
|
+
cachedSnapshot(): TaskBoardSnapshot | null {
|
|
518
|
+
const sessionId = deps.getSessionId?.() ?? null;
|
|
519
|
+
return !dirty && cachedSessionId === sessionId ? board : null;
|
|
520
|
+
},
|
|
521
|
+
historySnapshot(): ReadonlyArray<SessionTaskHistoryBoard> {
|
|
522
|
+
syncToSession();
|
|
523
|
+
try {
|
|
524
|
+
return deps.readEntries ? foldSessionTaskHistory(deps.readEntries()) : [];
|
|
525
|
+
} catch {
|
|
526
|
+
return [];
|
|
527
|
+
}
|
|
528
|
+
},
|
|
353
529
|
apply(mutation: TaskBoardMutation): TaskBoardMutationResult {
|
|
354
530
|
syncToSession();
|
|
355
531
|
const result = applyMutation(board, mutation);
|
|
356
532
|
if ("error" in result) return { ok: false, message: result.error };
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
533
|
+
const needsBoardId = mutation.op === "plan" || result.board.boardId.length === 0;
|
|
534
|
+
const nextBoard = needsBoardId ? { ...result.board, boardId: deps.createBoardId?.() ?? randomUUID() } : result.board;
|
|
535
|
+
if (mutationRequiresAcknowledgement(board, mutation)) {
|
|
536
|
+
if (!deps.appendEntry) {
|
|
537
|
+
return { ok: false, message: "durable task-ledger persistence is unavailable for operator-linked work" };
|
|
538
|
+
}
|
|
539
|
+
try {
|
|
540
|
+
deps.appendEntry(toTaskLedgerEntryFields(nextBoard, deps.now?.() ?? new Date()));
|
|
541
|
+
} catch (error) {
|
|
542
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
543
|
+
return { ok: false, message: `could not persist operator-linked task board: ${message}` };
|
|
544
|
+
}
|
|
545
|
+
board = nextBoard;
|
|
546
|
+
return { ok: true, board: nextBoard, notes: result.notes };
|
|
547
|
+
}
|
|
548
|
+
board = nextBoard;
|
|
549
|
+
persist(nextBoard);
|
|
550
|
+
return { ok: true, board: nextBoard, notes: result.notes };
|
|
360
551
|
},
|
|
361
552
|
attachRun(runId: string): void {
|
|
362
553
|
syncToSession();
|
|
@@ -371,5 +562,8 @@ export function createTaskBoardStore(deps: TaskBoardStoreDeps = {}): TaskBoardSt
|
|
|
371
562
|
board = { ...board, activeRunIds: board.activeRunIds.filter((id) => id !== runId) };
|
|
372
563
|
persist(board);
|
|
373
564
|
},
|
|
565
|
+
invalidate(): void {
|
|
566
|
+
dirty = true;
|
|
567
|
+
},
|
|
374
568
|
};
|
|
375
569
|
}
|
|
@@ -12,8 +12,14 @@ import type { MessageEntry, SessionEntry } from "../entries.js";
|
|
|
12
12
|
* - message entries on the active path,
|
|
13
13
|
* - sidecar entries anchored to a path turn (parentTurnId or targetTurnId),
|
|
14
14
|
* - compaction summaries whose firstKeptTurnId or parent lands on the path,
|
|
15
|
-
* - unanchored sidecars (parentTurnId null)
|
|
16
|
-
*
|
|
15
|
+
* - unanchored sidecars (parentTurnId null) written at or before the leaf's
|
|
16
|
+
* position in the file. `fork.ts` shares this same rule (`entryBelongsToPath`
|
|
17
|
+
* below) for the same reason: an unanchored sidecar records state as of
|
|
18
|
+
* the moment it was written, and a sidecar written after the turn a
|
|
19
|
+
* reconstruction stands at was not visible then, on any branch. Before
|
|
20
|
+
* issue #94 this filter kept every unanchored sidecar regardless of
|
|
21
|
+
* position while fork applied the positional cut, so the same turn
|
|
22
|
+
* reached by /tree switch versus /fork saw two different task boards.
|
|
17
23
|
*
|
|
18
24
|
* A plain chain is returned unchanged unless a live caller explicitly pins an
|
|
19
25
|
* earlier leaf. That preserves historical linear replay (including old parent
|
|
@@ -47,7 +53,8 @@ export function filterEntriesToActivePath(entries: ReadonlyArray<SessionEntry>,
|
|
|
47
53
|
// as the root rather than failing the whole replay.
|
|
48
54
|
current = messagesById.get(current.parentTurnId);
|
|
49
55
|
}
|
|
50
|
-
|
|
56
|
+
const leafIndex = entries.findIndex((entry) => entry.kind === "message" && entry.turnId === leaf.turnId);
|
|
57
|
+
return entries.filter((entry, index) => entryBelongsToPath(entry, pathIds, leafIndex >= 0 && index <= leafIndex));
|
|
51
58
|
}
|
|
52
59
|
|
|
53
60
|
/**
|
|
@@ -87,12 +94,44 @@ function hasBranch(messages: ReadonlyArray<MessageEntry>): boolean {
|
|
|
87
94
|
return false;
|
|
88
95
|
}
|
|
89
96
|
|
|
90
|
-
|
|
97
|
+
/**
|
|
98
|
+
* Shared verdict for whether a session entry belongs to a reconstruction
|
|
99
|
+
* standing at the turn `pathIds` traces back to. Used by both live
|
|
100
|
+
* `/tree`-switch replay (above) and `/fork` (`fork.ts`), so the two surfaces
|
|
101
|
+
* agree on the one thing that was inconsistent between them: an unanchored
|
|
102
|
+
* sidecar (`parentTurnId === null`, e.g. `taskLedger`, a routing notice, a
|
|
103
|
+
* leafless `workerRun`) carries no turn pointer, so file position is the only
|
|
104
|
+
* signal available for it. `atOrBeforeLeaf` is that positional verdict,
|
|
105
|
+
* computed by the caller: was the entry written at or before the leaf's
|
|
106
|
+
* position in the file. A sidecar written after the leaf's position was not
|
|
107
|
+
* visible when a reconstruction standing at that leaf would have looked, on
|
|
108
|
+
* any branch, so it is excluded (issue #94; before this fix, live replay kept
|
|
109
|
+
* every unanchored sidecar regardless of position while fork dropped anything
|
|
110
|
+
* after the fork point, so the same turn reached the two ways produced two
|
|
111
|
+
* different task boards).
|
|
112
|
+
*
|
|
113
|
+
* `compactionSummary` is deliberately not given the same positional
|
|
114
|
+
* treatment here: a compaction anchored to a turn on the path is ordinarily
|
|
115
|
+
* appended after that turn's own message (compaction runs on top of a
|
|
116
|
+
* finished conversation, not before it), so gating it by leaf position would
|
|
117
|
+
* drop the compaction that legitimately covers the leaf itself. `fork.ts`
|
|
118
|
+
* layers its own, stricter compaction gate on top of this function, because
|
|
119
|
+
* a fork represents a snapshot frozen at one moment and a compaction written
|
|
120
|
+
* after that moment did not exist at the fork point even when its anchor
|
|
121
|
+
* turn is an ancestor. A `sessionInfo` entry with no `targetTurnId` is a
|
|
122
|
+
* session-wide fact (e.g. a rename), not scoped to any branch or moment, so
|
|
123
|
+
* it is always kept.
|
|
124
|
+
*/
|
|
125
|
+
export function entryBelongsToPath(
|
|
126
|
+
entry: SessionEntry,
|
|
127
|
+
pathIds: ReadonlySet<string>,
|
|
128
|
+
atOrBeforeLeaf: boolean,
|
|
129
|
+
): boolean {
|
|
91
130
|
if (entry.kind === "message") return pathIds.has(entry.turnId);
|
|
92
131
|
if (entry.kind === "label") return pathIds.has(entry.targetTurnId);
|
|
93
132
|
if (entry.kind === "sessionInfo") return entry.targetTurnId === undefined || pathIds.has(entry.targetTurnId);
|
|
94
133
|
if (entry.kind === "compactionSummary" && entry.firstKeptTurnId.length > 0 && pathIds.has(entry.firstKeptTurnId)) {
|
|
95
134
|
return true;
|
|
96
135
|
}
|
|
97
|
-
return entry.parentTurnId === null
|
|
136
|
+
return entry.parentTurnId === null ? atOrBeforeLeaf : pathIds.has(entry.parentTurnId);
|
|
98
137
|
}
|
|
@@ -4,6 +4,7 @@ import type { SessionMeta } from "../contract.js";
|
|
|
4
4
|
import { isSessionHeader, type SessionEntry } from "../entries.js";
|
|
5
5
|
import { enrichForkMeta } from "../history.js";
|
|
6
6
|
import { type SessionManagerState, startSession } from "../manager.js";
|
|
7
|
+
import { entryBelongsToPath } from "./active-path.js";
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* Single-point fork-from-parent-turn orchestration. Closes the caller's
|
|
@@ -80,32 +81,21 @@ function treeFromLinearPath(path: ReadonlyArray<LinkedRecord>): SessionTreeNode[
|
|
|
80
81
|
}
|
|
81
82
|
|
|
82
83
|
/**
|
|
83
|
-
*
|
|
84
|
-
*
|
|
85
|
-
*
|
|
86
|
-
*
|
|
84
|
+
* Fork-specific tightening of the shared `entryBelongsToPath` verdict. A fork
|
|
85
|
+
* is a snapshot frozen at `parentTurnId`: a compaction summary written after
|
|
86
|
+
* that point did not exist at the fork moment even when its `firstKeptTurnId`
|
|
87
|
+
* names an ancestor turn, so it must not ride along just because that turn
|
|
88
|
+
* happens to be on the path. Live `/tree`-switch replay does not need this
|
|
89
|
+
* extra gate (see the comment on the shared function for why), which is the
|
|
90
|
+
* one place fork and live replay still deliberately disagree.
|
|
87
91
|
*/
|
|
88
92
|
function sessionEntryBelongsToPath(
|
|
89
93
|
entry: SessionEntry,
|
|
90
94
|
pathIds: ReadonlySet<string>,
|
|
91
95
|
atOrBeforeForkPoint: boolean,
|
|
92
96
|
): boolean {
|
|
93
|
-
if (entry.kind === "
|
|
94
|
-
|
|
95
|
-
if (entry.kind === "sessionInfo") return entry.targetTurnId ? pathIds.has(entry.targetTurnId) : false;
|
|
96
|
-
if (entry.kind === "compactionSummary") {
|
|
97
|
-
// A summary describes history as of its write position. One written
|
|
98
|
-
// after the fork point did not exist when the forked timeline split,
|
|
99
|
-
// even when its firstKeptTurnId lands on the fork path; copying it
|
|
100
|
-
// would open the fork at the summary boundary and hide the transcript.
|
|
101
|
-
if (!atOrBeforeForkPoint) return false;
|
|
102
|
-
if (entry.firstKeptTurnId.length > 0 && pathIds.has(entry.firstKeptTurnId)) return true;
|
|
103
|
-
}
|
|
104
|
-
return entry.parentTurnId === null ? atOrBeforeForkPoint : pathIds.has(entry.parentTurnId);
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
function entryBelongsToPath(entry: SessionEntry, pathIds: ReadonlySet<string>, atOrBeforeForkPoint: boolean): boolean {
|
|
108
|
-
return sessionEntryBelongsToPath(entry, pathIds, atOrBeforeForkPoint);
|
|
97
|
+
if (entry.kind === "compactionSummary" && !atOrBeforeForkPoint) return false;
|
|
98
|
+
return entryBelongsToPath(entry, pathIds, atOrBeforeForkPoint);
|
|
109
99
|
}
|
|
110
100
|
|
|
111
101
|
function branchEntriesFromParent(
|
|
@@ -124,7 +114,7 @@ function branchEntriesFromParent(
|
|
|
124
114
|
const pathIds = new Set(path.map((record) => record.id));
|
|
125
115
|
const forkPointIndex = parsed.findIndex((entry) => linkedRecordFromEntry(entry).id === leafTurnId);
|
|
126
116
|
const entries = parsed.filter((entry, index) =>
|
|
127
|
-
|
|
117
|
+
sessionEntryBelongsToPath(entry, pathIds, forkPointIndex >= 0 && index <= forkPointIndex),
|
|
128
118
|
);
|
|
129
119
|
return {
|
|
130
120
|
parentCurrentPath,
|
|
@@ -134,15 +124,21 @@ function branchEntriesFromParent(
|
|
|
134
124
|
}
|
|
135
125
|
|
|
136
126
|
/**
|
|
137
|
-
* Fork the given state into a new session. Closes the prior writer
|
|
138
|
-
*
|
|
139
|
-
*
|
|
127
|
+
* Fork the given state into a new session. Closes the prior writer once the
|
|
128
|
+
* child session is known good, so the on-disk endedAt marker on the parent is
|
|
129
|
+
* never written for a fork that failed; the caller is responsible for
|
|
130
|
+
* replacing its own state pointer with `result.next`.
|
|
140
131
|
*/
|
|
141
132
|
export function forkFromState(input: ForkInput): ForkResult {
|
|
142
133
|
const parentMeta = input.from.meta;
|
|
143
|
-
//
|
|
144
|
-
// the
|
|
145
|
-
|
|
134
|
+
// Appends are already synchronous writes (writeSync in the engine writer),
|
|
135
|
+
// so the read below already sees everything appended in this process
|
|
136
|
+
// without closing first; flushAppends only fsyncs for durability. Reading
|
|
137
|
+
// (and traceAncestry inside branchEntriesFromParent, which throws on an
|
|
138
|
+
// unknown or broken parent chain) happens before the parent writer is
|
|
139
|
+
// touched, so a broken fork point leaves the parent open and un-ended
|
|
140
|
+
// instead of orphaning the caller (issue #93).
|
|
141
|
+
input.from.writer.flushAppends();
|
|
146
142
|
const branch = branchEntriesFromParent(parentMeta, input.parentTurnId);
|
|
147
143
|
|
|
148
144
|
const cwd = input.cwd ?? parentMeta.cwd;
|
|
@@ -156,5 +152,8 @@ export function forkFromState(input: ForkInput): ForkResult {
|
|
|
156
152
|
parentTurnId: input.parentTurnId,
|
|
157
153
|
});
|
|
158
154
|
enrichForkMeta(next.meta, parentMeta.id, input.parentTurnId);
|
|
155
|
+
// Only now is the child known good: created, seeded, and stamped with its
|
|
156
|
+
// parent pointers. Close (and stamp endedAt on) the parent last.
|
|
157
|
+
void input.from.writer.close();
|
|
159
158
|
return { next, parentMeta, nodes: branch.tree };
|
|
160
159
|
}
|
|
@@ -21,10 +21,10 @@ import { stripTokenizerSentinels } from "../../../engine/strip-tokenizer-sentine
|
|
|
21
21
|
* and optional label suffix. Callers that need a tighter budget can clamp
|
|
22
22
|
* the output further.
|
|
23
23
|
*/
|
|
24
|
-
|
|
24
|
+
const TURN_PREVIEW_MAX_CHARS = 60;
|
|
25
25
|
|
|
26
26
|
/** Minimal turn shape buildTurnPreview accepts. */
|
|
27
|
-
|
|
27
|
+
type TurnPreviewInput = Pick<ClioTurnRecord, "kind" | "payload">;
|
|
28
28
|
|
|
29
29
|
/**
|
|
30
30
|
* Strip ANSI escape sequences. Tool outputs sometimes carry colour codes
|
|
@@ -104,27 +104,31 @@ function remoteFrom(raw: string | null): string | null {
|
|
|
104
104
|
export function probeGit(cwd: string): GitProbeResult {
|
|
105
105
|
const inside = gitOk(cwd, ["rev-parse", "--is-inside-work-tree"]);
|
|
106
106
|
if (inside !== "true") return EMPTY_PROBE;
|
|
107
|
+
const ignored = gitOk(cwd, ["check-ignore", "--quiet", "--", "."]);
|
|
108
|
+
if (ignored !== null) return EMPTY_PROBE;
|
|
107
109
|
const branch = branchFrom(gitOk(cwd, ["rev-parse", "--abbrev-ref", "HEAD"]));
|
|
108
|
-
const dirty = dirtyFrom(gitOk(cwd, ["status", "--porcelain"]));
|
|
110
|
+
const dirty = dirtyFrom(gitOk(cwd, ["status", "--porcelain", "--", "."]));
|
|
109
111
|
const { ahead, behind } = aheadBehindFrom(gitOk(cwd, ["rev-list", "--left-right", "--count", "HEAD...@{u}"]));
|
|
110
|
-
const recentCommits = recentCommitsFrom(gitOk(cwd, ["log", "-5", "--format=%H%x09%s"]));
|
|
112
|
+
const recentCommits = recentCommitsFrom(gitOk(cwd, ["log", "-5", "--format=%H%x09%s", "--", "."]));
|
|
111
113
|
const remoteUrl = remoteFrom(gitOk(cwd, ["remote", "get-url", "origin"]));
|
|
112
114
|
return { isGit: true, branch, dirty, ahead, behind, recentCommits, remoteUrl };
|
|
113
115
|
}
|
|
114
116
|
|
|
115
117
|
/**
|
|
116
|
-
* The full probe without blocking the event loop.
|
|
117
|
-
*
|
|
118
|
-
* are independent
|
|
118
|
+
* The full probe without blocking the event loop. Once Git confirms the exact
|
|
119
|
+
* workspace is both inside a work tree and not ignored, the remaining five
|
|
120
|
+
* subprocesses are independent and run concurrently.
|
|
119
121
|
*/
|
|
120
122
|
export async function probeGitAsync(cwd: string): Promise<GitProbeResult> {
|
|
121
123
|
const inside = await gitOkAsync(cwd, ["rev-parse", "--is-inside-work-tree"]);
|
|
122
124
|
if (inside !== "true") return EMPTY_PROBE;
|
|
125
|
+
const ignored = await gitOkAsync(cwd, ["check-ignore", "--quiet", "--", "."]);
|
|
126
|
+
if (ignored !== null) return EMPTY_PROBE;
|
|
123
127
|
const [branchRaw, status, aheadBehindRaw, log, remoteRaw] = await Promise.all([
|
|
124
128
|
gitOkAsync(cwd, ["rev-parse", "--abbrev-ref", "HEAD"]),
|
|
125
|
-
gitOkAsync(cwd, ["status", "--porcelain"]),
|
|
129
|
+
gitOkAsync(cwd, ["status", "--porcelain", "--", "."]),
|
|
126
130
|
gitOkAsync(cwd, ["rev-list", "--left-right", "--count", "HEAD...@{u}"]),
|
|
127
|
-
gitOkAsync(cwd, ["log", "-5", "--format=%H%x09%s"]),
|
|
131
|
+
gitOkAsync(cwd, ["log", "-5", "--format=%H%x09%s", "--", "."]),
|
|
128
132
|
gitOkAsync(cwd, ["remote", "get-url", "origin"]),
|
|
129
133
|
]);
|
|
130
134
|
const { ahead, behind } = aheadBehindFrom(aheadBehindRaw);
|
|
@@ -140,16 +144,18 @@ export async function probeGitAsync(cwd: string): Promise<GitProbeResult> {
|
|
|
140
144
|
}
|
|
141
145
|
|
|
142
146
|
/**
|
|
143
|
-
* Branch, dirty flag, and remote only
|
|
144
|
-
* concurrently and off the loop. This is what
|
|
145
|
-
*
|
|
147
|
+
* Branch, dirty flag, and remote only. After the work-tree and ignored-workspace
|
|
148
|
+
* gates, the three fact probes run concurrently and off the loop. This is what
|
|
149
|
+
* the interactive footer polls and re-reads at the end of every turn.
|
|
146
150
|
*/
|
|
147
151
|
export async function probeGitStatusAsync(cwd: string): Promise<GitStatusProbeResult> {
|
|
148
152
|
const inside = await gitOkAsync(cwd, ["rev-parse", "--is-inside-work-tree"]);
|
|
149
153
|
if (inside !== "true") return EMPTY_STATUS_PROBE;
|
|
154
|
+
const ignored = await gitOkAsync(cwd, ["check-ignore", "--quiet", "--", "."]);
|
|
155
|
+
if (ignored !== null) return EMPTY_STATUS_PROBE;
|
|
150
156
|
const [branchRaw, status, remoteRaw] = await Promise.all([
|
|
151
157
|
gitOkAsync(cwd, ["rev-parse", "--abbrev-ref", "HEAD"]),
|
|
152
|
-
gitOkAsync(cwd, ["status", "--porcelain"]),
|
|
158
|
+
gitOkAsync(cwd, ["status", "--porcelain", "--", "."]),
|
|
153
159
|
gitOkAsync(cwd, ["remote", "get-url", "origin"]),
|
|
154
160
|
]);
|
|
155
161
|
return {
|