@iowarp/clio-coder 0.3.0 → 0.3.1
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 +33 -0
- package/README.md +50 -53
- package/dist/acp-FPR54DGL.js +138 -0
- package/dist/{agents-Q4MYPMUW.js → agents-OGPIHPJH.js} +33 -25
- package/dist/assets/codewiki.json +1 -0
- package/dist/assets/grammars/notices/@vscode__tree-sitter-wasm/LICENSE +21 -0
- package/dist/assets/grammars/notices/@vscode__tree-sitter-wasm/cgmanifest.json +16 -0
- package/dist/assets/grammars/notices/tree-sitter-wasms/LICENSE +24 -0
- package/dist/assets/grammars/tree-sitter-c-sharp.wasm +0 -0
- package/dist/assets/grammars/tree-sitter-c.wasm +0 -0
- package/dist/assets/grammars/tree-sitter-cpp.wasm +0 -0
- package/dist/assets/grammars/tree-sitter-go.wasm +0 -0
- package/dist/assets/grammars/tree-sitter-java.wasm +0 -0
- package/dist/assets/grammars/tree-sitter-javascript.wasm +0 -0
- package/dist/assets/grammars/tree-sitter-python.wasm +0 -0
- package/dist/assets/grammars/tree-sitter-ruby.wasm +0 -0
- package/dist/assets/grammars/tree-sitter-rust.wasm +0 -0
- package/dist/assets/grammars/tree-sitter-tsx.wasm +0 -0
- package/dist/assets/grammars/tree-sitter-typescript.wasm +0 -0
- package/dist/assets/grammars/tree-sitter.wasm +0 -0
- package/dist/{auth-O6HYIJ6J.js → auth-IC3K6NIZ.js} +22 -15
- package/dist/{chunk-KKKPTZLM.js → chunk-2STGEDFV.js} +8 -1
- package/dist/chunk-3I7MS7N2.js +40 -0
- package/dist/chunk-3R73A4XB.js +69 -0
- package/dist/{chunk-26BZQOAD.js → chunk-474KN5II.js} +86 -115
- package/dist/{chunk-NI4DEJMC.js → chunk-4QKXUHSR.js} +26 -3
- package/dist/{chunk-X3BR7HWV.js → chunk-5WIGXA4T.js} +7 -1
- package/dist/{chunk-TFSSEXL6.js → chunk-673JJUWJ.js} +14 -4
- package/dist/{chunk-GNGDQYDU.js → chunk-7SS2CTV2.js} +27922 -1249
- package/dist/{chunk-7RBKDI66.js → chunk-ASND7OZK.js} +104 -12
- package/dist/{chunk-X3NE4WVW.js → chunk-BNAZZHFG.js} +7 -1
- package/dist/{chunk-RQDWMVRB.js → chunk-BSU2YIWB.js} +9 -3
- package/dist/{chunk-CLJ5HLUD.js → chunk-C4PTHK7P.js} +24 -5
- package/dist/{chunk-QV47YRF4.js → chunk-CGKSTWHD.js} +7 -1
- package/dist/{chunk-BYEU76JP.js → chunk-DKGKUHFA.js} +34 -9
- package/dist/chunk-EYOKLTMF.js +170 -0
- package/dist/{chunk-PS4PFJQP.js → chunk-FCIH3BIZ.js} +15258 -14130
- package/dist/{chunk-2J63S4SF.js → chunk-FST4FYJB.js} +82 -14
- package/dist/{chunk-3DANZDGR.js → chunk-G34LV2PF.js} +34 -9
- package/dist/{chunk-BBUH4VAA.js → chunk-GAEBEQVI.js} +34 -21
- package/dist/chunk-GB6QRBXN.js +8543 -0
- package/dist/chunk-GEP36Y4X.js +12796 -0
- package/dist/{chunk-TKHQ4DGZ.js → chunk-H6F6BYOH.js} +496 -121
- package/dist/{chunk-UGYAX5YI.js → chunk-HQQID6OA.js} +10 -5
- package/dist/chunk-IHXBNWMM.js +137 -0
- package/dist/{chunk-ME6DNWIU.js → chunk-IS3ONKU3.js} +7 -1
- package/dist/{chunk-DXQNI4PC.js → chunk-IWHMRKLL.js} +8 -1
- package/dist/chunk-K2ITRMHZ.js +642 -0
- package/dist/{chunk-KBR4MZZR.js → chunk-K5XEMXTI.js} +7 -1
- package/dist/{chunk-AMFR5YA3.js → chunk-KKNLWXI6.js} +24 -10
- package/dist/{chunk-JWHCJDCI.js → chunk-KY56HMHH.js} +145 -61
- package/dist/{chunk-E3NYWENM.js → chunk-LU4TK2PR.js} +52 -7
- package/dist/{chunk-UWIJNAOB.js → chunk-M5T5VO65.js} +109 -42
- package/dist/{chunk-JPOWPFCU.js → chunk-MAR7Y6HW.js} +38 -16
- package/dist/chunk-N6F52NLF.js +6951 -0
- package/dist/{chunk-UHTSULZS.js → chunk-NMOX6HFD.js} +20 -7
- package/dist/{chunk-WD6AJM35.js → chunk-OLBBMFRD.js} +30 -13
- package/dist/{chunk-VOO7NYPP.js → chunk-PFEFKVGL.js} +22 -6
- package/dist/{chunk-6CWDTGUC.js → chunk-PIUMUEMV.js} +7 -1
- package/dist/chunk-PV4JUBVJ.js +462 -0
- package/dist/{chunk-527KG6XR.js → chunk-Q3RUPKEJ.js} +22 -4
- package/dist/{chunk-D5YD55AR.js → chunk-Q5WJOSJ7.js} +11 -1
- package/dist/{chunk-5N2FG33Q.js → chunk-R346GLFC.js} +7 -1
- package/dist/{chunk-4UQA7NCT.js → chunk-R5KLMSBV.js} +7 -2
- package/dist/{chunk-PIDUD6M2.js → chunk-RDLVBZEO.js} +11 -6
- package/dist/{chunk-O4EJEDHO.js → chunk-RPTR2H26.js} +40 -31
- package/dist/{chunk-HBU5MTAM.js → chunk-SVNXH4L2.js} +7 -1
- package/dist/{chunk-XNISANGE.js → chunk-TEKV33Q5.js} +122 -57
- package/dist/chunk-TXOTCRLG.js +15 -0
- package/dist/{chunk-VPAWTYLY.js → chunk-WEPFGWHJ.js} +7 -1
- package/dist/{chunk-HMYNFFY4.js → chunk-XPLRXC72.js} +7 -2
- package/dist/{chunk-UU3R62TT.js → chunk-XYWBQRDM.js} +13 -4
- package/dist/{chunk-7BHLZB3A.js → chunk-ZPY3JZ5E.js} +32 -10
- package/dist/cli/index.js +39 -33
- package/dist/clio-BZVGEUFJ.js +58 -0
- package/dist/{components-JVHMUBEB.js → components-DMAOEKFB.js} +26 -9
- package/dist/{config-ZFCDBMDC.js → config-IRUQ7SE4.js} +42 -31
- package/dist/configure-S7S6F6CL.js +32 -0
- package/dist/{context-CDXTP2MP.js → context-3KWFLHJG.js} +17 -11
- package/dist/{context-E3KIFVXI.js → context-5RADCKTR.js} +33 -28
- package/dist/{context-clear-3F4PLXOS.js → context-clear-7TSNPAAI.js} +36 -28
- package/dist/{context-index-Q7YSYTR3.js → context-index-W4RLWOQH.js} +10 -4
- package/dist/{docs-YIETIWZI.js → docs-5AWSPS37.js} +16 -10
- package/dist/doctor-UC5NAJYQ.js +77 -0
- package/dist/{eval-B3KZZESM.js → eval-U6TJHRLX.js} +77 -24
- package/dist/{evidence-V67CHM35.js → evidence-YEGUW4L3.js} +34 -26
- package/dist/{evolve-YDZSUQYA.js → evolve-TXARCTPG.js} +39 -26
- package/dist/{extensions-SRG7XCAH.js → extensions-OZFJ3A3G.js} +13 -7
- package/dist/{fleet-CA2CRTVG.js → fleet-6G3DHNYE.js} +45 -37
- package/dist/fleet-preflight-DSNT37JK.js +23 -0
- package/dist/{init-2OZDJE2D.js → init-KZ5QTF6M.js} +42 -34
- package/dist/{memory-3PIQQAKX.js → memory-73ESV5YC.js} +35 -27
- package/dist/{models-DY35XI7Y.js → models-A4PVNWJK.js} +34 -23
- package/dist/{paths-5OMXW7Z4.js → paths-C4H6IV77.js} +12 -6
- package/dist/preload-6WVMHX3A.js +13 -0
- package/dist/{reset-PIFYNOS3.js → reset-BGW6OGMV.js} +17 -11
- package/dist/{run-3VSPP24F.js → run-YTPEYQOH.js} +60 -48
- package/dist/{share-D36RQCXM.js → share-YIFFV4NQ.js} +16 -10
- package/dist/{skills-F2MRLELY.js → skills-2V6RA3OQ.js} +18 -11
- package/dist/{skills-eval-E2ZTW4PL.js → skills-eval-S2TVJO4F.js} +45 -36
- package/dist/{targets-DZMEZAH4.js → targets-TYXLPB23.js} +61 -59
- package/dist/{trace-7NYCUI2J.js → trace-GGOJ6Q6Z.js} +9 -3
- package/dist/{uninstall-AD3JWHBB.js → uninstall-LLLT4F4W.js} +14 -8
- package/dist/{upgrade-WYYBKGDY.js → upgrade-33G2LMM5.js} +45 -23
- package/dist/{usage-ULIDAGFF.js → usage-ZAFSXKKG.js} +35 -27
- package/dist/version-KGEG7EPO.js +21 -0
- package/dist/{wiki-generate-PKFIX6OB.js → wiki-generate-NUQCVOQ3.js} +55 -45
- package/dist/worker/entry.js +101 -43
- package/docs/README.md +12 -9
- package/docs/acp.md +28 -5
- package/docs/alcf-provider.md +1 -1
- package/docs/architecture.md +23 -2
- package/docs/artifact-placement.md +101 -0
- package/docs/artifact-versions.md +1 -1
- package/docs/built-in-agents.md +4 -2
- package/docs/capacity-and-scheduling.md +1 -1
- package/docs/commands-and-modes.md +125 -41
- package/docs/configuration-and-targets.md +88 -18
- package/docs/context-engine.md +6 -2
- package/docs/development-pipeline.md +77 -0
- package/docs/documentation-coverage.md +4 -4
- package/docs/documentation-guide.md +3 -3
- package/docs/environment-variables.md +2 -1
- package/docs/eval-runner.md +3 -3
- package/docs/evals-internal.md +2 -2
- package/docs/evidence-and-memory.md +6 -2
- package/docs/evolution.md +1 -1
- package/docs/exit-codes-and-output.md +1 -1
- package/docs/extensions-and-sharing.md +18 -11
- package/docs/fleet-demo-runbook.md +22 -23
- package/docs/fleet-dispatch.md +111 -12
- package/docs/glossary.md +107 -15
- package/docs/html/agents_blueprint.html +3 -3
- package/docs/html/alcf_blueprint.html +3 -3
- package/docs/html/architecture_blueprint.html +3 -3
- package/docs/html/commands_blueprint.html +187 -42
- package/docs/html/configuration_blueprint.html +7 -7
- package/docs/html/context_blueprint.html +3 -3
- package/docs/html/documentation_blueprint.html +1 -1
- package/docs/html/environment_blueprint.html +3 -3
- package/docs/html/eval_blueprint.html +4 -4
- package/docs/html/evals_internal_blueprint.html +3 -3
- package/docs/html/evolution_blueprint.html +3 -3
- package/docs/html/extensions_blueprint.html +3 -3
- package/docs/html/fleet_dispatch_blueprint.html +8 -8
- package/docs/html/index.html +5 -5
- package/docs/html/lifecycle_blueprint.html +4 -4
- package/docs/html/memory_blueprint.html +3 -3
- package/docs/html/middleware_blueprint.html +3 -3
- package/docs/html/models_blueprint.html +2 -2
- package/docs/html/observability_blueprint.html +2 -2
- package/docs/html/provider_adapter_blueprint.html +3 -3
- package/docs/html/safety_blueprint.html +3 -3
- package/docs/html/skills_blueprint.html +2 -2
- package/docs/html/soak_blueprint.html +3 -3
- package/docs/html/tool_usage_blueprint.html +4 -4
- package/docs/html/tools_blueprint.html +2 -2
- package/docs/html/trace_blueprint.html +3 -3
- package/docs/html/tui_design_blueprint.html +100 -40
- package/docs/html/validation_blueprint.html +1 -1
- package/docs/html/worker_dispatch_blueprint.html +3 -3
- package/docs/installation-and-lifecycle.md +62 -11
- package/docs/middleware-and-components.md +1 -1
- package/docs/model-catalog.md +2 -2
- package/docs/observability.md +3 -3
- package/docs/proactive-memory.md +12 -12
- package/docs/prompt-envelope-and-tools.md +2 -2
- package/docs/provider-adapter-cookbook.md +1 -1
- package/docs/release-cut-checklist.md +4 -0
- package/docs/safety-model.md +21 -5
- package/docs/scientific-validation.md +3 -3
- package/docs/session-lifecycle.md +2 -2
- package/docs/skills-marketplace.md +1 -1
- package/docs/time-conventions.md +101 -0
- package/docs/tool-usage.md +5 -4
- package/docs/trace-store.md +1 -1
- package/docs/troubleshooting.md +1 -1
- package/docs/tui-design.md +83 -27
- package/docs/worker-dispatch-mechanics.md +3 -3
- package/package.json +16 -16
- package/skills/README.md +5 -6
- package/skills/git/file-ticket/SKILL.md +107 -0
- package/skills/git/file-ticket/evals.md +54 -0
- package/skills/git/fix-issue/SKILL.md +106 -0
- package/skills/git/fix-issue/evals.md +71 -0
- package/skills/git/ship/SKILL.md +92 -0
- package/skills/git/ship/evals.md +72 -0
- package/skills/skill-marketplace.json +12 -20
- package/src/cli/acp.ts +88 -0
- package/src/cli/agents.ts +60 -0
- package/src/cli/args.ts +280 -0
- package/src/cli/argv.ts +170 -0
- package/src/cli/ask.ts +34 -0
- package/src/cli/auth.ts +468 -0
- package/src/cli/bootstrap-generate.ts +498 -0
- package/src/cli/clio.ts +34 -0
- package/src/cli/components.ts +195 -0
- package/src/cli/config-inspect.ts +330 -0
- package/src/cli/config.ts +72 -0
- package/src/cli/configure-interop.ts +67 -0
- package/src/cli/configure-layout.ts +172 -0
- package/src/cli/configure.ts +1487 -0
- package/src/cli/context-clear.ts +76 -0
- package/src/cli/context-index.ts +102 -0
- package/src/cli/context.ts +316 -0
- package/src/cli/default-target.ts +63 -0
- package/src/cli/docs.ts +340 -0
- package/src/cli/doctor.ts +54 -0
- package/src/cli/eval.ts +315 -0
- package/src/cli/evidence.ts +222 -0
- package/src/cli/evolve.ts +219 -0
- package/src/cli/extensions.ts +205 -0
- package/src/cli/fleet.ts +827 -0
- package/src/cli/index.ts +309 -0
- package/src/cli/init.ts +219 -0
- package/src/cli/initial-message.ts +47 -0
- package/src/cli/internal-dispatch.ts +55 -0
- package/src/cli/memory.ts +180 -0
- package/src/cli/models.ts +257 -0
- package/src/cli/modes/json-stream.ts +85 -0
- package/src/cli/modes/jsonl.ts +9 -0
- package/src/cli/modes/print.ts +589 -0
- package/src/cli/oauth-manual-input.ts +72 -0
- package/src/cli/oauth-select.ts +36 -0
- package/src/cli/output-guard.ts +48 -0
- package/src/cli/paths.ts +44 -0
- package/src/cli/provider-target.ts +113 -0
- package/src/cli/removal.ts +72 -0
- package/src/cli/reset.ts +253 -0
- package/src/cli/run.ts +497 -0
- package/src/cli/share.ts +243 -0
- package/src/cli/shared.ts +60 -0
- package/src/cli/skills-eval.ts +1225 -0
- package/src/cli/skills.ts +470 -0
- package/src/cli/steer-channel.ts +86 -0
- package/src/cli/targets.ts +1150 -0
- package/src/cli/text-layout.ts +102 -0
- package/src/cli/trace.ts +274 -0
- package/src/cli/uninstall.ts +405 -0
- package/src/cli/upgrade.ts +270 -0
- package/src/cli/usage.ts +869 -0
- package/src/cli/validate-model.ts +28 -0
- package/src/cli/version.ts +7 -0
- package/src/cli/wiki-generate.ts +509 -0
- package/src/core/artifact-paths.ts +43 -0
- package/src/core/bash-exec.ts +242 -0
- package/src/core/boot-trace.ts +37 -0
- package/src/core/bus-events.ts +728 -0
- package/src/core/bus-trace.ts +53 -0
- package/src/core/c-header-language.ts +265 -0
- package/src/core/clio-repo.ts +78 -0
- package/src/core/config.ts +1593 -0
- package/src/core/context-floor.ts +33 -0
- package/src/core/defaults.ts +625 -0
- package/src/core/domain-loader.ts +170 -0
- package/src/core/event-bus.ts +94 -0
- package/src/core/file-references.ts +282 -0
- package/src/core/guardrails.ts +185 -0
- package/src/core/headless-permission.ts +21 -0
- package/src/core/init.ts +223 -0
- package/src/core/json-payload.ts +58 -0
- package/src/core/package-root.ts +54 -0
- package/src/core/path-canonical.ts +37 -0
- package/src/core/process-identity.ts +41 -0
- package/src/core/recent-models.ts +91 -0
- package/src/core/release.ts +2 -0
- package/src/core/residency-protection.ts +56 -0
- package/src/core/resolve-config-value.ts +88 -0
- package/src/core/response-schema.ts +279 -0
- package/src/core/run-overrides.ts +77 -0
- package/src/core/safe-exec.ts +193 -0
- package/src/core/safe-id.ts +37 -0
- package/src/core/safe-resource-write.ts +162 -0
- package/src/core/session-routing.ts +339 -0
- package/src/core/settings-layers.ts +220 -0
- package/src/core/shared-bus.ts +8 -0
- package/src/core/shell-quote.ts +26 -0
- package/src/core/skill-activation.ts +190 -0
- package/src/core/startup-timer.ts +37 -0
- package/src/core/state-file-lock.ts +207 -0
- package/src/core/termination.ts +202 -0
- package/src/core/timers.ts +38 -0
- package/src/core/tool-names.ts +65 -0
- package/src/core/verification-scripts.ts +13 -0
- package/src/core/workspace-files.ts +492 -0
- package/src/core/xdg.ts +177 -0
- package/src/domains/agents/builtins/architect.md +4 -4
- package/src/domains/agents/builtins/coder.md +3 -2
- package/src/domains/agents/builtins/debugger.md +1 -1
- package/src/domains/agents/builtins/documenter.md +1 -1
- package/src/domains/agents/builtins/git-master.md +3 -3
- package/src/domains/agents/builtins/provenance.md +1 -1
- package/src/domains/agents/builtins/researcher.md +1 -1
- package/src/domains/agents/builtins/scout.md +1 -1
- package/src/domains/agents/builtins/tester.md +1 -1
- package/src/domains/agents/builtins/verifier.md +1 -1
- package/src/domains/agents/builtins/wiki-writer.md +1 -1
- package/src/domains/agents/catalog.ts +172 -0
- package/src/domains/agents/contract.ts +16 -0
- package/src/domains/agents/extension.ts +110 -0
- package/src/domains/agents/fleet-commands.ts +154 -0
- package/src/domains/agents/fleet-contract.ts +797 -0
- package/src/domains/agents/frontmatter.ts +40 -0
- package/src/domains/agents/index.ts +102 -0
- package/src/domains/agents/manifest.ts +6 -0
- package/src/domains/agents/recipe-schema.ts +202 -0
- package/src/domains/agents/recipe.ts +125 -0
- package/src/domains/agents/registry.ts +111 -0
- package/src/domains/agents/result-contract.ts +1265 -0
- package/src/domains/agents/spec.ts +371 -0
- package/src/domains/agents/write-boundary.ts +109 -0
- package/src/domains/components/diff.ts +99 -0
- package/src/domains/components/hash.ts +21 -0
- package/src/domains/components/index.ts +3 -0
- package/src/domains/components/scan.ts +304 -0
- package/src/domains/components/snapshot.ts +108 -0
- package/src/domains/components/types.ts +82 -0
- package/src/domains/config/agent-namespace.ts +13 -0
- package/src/domains/config/classify.ts +94 -0
- package/src/domains/config/contract.ts +22 -0
- package/src/domains/config/extension.ts +136 -0
- package/src/domains/config/index.ts +13 -0
- package/src/domains/config/keybindings.ts +164 -0
- package/src/domains/config/manifest.ts +6 -0
- package/src/domains/config/watcher.ts +41 -0
- package/src/domains/context/adoption.ts +880 -0
- package/src/domains/context/bootstrap-prompt.ts +273 -0
- package/src/domains/context/bootstrap.ts +1409 -0
- package/src/domains/context/clear.ts +86 -0
- package/src/domains/context/clio-md.ts +327 -0
- package/src/domains/context/codewiki/cmake.ts +356 -0
- package/src/domains/context/codewiki/cooperative.ts +46 -0
- package/src/domains/context/codewiki/digest.ts +135 -0
- package/src/domains/context/codewiki/grammar-assets.ts +33 -0
- package/src/domains/context/codewiki/indexer.ts +1614 -0
- package/src/domains/context/codewiki/tree-sitter.ts +771 -0
- package/src/domains/context/contract.ts +62 -0
- package/src/domains/context/excluded-dirs.ts +1 -0
- package/src/domains/context/extension.ts +407 -0
- package/src/domains/context/fingerprint.ts +196 -0
- package/src/domains/context/index.ts +164 -0
- package/src/domains/context/init-options.ts +69 -0
- package/src/domains/context/manifest.ts +6 -0
- package/src/domains/context/operator-profile.ts +157 -0
- package/src/domains/context/project-metadata.ts +510 -0
- package/src/domains/context/project-rules.ts +227 -0
- package/src/domains/context/prompt-context.ts +62 -0
- package/src/domains/context/refresh.ts +170 -0
- package/src/domains/context/sibling-files.ts +10 -0
- package/src/domains/context/state.ts +237 -0
- package/src/domains/context/wiki/assemble.ts +303 -0
- package/src/domains/context/wiki/frontmatter.ts +210 -0
- package/src/domains/context/wiki/generate.ts +590 -0
- package/src/domains/context/wiki/layout.ts +111 -0
- package/src/domains/context/wiki/meta.ts +221 -0
- package/src/domains/context/wiki/plan-store.ts +217 -0
- package/src/domains/context/wiki/plan.ts +250 -0
- package/src/domains/context/wiki/prompts.ts +270 -0
- package/src/domains/context/wiki/staleness.ts +198 -0
- package/src/domains/dispatch/active-route-planner.ts +168 -0
- package/src/domains/dispatch/admission-queue.ts +150 -0
- package/src/domains/dispatch/admission.ts +334 -0
- package/src/domains/dispatch/agent-candidates.ts +307 -0
- package/src/domains/dispatch/agent-ledger-hub.ts +71 -0
- package/src/domains/dispatch/agent-ledger-store.ts +257 -0
- package/src/domains/dispatch/agent-ledger.ts +212 -0
- package/src/domains/dispatch/agent-plan-adapter.ts +85 -0
- package/src/domains/dispatch/assignment-events.ts +132 -0
- package/src/domains/dispatch/assignment-reconcile.ts +76 -0
- package/src/domains/dispatch/assignment-store.ts +162 -0
- package/src/domains/dispatch/assignment.ts +278 -0
- package/src/domains/dispatch/backoff.ts +59 -0
- package/src/domains/dispatch/batch-store.ts +134 -0
- package/src/domains/dispatch/batch-tracker.ts +66 -0
- package/src/domains/dispatch/capability-match.ts +155 -0
- package/src/domains/dispatch/capacity-lease.ts +413 -0
- package/src/domains/dispatch/code-step-store.ts +52 -0
- package/src/domains/dispatch/code-step.ts +368 -0
- package/src/domains/dispatch/contract.ts +278 -0
- package/src/domains/dispatch/dedup.ts +133 -0
- package/src/domains/dispatch/event-pump.ts +251 -0
- package/src/domains/dispatch/execution-handoff.ts +29 -0
- package/src/domains/dispatch/execution-plan.ts +328 -0
- package/src/domains/dispatch/execution-role.ts +277 -0
- package/src/domains/dispatch/execution-scheduler.ts +583 -0
- package/src/domains/dispatch/extension.ts +5869 -0
- package/src/domains/dispatch/failure-classification.ts +141 -0
- package/src/domains/dispatch/fleet-plan.ts +225 -0
- package/src/domains/dispatch/fleet-preflight.ts +394 -0
- package/src/domains/dispatch/gate-decisions.ts +1040 -0
- package/src/domains/dispatch/gate-role-prompts.ts +58 -0
- package/src/domains/dispatch/heartbeat.ts +27 -0
- package/src/domains/dispatch/index.ts +137 -0
- package/src/domains/dispatch/joint-route-adapter.ts +114 -0
- package/src/domains/dispatch/joint-route-resolver.ts +283 -0
- package/src/domains/dispatch/manifest.ts +6 -0
- package/src/domains/dispatch/orphan-recovery.ts +224 -0
- package/src/domains/dispatch/outcome.ts +109 -0
- package/src/domains/dispatch/phase-timing.ts +47 -0
- package/src/domains/dispatch/placement.ts +202 -0
- package/src/domains/dispatch/receipt-findings.ts +255 -0
- package/src/domains/dispatch/receipt-integrity.ts +378 -0
- package/src/domains/dispatch/recovery-candidates.ts +74 -0
- package/src/domains/dispatch/reproducibility.ts +48 -0
- package/src/domains/dispatch/reservation-store.ts +501 -0
- package/src/domains/dispatch/route-approval.ts +177 -0
- package/src/domains/dispatch/route-candidates.ts +57 -0
- package/src/domains/dispatch/route-decision.ts +1079 -0
- package/src/domains/dispatch/route-facts.ts +187 -0
- package/src/domains/dispatch/route-history.ts +238 -0
- package/src/domains/dispatch/route-observer.ts +488 -0
- package/src/domains/dispatch/route-policy.ts +327 -0
- package/src/domains/dispatch/route-quality.ts +256 -0
- package/src/domains/dispatch/route-readiness.ts +120 -0
- package/src/domains/dispatch/routing-intent.ts +287 -0
- package/src/domains/dispatch/run-identity.ts +56 -0
- package/src/domains/dispatch/scout-transition.ts +130 -0
- package/src/domains/dispatch/state.ts +277 -0
- package/src/domains/dispatch/tool-stats.ts +132 -0
- package/src/domains/dispatch/transport.ts +209 -0
- package/src/domains/dispatch/types.ts +785 -0
- package/src/domains/dispatch/validation-grounding.ts +154 -0
- package/src/domains/dispatch/validation.ts +721 -0
- package/src/domains/dispatch/worker-protocol.ts +275 -0
- package/src/domains/dispatch/worker-spawn.ts +566 -0
- package/src/domains/dispatch/write-boundary-enforcer.ts +97 -0
- package/src/domains/dispatch/write-boundary.ts +426 -0
- package/src/domains/eval/artifacts/redact.ts +42 -0
- package/src/domains/eval/artifacts/store.ts +173 -0
- package/src/domains/eval/compare/compare.ts +33 -0
- package/src/domains/eval/compare/gates.ts +66 -0
- package/src/domains/eval/compare/thresholds.ts +92 -0
- package/src/domains/eval/harness-metrics.ts +62 -0
- package/src/domains/eval/index.ts +66 -0
- package/src/domains/eval/metrics/chaos-stream.ts +93 -0
- package/src/domains/eval/metrics/context.ts +34 -0
- package/src/domains/eval/metrics/coverage.ts +21 -0
- package/src/domains/eval/metrics/evidence.ts +182 -0
- package/src/domains/eval/metrics/fleet-loop-stream.ts +196 -0
- package/src/domains/eval/metrics/invariants.ts +736 -0
- package/src/domains/eval/metrics/latency.ts +4 -0
- package/src/domains/eval/metrics/token-stream.ts +139 -0
- package/src/domains/eval/metrics/tokens.ts +51 -0
- package/src/domains/eval/metrics/tool-calls.ts +7 -0
- package/src/domains/eval/proactive-memory.ts +279 -0
- package/src/domains/eval/provenance.ts +35 -0
- package/src/domains/eval/report.ts +234 -0
- package/src/domains/eval/reports/json.ts +5 -0
- package/src/domains/eval/reports/junit.ts +23 -0
- package/src/domains/eval/reports/markdown.ts +20 -0
- package/src/domains/eval/reports/swe-jsonl.ts +16 -0
- package/src/domains/eval/reports/text.ts +25 -0
- package/src/domains/eval/run-compare.ts +274 -0
- package/src/domains/eval/runner.ts +244 -0
- package/src/domains/eval/runners/clio-run.ts +148 -0
- package/src/domains/eval/runners/context-index.ts +56 -0
- package/src/domains/eval/runners/context-init.ts +203 -0
- package/src/domains/eval/runners/external-command.ts +350 -0
- package/src/domains/eval/runtime-paths.ts +171 -0
- package/src/domains/eval/schema/artifact.ts +75 -0
- package/src/domains/eval/schema/suite.ts +235 -0
- package/src/domains/eval/schema/validate.ts +339 -0
- package/src/domains/eval/store.ts +392 -0
- package/src/domains/eval/suites/load.ts +74 -0
- package/src/domains/eval/suites/matrix.ts +19 -0
- package/src/domains/eval/suites/resolve.ts +44 -0
- package/src/domains/eval/suites/run.ts +325 -0
- package/src/domains/eval/task-file.ts +186 -0
- package/src/domains/eval/types.ts +141 -0
- package/src/domains/eval/verifiers/command.ts +27 -0
- package/src/domains/eval/verifiers/file-exists.ts +6 -0
- package/src/domains/eval/verifiers/patch.ts +22 -0
- package/src/domains/eval/workspaces/git.ts +41 -0
- package/src/domains/eval/workspaces/local.ts +17 -0
- package/src/domains/eval/workspaces/temp-copy.ts +29 -0
- package/src/domains/evidence/build.ts +1714 -0
- package/src/domains/evidence/eval.ts +605 -0
- package/src/domains/evidence/failure-attribution.ts +54 -0
- package/src/domains/evidence/finish-contract-map.ts +42 -0
- package/src/domains/evidence/index.ts +55 -0
- package/src/domains/evidence/provenance.ts +200 -0
- package/src/domains/evidence/redact.ts +81 -0
- package/src/domains/evidence/store.ts +291 -0
- package/src/domains/evidence/types.ts +325 -0
- package/src/domains/evolution/SELF_EDIT_GATE.md +91 -0
- package/src/domains/evolution/index.ts +26 -0
- package/src/domains/evolution/manifest.ts +154 -0
- package/src/domains/evolution/validate.ts +304 -0
- package/src/domains/extensions/contract.ts +22 -0
- package/src/domains/extensions/discovery.ts +193 -0
- package/src/domains/extensions/extension.ts +46 -0
- package/src/domains/extensions/index.ts +34 -0
- package/src/domains/extensions/manager.ts +30 -0
- package/src/domains/extensions/manifest.ts +6 -0
- package/src/domains/extensions/resources.ts +38 -0
- package/src/domains/extensions/state.ts +224 -0
- package/src/domains/extensions/types.ts +83 -0
- package/src/domains/interop/consent.ts +185 -0
- package/src/domains/interop/contract.ts +29 -0
- package/src/domains/interop/detect.ts +173 -0
- package/src/domains/interop/extension.ts +59 -0
- package/src/domains/interop/index.ts +34 -0
- package/src/domains/interop/manifest.ts +6 -0
- package/src/domains/interop/registry.ts +139 -0
- package/src/domains/interop/state.ts +92 -0
- package/src/domains/interop/types.ts +109 -0
- package/src/domains/lifecycle/contract.ts +11 -0
- package/src/domains/lifecycle/doctor.ts +536 -0
- package/src/domains/lifecycle/extension.ts +23 -0
- package/src/domains/lifecycle/index.ts +21 -0
- package/src/domains/lifecycle/install-method.ts +51 -0
- package/src/domains/lifecycle/manifest.ts +6 -0
- package/src/domains/lifecycle/migrations/index.ts +94 -0
- package/src/domains/lifecycle/state.ts +93 -0
- package/src/domains/lifecycle/upgrade-notice.ts +35 -0
- package/src/domains/lifecycle/version.ts +35 -0
- package/src/domains/memory/index.ts +128 -0
- package/src/domains/memory/operations.ts +143 -0
- package/src/domains/memory/prompt-section.ts +86 -0
- package/src/domains/memory/proposal.ts +180 -0
- package/src/domains/memory/store.ts +163 -0
- package/src/domains/memory/task-bank.ts +229 -0
- package/src/domains/memory/task-memory-handoff.ts +222 -0
- package/src/domains/memory/task-memory-policy.ts +602 -0
- package/src/domains/memory/task-memory-status.ts +58 -0
- package/src/domains/memory/task-memory-telemetry.ts +346 -0
- package/src/domains/memory/task-memory-trace.ts +89 -0
- package/src/domains/memory/types.ts +74 -0
- package/src/domains/memory/validate.ts +297 -0
- package/src/domains/middleware/budget.ts +216 -0
- package/src/domains/middleware/contract.ts +35 -0
- package/src/domains/middleware/dispatch-nudge.ts +469 -0
- package/src/domains/middleware/extension.ts +129 -0
- package/src/domains/middleware/hook-receipts.ts +70 -0
- package/src/domains/middleware/hooks-io.ts +174 -0
- package/src/domains/middleware/hooks.ts +432 -0
- package/src/domains/middleware/index.ts +154 -0
- package/src/domains/middleware/manifest.ts +6 -0
- package/src/domains/middleware/memory-intervention.ts +701 -0
- package/src/domains/middleware/rules.ts +42 -0
- package/src/domains/middleware/runtime.ts +333 -0
- package/src/domains/middleware/skills-reminder.ts +187 -0
- package/src/domains/middleware/snapshot.ts +71 -0
- package/src/domains/middleware/stalled-turn.ts +71 -0
- package/src/domains/middleware/task-board-reminder.ts +87 -0
- package/src/domains/middleware/task-nudge.ts +77 -0
- package/src/domains/middleware/tool-choice-control.ts +42 -0
- package/src/domains/middleware/types.ts +131 -0
- package/src/domains/middleware/validate.ts +329 -0
- package/src/domains/observability/accountability.ts +67 -0
- package/src/domains/observability/contract.ts +168 -0
- package/src/domains/observability/cost.ts +206 -0
- package/src/domains/observability/evidence-index.ts +123 -0
- package/src/domains/observability/extension.ts +281 -0
- package/src/domains/observability/index.ts +78 -0
- package/src/domains/observability/manifest.ts +10 -0
- package/src/domains/observability/metrics.ts +37 -0
- package/src/domains/observability/projection.ts +477 -0
- package/src/domains/observability/telemetry.ts +89 -0
- package/src/domains/observability/trace-store.ts +1454 -0
- package/src/domains/prompts/compiler.ts +556 -0
- package/src/domains/prompts/contract.ts +30 -0
- package/src/domains/prompts/extension.ts +304 -0
- package/src/domains/prompts/fragment-loader.ts +139 -0
- package/src/domains/prompts/fragments/identity/clio.md +3 -2
- package/src/domains/prompts/fragments/identity/self-awareness.md +63 -0
- package/src/domains/prompts/fragments/operating/contract.md +10 -1
- package/src/domains/prompts/hash.ts +73 -0
- package/src/domains/prompts/index.ts +32 -0
- package/src/domains/prompts/manifest.ts +8 -0
- package/src/domains/prompts/memory-intervention.ts +57 -0
- package/src/domains/prompts/preload.ts +82 -0
- package/src/domains/providers/auth/api-key.ts +47 -0
- package/src/domains/providers/auth/backend-file.ts +69 -0
- package/src/domains/providers/auth/backend-memory.ts +17 -0
- package/src/domains/providers/auth/index.ts +37 -0
- package/src/domains/providers/auth/oauth.ts +36 -0
- package/src/domains/providers/auth/storage.ts +667 -0
- package/src/domains/providers/capabilities.ts +50 -0
- package/src/domains/providers/catalog.ts +162 -0
- package/src/domains/providers/contract.ts +151 -0
- package/src/domains/providers/credentials.ts +20 -0
- package/src/domains/providers/eligibility.ts +24 -0
- package/src/domains/providers/errors.ts +64 -0
- package/src/domains/providers/extension.ts +536 -0
- package/src/domains/providers/index.ts +142 -0
- package/src/domains/providers/knowledge-base-path.ts +102 -0
- package/src/domains/providers/manifest.ts +6 -0
- package/src/domains/providers/model-capabilities.ts +136 -0
- package/src/domains/providers/model-discovery.ts +144 -0
- package/src/domains/providers/model-family.ts +32 -0
- package/src/domains/providers/model-runtime-capabilities.ts +712 -0
- package/src/domains/providers/models/local-models/clio-local-coding-targets.yaml +2 -2
- package/src/domains/providers/plugins.ts +59 -0
- package/src/domains/providers/probe/fingerprint.ts +44 -0
- package/src/domains/providers/probe/http.ts +114 -0
- package/src/domains/providers/probe/reasoning.ts +111 -0
- package/src/domains/providers/registry.ts +166 -0
- package/src/domains/providers/resolver.ts +156 -0
- package/src/domains/providers/runtime-resolution.ts +720 -0
- package/src/domains/providers/runtimes/antigravity/antigravity-code.ts +90 -0
- package/src/domains/providers/runtimes/builtins.ts +78 -0
- package/src/domains/providers/runtimes/claude/claude-code.ts +38 -0
- package/src/domains/providers/runtimes/claude/claude-sdk.ts +38 -0
- package/src/domains/providers/runtimes/claude/common.ts +55 -0
- package/src/domains/providers/runtimes/cloud/alcf.ts +171 -0
- package/src/domains/providers/runtimes/cloud/anthropic-max.ts +71 -0
- package/src/domains/providers/runtimes/cloud/anthropic.ts +43 -0
- package/src/domains/providers/runtimes/cloud/bedrock.ts +35 -0
- package/src/domains/providers/runtimes/cloud/deepseek.ts +50 -0
- package/src/domains/providers/runtimes/cloud/google.ts +41 -0
- package/src/domains/providers/runtimes/cloud/groq.ts +46 -0
- package/src/domains/providers/runtimes/cloud/mistral.ts +46 -0
- package/src/domains/providers/runtimes/cloud/openai-codex.ts +49 -0
- package/src/domains/providers/runtimes/cloud/openai.ts +46 -0
- package/src/domains/providers/runtimes/cloud/openrouter.ts +111 -0
- package/src/domains/providers/runtimes/common/lmstudio-logger.ts +32 -0
- package/src/domains/providers/runtimes/common/local-synth.ts +165 -0
- package/src/domains/providers/runtimes/common/probe-helpers.ts +474 -0
- package/src/domains/providers/runtimes/local-native/lemonade-anthropic.ts +27 -0
- package/src/domains/providers/runtimes/local-native/lemonade-openai.ts +26 -0
- package/src/domains/providers/runtimes/local-native/llamacpp-anthropic.ts +88 -0
- package/src/domains/providers/runtimes/local-native/llamacpp-completion.ts +207 -0
- package/src/domains/providers/runtimes/local-native/llamacpp-embed.ts +180 -0
- package/src/domains/providers/runtimes/local-native/llamacpp-rerank.ts +126 -0
- package/src/domains/providers/runtimes/local-native/llamacpp.ts +98 -0
- package/src/domains/providers/runtimes/local-native/lmstudio-native.ts +491 -0
- package/src/domains/providers/runtimes/local-native/ollama-native.ts +117 -0
- package/src/domains/providers/runtimes/local-native/sglang.ts +26 -0
- package/src/domains/providers/runtimes/local-native/vllm.ts +27 -0
- package/src/domains/providers/runtimes/protocol/anthropic-compat.ts +104 -0
- package/src/domains/providers/runtimes/protocol/anthropic-messages.ts +28 -0
- package/src/domains/providers/runtimes/protocol/bedrock.ts +26 -0
- package/src/domains/providers/runtimes/protocol/google.ts +27 -0
- package/src/domains/providers/runtimes/protocol/openai-compat.ts +145 -0
- package/src/domains/providers/support.ts +238 -0
- package/src/domains/providers/thinking-control-policy.ts +85 -0
- package/src/domains/providers/types/capability-flags.ts +114 -0
- package/src/domains/providers/types/cost-provenance.ts +7 -0
- package/src/domains/providers/types/inference.ts +41 -0
- package/src/domains/providers/types/knowledge-base.ts +156 -0
- package/src/domains/providers/types/local-model-quirks.ts +218 -0
- package/src/domains/providers/types/runtime-descriptor.ts +170 -0
- package/src/domains/providers/types/target-descriptor.ts +38 -0
- package/src/domains/resources/collision.ts +92 -0
- package/src/domains/resources/common-loader.ts +140 -0
- package/src/domains/resources/contract.ts +25 -0
- package/src/domains/resources/extension.ts +61 -0
- package/src/domains/resources/index.ts +74 -0
- package/src/domains/resources/loader.ts +86 -0
- package/src/domains/resources/manifest.ts +6 -0
- package/src/domains/resources/prompts/loader.ts +232 -0
- package/src/domains/resources/prompts/substitute.ts +65 -0
- package/src/domains/resources/skills/content-hash.ts +105 -0
- package/src/domains/resources/skills/evals.ts +175 -0
- package/src/domains/resources/skills/install.ts +410 -0
- package/src/domains/resources/skills/loader.ts +978 -0
- package/src/domains/resources/skills/marketplace.ts +255 -0
- package/src/domains/resources/skills/provenance-pin.ts +115 -0
- package/src/domains/safety/action-classifier.ts +268 -0
- package/src/domains/safety/approval-axis.ts +23 -0
- package/src/domains/safety/audit.ts +487 -0
- package/src/domains/safety/autonomy.ts +174 -0
- package/src/domains/safety/call-target.ts +59 -0
- package/src/domains/safety/contract.ts +65 -0
- package/src/domains/safety/damage-control.ts +44 -0
- package/src/domains/safety/default-path-policy.ts +117 -0
- package/src/domains/safety/extension.ts +383 -0
- package/src/domains/safety/finish-contract-registration.ts +128 -0
- package/src/domains/safety/finish-contract.ts +554 -0
- package/src/domains/safety/index.ts +44 -0
- package/src/domains/safety/loop-detector.ts +143 -0
- package/src/domains/safety/manifest.ts +6 -0
- package/src/domains/safety/path-policy.ts +164 -0
- package/src/domains/safety/policy-engine.ts +994 -0
- package/src/domains/safety/project-policy.ts +391 -0
- package/src/domains/safety/protected-artifacts-registration.ts +189 -0
- package/src/domains/safety/protected-artifacts.ts +993 -0
- package/src/domains/safety/rejection-feedback.ts +102 -0
- package/src/domains/safety/rigor.ts +72 -0
- package/src/domains/safety/rule-compiler.ts +48 -0
- package/src/domains/safety/rule-pack-loader.ts +92 -0
- package/src/domains/safety/run-effects.ts +197 -0
- package/src/domains/safety/scope.ts +61 -0
- package/src/domains/scheduling/budget.ts +35 -0
- package/src/domains/scheduling/cluster.ts +175 -0
- package/src/domains/scheduling/contract.ts +30 -0
- package/src/domains/scheduling/extension.ts +91 -0
- package/src/domains/scheduling/index.ts +12 -0
- package/src/domains/scheduling/manifest.ts +6 -0
- package/src/domains/session/archive-readers.ts +208 -0
- package/src/domains/session/checkpoint.ts +38 -0
- package/src/domains/session/compaction/auto.ts +89 -0
- package/src/domains/session/compaction/branch-summary.ts +186 -0
- package/src/domains/session/compaction/compact.ts +493 -0
- package/src/domains/session/compaction/cut-point.ts +171 -0
- package/src/domains/session/compaction/defaults.ts +34 -0
- package/src/domains/session/compaction/mask-observations.ts +265 -0
- package/src/domains/session/compaction/session-entries.ts +18 -0
- package/src/domains/session/compaction/tokens.ts +147 -0
- package/src/domains/session/context-accounting.ts +583 -0
- package/src/domains/session/context-ledger.ts +348 -0
- package/src/domains/session/contract.ts +144 -0
- package/src/domains/session/cwd-fallback.ts +65 -0
- package/src/domains/session/entries.ts +509 -0
- package/src/domains/session/extension.ts +322 -0
- package/src/domains/session/history.ts +172 -0
- package/src/domains/session/index.ts +84 -0
- package/src/domains/session/manager.ts +128 -0
- package/src/domains/session/manifest.ts +6 -0
- package/src/domains/session/migrations/index.ts +27 -0
- package/src/domains/session/prompt-manifest.ts +173 -0
- package/src/domains/session/protected-artifact-journal.ts +241 -0
- package/src/domains/session/protected-artifacts.ts +90 -0
- package/src/domains/session/retry.ts +238 -0
- package/src/domains/session/task-board.ts +375 -0
- package/src/domains/session/tree/active-path.ts +98 -0
- package/src/domains/session/tree/fork.ts +160 -0
- package/src/domains/session/tree/manager.ts +128 -0
- package/src/domains/session/tree/navigator.ts +177 -0
- package/src/domains/session/tree/preview.ts +259 -0
- package/src/domains/session/usage.ts +148 -0
- package/src/domains/session/workspace/git-probe.ts +161 -0
- package/src/domains/session/workspace/index.ts +4 -0
- package/src/domains/session/workspace/project-type.ts +217 -0
- package/src/domains/session/workspace/snapshot.ts +74 -0
- package/src/domains/share/archive.ts +684 -0
- package/src/domains/share/contract.ts +9 -0
- package/src/domains/share/extension.ts +26 -0
- package/src/domains/share/index.ts +28 -0
- package/src/domains/share/manifest.ts +6 -0
- package/src/engine/acp/adapter.ts +397 -0
- package/src/engine/acp/errors.ts +32 -0
- package/src/engine/acp/event-mapper.ts +154 -0
- package/src/engine/acp/server.ts +656 -0
- package/src/engine/acp/tool-mediator.ts +686 -0
- package/src/engine/acp/transport.ts +654 -0
- package/src/engine/acp/types.ts +170 -0
- package/src/engine/agent.ts +29 -0
- package/src/engine/ai.ts +202 -0
- package/src/engine/alcf-oauth.ts +198 -0
- package/src/engine/antigravity/subprocess-runtime.ts +205 -0
- package/src/engine/apis/degraded-inference.ts +95 -0
- package/src/engine/apis/index.ts +20 -0
- package/src/engine/apis/llamacpp-residency.ts +252 -0
- package/src/engine/apis/lmstudio-native.ts +1438 -0
- package/src/engine/apis/lmstudio-residency.ts +92 -0
- package/src/engine/apis/ollama-native.ts +507 -0
- package/src/engine/apis/openai-completions.ts +716 -0
- package/src/engine/apis/output-budget.ts +99 -0
- package/src/engine/apis/residency-lock.ts +29 -0
- package/src/engine/apis/residency.ts +640 -0
- package/src/engine/apis/resident-models.ts +42 -0
- package/src/engine/apis/sampling-overrides.ts +38 -0
- package/src/engine/apis/thinking-replay.ts +11 -0
- package/src/engine/claude/sdk-runtime.ts +685 -0
- package/src/engine/claude/session-id.ts +5 -0
- package/src/engine/claude/subprocess-runtime.ts +316 -0
- package/src/engine/claude/tool-safety.ts +400 -0
- package/src/engine/external-subprocess.ts +23 -0
- package/src/engine/harmony-response.ts +165 -0
- package/src/engine/loop-guard.ts +1127 -0
- package/src/engine/oauth.ts +192 -0
- package/src/engine/pi-mono-names.ts +13 -0
- package/src/engine/provider-payload.ts +315 -0
- package/src/engine/select-list.ts +53 -0
- package/src/engine/session.ts +834 -0
- package/src/engine/strip-tokenizer-sentinels.ts +125 -0
- package/src/engine/tui.ts +103 -0
- package/src/engine/types.ts +66 -0
- package/src/engine/worker-events.ts +100 -0
- package/src/engine/worker-runtime.ts +1022 -0
- package/src/engine/worker-tools.ts +203 -0
- package/src/entry/orchestrator.ts +1873 -0
- package/src/interactive/application-controller.ts +346 -0
- package/src/interactive/bus-notices.ts +265 -0
- package/src/interactive/chat-loop-messages.ts +626 -0
- package/src/interactive/chat-loop-policy.ts +18 -0
- package/src/interactive/chat-loop.ts +865 -0
- package/src/interactive/chat-panel.ts +1694 -0
- package/src/interactive/chat-renderer.ts +1038 -0
- package/src/interactive/clio-editor.ts +166 -0
- package/src/interactive/command-fallbacks.ts +23 -0
- package/src/interactive/command-output.ts +85 -0
- package/src/interactive/context-activity.ts +203 -0
- package/src/interactive/context-meter.ts +223 -0
- package/src/interactive/context-overlay.ts +220 -0
- package/src/interactive/cost-overlay.ts +279 -0
- package/src/interactive/dispatch-board.ts +1319 -0
- package/src/interactive/dispatch-steering.ts +86 -0
- package/src/interactive/editor-bash.ts +46 -0
- package/src/interactive/editor-steer.ts +51 -0
- package/src/interactive/editor-submit.ts +303 -0
- package/src/interactive/external-editor.ts +67 -0
- package/src/interactive/follow-up-queue-panel.ts +75 -0
- package/src/interactive/footer/dashboard.ts +534 -0
- package/src/interactive/footer/notifications.ts +275 -0
- package/src/interactive/footer/widgets.ts +1246 -0
- package/src/interactive/footer-panel.ts +187 -0
- package/src/interactive/format-time.ts +85 -0
- package/src/interactive/index.ts +11 -0
- package/src/interactive/interactive-application.ts +755 -0
- package/src/interactive/interactive-event-projection.ts +380 -0
- package/src/interactive/interactive-input-runtime.ts +261 -0
- package/src/interactive/interactive-presentation.ts +452 -0
- package/src/interactive/interactive-shell.ts +134 -0
- package/src/interactive/interactive-slash-runtime.ts +492 -0
- package/src/interactive/interactive-subscriptions.ts +111 -0
- package/src/interactive/interactive-tickers.ts +152 -0
- package/src/interactive/keybinding-manager.ts +496 -0
- package/src/interactive/layout.ts +20 -0
- package/src/interactive/leader-key.ts +143 -0
- package/src/interactive/loop-guard-interrupt.ts +101 -0
- package/src/interactive/memory-overlay.ts +280 -0
- package/src/interactive/overlay-ask-user-lifecycle.ts +110 -0
- package/src/interactive/overlay-auth-lifecycle.ts +308 -0
- package/src/interactive/overlay-frame.ts +502 -0
- package/src/interactive/overlay-general-openers.ts +217 -0
- package/src/interactive/overlay-key-routing.ts +213 -0
- package/src/interactive/overlay-lifecycle.ts +413 -0
- package/src/interactive/overlay-model-selectors.ts +127 -0
- package/src/interactive/overlay-permission-lifecycle.ts +344 -0
- package/src/interactive/overlay-resource-openers.ts +112 -0
- package/src/interactive/overlay-session-lifecycle.ts +270 -0
- package/src/interactive/overlay-transitions.ts +57 -0
- package/src/interactive/overlays/agents.ts +69 -0
- package/src/interactive/overlays/ask-user.ts +921 -0
- package/src/interactive/overlays/auth-dialog.ts +221 -0
- package/src/interactive/overlays/context-reset.ts +108 -0
- package/src/interactive/overlays/cwd-fallback.ts +141 -0
- package/src/interactive/overlays/extensions.ts +54 -0
- package/src/interactive/overlays/help-reference.ts +140 -0
- package/src/interactive/overlays/interop.ts +139 -0
- package/src/interactive/overlays/keybinding-detail.ts +90 -0
- package/src/interactive/overlays/list-overlay.ts +606 -0
- package/src/interactive/overlays/message-picker.ts +155 -0
- package/src/interactive/overlays/model-selector.ts +1091 -0
- package/src/interactive/overlays/prompts.ts +72 -0
- package/src/interactive/overlays/session-selector-search.ts +31 -0
- package/src/interactive/overlays/session-selector.ts +266 -0
- package/src/interactive/overlays/settings.ts +3363 -0
- package/src/interactive/overlays/skills-hub.ts +237 -0
- package/src/interactive/overlays/tree-selector.ts +387 -0
- package/src/interactive/permission-overlay.ts +170 -0
- package/src/interactive/render-trace.ts +125 -0
- package/src/interactive/renderers/branch-summary.ts +86 -0
- package/src/interactive/renderers/code-ink.ts +420 -0
- package/src/interactive/renderers/compaction-summary.ts +112 -0
- package/src/interactive/renderers/diff.ts +126 -0
- package/src/interactive/renderers/notice.ts +28 -0
- package/src/interactive/renderers/retry-status.ts +31 -0
- package/src/interactive/renderers/structured.ts +89 -0
- package/src/interactive/renderers/tool-execution.ts +1104 -0
- package/src/interactive/renderers/worker-entry.ts +264 -0
- package/src/interactive/session-last-turn.ts +186 -0
- package/src/interactive/session-transcript.ts +105 -0
- package/src/interactive/session-usage-reseed.ts +74 -0
- package/src/interactive/slash-autocomplete.ts +364 -0
- package/src/interactive/slash-commands.ts +1319 -0
- package/src/interactive/slash-spec.ts +453 -0
- package/src/interactive/status/controller.ts +256 -0
- package/src/interactive/status/index.ts +23 -0
- package/src/interactive/status/state-machine.ts +530 -0
- package/src/interactive/status/summary.ts +170 -0
- package/src/interactive/status/types.ts +121 -0
- package/src/interactive/status/verbs.ts +163 -0
- package/src/interactive/status/watchdog.ts +24 -0
- package/src/interactive/tasks-overlay.ts +186 -0
- package/src/interactive/theme/components.ts +55 -0
- package/src/interactive/theme/glyphs.ts +70 -0
- package/src/interactive/theme/index.ts +15 -0
- package/src/interactive/theme/labels.ts +88 -0
- package/src/interactive/theme/rules.ts +138 -0
- package/src/interactive/theme/segments.ts +88 -0
- package/src/interactive/theme/tokens.ts +121 -0
- package/src/interactive/thinking-level-policy.ts +6 -0
- package/src/interactive/tool-prose-loop.ts +122 -0
- package/src/interactive/tool-prose-registration.ts +48 -0
- package/src/interactive/turn-context.ts +854 -0
- package/src/interactive/turn-middleware.ts +283 -0
- package/src/interactive/turn-persistence.ts +441 -0
- package/src/interactive/turn-queues.ts +169 -0
- package/src/interactive/turn-recovery.ts +306 -0
- package/src/interactive/turn-runtime.ts +802 -0
- package/src/interactive/turn-state.ts +123 -0
- package/src/interactive/view/artifacts.ts +1342 -0
- package/src/interactive/view/view-overlay.ts +732 -0
- package/src/interactive/welcome-dashboard.ts +536 -0
- package/src/interactive/worker-receipts.ts +94 -0
- package/src/interactive/worker-replay.ts +111 -0
- package/src/interactive/worker-share.ts +100 -0
- package/src/interactive/worker-stream.ts +442 -0
- package/src/interactive/workspace-facts.ts +141 -0
- package/src/tools/agent-tools.ts +382 -0
- package/src/tools/artifact.ts +103 -0
- package/src/tools/ask-user.ts +656 -0
- package/src/tools/bash.ts +176 -0
- package/src/tools/bootstrap.ts +474 -0
- package/src/tools/codewiki/code-nav.ts +563 -0
- package/src/tools/codewiki/shared.ts +115 -0
- package/src/tools/compete-worktrees.ts +898 -0
- package/src/tools/context/docs-engine.ts +619 -0
- package/src/tools/context/index.ts +435 -0
- package/src/tools/credential-present.ts +151 -0
- package/src/tools/dispatch-arguments.ts +228 -0
- package/src/tools/dispatch-plan.ts +741 -0
- package/src/tools/dispatch-scout.ts +461 -0
- package/src/tools/dispatch.ts +3338 -0
- package/src/tools/edit-diff.ts +534 -0
- package/src/tools/edit.ts +128 -0
- package/src/tools/executables.ts +22 -0
- package/src/tools/file-mutation-queue.ts +35 -0
- package/src/tools/find.ts +292 -0
- package/src/tools/grep.ts +495 -0
- package/src/tools/ignore-policy.ts +169 -0
- package/src/tools/ledger.ts +206 -0
- package/src/tools/ls.ts +110 -0
- package/src/tools/monitor.ts +797 -0
- package/src/tools/network-policy.ts +29 -0
- package/src/tools/observation.ts +421 -0
- package/src/tools/observers.ts +99 -0
- package/src/tools/path-utils.ts +79 -0
- package/src/tools/policy.ts +154 -0
- package/src/tools/profiles.ts +108 -0
- package/src/tools/read.ts +173 -0
- package/src/tools/registry.ts +1157 -0
- package/src/tools/result-shaping.ts +204 -0
- package/src/tools/safe-exec.ts +128 -0
- package/src/tools/spawn-hygiene.ts +182 -0
- package/src/tools/steer.ts +88 -0
- package/src/tools/string-enum.ts +15 -0
- package/src/tools/tasks.ts +168 -0
- package/src/tools/truncate-utf8.ts +17 -0
- package/src/tools/truncate.ts +202 -0
- package/src/tools/verify/frontend.ts +685 -0
- package/src/tools/verify/index.ts +66 -0
- package/src/tools/verify/scripts.ts +108 -0
- package/src/tools/web-fetch.ts +777 -0
- package/src/tools/worker-evidence.ts +215 -0
- package/src/tools/write.ts +52 -0
- package/src/utils/exif-orientation.ts +192 -0
- package/src/utils/git.ts +24 -0
- package/src/utils/image-resize.ts +148 -0
- package/src/utils/photon.ts +103 -0
- package/src/worker/control-lane.ts +22 -0
- package/src/worker/entry.ts +257 -0
- package/src/worker/event-projection.ts +56 -0
- package/src/worker/heartbeat.ts +24 -0
- package/src/worker/ledger-mirror.ts +95 -0
- package/src/worker/ndjson.ts +40 -0
- package/src/worker/protocol.ts +529 -0
- package/src/worker/resource-facts.ts +79 -0
- package/src/worker/runtime-registry.ts +12 -0
- package/src/worker/spec-contract.ts +654 -0
- package/src/worker/stdin-demux.ts +316 -0
- package/dist/acp-UMLFVA3F.js +0 -92
- package/dist/chunk-262G75JS.js +0 -35
- package/dist/chunk-5LDRNKX2.js +0 -1063
- package/dist/chunk-67MTHP2E.js +0 -135
- package/dist/chunk-GOTUR54M.js +0 -9
- package/dist/chunk-TPOCL34A.js +0 -2876
- package/dist/chunk-XV4ZJ6ZM.js +0 -3177
- package/dist/clio-KIQ5SNDS.js +0 -53
- package/dist/configure-G4E3A2PG.js +0 -27
- package/dist/doctor-M5HJJZOL.js +0 -61
- package/dist/domains/agents/builtins/architect.md +0 -33
- package/dist/domains/agents/builtins/coder.md +0 -31
- package/dist/domains/agents/builtins/context-bootstrap.md +0 -38
- package/dist/domains/agents/builtins/debugger.md +0 -30
- package/dist/domains/agents/builtins/documenter.md +0 -31
- package/dist/domains/agents/builtins/git-master.md +0 -30
- package/dist/domains/agents/builtins/provenance.md +0 -30
- package/dist/domains/agents/builtins/researcher.md +0 -71
- package/dist/domains/agents/builtins/scout.md +0 -42
- package/dist/domains/agents/builtins/tester.md +0 -31
- package/dist/domains/agents/builtins/verifier.md +0 -30
- package/dist/domains/agents/builtins/wiki-writer.md +0 -41
- package/dist/fleet-preflight-CLIAX7YR.js +0 -21
- package/dist/preload-KZVHET2B.js +0 -11
- package/dist/version-ROZ6CZKH.js +0 -16
- package/skills/git/commit-crafting/SKILL.md +0 -79
- package/skills/git/commit-crafting/evals.md +0 -92
- package/skills/git/create-pr/SKILL.md +0 -116
- package/skills/git/create-pr/evals.md +0 -114
- package/skills/git/investigate-issue/SKILL.md +0 -139
- package/skills/git/investigate-issue/evals.md +0 -94
- package/skills/git/review-changes/SKILL.md +0 -103
- package/skills/git/review-changes/evals.md +0 -85
|
@@ -0,0 +1,921 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type Component,
|
|
3
|
+
Input,
|
|
4
|
+
matchesKey,
|
|
5
|
+
type OverlayHandle,
|
|
6
|
+
type OverlayOptions,
|
|
7
|
+
type SelectItem,
|
|
8
|
+
SelectList,
|
|
9
|
+
type TUI,
|
|
10
|
+
truncateToWidth,
|
|
11
|
+
visibleWidth,
|
|
12
|
+
wrapTextWithAnsi,
|
|
13
|
+
} from "../../engine/tui.js";
|
|
14
|
+
import type { AskUserAnswer, AskUserQuestion, AskUserResult } from "../../tools/ask-user.js";
|
|
15
|
+
import { ASK_USER_OTHER_LABEL, cancelledAskUserResult } from "../../tools/ask-user.js";
|
|
16
|
+
import { buildHint, DEFAULT_SELECT_THEME, showClioOverlayFrame } from "../overlay-frame.js";
|
|
17
|
+
import { type ClioToken, clioTheme, dotSep, GLYPH, screenTitle } from "../theme/index.js";
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* The border and title token while a decision is pending.
|
|
21
|
+
*
|
|
22
|
+
* Orange is the token that means Clio is acting, and a prompt holding the
|
|
23
|
+
* keyboard is the moment the operator has to act with it. Everything
|
|
24
|
+
* informational keeps the teal frame, so the one border that is not teal is the
|
|
25
|
+
* one asking for an answer. All three surfaces carry it: what changes between
|
|
26
|
+
* them is the size and the place, never the signal.
|
|
27
|
+
*/
|
|
28
|
+
export const ASK_USER_DECISION_TONE: ClioToken = "action";
|
|
29
|
+
export const ASK_USER_DECISION_TITLE = "Decision required";
|
|
30
|
+
export const ASK_USER_WAITING_TITLE = "Ask User";
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* The shape a request draws itself in.
|
|
34
|
+
*
|
|
35
|
+
* One overlay served three interactions through one centered full-height modal,
|
|
36
|
+
* so a two-option confirmation arrived as a thirty-five-row box with twenty-five
|
|
37
|
+
* blank rows under the options. The surfaces differ in size and placement:
|
|
38
|
+
*
|
|
39
|
+
* - `compact` is a small bar low on the screen, where the operator's eyes
|
|
40
|
+
* already are, for one question with a handful of choices.
|
|
41
|
+
* - `panel` is a medium centered box for one question whose option list is too
|
|
42
|
+
* long to read in a bar.
|
|
43
|
+
* - `interview` is the full surface with the round strip and the answer ledger,
|
|
44
|
+
* for a round of several questions or any round after the first.
|
|
45
|
+
*/
|
|
46
|
+
export type AskUserSurface = "compact" | "panel" | "interview";
|
|
47
|
+
|
|
48
|
+
/** Options a single question may carry and still be answered in the bar. */
|
|
49
|
+
export const ASK_USER_COMPACT_MAX_OPTIONS = 3;
|
|
50
|
+
|
|
51
|
+
/** The surface an overlay waits on before its first round decides one. */
|
|
52
|
+
export const ASK_USER_DEFAULT_SURFACE: AskUserSurface = "panel";
|
|
53
|
+
|
|
54
|
+
interface AskUserSurfaceGeometry {
|
|
55
|
+
/** Box width in columns; zero fills the row. The frame clamps to the terminal. */
|
|
56
|
+
width: number;
|
|
57
|
+
/** Rows the body may use, before the borders. */
|
|
58
|
+
maxInnerRows: number;
|
|
59
|
+
anchor: NonNullable<OverlayOptions["anchor"]>;
|
|
60
|
+
margin: NonNullable<OverlayOptions["margin"]>;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Where each surface sits and how big it is allowed to get.
|
|
65
|
+
*
|
|
66
|
+
* The compact bar anchors to the bottom because a decision that has taken the
|
|
67
|
+
* keyboard should appear where the operator was already typing, not in the
|
|
68
|
+
* middle of the transcript. It covers the composer, which is honest: the
|
|
69
|
+
* composer accepts nothing while a decision is pending.
|
|
70
|
+
*
|
|
71
|
+
* Every surface's margin is one row top and bottom, which is what
|
|
72
|
+
* `ASK_USER_FRAME_AND_MARGIN_ROWS` counts alongside the two border rows.
|
|
73
|
+
*/
|
|
74
|
+
export const ASK_USER_SURFACE_GEOMETRY: Record<AskUserSurface, AskUserSurfaceGeometry> = {
|
|
75
|
+
compact: { width: 68, maxInnerRows: 10, anchor: "bottom-center", margin: { top: 1, right: 2, bottom: 1, left: 2 } },
|
|
76
|
+
panel: { width: 88, maxInnerRows: 18, anchor: "center", margin: 1 },
|
|
77
|
+
interview: { width: 0, maxInnerRows: 42, anchor: "center", margin: 1 },
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
const ASK_USER_FRAME_ROWS = 2;
|
|
81
|
+
const ASK_USER_FRAME_AND_MARGIN_ROWS = 4;
|
|
82
|
+
const MIN_VISIBLE_OPTIONS = 3;
|
|
83
|
+
const MAX_VISIBLE_OPTIONS = 12;
|
|
84
|
+
const ELLIPSIS = "…";
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* The surface a request renders on, from the request shape alone.
|
|
88
|
+
*
|
|
89
|
+
* `priorRounds` is what makes an interview an interview. The tool's `mode`
|
|
90
|
+
* cannot answer this: `single_question` is the mode an interview asks its
|
|
91
|
+
* rounds in, and a first single question is exactly the confirmation that
|
|
92
|
+
* should not take the screen. A round that follows an answered one has captured
|
|
93
|
+
* answers to keep on screen, which is the full surface's whole job.
|
|
94
|
+
*/
|
|
95
|
+
export function askUserSurface(questions: ReadonlyArray<AskUserQuestion>, priorRounds = 0): AskUserSurface {
|
|
96
|
+
if (priorRounds > 0 || questions.length !== 1) return "interview";
|
|
97
|
+
const question = questions[0];
|
|
98
|
+
if (!question) return "interview";
|
|
99
|
+
return (question.options?.length ?? 0) <= ASK_USER_COMPACT_MAX_OPTIONS ? "compact" : "panel";
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export interface OpenAskUserOverlayDeps {
|
|
103
|
+
onCancel: () => void;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export interface AskUserOverlaySession extends OverlayHandle {
|
|
107
|
+
ask(questions: ReadonlyArray<AskUserQuestion>): Promise<AskUserResult>;
|
|
108
|
+
cancel(): void;
|
|
109
|
+
close(): void;
|
|
110
|
+
isWaiting(): boolean;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
type Mode = "select" | "text";
|
|
114
|
+
type InterviewPhase = "waiting" | "asking" | "closed";
|
|
115
|
+
|
|
116
|
+
interface QuestionState {
|
|
117
|
+
mode: Mode;
|
|
118
|
+
selected: Set<number>;
|
|
119
|
+
customAnswer: string;
|
|
120
|
+
inputValue: string;
|
|
121
|
+
answer: string;
|
|
122
|
+
focusedValue?: string;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
interface AskUserOverlayViewDeps extends OpenAskUserOverlayDeps {
|
|
126
|
+
getTerminalRows: () => number;
|
|
127
|
+
requestRender: () => void;
|
|
128
|
+
/** Called when the request shape moves the body to a differently sized box. */
|
|
129
|
+
onSurface: (surface: AskUserSurface) => void;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function questionHasOptions(question: AskUserQuestion): boolean {
|
|
133
|
+
return (question.options?.length ?? 0) > 0;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function initialMode(question: AskUserQuestion): Mode {
|
|
137
|
+
return questionHasOptions(question) ? "select" : "text";
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function createQuestionState(question: AskUserQuestion): QuestionState {
|
|
141
|
+
return {
|
|
142
|
+
mode: initialMode(question),
|
|
143
|
+
selected: new Set<number>(),
|
|
144
|
+
customAnswer: "",
|
|
145
|
+
inputValue: "",
|
|
146
|
+
answer: "",
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function isOtherOption(label: string): boolean {
|
|
151
|
+
const normalized = label
|
|
152
|
+
.toLowerCase()
|
|
153
|
+
.replace(/[^a-z0-9]+/g, " ")
|
|
154
|
+
.trim();
|
|
155
|
+
return (
|
|
156
|
+
normalized === "other" ||
|
|
157
|
+
normalized === "custom" ||
|
|
158
|
+
normalized === "something else" ||
|
|
159
|
+
normalized.startsWith("other ")
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function optionItems(question: AskUserQuestion, selected: ReadonlySet<number>): SelectItem[] {
|
|
164
|
+
const options = question.options ?? [];
|
|
165
|
+
const explicitOtherIndex = options.findIndex((option) => isOtherOption(option.label));
|
|
166
|
+
const items: SelectItem[] = [];
|
|
167
|
+
for (let index = 0; index < options.length; index += 1) {
|
|
168
|
+
const option = options[index];
|
|
169
|
+
if (!option) continue;
|
|
170
|
+
const isExplicitOther = index === explicitOtherIndex;
|
|
171
|
+
const label =
|
|
172
|
+
question.multi_select === true && !isExplicitOther
|
|
173
|
+
? `${selected.has(index) ? "[x]" : "[ ]"} ${option.label}`
|
|
174
|
+
: option.label;
|
|
175
|
+
const item: SelectItem = {
|
|
176
|
+
value: isExplicitOther ? "other" : `option:${index}`,
|
|
177
|
+
label,
|
|
178
|
+
};
|
|
179
|
+
if (option.description) item.description = option.description;
|
|
180
|
+
items.push(item);
|
|
181
|
+
}
|
|
182
|
+
if (explicitOtherIndex === -1) {
|
|
183
|
+
items.push({
|
|
184
|
+
value: "other",
|
|
185
|
+
label: question.multi_select === true ? `[ ] ${ASK_USER_OTHER_LABEL}` : ASK_USER_OTHER_LABEL,
|
|
186
|
+
description: "type your answer",
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
return items;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
function optionIndexFromValue(value: string): number | null {
|
|
193
|
+
if (!value.startsWith("option:")) return null;
|
|
194
|
+
const index = Number(value.slice("option:".length));
|
|
195
|
+
return Number.isInteger(index) && index >= 0 ? index : null;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function answerText(question: AskUserQuestion, selected: ReadonlySet<number>, customAnswer: string): string {
|
|
199
|
+
const parts: string[] = [];
|
|
200
|
+
for (const index of [...selected].sort((a, b) => a - b)) {
|
|
201
|
+
const label = question.options?.[index]?.label;
|
|
202
|
+
if (label) parts.push(label);
|
|
203
|
+
}
|
|
204
|
+
const custom = customAnswer.trim();
|
|
205
|
+
if (custom.length > 0) parts.push(custom);
|
|
206
|
+
return parts.join("; ");
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
function fitLine(text: string, width: number): string {
|
|
210
|
+
const safeWidth = Math.max(1, width);
|
|
211
|
+
if (visibleWidth(text) <= safeWidth) return text;
|
|
212
|
+
return truncateToWidth(text, safeWidth, ELLIPSIS, true);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
function compactTitle(question: AskUserQuestion): string {
|
|
216
|
+
return (question.header ?? question.question).replace(/\s+/g, " ").trim();
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
class AskUserOverlayView implements Component {
|
|
220
|
+
private phase: InterviewPhase = "waiting";
|
|
221
|
+
private surface: AskUserSurface = ASK_USER_DEFAULT_SURFACE;
|
|
222
|
+
private index = 0;
|
|
223
|
+
private status = "";
|
|
224
|
+
private questions: ReadonlyArray<AskUserQuestion> = [];
|
|
225
|
+
private states: QuestionState[] = [];
|
|
226
|
+
private history: AskUserAnswer[] = [];
|
|
227
|
+
private list: SelectList | null = null;
|
|
228
|
+
private input: Input | null = null;
|
|
229
|
+
private resolveCurrent: ((result: AskUserResult) => void) | null = null;
|
|
230
|
+
|
|
231
|
+
constructor(private readonly deps: AskUserOverlayViewDeps) {}
|
|
232
|
+
|
|
233
|
+
begin(questions: ReadonlyArray<AskUserQuestion>): Promise<AskUserResult> {
|
|
234
|
+
if (this.phase === "closed") return Promise.resolve(cancelledAskUserResult());
|
|
235
|
+
if (this.resolveCurrent) return Promise.resolve(cancelledAskUserResult());
|
|
236
|
+
this.phase = "asking";
|
|
237
|
+
this.index = 0;
|
|
238
|
+
this.status = "";
|
|
239
|
+
this.questions = [...questions];
|
|
240
|
+
this.states = this.questions.map((question) => createQuestionState(question));
|
|
241
|
+
this.list = null;
|
|
242
|
+
this.input = null;
|
|
243
|
+
// Before the controls, because how many option rows fit is a property of
|
|
244
|
+
// the box this round is about to be drawn in.
|
|
245
|
+
this.setSurface(askUserSurface(this.questions, this.history.length));
|
|
246
|
+
this.rebuildControl();
|
|
247
|
+
this.deps.requestRender();
|
|
248
|
+
return new Promise<AskUserResult>((resolve) => {
|
|
249
|
+
this.resolveCurrent = resolve;
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
cancel(): void {
|
|
254
|
+
this.finish(cancelledAskUserResult());
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
close(): void {
|
|
258
|
+
this.phase = "closed";
|
|
259
|
+
this.finish(cancelledAskUserResult());
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
isWaiting(): boolean {
|
|
263
|
+
return this.phase === "waiting" && this.resolveCurrent === null;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/** True while the overlay is holding a question the operator has to answer. */
|
|
267
|
+
isDecisionPending(): boolean {
|
|
268
|
+
return this.phase === "asking";
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
currentSurface(): AskUserSurface {
|
|
272
|
+
return this.surface;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
invalidate(): void {
|
|
276
|
+
this.list?.invalidate();
|
|
277
|
+
this.input?.invalidate();
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
handleInput(data: string): void {
|
|
281
|
+
if (this.phase !== "asking") return;
|
|
282
|
+
const question = this.currentQuestion();
|
|
283
|
+
const state = this.currentState();
|
|
284
|
+
if (!question || !state) return;
|
|
285
|
+
|
|
286
|
+
if (state.mode === "text") {
|
|
287
|
+
if (this.isTextModePreviousKey(data)) {
|
|
288
|
+
this.goToRelativeQuestion(-1);
|
|
289
|
+
return;
|
|
290
|
+
}
|
|
291
|
+
if (this.isTextModeNextKey(data)) {
|
|
292
|
+
this.goToRelativeQuestion(1);
|
|
293
|
+
return;
|
|
294
|
+
}
|
|
295
|
+
this.input?.handleInput(data);
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
if (this.isPreviousQuestionKey(data)) {
|
|
300
|
+
this.goToRelativeQuestion(-1);
|
|
301
|
+
return;
|
|
302
|
+
}
|
|
303
|
+
if (this.isNextQuestionKey(data)) {
|
|
304
|
+
this.goToRelativeQuestion(1);
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
if (question.multi_select === true && data === " ") {
|
|
308
|
+
this.toggleCurrentSelection(question, state);
|
|
309
|
+
return;
|
|
310
|
+
}
|
|
311
|
+
if (question.multi_select === true && (matchesKey(data, "enter") || data === "\n")) {
|
|
312
|
+
this.commitMultiSelectOrOpenOther(state);
|
|
313
|
+
return;
|
|
314
|
+
}
|
|
315
|
+
this.list?.handleInput(data);
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* The body, sized to what it has to say.
|
|
320
|
+
*
|
|
321
|
+
* Nothing pads to a target height any more. A two-option confirmation is six
|
|
322
|
+
* rows and draws six rows; the round strip and the answer ledger are what
|
|
323
|
+
* make an interview tall, not filler. The trailing slice is the guarantee the
|
|
324
|
+
* compact bar rests on: whatever the question and its options come to, the
|
|
325
|
+
* body never returns more rows than its surface owns.
|
|
326
|
+
*/
|
|
327
|
+
render(width: number): string[] {
|
|
328
|
+
const safeWidth = Math.max(1, width);
|
|
329
|
+
const maxRows = this.maxInnerRows();
|
|
330
|
+
if (this.phase !== "asking") return this.renderWaiting(safeWidth, maxRows);
|
|
331
|
+
const question = this.currentQuestion();
|
|
332
|
+
if (!question) return [clioTheme().fg("muted", "No questions.")];
|
|
333
|
+
|
|
334
|
+
const interview = this.surface === "interview";
|
|
335
|
+
const controlLines = this.renderControlLines(safeWidth);
|
|
336
|
+
const ledgerLines = interview ? this.renderAnswerLedger(safeWidth) : [];
|
|
337
|
+
const statusLines = this.status.length > 0 ? ["", fitLine(clioTheme().fg("dim", this.status), safeWidth)] : [];
|
|
338
|
+
const stripLines = interview ? [this.renderQuestionStrip(safeWidth), ""] : [];
|
|
339
|
+
const headerLine = this.renderQuestionHeader(question, safeWidth);
|
|
340
|
+
const headerLines = headerLine.length > 0 ? [headerLine] : [];
|
|
341
|
+
const spent =
|
|
342
|
+
stripLines.length + headerLines.length + statusLines.length + 1 + controlLines.length + ledgerLines.length;
|
|
343
|
+
const questionLines = wrapTextWithAnsi(question.question, safeWidth).slice(0, Math.max(1, maxRows - spent));
|
|
344
|
+
|
|
345
|
+
return [...stripLines, ...headerLines, ...questionLines, ...statusLines, "", ...controlLines, ...ledgerLines].slice(
|
|
346
|
+
0,
|
|
347
|
+
maxRows,
|
|
348
|
+
);
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
footerHint(): string {
|
|
352
|
+
if (this.phase !== "asking") {
|
|
353
|
+
return buildHint([]);
|
|
354
|
+
}
|
|
355
|
+
const question = this.currentQuestion();
|
|
356
|
+
const state = this.currentState();
|
|
357
|
+
if (!question || !state) return buildHint([]);
|
|
358
|
+
if (state.mode === "text") {
|
|
359
|
+
return this.questions.length > 1
|
|
360
|
+
? buildHint([
|
|
361
|
+
{ key: "Enter", verb: "submit" },
|
|
362
|
+
{ key: "Alt+Left/Right", verb: "question" },
|
|
363
|
+
])
|
|
364
|
+
: buildHint([{ key: "Enter", verb: "submit" }]);
|
|
365
|
+
}
|
|
366
|
+
// `accept` rather than `select` or `commit`: the footer of a decision prompt
|
|
367
|
+
// has one job, which is to name the key that answers it. Esc keeps the
|
|
368
|
+
// product's one word for the way out, since it closes the prompt and the
|
|
369
|
+
// interview together.
|
|
370
|
+
if (question.multi_select === true) {
|
|
371
|
+
return this.questions.length > 1
|
|
372
|
+
? buildHint([
|
|
373
|
+
{ key: "Left/Right", verb: "question" },
|
|
374
|
+
{ key: "Space", verb: "toggle" },
|
|
375
|
+
{ key: "Enter", verb: "accept" },
|
|
376
|
+
])
|
|
377
|
+
: buildHint([
|
|
378
|
+
{ key: "Space", verb: "toggle" },
|
|
379
|
+
{ key: "Enter", verb: "accept" },
|
|
380
|
+
]);
|
|
381
|
+
}
|
|
382
|
+
return this.questions.length > 1
|
|
383
|
+
? buildHint([
|
|
384
|
+
{ key: "Left/Right", verb: "question" },
|
|
385
|
+
{ key: "Enter", verb: "accept" },
|
|
386
|
+
])
|
|
387
|
+
: buildHint([{ key: "Enter", verb: "accept" }]);
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
private setSurface(next: AskUserSurface): void {
|
|
391
|
+
if (this.surface === next) return;
|
|
392
|
+
this.surface = next;
|
|
393
|
+
this.deps.onSurface(next);
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
private finish(result: AskUserResult): void {
|
|
397
|
+
const resolve = this.resolveCurrent;
|
|
398
|
+
this.resolveCurrent = null;
|
|
399
|
+
this.list = null;
|
|
400
|
+
this.input = null;
|
|
401
|
+
this.status = "";
|
|
402
|
+
if (result.cancelled !== true) this.history.push(...result.answers);
|
|
403
|
+
if (this.phase !== "closed") this.phase = "waiting";
|
|
404
|
+
// A round that follows an answered one is an interview, so the box grows
|
|
405
|
+
// here rather than at the next `begin`. The waiting frame between rounds
|
|
406
|
+
// is then already the size of the round it is waiting for.
|
|
407
|
+
if (this.history.length > 0) this.setSurface("interview");
|
|
408
|
+
this.deps.requestRender();
|
|
409
|
+
resolve?.(result);
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
private renderWaiting(width: number, maxRows: number): string[] {
|
|
413
|
+
const theme = clioTheme();
|
|
414
|
+
const lines = [
|
|
415
|
+
screenTitle(theme, "Interview"),
|
|
416
|
+
"",
|
|
417
|
+
theme.fg(
|
|
418
|
+
"muted",
|
|
419
|
+
this.history.length > 0
|
|
420
|
+
? "Answer sent. Waiting for Clio to prepare the next interview question."
|
|
421
|
+
: "Waiting for Clio to prepare the interview.",
|
|
422
|
+
),
|
|
423
|
+
];
|
|
424
|
+
if (this.history.length > 0) {
|
|
425
|
+
lines.push("", theme.fg("dim", "── Collected answers"));
|
|
426
|
+
for (let index = 0; index < this.history.length; index += 1) {
|
|
427
|
+
const answer = this.history[index];
|
|
428
|
+
if (!answer) continue;
|
|
429
|
+
lines.push(fitLine(`${theme.fg("dim", `${index + 1}.`)} ${theme.fg("muted", answer.answer)}`, width));
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
return lines.map((line) => fitLine(line, width)).slice(0, maxRows);
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
/**
|
|
436
|
+
* Rows the body may draw on this surface.
|
|
437
|
+
*
|
|
438
|
+
* The frame budgets the same number, because its `maxHeight` is this cap plus
|
|
439
|
+
* the two border rows and both clamp to the terminal the same way. That is
|
|
440
|
+
* what keeps `fitBody`'s "… N more rows" off the compact bar: the body never
|
|
441
|
+
* hands the frame more than the frame is prepared to draw.
|
|
442
|
+
*/
|
|
443
|
+
private maxInnerRows(): number {
|
|
444
|
+
const cap = ASK_USER_SURFACE_GEOMETRY[this.surface].maxInnerRows;
|
|
445
|
+
const rows = this.deps.getTerminalRows();
|
|
446
|
+
if (!Number.isFinite(rows) || rows <= 0) return cap;
|
|
447
|
+
return Math.max(1, Math.min(cap, Math.floor(rows) - ASK_USER_FRAME_AND_MARGIN_ROWS));
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
private maxVisibleOptions(): number {
|
|
451
|
+
const inner = this.maxInnerRows();
|
|
452
|
+
// The interview surface spends rows on the round strip and the ledger
|
|
453
|
+
// before an option ever renders. The other two spend them on a header, a
|
|
454
|
+
// question, and a separator, so the options get nearly everything.
|
|
455
|
+
if (this.surface === "interview") {
|
|
456
|
+
return Math.max(MIN_VISIBLE_OPTIONS, Math.min(MAX_VISIBLE_OPTIONS, inner - 12));
|
|
457
|
+
}
|
|
458
|
+
return Math.max(1, Math.min(MAX_VISIBLE_OPTIONS, inner - 4));
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
private currentQuestion(): AskUserQuestion | null {
|
|
462
|
+
return this.questions[this.index] ?? null;
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
private currentState(): QuestionState | null {
|
|
466
|
+
return this.states[this.index] ?? null;
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
private isPreviousQuestionKey(data: string): boolean {
|
|
470
|
+
return this.questions.length > 1 && matchesKey(data, "left");
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
private isNextQuestionKey(data: string): boolean {
|
|
474
|
+
return this.questions.length > 1 && matchesKey(data, "right");
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
private isTextModePreviousKey(data: string): boolean {
|
|
478
|
+
return this.questions.length > 1 && (matchesKey(data, "alt+left") || matchesKey(data, "ctrl+left"));
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
private isTextModeNextKey(data: string): boolean {
|
|
482
|
+
return this.questions.length > 1 && (matchesKey(data, "alt+right") || matchesKey(data, "ctrl+right"));
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
/**
|
|
486
|
+
* The row above the question, or nothing.
|
|
487
|
+
*
|
|
488
|
+
* `Question 1/1` was a counter over a set of one, printed on every single
|
|
489
|
+
* confirmation. A one-question surface shows the question's own header if it
|
|
490
|
+
* has one and skips the row entirely if it does not.
|
|
491
|
+
*/
|
|
492
|
+
private renderQuestionHeader(question: AskUserQuestion, width: number): string {
|
|
493
|
+
const theme = clioTheme();
|
|
494
|
+
const parts: string[] = [];
|
|
495
|
+
if (this.questions.length > 1) parts.push(theme.fg("dim", `Question ${this.index + 1}/${this.questions.length}`));
|
|
496
|
+
if (question.header) parts.push(screenTitle(theme, question.header));
|
|
497
|
+
if (this.currentState()?.answer.trim()) parts.push(theme.fg("muted", "answered"));
|
|
498
|
+
return parts.length > 0 ? fitLine(parts.join(dotSep(theme)), width) : "";
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
private renderQuestionStrip(width: number): string {
|
|
502
|
+
const theme = clioTheme();
|
|
503
|
+
const total = this.questions.length;
|
|
504
|
+
// A single-question interview round is the phased shape: one question per
|
|
505
|
+
// round, several rounds. Its position is the round number, since there is
|
|
506
|
+
// no set of siblings to draw a strip across.
|
|
507
|
+
if (total <= 1) {
|
|
508
|
+
const round = theme.fg("dim", `Round ${this.history.length + 1}`);
|
|
509
|
+
return fitLine(`${screenTitle(theme, "Interview")}${dotSep(theme)}${round}`, width);
|
|
510
|
+
}
|
|
511
|
+
const gap = " ";
|
|
512
|
+
const slotWidth = Math.max(10, Math.floor((width - visibleWidth(gap) * (total - 1)) / total));
|
|
513
|
+
const parts = this.questions.map((question, index) => {
|
|
514
|
+
const state = this.states[index];
|
|
515
|
+
const active = index === this.index;
|
|
516
|
+
const marker = active ? theme.fg("accent", `${GLYPH.cursor} `) : " ";
|
|
517
|
+
const answerState = state?.answer.trim() ? theme.fg("muted", "answered") : theme.fg("dim", "pending");
|
|
518
|
+
const title = active
|
|
519
|
+
? theme.style("accent", compactTitle(question), { bold: true })
|
|
520
|
+
: theme.fg("muted", compactTitle(question));
|
|
521
|
+
return fitLine(`${marker}${theme.fg("dim", `Q${index + 1}`)} ${answerState} ${title}`, slotWidth);
|
|
522
|
+
});
|
|
523
|
+
return fitLine(parts.join(gap), width);
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
private renderControlLines(width: number): string[] {
|
|
527
|
+
this.ensureControl();
|
|
528
|
+
const state = this.currentState();
|
|
529
|
+
if (state?.mode === "text") return this.renderTextInput(width);
|
|
530
|
+
return this.renderSelectControl(width);
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
/**
|
|
534
|
+
* Everything this interview has captured, rounds already answered first.
|
|
535
|
+
*
|
|
536
|
+
* The ledger used to read only the current round's states, so a phased
|
|
537
|
+
* interview asking one question per round showed nothing at all: each round
|
|
538
|
+
* was a set of one and the summary bailed out. What the operator has already
|
|
539
|
+
* told Clio is the reason the full surface exists.
|
|
540
|
+
*/
|
|
541
|
+
private renderAnswerLedger(width: number): string[] {
|
|
542
|
+
const theme = clioTheme();
|
|
543
|
+
const rows: string[] = [];
|
|
544
|
+
for (let index = 0; index < this.history.length; index += 1) {
|
|
545
|
+
const answer = this.history[index];
|
|
546
|
+
if (!answer) continue;
|
|
547
|
+
rows.push(fitLine(`${theme.fg("dim", `${index + 1}.`)} ${theme.fg("muted", answer.answer)}`, width));
|
|
548
|
+
}
|
|
549
|
+
// A round of one question needs no per-question roll: the strip already
|
|
550
|
+
// names the round and the question is on screen above this.
|
|
551
|
+
if (this.questions.length > 1) {
|
|
552
|
+
for (let index = 0; index < this.questions.length; index += 1) {
|
|
553
|
+
const answer = this.states[index]?.answer.trim();
|
|
554
|
+
const value = answer && answer.length > 0 ? theme.fg("muted", answer) : theme.fg("dim", "pending");
|
|
555
|
+
rows.push(fitLine(`${theme.fg("dim", `Q${index + 1}`)} ${value}`, width));
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
if (rows.length === 0) return [];
|
|
559
|
+
return ["", fitLine(theme.fg("dim", "── Answers"), width), ...rows];
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
private renderTextInput(width: number): string[] {
|
|
563
|
+
const theme = clioTheme();
|
|
564
|
+
return (this.input?.render(width) ?? [""]).map((line) =>
|
|
565
|
+
fitLine(line.startsWith("> ") ? `${theme.fg("accent", `${GLYPH.cursor} `)}${line.slice(2)}` : line, width),
|
|
566
|
+
);
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
private renderSelectControl(width: number): string[] {
|
|
570
|
+
const question = this.currentQuestion();
|
|
571
|
+
const state = this.currentState();
|
|
572
|
+
const selectedItem = this.list?.getSelectedItem();
|
|
573
|
+
if (!question || !state || !selectedItem) return [""];
|
|
574
|
+
const theme = clioTheme();
|
|
575
|
+
const items = optionItems(question, state.selected);
|
|
576
|
+
const selectedIndex = Math.max(
|
|
577
|
+
0,
|
|
578
|
+
items.findIndex((item) => item.value === selectedItem.value),
|
|
579
|
+
);
|
|
580
|
+
const visibleCount = Math.min(this.maxVisibleOptions(), Math.max(1, items.length));
|
|
581
|
+
const start = Math.max(0, Math.min(selectedIndex - Math.floor(visibleCount / 2), items.length - visibleCount));
|
|
582
|
+
const end = Math.min(items.length, start + visibleCount);
|
|
583
|
+
const primaryColumnWidth = this.primaryColumnWidth(items, width);
|
|
584
|
+
const lines: string[] = [];
|
|
585
|
+
|
|
586
|
+
const acceptKey = question.multi_select === true ? "Space" : "Enter";
|
|
587
|
+
for (let index = start; index < end; index += 1) {
|
|
588
|
+
const item = items[index];
|
|
589
|
+
if (!item) continue;
|
|
590
|
+
lines.push(this.renderOptionRow(item, index === selectedIndex, width, primaryColumnWidth, acceptKey));
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
if (start > 0 || end < items.length) {
|
|
594
|
+
lines.push(fitLine(theme.fg("dim", ` (${selectedIndex + 1}/${items.length})`), width));
|
|
595
|
+
}
|
|
596
|
+
return lines;
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
private primaryColumnWidth(items: ReadonlyArray<SelectItem>, width: number): number {
|
|
600
|
+
const widest = items.reduce((max, item) => Math.max(max, visibleWidth(item.label) + 2), 0);
|
|
601
|
+
const bounded = Math.max(24, Math.min(38, widest));
|
|
602
|
+
return Math.max(1, Math.min(bounded, Math.max(1, width - 4)));
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
private renderOptionRow(
|
|
606
|
+
item: SelectItem,
|
|
607
|
+
selected: boolean,
|
|
608
|
+
width: number,
|
|
609
|
+
primaryColumnWidth: number,
|
|
610
|
+
acceptKey: string,
|
|
611
|
+
): string {
|
|
612
|
+
const theme = clioTheme();
|
|
613
|
+
const prefix = selected ? theme.fg("accent", `${GLYPH.cursor} `) : " ";
|
|
614
|
+
// The key that answers rides on the focused row. An operator whose eyes are
|
|
615
|
+
// already on the option they want should not have to travel to the footer
|
|
616
|
+
// to learn what commits it.
|
|
617
|
+
const affordance = selected ? ` ${theme.style("accent", `[${acceptKey}]`, { bold: true })}` : "";
|
|
618
|
+
const available = Math.max(1, width - 2 - visibleWidth(affordance));
|
|
619
|
+
const description = item.description?.replace(/[\r\n]+/g, " ").trim();
|
|
620
|
+
|
|
621
|
+
let body: string;
|
|
622
|
+
if (description && width > 40) {
|
|
623
|
+
const labelWidth = Math.max(1, Math.min(primaryColumnWidth - 2, available - 4));
|
|
624
|
+
const label = truncateToWidth(item.label, labelWidth, ELLIPSIS, false);
|
|
625
|
+
const spacing = " ".repeat(Math.max(1, primaryColumnWidth - visibleWidth(label)));
|
|
626
|
+
const descriptionWidth = Math.max(1, available - visibleWidth(label) - visibleWidth(spacing));
|
|
627
|
+
const desc = truncateToWidth(description, descriptionWidth, ELLIPSIS, false);
|
|
628
|
+
body = selected
|
|
629
|
+
? theme.style("accent", `${label}${spacing}${desc}`, { bold: true })
|
|
630
|
+
: `${label}${theme.fg("muted", `${spacing}${desc}`)}`;
|
|
631
|
+
} else {
|
|
632
|
+
const label = truncateToWidth(item.label, available, ELLIPSIS, false);
|
|
633
|
+
body = selected ? theme.style("accent", label, { bold: true }) : label;
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
return fitLine(`${prefix}${body}${affordance}`, width);
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
private ensureControl(): void {
|
|
640
|
+
const question = this.currentQuestion();
|
|
641
|
+
const state = this.currentState();
|
|
642
|
+
if (!question || !state) return;
|
|
643
|
+
if (state.mode === "text" && !this.input) this.rebuildTextInput(question, state);
|
|
644
|
+
if (state.mode === "select" && !this.list) this.rebuildSelectList(question, state);
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
private rebuildControl(): void {
|
|
648
|
+
const question = this.currentQuestion();
|
|
649
|
+
const state = this.currentState();
|
|
650
|
+
if (!question || !state) {
|
|
651
|
+
this.input = null;
|
|
652
|
+
this.list = null;
|
|
653
|
+
return;
|
|
654
|
+
}
|
|
655
|
+
if (state.mode === "text") this.rebuildTextInput(question, state);
|
|
656
|
+
else this.rebuildSelectList(question, state);
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
private rebuildTextInput(question: AskUserQuestion, state: QuestionState): void {
|
|
660
|
+
const activeInput = new Input();
|
|
661
|
+
activeInput.setValue(state.inputValue || state.customAnswer || state.answer);
|
|
662
|
+
activeInput.onSubmit = (value) => {
|
|
663
|
+
const answer = value.trim();
|
|
664
|
+
if (answer.length === 0) {
|
|
665
|
+
this.status = "Enter an answer or press Esc to cancel.";
|
|
666
|
+
this.deps.requestRender();
|
|
667
|
+
return;
|
|
668
|
+
}
|
|
669
|
+
state.inputValue = answer;
|
|
670
|
+
if (questionHasOptions(question) && question.multi_select === true) {
|
|
671
|
+
state.customAnswer = answer;
|
|
672
|
+
this.commitCurrentAnswer();
|
|
673
|
+
} else {
|
|
674
|
+
state.customAnswer = questionHasOptions(question) ? answer : "";
|
|
675
|
+
state.answer = answer;
|
|
676
|
+
this.finishIfCompleteOrAdvance();
|
|
677
|
+
}
|
|
678
|
+
};
|
|
679
|
+
activeInput.onEscape = () => this.cancel();
|
|
680
|
+
this.input = activeInput;
|
|
681
|
+
this.list = null;
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
private rebuildSelectList(question: AskUserQuestion, state: QuestionState): void {
|
|
685
|
+
const items = optionItems(question, state.selected);
|
|
686
|
+
const activeList = new SelectList(
|
|
687
|
+
items,
|
|
688
|
+
Math.min(this.maxVisibleOptions(), Math.max(1, items.length)),
|
|
689
|
+
DEFAULT_SELECT_THEME,
|
|
690
|
+
{
|
|
691
|
+
minPrimaryColumnWidth: 24,
|
|
692
|
+
maxPrimaryColumnWidth: 38,
|
|
693
|
+
},
|
|
694
|
+
);
|
|
695
|
+
activeList.onSelect = (item) => {
|
|
696
|
+
if (item.value === "other") {
|
|
697
|
+
this.openTextInput("Other answer");
|
|
698
|
+
return;
|
|
699
|
+
}
|
|
700
|
+
const optionIndex = optionIndexFromValue(item.value);
|
|
701
|
+
if (optionIndex === null) return;
|
|
702
|
+
if (question.multi_select === true) {
|
|
703
|
+
this.toggleSelectionIndex(question, state, optionIndex);
|
|
704
|
+
return;
|
|
705
|
+
}
|
|
706
|
+
state.selected = new Set<number>([optionIndex]);
|
|
707
|
+
state.answer = question.options?.[optionIndex]?.label ?? item.label;
|
|
708
|
+
state.focusedValue = item.value;
|
|
709
|
+
this.status = "";
|
|
710
|
+
this.finishIfCompleteOrAdvance();
|
|
711
|
+
};
|
|
712
|
+
activeList.onCancel = () => this.cancel();
|
|
713
|
+
activeList.onSelectionChange = (item) => {
|
|
714
|
+
state.focusedValue = item.value;
|
|
715
|
+
};
|
|
716
|
+
const selectedIndex = this.preferredSelectedIndex(question, state, items);
|
|
717
|
+
if (selectedIndex >= 0) activeList.setSelectedIndex(selectedIndex);
|
|
718
|
+
this.input = null;
|
|
719
|
+
this.list = activeList;
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
private preferredSelectedIndex(
|
|
723
|
+
question: AskUserQuestion,
|
|
724
|
+
state: QuestionState,
|
|
725
|
+
items: ReadonlyArray<SelectItem>,
|
|
726
|
+
): number {
|
|
727
|
+
if (state.focusedValue) {
|
|
728
|
+
const focused = items.findIndex((item) => item.value === state.focusedValue);
|
|
729
|
+
if (focused >= 0) return focused;
|
|
730
|
+
}
|
|
731
|
+
const firstSelected = [...state.selected][0];
|
|
732
|
+
if (firstSelected !== undefined) {
|
|
733
|
+
const selected = items.findIndex((item) => item.value === `option:${firstSelected}`);
|
|
734
|
+
if (selected >= 0) return selected;
|
|
735
|
+
}
|
|
736
|
+
if (state.customAnswer.length > 0 || (questionHasOptions(question) && isOtherOption(state.answer))) {
|
|
737
|
+
const other = items.findIndex((item) => item.value === "other");
|
|
738
|
+
if (other >= 0) return other;
|
|
739
|
+
}
|
|
740
|
+
return 0;
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
private openTextInput(nextStatus: string): void {
|
|
744
|
+
const state = this.currentState();
|
|
745
|
+
const question = this.currentQuestion();
|
|
746
|
+
if (!state || !question) return;
|
|
747
|
+
this.syncActiveControl();
|
|
748
|
+
state.mode = "text";
|
|
749
|
+
this.status = nextStatus;
|
|
750
|
+
this.rebuildTextInput(question, state);
|
|
751
|
+
this.deps.requestRender();
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
private toggleCurrentSelection(question: AskUserQuestion, state: QuestionState): void {
|
|
755
|
+
const current = this.list?.getSelectedItem();
|
|
756
|
+
if (!current) return;
|
|
757
|
+
if (current.value === "other") {
|
|
758
|
+
this.openTextInput("Other answer");
|
|
759
|
+
return;
|
|
760
|
+
}
|
|
761
|
+
const optionIndex = optionIndexFromValue(current.value);
|
|
762
|
+
if (optionIndex === null) return;
|
|
763
|
+
this.toggleSelectionIndex(question, state, optionIndex);
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
private toggleSelectionIndex(question: AskUserQuestion, state: QuestionState, optionIndex: number): void {
|
|
767
|
+
if (state.selected.has(optionIndex)) state.selected.delete(optionIndex);
|
|
768
|
+
else state.selected.add(optionIndex);
|
|
769
|
+
state.focusedValue = `option:${optionIndex}`;
|
|
770
|
+
this.status = "";
|
|
771
|
+
this.rebuildSelectList(question, state);
|
|
772
|
+
this.deps.requestRender();
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
private commitMultiSelectOrOpenOther(state: QuestionState): void {
|
|
776
|
+
const current = this.list?.getSelectedItem();
|
|
777
|
+
if (current?.value === "other") {
|
|
778
|
+
this.openTextInput("Other answer");
|
|
779
|
+
return;
|
|
780
|
+
}
|
|
781
|
+
const optionIndex = current ? optionIndexFromValue(current.value) : null;
|
|
782
|
+
if (state.selected.size === 0 && optionIndex !== null) state.selected.add(optionIndex);
|
|
783
|
+
this.commitCurrentAnswer();
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
private commitCurrentAnswer(): void {
|
|
787
|
+
const question = this.currentQuestion();
|
|
788
|
+
const state = this.currentState();
|
|
789
|
+
if (!question || !state) return;
|
|
790
|
+
if (questionHasOptions(question) && question.multi_select === true) {
|
|
791
|
+
const answer = answerText(question, state.selected, state.customAnswer);
|
|
792
|
+
if (answer.length === 0) {
|
|
793
|
+
this.status = "Select at least one answer or choose Other.";
|
|
794
|
+
this.deps.requestRender();
|
|
795
|
+
return;
|
|
796
|
+
}
|
|
797
|
+
state.answer = answer;
|
|
798
|
+
}
|
|
799
|
+
this.status = "";
|
|
800
|
+
this.finishIfCompleteOrAdvance();
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
private finishIfCompleteOrAdvance(): void {
|
|
804
|
+
this.syncActiveControl();
|
|
805
|
+
if (this.allAnswered()) {
|
|
806
|
+
this.finish({ answers: this.answers() });
|
|
807
|
+
return;
|
|
808
|
+
}
|
|
809
|
+
const next = this.nextUnansweredIndex();
|
|
810
|
+
if (next !== null) {
|
|
811
|
+
this.index = next;
|
|
812
|
+
const nextState = this.currentState();
|
|
813
|
+
const nextQuestion = this.currentQuestion();
|
|
814
|
+
if (nextState && nextQuestion && !nextState.answer.trim()) nextState.mode = initialMode(nextQuestion);
|
|
815
|
+
this.rebuildControl();
|
|
816
|
+
}
|
|
817
|
+
this.deps.requestRender();
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
private nextUnansweredIndex(): number | null {
|
|
821
|
+
for (let offset = 1; offset <= this.states.length; offset += 1) {
|
|
822
|
+
const candidate = (this.index + offset) % this.states.length;
|
|
823
|
+
if (!this.states[candidate]?.answer.trim()) return candidate;
|
|
824
|
+
}
|
|
825
|
+
return null;
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
private allAnswered(): boolean {
|
|
829
|
+
return this.states.length > 0 && this.states.every((state) => state.answer.trim().length > 0);
|
|
830
|
+
}
|
|
831
|
+
|
|
832
|
+
private answers(): AskUserResult["answers"] {
|
|
833
|
+
const answers: AskUserResult["answers"] = [];
|
|
834
|
+
for (let index = 0; index < this.questions.length; index += 1) {
|
|
835
|
+
const question = this.questions[index];
|
|
836
|
+
const answer = this.states[index]?.answer.trim();
|
|
837
|
+
if (question && answer && answer.length > 0) answers.push({ question: question.question, answer });
|
|
838
|
+
}
|
|
839
|
+
return answers;
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
private goToRelativeQuestion(delta: -1 | 1): void {
|
|
843
|
+
if (this.questions.length <= 1) return;
|
|
844
|
+
this.syncActiveControl();
|
|
845
|
+
this.index = (this.index + delta + this.questions.length) % this.questions.length;
|
|
846
|
+
this.status = "";
|
|
847
|
+
this.rebuildControl();
|
|
848
|
+
this.deps.requestRender();
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
private syncActiveControl(): void {
|
|
852
|
+
const state = this.currentState();
|
|
853
|
+
if (!state) return;
|
|
854
|
+
if (this.list) {
|
|
855
|
+
const current = this.list.getSelectedItem();
|
|
856
|
+
if (current) state.focusedValue = current.value;
|
|
857
|
+
}
|
|
858
|
+
if (this.input) state.inputValue = this.input.getValue();
|
|
859
|
+
}
|
|
860
|
+
}
|
|
861
|
+
|
|
862
|
+
/**
|
|
863
|
+
* Show the ask_user overlay, on whichever surface the request calls for.
|
|
864
|
+
*
|
|
865
|
+
* A box's anchor, width, and height budget are fixed when the engine mounts it,
|
|
866
|
+
* so moving between surfaces means mounting a new frame around the same body and
|
|
867
|
+
* dropping the old one. That happens at most once per round, when the shape of
|
|
868
|
+
* the request actually changes; the new frame is shown before the old one is
|
|
869
|
+
* hidden so the keyboard passes straight across instead of returning to the
|
|
870
|
+
* composer for a frame.
|
|
871
|
+
*/
|
|
872
|
+
export function openAskUserOverlay(tui: TUI, deps: OpenAskUserOverlayDeps): AskUserOverlaySession {
|
|
873
|
+
let handle: OverlayHandle | null = null;
|
|
874
|
+
let mounted: AskUserSurface | null = null;
|
|
875
|
+
let closed = false;
|
|
876
|
+
|
|
877
|
+
const view = new AskUserOverlayView({
|
|
878
|
+
...deps,
|
|
879
|
+
getTerminalRows: () => tui.terminal?.rows ?? 0,
|
|
880
|
+
requestRender: () => tui.requestRender(),
|
|
881
|
+
onSurface: (surface) => mount(surface),
|
|
882
|
+
});
|
|
883
|
+
|
|
884
|
+
const mount = (surface: AskUserSurface): void => {
|
|
885
|
+
if (closed || mounted === surface) return;
|
|
886
|
+
const geometry = ASK_USER_SURFACE_GEOMETRY[surface];
|
|
887
|
+
const previous = handle;
|
|
888
|
+
handle = showClioOverlayFrame(tui, view, {
|
|
889
|
+
anchor: geometry.anchor,
|
|
890
|
+
width: geometry.width,
|
|
891
|
+
maxHeight: geometry.maxInnerRows + ASK_USER_FRAME_ROWS,
|
|
892
|
+
margin: geometry.margin,
|
|
893
|
+
title: () => (view.isDecisionPending() ? ASK_USER_DECISION_TITLE : ASK_USER_WAITING_TITLE),
|
|
894
|
+
tone: () => (view.isDecisionPending() ? ASK_USER_DECISION_TONE : undefined),
|
|
895
|
+
footerHint: () => view.footerHint(),
|
|
896
|
+
});
|
|
897
|
+
mounted = surface;
|
|
898
|
+
previous?.hide();
|
|
899
|
+
};
|
|
900
|
+
|
|
901
|
+
mount(view.currentSurface());
|
|
902
|
+
|
|
903
|
+
const close = (): void => {
|
|
904
|
+
closed = true;
|
|
905
|
+
view.close();
|
|
906
|
+
handle?.hide();
|
|
907
|
+
handle = null;
|
|
908
|
+
};
|
|
909
|
+
return {
|
|
910
|
+
setHidden: (hidden) => handle?.setHidden(hidden),
|
|
911
|
+
isHidden: () => handle?.isHidden() ?? true,
|
|
912
|
+
focus: () => handle?.focus(),
|
|
913
|
+
unfocus: (options) => (options ? handle?.unfocus(options) : handle?.unfocus()),
|
|
914
|
+
isFocused: () => handle?.isFocused() ?? false,
|
|
915
|
+
ask: (questions) => view.begin(questions),
|
|
916
|
+
cancel: () => view.cancel(),
|
|
917
|
+
close,
|
|
918
|
+
hide: close,
|
|
919
|
+
isWaiting: () => view.isWaiting(),
|
|
920
|
+
};
|
|
921
|
+
}
|