@garygentry/feature-forge 0.2.14 → 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/README.md +6 -3
- package/adapters/GENERATION-REPORT.md +20 -0
- package/adapters/claude/.feature-forge-bundle.json +1 -1
- package/adapters/claude/agents/forge-verifier.md +1 -1
- package/adapters/claude/references/forge-config-schema.json +2 -2
- package/adapters/claude/references/pipeline-state-schema.json +1 -1
- package/adapters/claude/references/shared-conventions.md +62 -12
- package/adapters/claude/references/stage-exit-protocol.md +14 -4
- package/adapters/claude/references/vendor-construct-inventory.md +1 -1
- package/adapters/claude/scripts/epic-manifest.py +49 -6
- package/adapters/claude/scripts/forge-root.sh +47 -3
- package/adapters/claude/scripts/forge-session.py +1179 -9
- package/adapters/claude/scripts/validate-traceability.py +6 -1
- package/adapters/claude/skills/forge/SKILL.md +11 -5
- package/adapters/claude/skills/forge/references/pipeline-state-schema.json +1 -1
- package/adapters/claude/skills/forge/references/shared-conventions.md +62 -12
- package/adapters/claude/skills/forge/references/stage-exit-protocol.md +14 -4
- package/adapters/claude/skills/forge-0-epic/SKILL.md +1 -1
- package/adapters/claude/skills/forge-0-epic/references/pipeline-state-schema.json +1 -1
- package/adapters/claude/skills/forge-0-epic/references/shared-conventions.md +62 -12
- package/adapters/claude/skills/forge-0-epic/references/stage-exit-protocol.md +14 -4
- package/adapters/claude/skills/forge-1-prd/SKILL.md +25 -8
- package/adapters/claude/skills/forge-1-prd/references/shared-conventions.md +62 -12
- package/adapters/claude/skills/forge-1-prd/references/stage-exit-protocol.md +14 -4
- package/adapters/claude/skills/forge-2-tech/SKILL.md +25 -7
- package/adapters/claude/skills/forge-2-tech/references/shared-conventions.md +62 -12
- package/adapters/claude/skills/forge-2-tech/references/stage-exit-protocol.md +14 -4
- package/adapters/claude/skills/forge-3-specs/SKILL.md +24 -7
- package/adapters/claude/skills/forge-3-specs/references/shared-conventions.md +62 -12
- package/adapters/claude/skills/forge-3-specs/references/stage-exit-protocol.md +14 -4
- package/adapters/claude/skills/forge-4-backlog/SKILL.md +23 -7
- package/adapters/claude/skills/forge-4-backlog/references/shared-conventions.md +62 -12
- package/adapters/claude/skills/forge-4-backlog/references/stage-exit-protocol.md +14 -4
- package/adapters/claude/skills/forge-5-loop/SKILL.md +25 -25
- package/adapters/claude/skills/forge-5-loop/references/agent-selection.md +116 -0
- package/adapters/claude/skills/forge-5-loop/references/runner-contract.md +14 -107
- package/adapters/claude/skills/forge-5-loop/references/shared-conventions.md +62 -12
- package/adapters/claude/skills/forge-5-loop/references/stage-exit-protocol.md +14 -4
- package/adapters/claude/skills/forge-6-docs/SKILL.md +11 -5
- package/adapters/claude/skills/forge-6-docs/references/shared-conventions.md +62 -12
- package/adapters/claude/skills/forge-fix/references/shared-conventions.md +62 -12
- package/adapters/claude/skills/forge-fix/references/stage-exit-protocol.md +14 -4
- package/adapters/claude/skills/forge-guide/references/forge-config-schema.json +2 -2
- package/adapters/claude/skills/forge-guide/references/shared-conventions.md +62 -12
- package/adapters/claude/skills/forge-verify/SKILL.md +22 -12
- package/adapters/claude/skills/forge-verify/references/findings-template.md +157 -0
- package/adapters/claude/skills/forge-verify/references/pipeline-state-schema.json +1 -1
- package/adapters/claude/skills/forge-verify/references/shared-conventions.md +62 -12
- package/adapters/claude/skills/forge-verify/references/verification-checklists/backlog.md +97 -0
- package/adapters/claude/skills/forge-verify/references/verification-checklists/epic.md +79 -0
- package/adapters/claude/skills/forge-verify/references/verification-checklists/impl.md +48 -0
- package/adapters/claude/skills/forge-verify/references/verification-checklists/prd.md +31 -0
- package/adapters/claude/skills/forge-verify/references/verification-checklists/specs.md +64 -0
- package/adapters/claude/skills/forge-verify/references/verification-checklists/tech.md +35 -0
- package/adapters/codex/.feature-forge-bundle.json +1 -1
- package/adapters/codex/agents/forge-verifier.toml +1 -1
- package/adapters/codex/references/forge-config-schema.json +2 -2
- package/adapters/codex/references/pipeline-state-schema.json +1 -1
- package/adapters/codex/references/shared-conventions.md +62 -12
- package/adapters/codex/references/stage-exit-protocol.md +14 -4
- package/adapters/codex/references/vendor-construct-inventory.md +1 -1
- package/adapters/codex/scripts/epic-manifest.py +49 -6
- package/adapters/codex/scripts/forge-root.sh +47 -3
- package/adapters/codex/scripts/forge-session.py +1179 -9
- package/adapters/codex/scripts/validate-traceability.py +6 -1
- package/adapters/codex/skills/forge/SKILL.md +11 -5
- package/adapters/codex/skills/forge/references/pipeline-state-schema.json +1 -1
- package/adapters/codex/skills/forge/references/shared-conventions.md +62 -12
- package/adapters/codex/skills/forge/references/stage-exit-protocol.md +14 -4
- package/adapters/codex/skills/forge-0-epic/SKILL.md +1 -1
- package/adapters/codex/skills/forge-0-epic/references/pipeline-state-schema.json +1 -1
- package/adapters/codex/skills/forge-0-epic/references/shared-conventions.md +62 -12
- package/adapters/codex/skills/forge-0-epic/references/stage-exit-protocol.md +14 -4
- package/adapters/codex/skills/forge-1-prd/SKILL.md +25 -8
- package/adapters/codex/skills/forge-1-prd/references/shared-conventions.md +62 -12
- package/adapters/codex/skills/forge-1-prd/references/stage-exit-protocol.md +14 -4
- package/adapters/codex/skills/forge-2-tech/SKILL.md +25 -7
- package/adapters/codex/skills/forge-2-tech/references/shared-conventions.md +62 -12
- package/adapters/codex/skills/forge-2-tech/references/stage-exit-protocol.md +14 -4
- package/adapters/codex/skills/forge-3-specs/SKILL.md +24 -7
- package/adapters/codex/skills/forge-3-specs/references/shared-conventions.md +62 -12
- package/adapters/codex/skills/forge-3-specs/references/stage-exit-protocol.md +14 -4
- package/adapters/codex/skills/forge-4-backlog/SKILL.md +23 -7
- package/adapters/codex/skills/forge-4-backlog/references/shared-conventions.md +62 -12
- package/adapters/codex/skills/forge-4-backlog/references/stage-exit-protocol.md +14 -4
- package/adapters/codex/skills/forge-5-loop/SKILL.md +25 -25
- package/adapters/codex/skills/forge-5-loop/references/agent-selection.md +116 -0
- package/adapters/codex/skills/forge-5-loop/references/runner-contract.md +14 -107
- package/adapters/codex/skills/forge-5-loop/references/shared-conventions.md +62 -12
- package/adapters/codex/skills/forge-5-loop/references/stage-exit-protocol.md +14 -4
- package/adapters/codex/skills/forge-6-docs/SKILL.md +11 -5
- package/adapters/codex/skills/forge-6-docs/references/shared-conventions.md +62 -12
- package/adapters/codex/skills/forge-fix/references/shared-conventions.md +62 -12
- package/adapters/codex/skills/forge-fix/references/stage-exit-protocol.md +14 -4
- package/adapters/codex/skills/forge-guide/references/forge-config-schema.json +2 -2
- package/adapters/codex/skills/forge-guide/references/shared-conventions.md +62 -12
- package/adapters/codex/skills/forge-verify/SKILL.md +22 -12
- package/adapters/codex/skills/forge-verify/references/findings-template.md +157 -0
- package/adapters/codex/skills/forge-verify/references/pipeline-state-schema.json +1 -1
- package/adapters/codex/skills/forge-verify/references/shared-conventions.md +62 -12
- package/adapters/codex/skills/forge-verify/references/verification-checklists/backlog.md +97 -0
- package/adapters/codex/skills/forge-verify/references/verification-checklists/epic.md +79 -0
- package/adapters/codex/skills/forge-verify/references/verification-checklists/impl.md +48 -0
- package/adapters/codex/skills/forge-verify/references/verification-checklists/prd.md +31 -0
- package/adapters/codex/skills/forge-verify/references/verification-checklists/specs.md +64 -0
- package/adapters/codex/skills/forge-verify/references/verification-checklists/tech.md +35 -0
- package/adapters/copilot/.feature-forge-bundle.json +1 -1
- package/adapters/copilot/agents/forge-verifier.md +1 -1
- package/adapters/copilot/references/forge-config-schema.json +2 -2
- package/adapters/copilot/references/pipeline-state-schema.json +1 -1
- package/adapters/copilot/references/shared-conventions.md +62 -12
- package/adapters/copilot/references/stage-exit-protocol.md +14 -4
- package/adapters/copilot/references/vendor-construct-inventory.md +1 -1
- package/adapters/copilot/scripts/epic-manifest.py +49 -6
- package/adapters/copilot/scripts/forge-root.sh +47 -3
- package/adapters/copilot/scripts/forge-session.py +1179 -9
- package/adapters/copilot/scripts/validate-traceability.py +6 -1
- package/adapters/copilot/skills/forge/forge.md +11 -5
- package/adapters/copilot/skills/forge/references/pipeline-state-schema.json +1 -1
- package/adapters/copilot/skills/forge/references/shared-conventions.md +62 -12
- package/adapters/copilot/skills/forge/references/stage-exit-protocol.md +14 -4
- package/adapters/copilot/skills/forge-0-epic/forge-0-epic.md +1 -1
- package/adapters/copilot/skills/forge-0-epic/references/pipeline-state-schema.json +1 -1
- package/adapters/copilot/skills/forge-0-epic/references/shared-conventions.md +62 -12
- package/adapters/copilot/skills/forge-0-epic/references/stage-exit-protocol.md +14 -4
- package/adapters/copilot/skills/forge-1-prd/forge-1-prd.md +25 -8
- package/adapters/copilot/skills/forge-1-prd/references/shared-conventions.md +62 -12
- package/adapters/copilot/skills/forge-1-prd/references/stage-exit-protocol.md +14 -4
- package/adapters/copilot/skills/forge-2-tech/forge-2-tech.md +25 -7
- package/adapters/copilot/skills/forge-2-tech/references/shared-conventions.md +62 -12
- package/adapters/copilot/skills/forge-2-tech/references/stage-exit-protocol.md +14 -4
- package/adapters/copilot/skills/forge-3-specs/forge-3-specs.md +24 -7
- package/adapters/copilot/skills/forge-3-specs/references/shared-conventions.md +62 -12
- package/adapters/copilot/skills/forge-3-specs/references/stage-exit-protocol.md +14 -4
- package/adapters/copilot/skills/forge-4-backlog/forge-4-backlog.md +23 -7
- package/adapters/copilot/skills/forge-4-backlog/references/shared-conventions.md +62 -12
- package/adapters/copilot/skills/forge-4-backlog/references/stage-exit-protocol.md +14 -4
- package/adapters/copilot/skills/forge-5-loop/forge-5-loop.md +25 -25
- package/adapters/copilot/skills/forge-5-loop/references/agent-selection.md +116 -0
- package/adapters/copilot/skills/forge-5-loop/references/runner-contract.md +14 -107
- package/adapters/copilot/skills/forge-5-loop/references/shared-conventions.md +62 -12
- package/adapters/copilot/skills/forge-5-loop/references/stage-exit-protocol.md +14 -4
- package/adapters/copilot/skills/forge-6-docs/forge-6-docs.md +11 -5
- package/adapters/copilot/skills/forge-6-docs/references/shared-conventions.md +62 -12
- package/adapters/copilot/skills/forge-fix/references/shared-conventions.md +62 -12
- package/adapters/copilot/skills/forge-fix/references/stage-exit-protocol.md +14 -4
- package/adapters/copilot/skills/forge-guide/references/forge-config-schema.json +2 -2
- package/adapters/copilot/skills/forge-guide/references/shared-conventions.md +62 -12
- package/adapters/copilot/skills/forge-verify/forge-verify.md +22 -12
- package/adapters/copilot/skills/forge-verify/references/findings-template.md +157 -0
- package/adapters/copilot/skills/forge-verify/references/pipeline-state-schema.json +1 -1
- package/adapters/copilot/skills/forge-verify/references/shared-conventions.md +62 -12
- package/adapters/copilot/skills/forge-verify/references/verification-checklists/backlog.md +97 -0
- package/adapters/copilot/skills/forge-verify/references/verification-checklists/epic.md +79 -0
- package/adapters/copilot/skills/forge-verify/references/verification-checklists/impl.md +48 -0
- package/adapters/copilot/skills/forge-verify/references/verification-checklists/prd.md +31 -0
- package/adapters/copilot/skills/forge-verify/references/verification-checklists/specs.md +64 -0
- package/adapters/copilot/skills/forge-verify/references/verification-checklists/tech.md +35 -0
- package/adapters/cursor/.feature-forge-bundle.json +1 -1
- package/adapters/cursor/agents/forge-verifier.mdc +1 -1
- package/adapters/cursor/references/forge-config-schema.json +2 -2
- package/adapters/cursor/references/pipeline-state-schema.json +1 -1
- package/adapters/cursor/references/shared-conventions.md +62 -12
- package/adapters/cursor/references/stage-exit-protocol.md +14 -4
- package/adapters/cursor/references/vendor-construct-inventory.md +1 -1
- package/adapters/cursor/scripts/epic-manifest.py +49 -6
- package/adapters/cursor/scripts/forge-root.sh +47 -3
- package/adapters/cursor/scripts/forge-session.py +1179 -9
- package/adapters/cursor/scripts/validate-traceability.py +6 -1
- package/adapters/cursor/skills/forge/forge.mdc +11 -5
- package/adapters/cursor/skills/forge/references/pipeline-state-schema.json +1 -1
- package/adapters/cursor/skills/forge/references/shared-conventions.md +62 -12
- package/adapters/cursor/skills/forge/references/stage-exit-protocol.md +14 -4
- package/adapters/cursor/skills/forge-0-epic/forge-0-epic.mdc +1 -1
- package/adapters/cursor/skills/forge-0-epic/references/pipeline-state-schema.json +1 -1
- package/adapters/cursor/skills/forge-0-epic/references/shared-conventions.md +62 -12
- package/adapters/cursor/skills/forge-0-epic/references/stage-exit-protocol.md +14 -4
- package/adapters/cursor/skills/forge-1-prd/forge-1-prd.mdc +25 -8
- package/adapters/cursor/skills/forge-1-prd/references/shared-conventions.md +62 -12
- package/adapters/cursor/skills/forge-1-prd/references/stage-exit-protocol.md +14 -4
- package/adapters/cursor/skills/forge-2-tech/forge-2-tech.mdc +25 -7
- package/adapters/cursor/skills/forge-2-tech/references/shared-conventions.md +62 -12
- package/adapters/cursor/skills/forge-2-tech/references/stage-exit-protocol.md +14 -4
- package/adapters/cursor/skills/forge-3-specs/forge-3-specs.mdc +24 -7
- package/adapters/cursor/skills/forge-3-specs/references/shared-conventions.md +62 -12
- package/adapters/cursor/skills/forge-3-specs/references/stage-exit-protocol.md +14 -4
- package/adapters/cursor/skills/forge-4-backlog/forge-4-backlog.mdc +23 -7
- package/adapters/cursor/skills/forge-4-backlog/references/shared-conventions.md +62 -12
- package/adapters/cursor/skills/forge-4-backlog/references/stage-exit-protocol.md +14 -4
- package/adapters/cursor/skills/forge-5-loop/forge-5-loop.mdc +25 -25
- package/adapters/cursor/skills/forge-5-loop/references/agent-selection.md +116 -0
- package/adapters/cursor/skills/forge-5-loop/references/runner-contract.md +14 -107
- package/adapters/cursor/skills/forge-5-loop/references/shared-conventions.md +62 -12
- package/adapters/cursor/skills/forge-5-loop/references/stage-exit-protocol.md +14 -4
- package/adapters/cursor/skills/forge-6-docs/forge-6-docs.mdc +11 -5
- package/adapters/cursor/skills/forge-6-docs/references/shared-conventions.md +62 -12
- package/adapters/cursor/skills/forge-fix/references/shared-conventions.md +62 -12
- package/adapters/cursor/skills/forge-fix/references/stage-exit-protocol.md +14 -4
- package/adapters/cursor/skills/forge-guide/references/forge-config-schema.json +2 -2
- package/adapters/cursor/skills/forge-guide/references/shared-conventions.md +62 -12
- package/adapters/cursor/skills/forge-verify/forge-verify.mdc +22 -12
- package/adapters/cursor/skills/forge-verify/references/findings-template.md +157 -0
- package/adapters/cursor/skills/forge-verify/references/pipeline-state-schema.json +1 -1
- package/adapters/cursor/skills/forge-verify/references/shared-conventions.md +62 -12
- package/adapters/cursor/skills/forge-verify/references/verification-checklists/backlog.md +97 -0
- package/adapters/cursor/skills/forge-verify/references/verification-checklists/epic.md +79 -0
- package/adapters/cursor/skills/forge-verify/references/verification-checklists/impl.md +48 -0
- package/adapters/cursor/skills/forge-verify/references/verification-checklists/prd.md +31 -0
- package/adapters/cursor/skills/forge-verify/references/verification-checklists/specs.md +64 -0
- package/adapters/cursor/skills/forge-verify/references/verification-checklists/tech.md +35 -0
- package/adapters/gemini/.feature-forge-bundle.json +1 -1
- package/adapters/gemini/agents/forge-verifier.md +1 -1
- package/adapters/gemini/gemini-extension.json +1 -1
- package/adapters/gemini/references/forge-config-schema.json +2 -2
- package/adapters/gemini/references/pipeline-state-schema.json +1 -1
- package/adapters/gemini/references/shared-conventions.md +62 -12
- package/adapters/gemini/references/stage-exit-protocol.md +14 -4
- package/adapters/gemini/references/vendor-construct-inventory.md +1 -1
- package/adapters/gemini/scripts/epic-manifest.py +49 -6
- package/adapters/gemini/scripts/forge-root.sh +47 -3
- package/adapters/gemini/scripts/forge-session.py +1179 -9
- package/adapters/gemini/scripts/validate-traceability.py +6 -1
- package/adapters/gemini/skills/forge/forge.md +11 -5
- package/adapters/gemini/skills/forge/references/pipeline-state-schema.json +1 -1
- package/adapters/gemini/skills/forge/references/shared-conventions.md +62 -12
- package/adapters/gemini/skills/forge/references/stage-exit-protocol.md +14 -4
- package/adapters/gemini/skills/forge-0-epic/forge-0-epic.md +1 -1
- package/adapters/gemini/skills/forge-0-epic/references/pipeline-state-schema.json +1 -1
- package/adapters/gemini/skills/forge-0-epic/references/shared-conventions.md +62 -12
- package/adapters/gemini/skills/forge-0-epic/references/stage-exit-protocol.md +14 -4
- package/adapters/gemini/skills/forge-1-prd/forge-1-prd.md +25 -8
- package/adapters/gemini/skills/forge-1-prd/references/shared-conventions.md +62 -12
- package/adapters/gemini/skills/forge-1-prd/references/stage-exit-protocol.md +14 -4
- package/adapters/gemini/skills/forge-2-tech/forge-2-tech.md +25 -7
- package/adapters/gemini/skills/forge-2-tech/references/shared-conventions.md +62 -12
- package/adapters/gemini/skills/forge-2-tech/references/stage-exit-protocol.md +14 -4
- package/adapters/gemini/skills/forge-3-specs/forge-3-specs.md +24 -7
- package/adapters/gemini/skills/forge-3-specs/references/shared-conventions.md +62 -12
- package/adapters/gemini/skills/forge-3-specs/references/stage-exit-protocol.md +14 -4
- package/adapters/gemini/skills/forge-4-backlog/forge-4-backlog.md +23 -7
- package/adapters/gemini/skills/forge-4-backlog/references/shared-conventions.md +62 -12
- package/adapters/gemini/skills/forge-4-backlog/references/stage-exit-protocol.md +14 -4
- package/adapters/gemini/skills/forge-5-loop/forge-5-loop.md +25 -25
- package/adapters/gemini/skills/forge-5-loop/references/agent-selection.md +116 -0
- package/adapters/gemini/skills/forge-5-loop/references/runner-contract.md +14 -107
- package/adapters/gemini/skills/forge-5-loop/references/shared-conventions.md +62 -12
- package/adapters/gemini/skills/forge-5-loop/references/stage-exit-protocol.md +14 -4
- package/adapters/gemini/skills/forge-6-docs/forge-6-docs.md +11 -5
- package/adapters/gemini/skills/forge-6-docs/references/shared-conventions.md +62 -12
- package/adapters/gemini/skills/forge-fix/references/shared-conventions.md +62 -12
- package/adapters/gemini/skills/forge-fix/references/stage-exit-protocol.md +14 -4
- package/adapters/gemini/skills/forge-guide/references/forge-config-schema.json +2 -2
- package/adapters/gemini/skills/forge-guide/references/shared-conventions.md +62 -12
- package/adapters/gemini/skills/forge-verify/forge-verify.md +22 -12
- package/adapters/gemini/skills/forge-verify/references/findings-template.md +157 -0
- package/adapters/gemini/skills/forge-verify/references/pipeline-state-schema.json +1 -1
- package/adapters/gemini/skills/forge-verify/references/shared-conventions.md +62 -12
- package/adapters/gemini/skills/forge-verify/references/verification-checklists/backlog.md +97 -0
- package/adapters/gemini/skills/forge-verify/references/verification-checklists/epic.md +79 -0
- package/adapters/gemini/skills/forge-verify/references/verification-checklists/impl.md +48 -0
- package/adapters/gemini/skills/forge-verify/references/verification-checklists/prd.md +31 -0
- package/adapters/gemini/skills/forge-verify/references/verification-checklists/specs.md +64 -0
- package/adapters/gemini/skills/forge-verify/references/verification-checklists/tech.md +35 -0
- package/adapters/pi/.feature-forge-bundle.json +6 -0
- package/adapters/pi/agents/forge-researcher.md +139 -0
- package/adapters/pi/agents/forge-spec-writer.md +116 -0
- package/adapters/pi/agents/forge-verifier.md +126 -0
- package/adapters/pi/extensions/ask-user-question/LICENSE +21 -0
- package/adapters/pi/extensions/ask-user-question/README.md +91 -0
- package/adapters/pi/extensions/ask-user-question/ask-user-question.ts +298 -0
- package/adapters/pi/extensions/ask-user-question/config.ts +78 -0
- package/adapters/pi/extensions/ask-user-question/events.ts +57 -0
- package/adapters/pi/extensions/ask-user-question/index.ts +61 -0
- package/adapters/pi/extensions/ask-user-question/locales/de.json +27 -0
- package/adapters/pi/extensions/ask-user-question/locales/en.json +27 -0
- package/adapters/pi/extensions/ask-user-question/locales/es.json +27 -0
- package/adapters/pi/extensions/ask-user-question/locales/fr.json +27 -0
- package/adapters/pi/extensions/ask-user-question/locales/pt-BR.json +27 -0
- package/adapters/pi/extensions/ask-user-question/locales/pt.json +27 -0
- package/adapters/pi/extensions/ask-user-question/locales/ru.json +27 -0
- package/adapters/pi/extensions/ask-user-question/locales/uk.json +27 -0
- package/adapters/pi/extensions/ask-user-question/locales/zh.json +29 -0
- package/adapters/pi/extensions/ask-user-question/reconcile.ts +49 -0
- package/adapters/pi/extensions/ask-user-question/rpc-fallback.ts +168 -0
- package/adapters/pi/extensions/ask-user-question/state/build-questionnaire.ts +302 -0
- package/adapters/pi/extensions/ask-user-question/state/i18n-bridge.ts +53 -0
- package/adapters/pi/extensions/ask-user-question/state/key-router.ts +277 -0
- package/adapters/pi/extensions/ask-user-question/state/questionnaire-session.ts +234 -0
- package/adapters/pi/extensions/ask-user-question/state/row-intent.ts +145 -0
- package/adapters/pi/extensions/ask-user-question/state/selectors/contract.ts +26 -0
- package/adapters/pi/extensions/ask-user-question/state/selectors/derivations.ts +42 -0
- package/adapters/pi/extensions/ask-user-question/state/selectors/focus.ts +19 -0
- package/adapters/pi/extensions/ask-user-question/state/selectors/projections.ts +101 -0
- package/adapters/pi/extensions/ask-user-question/state/state-reducer.ts +292 -0
- package/adapters/pi/extensions/ask-user-question/state/state.ts +55 -0
- package/adapters/pi/extensions/ask-user-question/tool/format-answer.ts +31 -0
- package/adapters/pi/extensions/ask-user-question/tool/response-envelope.ts +49 -0
- package/adapters/pi/extensions/ask-user-question/tool/types.ts +147 -0
- package/adapters/pi/extensions/ask-user-question/tool/validate-questionnaire.ts +58 -0
- package/adapters/pi/extensions/ask-user-question/vendor-config-shim.ts +65 -0
- package/adapters/pi/extensions/ask-user-question/view/component-binding.ts +47 -0
- package/adapters/pi/extensions/ask-user-question/view/components/inline-input.ts +98 -0
- package/adapters/pi/extensions/ask-user-question/view/components/multi-select-view.ts +193 -0
- package/adapters/pi/extensions/ask-user-question/view/components/option-list-view.ts +70 -0
- package/adapters/pi/extensions/ask-user-question/view/components/preview/markdown-content-cache.ts +79 -0
- package/adapters/pi/extensions/ask-user-question/view/components/preview/preview-block-renderer.ts +111 -0
- package/adapters/pi/extensions/ask-user-question/view/components/preview/preview-box-renderer.ts +88 -0
- package/adapters/pi/extensions/ask-user-question/view/components/preview/preview-layout-decider.ts +202 -0
- package/adapters/pi/extensions/ask-user-question/view/components/preview/preview-pane.ts +228 -0
- package/adapters/pi/extensions/ask-user-question/view/components/submit-picker.ts +67 -0
- package/adapters/pi/extensions/ask-user-question/view/components/tab-bar.ts +59 -0
- package/adapters/pi/extensions/ask-user-question/view/components/wrapping-select.ts +293 -0
- package/adapters/pi/extensions/ask-user-question/view/dialog-builder.ts +224 -0
- package/adapters/pi/extensions/ask-user-question/view/props-adapter.ts +125 -0
- package/adapters/pi/extensions/ask-user-question/view/stateful-view.ts +26 -0
- package/adapters/pi/extensions/ask-user-question/view/tab-components.ts +18 -0
- package/adapters/pi/extensions/ask-user-question/view/tab-content-strategy.ts +252 -0
- package/adapters/pi/package.json +26 -0
- package/adapters/pi/references/epic-manifest-schema.json +125 -0
- package/adapters/{claude/skills/forge-5-loop → pi}/references/forge-config-schema.json +4 -4
- package/adapters/{claude/skills/forge-1-prd → pi}/references/pipeline-state-schema.json +1 -1
- package/adapters/pi/references/portable-root.md +71 -0
- package/adapters/pi/references/process-overview.md +143 -0
- package/adapters/pi/references/ralph-loop-contract.md +221 -0
- package/adapters/pi/references/shared-conventions.md +345 -0
- package/adapters/pi/references/skill-frontmatter.schema.json +17 -0
- package/adapters/pi/references/stack-resolution.md +54 -0
- package/adapters/pi/references/stacks/_generic.md +111 -0
- package/adapters/pi/references/stacks/go.md +157 -0
- package/adapters/pi/references/stacks/python.md +184 -0
- package/adapters/pi/references/stacks/rust.md +170 -0
- package/adapters/pi/references/stacks/typescript.md +134 -0
- package/adapters/pi/references/stage-exit-protocol.md +268 -0
- package/adapters/pi/references/templates/specs-hygiene/AGENTS.md +32 -0
- package/adapters/pi/references/templates/specs-hygiene/CLAUDE.md +31 -0
- package/adapters/pi/references/vendor-construct-inventory.md +50 -0
- package/adapters/pi/scripts/epic-manifest.py +1737 -0
- package/adapters/pi/scripts/forge-bootstrap.py +1070 -0
- package/adapters/pi/scripts/forge-init.sh +58 -0
- package/adapters/pi/scripts/forge-root.sh +179 -0
- package/adapters/pi/scripts/forge-session.py +3036 -0
- package/adapters/pi/scripts/validate-traceability.py +155 -0
- package/adapters/pi/skills/forge/SKILL.md +249 -0
- package/adapters/{claude/skills/forge-4-backlog → pi/skills/forge}/references/pipeline-state-schema.json +1 -1
- package/adapters/pi/skills/forge/references/process-overview.md +143 -0
- package/adapters/pi/skills/forge/references/shared-conventions.md +345 -0
- package/adapters/pi/skills/forge/references/stage-exit-protocol.md +268 -0
- package/adapters/pi/skills/forge-0-epic/SKILL.md +308 -0
- package/adapters/pi/skills/forge-0-epic/references/edit-mode.md +266 -0
- package/adapters/pi/skills/forge-0-epic/references/epic-manifest-subcommands.md +75 -0
- package/adapters/{claude/skills/forge-2-tech → pi/skills/forge-0-epic}/references/pipeline-state-schema.json +1 -1
- package/adapters/pi/skills/forge-0-epic/references/portable-root.md +71 -0
- package/adapters/pi/skills/forge-0-epic/references/shared-conventions.md +345 -0
- package/adapters/pi/skills/forge-0-epic/references/stage-exit-protocol.md +268 -0
- package/adapters/pi/skills/forge-1-prd/SKILL.md +181 -0
- package/adapters/pi/skills/forge-1-prd/references/prd-template.md +106 -0
- package/adapters/pi/skills/forge-1-prd/references/shared-conventions.md +345 -0
- package/adapters/pi/skills/forge-1-prd/references/stage-exit-protocol.md +268 -0
- package/adapters/pi/skills/forge-2-tech/SKILL.md +243 -0
- package/adapters/pi/skills/forge-2-tech/references/shared-conventions.md +345 -0
- package/adapters/pi/skills/forge-2-tech/references/stack-discovery-checklist.md +95 -0
- package/adapters/pi/skills/forge-2-tech/references/stack-resolution.md +54 -0
- package/adapters/pi/skills/forge-2-tech/references/stacks/_generic.md +111 -0
- package/adapters/pi/skills/forge-2-tech/references/stacks/go.md +157 -0
- package/adapters/pi/skills/forge-2-tech/references/stacks/python.md +184 -0
- package/adapters/pi/skills/forge-2-tech/references/stacks/rust.md +170 -0
- package/adapters/pi/skills/forge-2-tech/references/stacks/typescript.md +134 -0
- package/adapters/pi/skills/forge-2-tech/references/stage-exit-protocol.md +268 -0
- package/adapters/pi/skills/forge-3-specs/SKILL.md +195 -0
- package/adapters/pi/skills/forge-3-specs/references/shared-conventions.md +345 -0
- package/adapters/pi/skills/forge-3-specs/references/spec-archetypes.md +106 -0
- package/adapters/pi/skills/forge-3-specs/references/spec-examples.md +71 -0
- package/adapters/pi/skills/forge-3-specs/references/stacks/_generic.md +111 -0
- package/adapters/pi/skills/forge-3-specs/references/stacks/go.md +157 -0
- package/adapters/pi/skills/forge-3-specs/references/stacks/python.md +184 -0
- package/adapters/pi/skills/forge-3-specs/references/stacks/rust.md +170 -0
- package/adapters/pi/skills/forge-3-specs/references/stacks/typescript.md +134 -0
- package/adapters/pi/skills/forge-3-specs/references/stage-exit-protocol.md +268 -0
- package/adapters/pi/skills/forge-4-backlog/SKILL.md +191 -0
- package/adapters/pi/skills/forge-4-backlog/references/shared-conventions.md +345 -0
- package/adapters/pi/skills/forge-4-backlog/references/stage-exit-protocol.md +268 -0
- package/adapters/pi/skills/forge-5-loop/SKILL.md +314 -0
- package/adapters/pi/skills/forge-5-loop/references/agent-selection.md +116 -0
- package/adapters/pi/skills/forge-5-loop/references/ralph-loop-contract.md +221 -0
- package/adapters/pi/skills/forge-5-loop/references/result-reporting.md +85 -0
- package/adapters/pi/skills/forge-5-loop/references/runner-contract.md +248 -0
- package/adapters/pi/skills/forge-5-loop/references/shared-conventions.md +345 -0
- package/adapters/pi/skills/forge-5-loop/references/stage-exit-protocol.md +268 -0
- package/adapters/pi/skills/forge-6-docs/SKILL.md +208 -0
- package/adapters/pi/skills/forge-6-docs/references/doc-conventions.md +126 -0
- package/adapters/pi/skills/forge-6-docs/references/shared-conventions.md +345 -0
- package/adapters/pi/skills/forge-bootstrap/SKILL.md +250 -0
- package/adapters/pi/skills/forge-bootstrap/references/templates/ci/github-actions.yml +12 -0
- package/adapters/pi/skills/forge-bootstrap/references/templates/generic/run.sh +3 -0
- package/adapters/pi/skills/forge-bootstrap/references/templates/generic/test.sh +13 -0
- package/adapters/pi/skills/forge-bootstrap/references/templates/go/go.mod +3 -0
- package/adapters/pi/skills/forge-bootstrap/references/templates/go/main.go +12 -0
- package/adapters/pi/skills/forge-bootstrap/references/templates/go/main_test.go +11 -0
- package/adapters/pi/skills/forge-bootstrap/references/templates/hygiene/AGENTS.md +35 -0
- package/adapters/pi/skills/forge-bootstrap/references/templates/hygiene/CLAUDE.md +36 -0
- package/adapters/pi/skills/forge-bootstrap/references/templates/hygiene/README.md +11 -0
- package/adapters/pi/skills/forge-bootstrap/references/templates/licenses/Apache-2.0/LICENSE +198 -0
- package/adapters/pi/skills/forge-bootstrap/references/templates/licenses/MIT/LICENSE +21 -0
- package/adapters/pi/skills/forge-bootstrap/references/templates/python/pyproject.toml +24 -0
- package/adapters/pi/skills/forge-bootstrap/references/templates/python/src/{{PKG}}/__init__.py +5 -0
- package/adapters/pi/skills/forge-bootstrap/references/templates/python/src/{{PKG}}/main.py +13 -0
- package/adapters/pi/skills/forge-bootstrap/references/templates/python/tests/test_smoke.py +8 -0
- package/adapters/pi/skills/forge-bootstrap/references/templates/rust/Cargo.toml +15 -0
- package/adapters/pi/skills/forge-bootstrap/references/templates/rust/src/lib.rs +7 -0
- package/adapters/pi/skills/forge-bootstrap/references/templates/rust/src/main.rs +5 -0
- package/adapters/pi/skills/forge-bootstrap/references/templates/rust/tests/smoke.rs +6 -0
- package/adapters/pi/skills/forge-bootstrap/references/templates/typescript/package.json +15 -0
- package/adapters/pi/skills/forge-bootstrap/references/templates/typescript/src/index.ts +4 -0
- package/adapters/pi/skills/forge-bootstrap/references/templates/typescript/test/smoke.test.ts +6 -0
- package/adapters/pi/skills/forge-bootstrap/references/templates/typescript/tsconfig.json +14 -0
- package/adapters/pi/skills/forge-fix/SKILL.md +98 -0
- package/adapters/pi/skills/forge-fix/references/shared-conventions.md +345 -0
- package/adapters/pi/skills/forge-fix/references/stage-exit-protocol.md +268 -0
- package/adapters/pi/skills/forge-guide/SKILL.md +192 -0
- package/adapters/{codex/skills/forge-4-backlog → pi/skills/forge-guide}/references/forge-config-schema.json +4 -4
- package/adapters/pi/skills/forge-guide/references/process-overview.md +143 -0
- package/adapters/pi/skills/forge-guide/references/ralph-loop-contract.md +221 -0
- package/adapters/pi/skills/forge-guide/references/shared-conventions.md +345 -0
- package/adapters/pi/skills/forge-guide/references/stack-resolution.md +54 -0
- package/adapters/pi/skills/forge-guide/references/stacks/_generic.md +111 -0
- package/adapters/pi/skills/forge-guide/references/stacks/go.md +157 -0
- package/adapters/pi/skills/forge-guide/references/stacks/python.md +184 -0
- package/adapters/pi/skills/forge-guide/references/stacks/rust.md +170 -0
- package/adapters/pi/skills/forge-guide/references/stacks/typescript.md +134 -0
- package/adapters/pi/skills/forge-init/SKILL.md +72 -0
- package/adapters/pi/skills/forge-verify/SKILL.md +283 -0
- package/adapters/pi/skills/forge-verify/references/findings-template.md +157 -0
- package/adapters/{claude/skills/forge-3-specs → pi/skills/forge-verify}/references/pipeline-state-schema.json +1 -1
- package/adapters/pi/skills/forge-verify/references/shared-conventions.md +345 -0
- package/adapters/pi/skills/forge-verify/references/verification-checklists/backlog.md +97 -0
- package/adapters/pi/skills/forge-verify/references/verification-checklists/epic.md +79 -0
- package/adapters/pi/skills/forge-verify/references/verification-checklists/impl.md +48 -0
- package/adapters/pi/skills/forge-verify/references/verification-checklists/prd.md +31 -0
- package/adapters/pi/skills/forge-verify/references/verification-checklists/specs.md +64 -0
- package/adapters/pi/skills/forge-verify/references/verification-checklists/tech.md +35 -0
- package/dist/agent-targets.d.ts +1 -1
- package/dist/agent-targets.js +23 -3
- package/dist/detect.d.ts +1 -1
- package/dist/detect.js +2 -1
- package/dist/manifest.d.ts +1 -1
- package/dist/manifest.js +2 -2
- package/dist/placements.js +5 -1
- package/dist/rauf.d.ts +4 -4
- package/dist/rauf.js +3 -3
- package/dist/types.d.ts +31 -6
- package/dist/types.js +6 -3
- package/package.json +14 -3
- package/adapters/claude/skills/forge-4-backlog/references/forge-config-schema.json +0 -236
- package/adapters/claude/skills/forge-6-docs/references/pipeline-state-schema.json +0 -191
- package/adapters/claude/skills/forge-verify/references/verification-checklists.md +0 -477
- package/adapters/codex/skills/forge-1-prd/references/pipeline-state-schema.json +0 -191
- package/adapters/codex/skills/forge-2-tech/references/pipeline-state-schema.json +0 -191
- package/adapters/codex/skills/forge-3-specs/references/pipeline-state-schema.json +0 -191
- package/adapters/codex/skills/forge-4-backlog/references/pipeline-state-schema.json +0 -191
- package/adapters/codex/skills/forge-5-loop/references/forge-config-schema.json +0 -236
- package/adapters/codex/skills/forge-6-docs/references/pipeline-state-schema.json +0 -191
- package/adapters/codex/skills/forge-verify/references/verification-checklists.md +0 -477
- package/adapters/copilot/skills/forge-1-prd/references/pipeline-state-schema.json +0 -191
- package/adapters/copilot/skills/forge-2-tech/references/pipeline-state-schema.json +0 -191
- package/adapters/copilot/skills/forge-3-specs/references/pipeline-state-schema.json +0 -191
- package/adapters/copilot/skills/forge-4-backlog/references/forge-config-schema.json +0 -236
- package/adapters/copilot/skills/forge-4-backlog/references/pipeline-state-schema.json +0 -191
- package/adapters/copilot/skills/forge-5-loop/references/forge-config-schema.json +0 -236
- package/adapters/copilot/skills/forge-6-docs/references/pipeline-state-schema.json +0 -191
- package/adapters/copilot/skills/forge-verify/references/verification-checklists.md +0 -477
- package/adapters/cursor/skills/forge-1-prd/references/pipeline-state-schema.json +0 -191
- package/adapters/cursor/skills/forge-2-tech/references/pipeline-state-schema.json +0 -191
- package/adapters/cursor/skills/forge-3-specs/references/pipeline-state-schema.json +0 -191
- package/adapters/cursor/skills/forge-4-backlog/references/forge-config-schema.json +0 -236
- package/adapters/cursor/skills/forge-4-backlog/references/pipeline-state-schema.json +0 -191
- package/adapters/cursor/skills/forge-5-loop/references/forge-config-schema.json +0 -236
- package/adapters/cursor/skills/forge-6-docs/references/pipeline-state-schema.json +0 -191
- package/adapters/cursor/skills/forge-verify/references/verification-checklists.md +0 -477
- package/adapters/gemini/skills/forge-1-prd/references/pipeline-state-schema.json +0 -191
- package/adapters/gemini/skills/forge-2-tech/references/pipeline-state-schema.json +0 -191
- package/adapters/gemini/skills/forge-3-specs/references/pipeline-state-schema.json +0 -191
- package/adapters/gemini/skills/forge-4-backlog/references/forge-config-schema.json +0 -236
- package/adapters/gemini/skills/forge-4-backlog/references/pipeline-state-schema.json +0 -191
- package/adapters/gemini/skills/forge-5-loop/references/forge-config-schema.json +0 -236
- package/adapters/gemini/skills/forge-6-docs/references/pipeline-state-schema.json +0 -191
- package/adapters/gemini/skills/forge-verify/references/verification-checklists.md +0 -477
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
// GENERATED — DO NOT EDIT. Source: adapter-src/pi/extensions/ask-user-question/state/key-router.ts
|
|
2
|
+
// Regenerate with: python3 scripts/build-adapters.py
|
|
3
|
+
import { Key, matchesKey } from "@earendil-works/pi-tui";
|
|
4
|
+
import type { QuestionAnswer } from "../tool/types.js";
|
|
5
|
+
import { ROW_INTENT_META } from "./row-intent.js";
|
|
6
|
+
import type { QuestionnaireRuntime, QuestionnaireState } from "./state.js";
|
|
7
|
+
|
|
8
|
+
const KEYBIND_UP = "tui.select.up";
|
|
9
|
+
const KEYBIND_DOWN = "tui.select.down";
|
|
10
|
+
const KEYBIND_CONFIRM = "tui.select.confirm";
|
|
11
|
+
const KEYBIND_CANCEL = "tui.select.cancel";
|
|
12
|
+
|
|
13
|
+
const NOTES_ACTIVATE_KEY = "n";
|
|
14
|
+
const SPACE_KEY = " ";
|
|
15
|
+
|
|
16
|
+
export type QuestionnaireAction =
|
|
17
|
+
| { kind: "nav"; nextIndex: number }
|
|
18
|
+
| { kind: "tab_switch"; nextTab: number }
|
|
19
|
+
| { kind: "confirm"; answer: QuestionAnswer; autoAdvanceTab?: number }
|
|
20
|
+
| { kind: "toggle"; index: number }
|
|
21
|
+
| { kind: "multi_confirm"; selected: string[]; autoAdvanceTab?: number }
|
|
22
|
+
| { kind: "cancel" }
|
|
23
|
+
| { kind: "notes_enter" }
|
|
24
|
+
| { kind: "notes_exit" }
|
|
25
|
+
| { kind: "submit" }
|
|
26
|
+
| { kind: "submit_nav"; nextIndex: 0 | 1 }
|
|
27
|
+
| { kind: "notes_forward"; data: string }
|
|
28
|
+
/** Flip `state.collapsed`. Always available, regardless of inner mode (see top intercept in `routeKey`). */
|
|
29
|
+
| { kind: "toggle_collapsed" }
|
|
30
|
+
| { kind: "ignore" };
|
|
31
|
+
|
|
32
|
+
export interface QuestionnaireKeybindings {
|
|
33
|
+
matches(data: string, name: string): boolean;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function wrapTab(index: number, total: number): number {
|
|
37
|
+
if (total <= 0) return 0;
|
|
38
|
+
return ((index % total) + total) % total;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function allAnswered(state: QuestionnaireState, runtime: QuestionnaireRuntime): boolean {
|
|
42
|
+
if (runtime.questions.length === 0) return false;
|
|
43
|
+
for (let i = 0; i < runtime.questions.length; i++) {
|
|
44
|
+
if (!state.answers.has(i)) return false;
|
|
45
|
+
}
|
|
46
|
+
return true;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function totalTabs(runtime: QuestionnaireRuntime): number {
|
|
50
|
+
return runtime.isMulti ? runtime.questions.length + 1 : 1;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function computeAutoAdvanceTab(state: QuestionnaireState, runtime: QuestionnaireRuntime): number | undefined {
|
|
54
|
+
if (!runtime.isMulti) return undefined;
|
|
55
|
+
if (state.currentTab < runtime.questions.length - 1) return state.currentTab + 1;
|
|
56
|
+
return runtime.questions.length;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function buildSingleSelectAnswer(state: QuestionnaireState, runtime: QuestionnaireRuntime): QuestionAnswer | null {
|
|
60
|
+
const q = runtime.questions[state.currentTab];
|
|
61
|
+
if (!q) return null;
|
|
62
|
+
|
|
63
|
+
const item = runtime.currentItem;
|
|
64
|
+
|
|
65
|
+
if (state.inputMode) {
|
|
66
|
+
const label = runtime.inputBuffer;
|
|
67
|
+
return {
|
|
68
|
+
questionIndex: state.currentTab,
|
|
69
|
+
question: q.question,
|
|
70
|
+
kind: "custom",
|
|
71
|
+
answer: label.length > 0 ? label : null,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
if (!item) return null;
|
|
75
|
+
if (item.kind === "other") {
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
if (item.kind === "next") {
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
return {
|
|
82
|
+
questionIndex: state.currentTab,
|
|
83
|
+
question: q.question,
|
|
84
|
+
kind: "option",
|
|
85
|
+
answer: item.label,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function buildMultiSelected(state: QuestionnaireState, runtime: QuestionnaireRuntime): string[] {
|
|
90
|
+
const q = runtime.questions[state.currentTab];
|
|
91
|
+
if (!q) return [];
|
|
92
|
+
const out: string[] = [];
|
|
93
|
+
for (let i = 0; i < q.options.length; i++) {
|
|
94
|
+
if (state.multiSelectChecked.has(i)) {
|
|
95
|
+
const label = q.options[i]?.label;
|
|
96
|
+
if (typeof label === "string") out.push(label);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return out;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function tabSwitchAction(
|
|
103
|
+
data: string,
|
|
104
|
+
state: QuestionnaireState,
|
|
105
|
+
runtime: QuestionnaireRuntime,
|
|
106
|
+
): QuestionnaireAction | null {
|
|
107
|
+
if (!runtime.isMulti) return null;
|
|
108
|
+
const total = totalTabs(runtime);
|
|
109
|
+
if (matchesKey(data, Key.tab) || matchesKey(data, Key.right)) {
|
|
110
|
+
return { kind: "tab_switch", nextTab: wrapTab(state.currentTab + 1, total) };
|
|
111
|
+
}
|
|
112
|
+
if (matchesKey(data, Key.shift("tab")) || matchesKey(data, Key.left)) {
|
|
113
|
+
return { kind: "tab_switch", nextTab: wrapTab(state.currentTab - 1, total) };
|
|
114
|
+
}
|
|
115
|
+
return null;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// DOWN at the last item wraps to the first (cycle through [option0, …, optionLast]).
|
|
119
|
+
function nextNavOnDown(state: QuestionnaireState, runtime: QuestionnaireRuntime): QuestionnaireAction {
|
|
120
|
+
return { kind: "nav", nextIndex: wrapTab(state.optionIndex + 1, Math.max(1, runtime.items.length)) };
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// UP at the first item wraps to the last (symmetric with nextNavOnDown).
|
|
124
|
+
function prevNavOnUp(state: QuestionnaireState, runtime: QuestionnaireRuntime): QuestionnaireAction {
|
|
125
|
+
return { kind: "nav", nextIndex: wrapTab(state.optionIndex - 1, Math.max(1, runtime.items.length)) };
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export function routeKey(data: string, state: QuestionnaireState, runtime: QuestionnaireRuntime): QuestionnaireAction {
|
|
129
|
+
const kb = runtime.keybindings;
|
|
130
|
+
|
|
131
|
+
// Collapse/expand toggle is a UI-level affordance — intercepted at the top so it
|
|
132
|
+
// works from every inner state (notes, inputMode, submit tab, multi-select)
|
|
133
|
+
// without reaching any branch that would otherwise consume the keystroke. The
|
|
134
|
+
// questionnaire overlay is fully hidden via `OverlayHandle.setHidden(true)` while
|
|
135
|
+
// collapsed; pi-tui's overlay stack updates accordingly, so overlay-aware consumers
|
|
136
|
+
// (e.g. `pi-station`) see no visible modal and chat scroll resumes. The toggle key is
|
|
137
|
+
// also captured at the raw terminal level via `ctx.ui.onTerminalInput` so it still
|
|
138
|
+
// routes here when the overlay is hidden (pi-tui does not deliver input to a hidden
|
|
139
|
+
// overlay's `component.handleInput`).
|
|
140
|
+
//
|
|
141
|
+
// The default `ctrl+]` is free in every mainstream macOS terminal (Terminal.app,
|
|
142
|
+
// iTerm2, Warp), every multiplexer (tmux, zellij, screen — none use it as a prefix),
|
|
143
|
+
// and the legacy telnet/ssh escape role doesn't apply because our overlay runs
|
|
144
|
+
// in-process. It is, however, awkward on keyboard layouts where `]` is on the
|
|
145
|
+
// shifted layer (Latin American `es-AR`/`es-MX` require `Ctrl+Shift+}` for `Ctrl+]`)
|
|
146
|
+
// — use the `collapseKey` config field to override.
|
|
147
|
+
// Treat a missing/non-string key as disabled. This can occur at runtime when
|
|
148
|
+
// a long-lived Pi process retains an older outer module while a package update
|
|
149
|
+
// replaces the lazily imported QuestionnaireSession graph on disk. Passing
|
|
150
|
+
// undefined into matchesKey reaches parseKeyId().toLowerCase() and crashes the
|
|
151
|
+
// entire host process, so keep the runtime boundary defensive even though the
|
|
152
|
+
// TypeScript contract requires a string.
|
|
153
|
+
if (
|
|
154
|
+
typeof runtime.collapseKey === "string" &&
|
|
155
|
+
runtime.collapseKey !== "off" &&
|
|
156
|
+
matchesKey(data, runtime.collapseKey as Parameters<typeof matchesKey>[1])
|
|
157
|
+
) {
|
|
158
|
+
return { kind: "toggle_collapsed" };
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Collapsed-mode lockout: while collapsed, swallow every keystroke except cancel so
|
|
162
|
+
// the user can read the now-uncovered transcript without accidentally mutating
|
|
163
|
+
// answers or notes. The collapse toggle itself is already handled above.
|
|
164
|
+
if (state.collapsed) {
|
|
165
|
+
if (kb.matches(data, KEYBIND_CANCEL)) return { kind: "cancel" };
|
|
166
|
+
return { kind: "ignore" };
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
if (state.notesVisible) {
|
|
170
|
+
if (kb.matches(data, KEYBIND_CANCEL)) return { kind: "notes_exit" };
|
|
171
|
+
if (kb.matches(data, KEYBIND_CONFIRM)) return { kind: "notes_exit" };
|
|
172
|
+
return { kind: "notes_forward", data };
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
if (state.inputMode) {
|
|
176
|
+
if (kb.matches(data, KEYBIND_CONFIRM)) {
|
|
177
|
+
const answer = buildSingleSelectAnswer(state, runtime);
|
|
178
|
+
if (!answer) return { kind: "ignore" };
|
|
179
|
+
return { kind: "confirm", answer, autoAdvanceTab: computeAutoAdvanceTab(state, runtime) };
|
|
180
|
+
}
|
|
181
|
+
if (kb.matches(data, KEYBIND_CANCEL)) return { kind: "cancel" };
|
|
182
|
+
if (kb.matches(data, KEYBIND_UP)) {
|
|
183
|
+
return prevNavOnUp(state, runtime);
|
|
184
|
+
}
|
|
185
|
+
if (kb.matches(data, KEYBIND_DOWN)) {
|
|
186
|
+
return nextNavOnDown(state, runtime);
|
|
187
|
+
}
|
|
188
|
+
return { kind: "ignore" };
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
if (runtime.isMulti && state.currentTab === runtime.questions.length) {
|
|
192
|
+
if (kb.matches(data, KEYBIND_CANCEL)) return { kind: "cancel" };
|
|
193
|
+
const tab = tabSwitchAction(data, state, runtime);
|
|
194
|
+
if (tab) return tab;
|
|
195
|
+
if (kb.matches(data, KEYBIND_UP) || kb.matches(data, KEYBIND_DOWN)) {
|
|
196
|
+
const delta = kb.matches(data, KEYBIND_DOWN) ? 1 : -1;
|
|
197
|
+
const next = wrapTab(state.submitChoiceIndex + delta, 2);
|
|
198
|
+
return { kind: "submit_nav", nextIndex: (next === 1 ? 1 : 0) as 0 | 1 };
|
|
199
|
+
}
|
|
200
|
+
if (kb.matches(data, KEYBIND_CONFIRM)) {
|
|
201
|
+
// D1 (revised): Submit always submits; Cancel always cancels. The warning header
|
|
202
|
+
// is informational only — `allAnswered(state)` no longer gates submission. Partial
|
|
203
|
+
// answers flow through `orderedAnswers()` in the host.
|
|
204
|
+
return state.submitChoiceIndex === 1 ? { kind: "cancel" } : { kind: "submit" };
|
|
205
|
+
}
|
|
206
|
+
return { kind: "ignore" };
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
const tab = tabSwitchAction(data, state, runtime);
|
|
210
|
+
if (tab) return tab;
|
|
211
|
+
|
|
212
|
+
const q = runtime.questions[state.currentTab];
|
|
213
|
+
if (!q) return { kind: "ignore" };
|
|
214
|
+
|
|
215
|
+
// Universal `n` activation (FR-1): the notes editor opens on every question tab
|
|
216
|
+
// (single- or multi-select, preview or no-preview). The blocks above already
|
|
217
|
+
// swallow `n` when it should NOT reach here — notesVisible forwards to the
|
|
218
|
+
// notes Input, inputMode forwards to the inline Input, the submit-tab block
|
|
219
|
+
// ignores it, and tabSwitchAction ignores it — so by the time we reach this
|
|
220
|
+
// gate, `n` is unambiguously a notes-enter request. Row intent (Next sentinel,
|
|
221
|
+
// "Type something.") is irrelevant: the gate sits ABOVE the multi-select
|
|
222
|
+
// toggle block and the Next sentinel never activates inputMode, so `n` is
|
|
223
|
+
// neither swallowed earlier nor blocked by `blocksMultiToggle`.
|
|
224
|
+
if (data === NOTES_ACTIVATE_KEY) {
|
|
225
|
+
return { kind: "notes_enter" };
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
if (kb.matches(data, KEYBIND_UP)) {
|
|
229
|
+
return prevNavOnUp(state, runtime);
|
|
230
|
+
}
|
|
231
|
+
if (kb.matches(data, KEYBIND_DOWN)) {
|
|
232
|
+
return nextNavOnDown(state, runtime);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
if (q.multiSelect) {
|
|
236
|
+
const focusedKind = runtime.currentItem?.kind;
|
|
237
|
+
const focusedMeta = focusedKind ? ROW_INTENT_META[focusedKind] : undefined;
|
|
238
|
+
// Space toggles the focused row's checkbox. Suppressed on rows whose META declares
|
|
239
|
+
// `blocksMultiToggle` (the Next sentinel) or `activatesInputMode` (the "Type
|
|
240
|
+
// something." row — it is an inline input, not a checkable option).
|
|
241
|
+
if (data === SPACE_KEY) {
|
|
242
|
+
if (focusedMeta?.blocksMultiToggle) return { kind: "ignore" };
|
|
243
|
+
if (focusedMeta?.activatesInputMode) return { kind: "ignore" };
|
|
244
|
+
return { kind: "toggle", index: state.optionIndex };
|
|
245
|
+
}
|
|
246
|
+
if (kb.matches(data, KEYBIND_CONFIRM)) {
|
|
247
|
+
// Enter on the "Type something." row is handled by the inputMode block above
|
|
248
|
+
// (→ confirm kind:"custom"). Defensive: never enter the toggle/multi_confirm
|
|
249
|
+
// path for an inputMode-activating row.
|
|
250
|
+
if (focusedMeta?.activatesInputMode) return { kind: "ignore" };
|
|
251
|
+
// Enter on a regular row toggles (matching Space) — committing the question is now
|
|
252
|
+
// gated behind explicit focus on a row whose META declares `autoSubmitsInMulti`
|
|
253
|
+
// (the Next sentinel), so Enter on options is a no-cost way to flip checkboxes
|
|
254
|
+
// without leaving the keyboard home row.
|
|
255
|
+
if (!focusedMeta?.autoSubmitsInMulti) return { kind: "toggle", index: state.optionIndex };
|
|
256
|
+
// Enter on Next: carry autoAdvanceTab so the host can advance to the next tab in
|
|
257
|
+
// multi-question mode, OR submit the dialog in single-question mode
|
|
258
|
+
// (autoAdvanceTab === undefined when !isMulti). Without this, a single multi-select
|
|
259
|
+
// question would have no way to commit at all.
|
|
260
|
+
return {
|
|
261
|
+
kind: "multi_confirm",
|
|
262
|
+
selected: buildMultiSelected(state, runtime),
|
|
263
|
+
autoAdvanceTab: computeAutoAdvanceTab(state, runtime),
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
if (kb.matches(data, KEYBIND_CANCEL)) return { kind: "cancel" };
|
|
267
|
+
return { kind: "ignore" };
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
if (kb.matches(data, KEYBIND_CONFIRM)) {
|
|
271
|
+
const answer = buildSingleSelectAnswer(state, runtime);
|
|
272
|
+
if (!answer) return { kind: "ignore" };
|
|
273
|
+
return { kind: "confirm", answer, autoAdvanceTab: computeAutoAdvanceTab(state, runtime) };
|
|
274
|
+
}
|
|
275
|
+
if (kb.matches(data, KEYBIND_CANCEL)) return { kind: "cancel" };
|
|
276
|
+
return { kind: "ignore" };
|
|
277
|
+
}
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
// GENERATED — DO NOT EDIT. Source: adapter-src/pi/extensions/ask-user-question/state/questionnaire-session.ts
|
|
2
|
+
// Regenerate with: python3 scripts/build-adapters.py
|
|
3
|
+
import type { Theme } from "@earendil-works/pi-coding-agent";
|
|
4
|
+
import { getKeybindings, type Input, type OverlayHandle } from "@earendil-works/pi-tui";
|
|
5
|
+
import type { QuestionData, QuestionnaireResult, QuestionParams } from "../tool/types.js";
|
|
6
|
+
import type { WrappingSelectItem } from "../view/components/wrapping-select.js";
|
|
7
|
+
import { COLLAPSED_HINT } from "../view/dialog-builder.js";
|
|
8
|
+
import type { QuestionnairePropsAdapter } from "../view/props-adapter.js";
|
|
9
|
+
import { buildQuestionnaire } from "./build-questionnaire.js";
|
|
10
|
+
import { t } from "./i18n-bridge.js";
|
|
11
|
+
import { type QuestionnaireAction, routeKey } from "./key-router.js";
|
|
12
|
+
import type { QuestionnaireRuntime, QuestionnaireState } from "./state.js";
|
|
13
|
+
import { type ApplyContext, type Effect, reduce } from "./state-reducer.js";
|
|
14
|
+
|
|
15
|
+
// Module-level constant; reused for cursor-end mutations after setValue rehydration.
|
|
16
|
+
// Ctrl-E → tui.editor.cursorLineEnd (public path; pi-tui keybindings.js:25-28).
|
|
17
|
+
const CURSOR_END = "\x05";
|
|
18
|
+
|
|
19
|
+
export interface QuestionnaireSessionConfig {
|
|
20
|
+
tui: { terminal: { columns: number; rows: number }; requestRender(): void };
|
|
21
|
+
theme: Theme;
|
|
22
|
+
params: QuestionParams;
|
|
23
|
+
itemsByTab: WrappingSelectItem[][];
|
|
24
|
+
done: (result: QuestionnaireResult) => void;
|
|
25
|
+
/** Key spec for the collapse/expand shortcut, e.g. `"ctrl+]"` or `"alt+o"`. */
|
|
26
|
+
collapseKey: string;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface QuestionnaireSessionComponent {
|
|
30
|
+
render(width: number): string[];
|
|
31
|
+
invalidate(): void;
|
|
32
|
+
handleInput(data: string): void;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function initialState(): QuestionnaireState {
|
|
36
|
+
return {
|
|
37
|
+
currentTab: 0,
|
|
38
|
+
optionIndex: 0,
|
|
39
|
+
inputMode: false,
|
|
40
|
+
notesVisible: false,
|
|
41
|
+
answers: new Map(),
|
|
42
|
+
multiSelectChecked: new Set(),
|
|
43
|
+
notesByTab: new Map(),
|
|
44
|
+
submitChoiceIndex: 0,
|
|
45
|
+
notesDraft: "",
|
|
46
|
+
collapsed: false,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Slim runtime: owns the canonical state cell, the input-buffer cell, the
|
|
52
|
+
* two-pass `notesVisible` dispatch loop, and the effect runner. State
|
|
53
|
+
* transitions go through the pure `reduce` reducer; UI fan-out goes through
|
|
54
|
+
* the `QuestionnairePropsAdapter` produced by `buildQuestionnaire`.
|
|
55
|
+
*/
|
|
56
|
+
export class QuestionnaireSession {
|
|
57
|
+
private state: QuestionnaireState = initialState();
|
|
58
|
+
|
|
59
|
+
private readonly questions: readonly QuestionData[];
|
|
60
|
+
private readonly isMulti: boolean;
|
|
61
|
+
private readonly itemsByTab: WrappingSelectItem[][];
|
|
62
|
+
|
|
63
|
+
private readonly notesInput: Input;
|
|
64
|
+
private readonly inlineInput: Input;
|
|
65
|
+
private readonly viewAdapter: QuestionnairePropsAdapter;
|
|
66
|
+
private readonly collapseKey: string;
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Overlay handle captured by `ctx.ui.custom`'s `onHandle` callback. Lets the session
|
|
70
|
+
* call `setHidden(true/false)` so pi-tui's overlay stack reflects the collapsed state
|
|
71
|
+
* and overlay-aware consumers (e.g. `pi-station`) can resume normal behaviour.
|
|
72
|
+
*/
|
|
73
|
+
private overlayHandle: OverlayHandle | undefined;
|
|
74
|
+
|
|
75
|
+
private readonly tui: QuestionnaireSessionConfig["tui"];
|
|
76
|
+
private readonly done: QuestionnaireSessionConfig["done"];
|
|
77
|
+
readonly component: QuestionnaireSessionComponent;
|
|
78
|
+
|
|
79
|
+
constructor(config: QuestionnaireSessionConfig) {
|
|
80
|
+
this.tui = config.tui;
|
|
81
|
+
this.done = config.done;
|
|
82
|
+
this.questions = config.params.questions;
|
|
83
|
+
this.isMulti = this.questions.length > 1;
|
|
84
|
+
this.itemsByTab = config.itemsByTab;
|
|
85
|
+
this.collapseKey = config.collapseKey;
|
|
86
|
+
|
|
87
|
+
const built = buildQuestionnaire({
|
|
88
|
+
tui: this.tui,
|
|
89
|
+
theme: config.theme,
|
|
90
|
+
questions: this.questions,
|
|
91
|
+
itemsByTab: this.itemsByTab,
|
|
92
|
+
isMulti: this.isMulti,
|
|
93
|
+
initialState: this.state,
|
|
94
|
+
getCurrentTab: () => this.state.currentTab,
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
this.notesInput = built.notesInput;
|
|
98
|
+
this.inlineInput = built.inlineInput;
|
|
99
|
+
this.viewAdapter = built.adapter;
|
|
100
|
+
|
|
101
|
+
const theme = config.theme;
|
|
102
|
+
// Collapsed render: a single dim row at the bottom of the overlay. pi-tui sizes
|
|
103
|
+
// the overlay to `min(lines.length, maxHeight)`, so returning one line shrinks
|
|
104
|
+
// the bottom-anchored overlay from full-height to one row and the transcript
|
|
105
|
+
// behind it becomes readable (#47). The overlay stays focused and in the
|
|
106
|
+
// stack, so Ctrl+] still routes here to expand.
|
|
107
|
+
const collapsedRender = (_width: number): string[] => [
|
|
108
|
+
theme.fg("dim", ` ${t("hint.expand_line", COLLAPSED_HINT)} `),
|
|
109
|
+
];
|
|
110
|
+
|
|
111
|
+
this.component = {
|
|
112
|
+
render: (width) => (this.state.collapsed ? collapsedRender(width) : built.render(width)),
|
|
113
|
+
invalidate: built.invalidate,
|
|
114
|
+
handleInput: (data) => this.dispatch(data),
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
this.viewAdapter.apply(this.state);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
dispatch(data: string): void {
|
|
121
|
+
const action = routeKey(data, this.state, this.runtime());
|
|
122
|
+
if (action.kind === "ignore") {
|
|
123
|
+
this.handleIgnoreInline(data);
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
this.commit(action);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
private commit(action: QuestionnaireAction): void {
|
|
130
|
+
const result = reduce(this.state, action, this.applyContext());
|
|
131
|
+
this.state = result.state;
|
|
132
|
+
for (const effect of result.effects) this.runEffect(effect);
|
|
133
|
+
this.state = this.mirrorNotesDraft(this.state);
|
|
134
|
+
this.viewAdapter.apply(this.state);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
private mirrorNotesDraft(s: QuestionnaireState): QuestionnaireState {
|
|
138
|
+
const draft = this.notesInput.getValue();
|
|
139
|
+
return s.notesDraft === draft ? s : { ...s, notesDraft: draft };
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
private runEffect(effect: Effect): void {
|
|
143
|
+
switch (effect.kind) {
|
|
144
|
+
case "set_input_buffer":
|
|
145
|
+
this.inlineInput.setValue(effect.value);
|
|
146
|
+
this.inlineInput.handleInput(CURSOR_END);
|
|
147
|
+
return;
|
|
148
|
+
case "clear_input_buffer":
|
|
149
|
+
this.inlineInput.setValue("");
|
|
150
|
+
return;
|
|
151
|
+
case "set_notes_value":
|
|
152
|
+
this.notesInput.setValue(effect.value);
|
|
153
|
+
return;
|
|
154
|
+
case "set_notes_focused":
|
|
155
|
+
this.notesInput.focused = effect.focused;
|
|
156
|
+
return;
|
|
157
|
+
case "forward_notes_keystroke":
|
|
158
|
+
this.notesInput.handleInput(effect.data);
|
|
159
|
+
return;
|
|
160
|
+
case "set_overlay_hidden":
|
|
161
|
+
// No-op until `setOverlayHandle` has been called (the handle arrives via
|
|
162
|
+
// `ctx.ui.custom`'s `onHandle` right after the overlay is shown).
|
|
163
|
+
this.overlayHandle?.setHidden(effect.hidden);
|
|
164
|
+
return;
|
|
165
|
+
case "done":
|
|
166
|
+
this.done(effect.result);
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Per-keystroke `ignore` fast path: delegates to the headless `inlineInput`
|
|
173
|
+
* Input so bracketed-paste accumulator (`input.js:33-63`) and Kitty CSI-u
|
|
174
|
+
* decode (`input.js:155-163`) take effect. Cursor is NOT force-reset here —
|
|
175
|
+
* doing so would corrupt split-chunk pastes (a `\x05` byte mid-paste lands
|
|
176
|
+
* verbatim in `pasteBuffer` and survives `handlePaste`'s narrow strip).
|
|
177
|
+
* Cursor advances naturally via `insertCharacter` on typing/paste; cursor-
|
|
178
|
+
* movement keys (Left/Right/Home/End/word-jumps) are now functional, with
|
|
179
|
+
* the always-end visual cursor marker drawn independently by
|
|
180
|
+
* `WrappingSelect.renderInlineInputRow`. `viewAdapter.apply` is called
|
|
181
|
+
* directly without a reducer round-trip — preserves the D3 fast-path
|
|
182
|
+
* latency profile from Phase 11.
|
|
183
|
+
*/
|
|
184
|
+
private handleIgnoreInline(data: string): void {
|
|
185
|
+
if (!this.state.inputMode) return;
|
|
186
|
+
this.inlineInput.handleInput(data);
|
|
187
|
+
this.viewAdapter.apply(this.state);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
private runtime(): QuestionnaireRuntime {
|
|
191
|
+
return {
|
|
192
|
+
keybindings: getKeybindings(),
|
|
193
|
+
inputBuffer: this.inlineInput.getValue(),
|
|
194
|
+
questions: this.questions,
|
|
195
|
+
isMulti: this.isMulti,
|
|
196
|
+
currentItem: this.currentItem(),
|
|
197
|
+
items: this.itemsByTab[this.state.currentTab] ?? [],
|
|
198
|
+
collapseKey: this.collapseKey,
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
private applyContext(): ApplyContext {
|
|
203
|
+
return {
|
|
204
|
+
questions: this.questions,
|
|
205
|
+
itemsByTab: this.itemsByTab,
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
private currentItem(): WrappingSelectItem | undefined {
|
|
210
|
+
const arr = this.itemsByTab[this.state.currentTab] ?? [];
|
|
211
|
+
return this.state.optionIndex < arr.length ? arr[this.state.optionIndex] : undefined;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Setter for the overlay handle, called by `ctx.ui.custom`'s `onHandle` callback once
|
|
216
|
+
* the TUI has created the overlay. Until this is called, `set_overlay_hidden` effects
|
|
217
|
+
* are no-ops — the session still tracks `state.collapsed` for the view layer.
|
|
218
|
+
*/
|
|
219
|
+
setOverlayHandle(handle: OverlayHandle): void {
|
|
220
|
+
this.overlayHandle = handle;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Public toggle used by the raw terminal input listener registered in `execute()`.
|
|
225
|
+
* pi-tui does not route input to a hidden overlay's `component.handleInput`, so the
|
|
226
|
+
* raw listener (which fires for terminal data regardless of overlay visibility)
|
|
227
|
+
* reaches the session through this method instead of the dispatch path. Routed
|
|
228
|
+
* through `commit` so the transition stays in the reducer and the overlay hide
|
|
229
|
+
* happens via the `set_overlay_hidden` effect like every other side effect.
|
|
230
|
+
*/
|
|
231
|
+
toggleCollapsedExternal(): void {
|
|
232
|
+
this.commit({ kind: "toggle_collapsed" });
|
|
233
|
+
}
|
|
234
|
+
}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
// GENERATED — DO NOT EDIT. Source: adapter-src/pi/extensions/ask-user-question/state/row-intent.ts
|
|
2
|
+
// Regenerate with: python3 scripts/build-adapters.py
|
|
3
|
+
import type { QuestionData } from "../tool/types.js";
|
|
4
|
+
import type { WrappingSelectItem } from "../view/components/wrapping-select.js";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Row kind discriminator. Single source of truth — derived from the runtime
|
|
8
|
+
* `WrappingSelectItem` union (`wrapping-select.ts:18-22`) so adding a new
|
|
9
|
+
* variant there forces a `ROW_INTENT_META` entry here (compile-time
|
|
10
|
+
* exhaustiveness via `Record<RowKind, …>`).
|
|
11
|
+
*/
|
|
12
|
+
export type RowKind = WrappingSelectItem["kind"];
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Sentinel kinds — the subset of `RowKind` representing protocol-driven rows
|
|
16
|
+
* (vs author-defined `option` rows). The auto-append walker, the reserved-label
|
|
17
|
+
* derivation, and `LABELS_BY_KIND` consumers iterate this list.
|
|
18
|
+
*/
|
|
19
|
+
export type SentinelKind = Exclude<RowKind, "option">;
|
|
20
|
+
export const SENTINEL_KINDS: readonly SentinelKind[] = ["other", "next"];
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Per-kind static metadata. Pure data — no closures, no per-kind handler
|
|
24
|
+
* functions. Behavior-bearing branches (answer construction in
|
|
25
|
+
* `key-router.ts:69-99`, the Next-row render block in `multi-select-view.ts`,
|
|
26
|
+
* and the inline-Input render branch in `wrapping-select.ts`) keep their
|
|
27
|
+
* exhaustive switches and READ flags from this table.
|
|
28
|
+
*
|
|
29
|
+
* Adding a new sentinel:
|
|
30
|
+
* 1. Add the variant to `WrappingSelectItem` (`wrapping-select.ts:18-22`).
|
|
31
|
+
* 2. Add an entry here. Compile fails until both edits are present.
|
|
32
|
+
* 3. (If user-facing) author wherever the row is synthesized — typically
|
|
33
|
+
* `buildItemsForQuestion` for main-list residents.
|
|
34
|
+
*
|
|
35
|
+
* Field semantics:
|
|
36
|
+
* - `label` — user-facing string. For `option` it's an empty placeholder
|
|
37
|
+
* (per-instance labels come from `QuestionData.options[i].label`); every
|
|
38
|
+
* sentinel uses its META entry as the single source of truth.
|
|
39
|
+
* - `reserved` — author-facing labels matching this string trigger
|
|
40
|
+
* `reserved_label` at validation time. `RESERVED_LABEL_SET` is derived.
|
|
41
|
+
* - `livesInMainList` — true iff the row appears in `itemsByTab[i]`. Every
|
|
42
|
+
* current sentinel lives in the main list (the `next` row is synthesized by
|
|
43
|
+
* `sentinelsToAppend`).
|
|
44
|
+
* - `numbered` — true iff the row contributes to the main-list numbering.
|
|
45
|
+
* Multi-select Next is the only `numbered=false` row that lives in the list.
|
|
46
|
+
* - `activatesInputMode` — true iff focusing the row should toggle
|
|
47
|
+
* `state.inputMode = true`. Read by `state-reducer.ts` `nav` case.
|
|
48
|
+
* - `blocksMultiToggle` — in multiSelect mode, Space (and Enter-as-toggle)
|
|
49
|
+
* on this row is suppressed. The Next sentinel is the only true.
|
|
50
|
+
* - `autoSubmitsInMulti` — in multiSelect mode, Enter on this row commits
|
|
51
|
+
* the question (emits `multi_confirm`). The Next sentinel is the only true.
|
|
52
|
+
* - `autoAppendOnSingleSelect` — `buildItemsForQuestion` appends
|
|
53
|
+
* this row when the question is single-select, regardless of whether any
|
|
54
|
+
* option carries a `preview`. The "other" sentinel is the only true.
|
|
55
|
+
* - `autoAppendOnMultiSelect` — `buildItemsForQuestion` appends this row
|
|
56
|
+
* when the question is multi-select. The `other` and `next` sentinels are both true.
|
|
57
|
+
*/
|
|
58
|
+
export interface RowIntentMeta {
|
|
59
|
+
label: string;
|
|
60
|
+
reserved: boolean;
|
|
61
|
+
livesInMainList: boolean;
|
|
62
|
+
numbered: boolean;
|
|
63
|
+
activatesInputMode: boolean;
|
|
64
|
+
blocksMultiToggle: boolean;
|
|
65
|
+
autoSubmitsInMulti: boolean;
|
|
66
|
+
autoAppendOnSingleSelect: boolean;
|
|
67
|
+
autoAppendOnMultiSelect: boolean;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export const ROW_INTENT_META: Record<RowKind, RowIntentMeta> = {
|
|
71
|
+
option: {
|
|
72
|
+
label: "",
|
|
73
|
+
reserved: false,
|
|
74
|
+
livesInMainList: true,
|
|
75
|
+
numbered: true,
|
|
76
|
+
activatesInputMode: false,
|
|
77
|
+
blocksMultiToggle: false,
|
|
78
|
+
autoSubmitsInMulti: false,
|
|
79
|
+
autoAppendOnSingleSelect: false,
|
|
80
|
+
autoAppendOnMultiSelect: false,
|
|
81
|
+
},
|
|
82
|
+
other: {
|
|
83
|
+
label: "Type something.",
|
|
84
|
+
reserved: true,
|
|
85
|
+
livesInMainList: true,
|
|
86
|
+
numbered: true,
|
|
87
|
+
activatesInputMode: true,
|
|
88
|
+
blocksMultiToggle: false,
|
|
89
|
+
autoSubmitsInMulti: false,
|
|
90
|
+
autoAppendOnSingleSelect: true,
|
|
91
|
+
autoAppendOnMultiSelect: true,
|
|
92
|
+
},
|
|
93
|
+
next: {
|
|
94
|
+
label: "Next",
|
|
95
|
+
reserved: true,
|
|
96
|
+
livesInMainList: true,
|
|
97
|
+
numbered: false,
|
|
98
|
+
activatesInputMode: false,
|
|
99
|
+
blocksMultiToggle: true,
|
|
100
|
+
autoSubmitsInMulti: true,
|
|
101
|
+
autoAppendOnSingleSelect: false,
|
|
102
|
+
autoAppendOnMultiSelect: true,
|
|
103
|
+
},
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Kind-keyed label view. `option` is excluded — its label is per-instance,
|
|
108
|
+
* not per-kind. `types.ts#SENTINEL_LABELS` re-sources from here.
|
|
109
|
+
*/
|
|
110
|
+
export const LABELS_BY_KIND: { readonly [K in SentinelKind]: string } = {
|
|
111
|
+
other: ROW_INTENT_META.other.label,
|
|
112
|
+
next: ROW_INTENT_META.next.label,
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Reserved-label set for runtime validation. Includes "Other" (a model-conditioned
|
|
117
|
+
* label that has no runtime kind) plus every sentinel with `reserved: true`.
|
|
118
|
+
*/
|
|
119
|
+
export const RESERVED_LABEL_SET: ReadonlySet<string> = new Set<string>([
|
|
120
|
+
"Other",
|
|
121
|
+
...SENTINEL_KINDS.filter((k) => ROW_INTENT_META[k].reserved).map((k) => ROW_INTENT_META[k].label),
|
|
122
|
+
]);
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Walk the META table to synthesize sentinel rows for one question. The two
|
|
126
|
+
* append predicates are mutually exclusive in practice (`multiSelect` vs
|
|
127
|
+
* single-select) but the walker doesn't enforce that — adding a third bucket
|
|
128
|
+
* only requires a new META flag.
|
|
129
|
+
*
|
|
130
|
+
* Returns sentinel descriptors in declaration order of `SENTINEL_KINDS`. The
|
|
131
|
+
* caller wraps each with the `WrappingSelectItem` shape (kind + label).
|
|
132
|
+
*/
|
|
133
|
+
export function sentinelsToAppend(question: QuestionData): SentinelKind[] {
|
|
134
|
+
const out: SentinelKind[] = [];
|
|
135
|
+
for (const k of SENTINEL_KINDS) {
|
|
136
|
+
const meta = ROW_INTENT_META[k];
|
|
137
|
+
if (!meta.livesInMainList) continue;
|
|
138
|
+
if (question.multiSelect === true) {
|
|
139
|
+
if (meta.autoAppendOnMultiSelect) out.push(k);
|
|
140
|
+
} else {
|
|
141
|
+
if (meta.autoAppendOnSingleSelect) out.push(k);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return out;
|
|
145
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
// GENERATED — DO NOT EDIT. Source: adapter-src/pi/extensions/ask-user-question/state/selectors/contract.ts
|
|
2
|
+
// Regenerate with: python3 scripts/build-adapters.py
|
|
3
|
+
import type { QuestionData } from "../../tool/types.js";
|
|
4
|
+
import type { PreviewPaneProps } from "../../view/components/preview/preview-pane.js";
|
|
5
|
+
import type { WrappingSelectItem } from "../../view/components/wrapping-select.js";
|
|
6
|
+
import type { ActiveView, StatefulView } from "../../view/stateful-view.js";
|
|
7
|
+
import type { TabComponents } from "../../view/tab-components.js";
|
|
8
|
+
import type { QuestionnaireState } from "../state.js";
|
|
9
|
+
|
|
10
|
+
export interface BindingContext {
|
|
11
|
+
readonly questions: readonly QuestionData[];
|
|
12
|
+
readonly itemsByTab: ReadonlyArray<readonly WrappingSelectItem[]>;
|
|
13
|
+
readonly totalQuestions: number;
|
|
14
|
+
readonly activeView: ActiveView;
|
|
15
|
+
readonly inputBuffer: string;
|
|
16
|
+
readonly inputCursorOffset: number | undefined;
|
|
17
|
+
readonly activePreviewPane: StatefulView<PreviewPaneProps>;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface PerTabBindingContext extends BindingContext {
|
|
21
|
+
readonly tab: TabComponents;
|
|
22
|
+
readonly i: number;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export type GlobalSelector<P> = (state: QuestionnaireState, ctx: BindingContext) => P;
|
|
26
|
+
export type PerTabSelector<P> = (state: QuestionnaireState, ctx: PerTabBindingContext) => P;
|