@garygentry/feature-forge 0.2.13 → 0.3.0
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/references/epic-manifest-schema.json +5 -0
- package/adapters/claude/references/forge-config-schema.json +2 -2
- package/adapters/claude/references/shared-conventions.md +12 -0
- package/adapters/claude/references/stacks/_generic.md +21 -0
- package/adapters/claude/references/stacks/go.md +19 -0
- package/adapters/claude/references/stacks/python.md +21 -0
- package/adapters/claude/references/stacks/rust.md +19 -0
- package/adapters/claude/references/stacks/typescript.md +23 -0
- package/adapters/claude/scripts/epic-manifest.py +75 -5
- package/adapters/claude/scripts/forge-root.sh +102 -14
- package/adapters/claude/scripts/forge-session.py +68 -9
- package/adapters/claude/skills/forge/references/shared-conventions.md +12 -0
- package/adapters/claude/skills/forge-0-epic/references/shared-conventions.md +12 -0
- package/adapters/claude/skills/forge-1-prd/SKILL.md +2 -0
- package/adapters/claude/skills/forge-1-prd/references/shared-conventions.md +12 -0
- package/adapters/claude/skills/forge-2-tech/SKILL.md +2 -0
- package/adapters/claude/skills/forge-2-tech/references/shared-conventions.md +12 -0
- package/adapters/claude/skills/forge-2-tech/references/stacks/_generic.md +21 -0
- package/adapters/claude/skills/forge-2-tech/references/stacks/go.md +19 -0
- package/adapters/claude/skills/forge-2-tech/references/stacks/python.md +21 -0
- package/adapters/claude/skills/forge-2-tech/references/stacks/rust.md +19 -0
- package/adapters/claude/skills/forge-2-tech/references/stacks/typescript.md +23 -0
- package/adapters/claude/skills/forge-3-specs/SKILL.md +2 -0
- package/adapters/claude/skills/forge-3-specs/references/shared-conventions.md +12 -0
- package/adapters/claude/skills/forge-3-specs/references/stacks/_generic.md +21 -0
- package/adapters/claude/skills/forge-3-specs/references/stacks/go.md +19 -0
- package/adapters/claude/skills/forge-3-specs/references/stacks/python.md +21 -0
- package/adapters/claude/skills/forge-3-specs/references/stacks/rust.md +19 -0
- package/adapters/claude/skills/forge-3-specs/references/stacks/typescript.md +23 -0
- package/adapters/claude/skills/forge-4-backlog/SKILL.md +5 -0
- package/adapters/claude/skills/forge-4-backlog/references/forge-config-schema.json +2 -2
- package/adapters/claude/skills/forge-4-backlog/references/shared-conventions.md +12 -0
- package/adapters/claude/skills/forge-5-loop/SKILL.md +7 -9
- package/adapters/claude/skills/forge-5-loop/references/forge-config-schema.json +2 -2
- package/adapters/claude/skills/forge-5-loop/references/runner-contract.md +41 -0
- package/adapters/claude/skills/forge-5-loop/references/shared-conventions.md +12 -0
- package/adapters/claude/skills/forge-6-docs/references/shared-conventions.md +12 -0
- package/adapters/claude/skills/forge-fix/references/shared-conventions.md +12 -0
- package/adapters/claude/skills/forge-guide/references/forge-config-schema.json +2 -2
- package/adapters/claude/skills/forge-guide/references/shared-conventions.md +12 -0
- package/adapters/claude/skills/forge-guide/references/stacks/_generic.md +21 -0
- package/adapters/claude/skills/forge-guide/references/stacks/go.md +19 -0
- package/adapters/claude/skills/forge-guide/references/stacks/python.md +21 -0
- package/adapters/claude/skills/forge-guide/references/stacks/rust.md +19 -0
- package/adapters/claude/skills/forge-guide/references/stacks/typescript.md +23 -0
- package/adapters/claude/skills/forge-verify/SKILL.md +3 -3
- package/adapters/claude/skills/forge-verify/references/shared-conventions.md +12 -0
- package/adapters/claude/skills/forge-verify/references/verification-checklists.md +82 -3
- package/adapters/codex/.feature-forge-bundle.json +1 -1
- package/adapters/codex/references/epic-manifest-schema.json +5 -0
- package/adapters/codex/references/forge-config-schema.json +2 -2
- package/adapters/codex/references/shared-conventions.md +12 -0
- package/adapters/codex/references/stacks/_generic.md +21 -0
- package/adapters/codex/references/stacks/go.md +19 -0
- package/adapters/codex/references/stacks/python.md +21 -0
- package/adapters/codex/references/stacks/rust.md +19 -0
- package/adapters/codex/references/stacks/typescript.md +23 -0
- package/adapters/codex/scripts/epic-manifest.py +75 -5
- package/adapters/codex/scripts/forge-root.sh +102 -14
- package/adapters/codex/scripts/forge-session.py +68 -9
- package/adapters/codex/skills/forge/references/shared-conventions.md +12 -0
- package/adapters/codex/skills/forge-0-epic/references/shared-conventions.md +12 -0
- package/adapters/codex/skills/forge-1-prd/SKILL.md +2 -0
- package/adapters/codex/skills/forge-1-prd/references/shared-conventions.md +12 -0
- package/adapters/codex/skills/forge-2-tech/SKILL.md +2 -0
- package/adapters/codex/skills/forge-2-tech/references/shared-conventions.md +12 -0
- package/adapters/codex/skills/forge-2-tech/references/stacks/_generic.md +21 -0
- package/adapters/codex/skills/forge-2-tech/references/stacks/go.md +19 -0
- package/adapters/codex/skills/forge-2-tech/references/stacks/python.md +21 -0
- package/adapters/codex/skills/forge-2-tech/references/stacks/rust.md +19 -0
- package/adapters/codex/skills/forge-2-tech/references/stacks/typescript.md +23 -0
- package/adapters/codex/skills/forge-3-specs/SKILL.md +2 -0
- package/adapters/codex/skills/forge-3-specs/references/shared-conventions.md +12 -0
- package/adapters/codex/skills/forge-3-specs/references/stacks/_generic.md +21 -0
- package/adapters/codex/skills/forge-3-specs/references/stacks/go.md +19 -0
- package/adapters/codex/skills/forge-3-specs/references/stacks/python.md +21 -0
- package/adapters/codex/skills/forge-3-specs/references/stacks/rust.md +19 -0
- package/adapters/codex/skills/forge-3-specs/references/stacks/typescript.md +23 -0
- package/adapters/codex/skills/forge-4-backlog/SKILL.md +5 -0
- package/adapters/codex/skills/forge-4-backlog/references/forge-config-schema.json +2 -2
- package/adapters/codex/skills/forge-4-backlog/references/shared-conventions.md +12 -0
- package/adapters/codex/skills/forge-5-loop/SKILL.md +7 -9
- package/adapters/codex/skills/forge-5-loop/references/forge-config-schema.json +2 -2
- package/adapters/codex/skills/forge-5-loop/references/runner-contract.md +41 -0
- package/adapters/codex/skills/forge-5-loop/references/shared-conventions.md +12 -0
- package/adapters/codex/skills/forge-6-docs/references/shared-conventions.md +12 -0
- package/adapters/codex/skills/forge-fix/references/shared-conventions.md +12 -0
- package/adapters/codex/skills/forge-guide/references/forge-config-schema.json +2 -2
- package/adapters/codex/skills/forge-guide/references/shared-conventions.md +12 -0
- package/adapters/codex/skills/forge-guide/references/stacks/_generic.md +21 -0
- package/adapters/codex/skills/forge-guide/references/stacks/go.md +19 -0
- package/adapters/codex/skills/forge-guide/references/stacks/python.md +21 -0
- package/adapters/codex/skills/forge-guide/references/stacks/rust.md +19 -0
- package/adapters/codex/skills/forge-guide/references/stacks/typescript.md +23 -0
- package/adapters/codex/skills/forge-verify/SKILL.md +3 -3
- package/adapters/codex/skills/forge-verify/references/shared-conventions.md +12 -0
- package/adapters/codex/skills/forge-verify/references/verification-checklists.md +82 -3
- package/adapters/copilot/.feature-forge-bundle.json +1 -1
- package/adapters/copilot/references/epic-manifest-schema.json +5 -0
- package/adapters/copilot/references/forge-config-schema.json +2 -2
- package/adapters/copilot/references/shared-conventions.md +12 -0
- package/adapters/copilot/references/stacks/_generic.md +21 -0
- package/adapters/copilot/references/stacks/go.md +19 -0
- package/adapters/copilot/references/stacks/python.md +21 -0
- package/adapters/copilot/references/stacks/rust.md +19 -0
- package/adapters/copilot/references/stacks/typescript.md +23 -0
- package/adapters/copilot/scripts/epic-manifest.py +75 -5
- package/adapters/copilot/scripts/forge-root.sh +102 -14
- package/adapters/copilot/scripts/forge-session.py +68 -9
- package/adapters/copilot/skills/forge/references/shared-conventions.md +12 -0
- package/adapters/copilot/skills/forge-0-epic/references/shared-conventions.md +12 -0
- package/adapters/copilot/skills/forge-1-prd/forge-1-prd.md +2 -0
- package/adapters/copilot/skills/forge-1-prd/references/shared-conventions.md +12 -0
- package/adapters/copilot/skills/forge-2-tech/forge-2-tech.md +2 -0
- package/adapters/copilot/skills/forge-2-tech/references/shared-conventions.md +12 -0
- package/adapters/copilot/skills/forge-2-tech/references/stacks/_generic.md +21 -0
- package/adapters/copilot/skills/forge-2-tech/references/stacks/go.md +19 -0
- package/adapters/copilot/skills/forge-2-tech/references/stacks/python.md +21 -0
- package/adapters/copilot/skills/forge-2-tech/references/stacks/rust.md +19 -0
- package/adapters/copilot/skills/forge-2-tech/references/stacks/typescript.md +23 -0
- package/adapters/copilot/skills/forge-3-specs/forge-3-specs.md +2 -0
- package/adapters/copilot/skills/forge-3-specs/references/shared-conventions.md +12 -0
- package/adapters/copilot/skills/forge-3-specs/references/stacks/_generic.md +21 -0
- package/adapters/copilot/skills/forge-3-specs/references/stacks/go.md +19 -0
- package/adapters/copilot/skills/forge-3-specs/references/stacks/python.md +21 -0
- package/adapters/copilot/skills/forge-3-specs/references/stacks/rust.md +19 -0
- package/adapters/copilot/skills/forge-3-specs/references/stacks/typescript.md +23 -0
- package/adapters/copilot/skills/forge-4-backlog/forge-4-backlog.md +5 -0
- package/adapters/copilot/skills/forge-4-backlog/references/forge-config-schema.json +2 -2
- package/adapters/copilot/skills/forge-4-backlog/references/shared-conventions.md +12 -0
- package/adapters/copilot/skills/forge-5-loop/forge-5-loop.md +7 -9
- package/adapters/copilot/skills/forge-5-loop/references/forge-config-schema.json +2 -2
- package/adapters/copilot/skills/forge-5-loop/references/runner-contract.md +41 -0
- package/adapters/copilot/skills/forge-5-loop/references/shared-conventions.md +12 -0
- package/adapters/copilot/skills/forge-6-docs/references/shared-conventions.md +12 -0
- package/adapters/copilot/skills/forge-fix/references/shared-conventions.md +12 -0
- package/adapters/copilot/skills/forge-guide/references/forge-config-schema.json +2 -2
- package/adapters/copilot/skills/forge-guide/references/shared-conventions.md +12 -0
- package/adapters/copilot/skills/forge-guide/references/stacks/_generic.md +21 -0
- package/adapters/copilot/skills/forge-guide/references/stacks/go.md +19 -0
- package/adapters/copilot/skills/forge-guide/references/stacks/python.md +21 -0
- package/adapters/copilot/skills/forge-guide/references/stacks/rust.md +19 -0
- package/adapters/copilot/skills/forge-guide/references/stacks/typescript.md +23 -0
- package/adapters/copilot/skills/forge-verify/forge-verify.md +3 -3
- package/adapters/copilot/skills/forge-verify/references/shared-conventions.md +12 -0
- package/adapters/copilot/skills/forge-verify/references/verification-checklists.md +82 -3
- package/adapters/cursor/.feature-forge-bundle.json +1 -1
- package/adapters/cursor/references/epic-manifest-schema.json +5 -0
- package/adapters/cursor/references/forge-config-schema.json +2 -2
- package/adapters/cursor/references/shared-conventions.md +12 -0
- package/adapters/cursor/references/stacks/_generic.md +21 -0
- package/adapters/cursor/references/stacks/go.md +19 -0
- package/adapters/cursor/references/stacks/python.md +21 -0
- package/adapters/cursor/references/stacks/rust.md +19 -0
- package/adapters/cursor/references/stacks/typescript.md +23 -0
- package/adapters/cursor/scripts/epic-manifest.py +75 -5
- package/adapters/cursor/scripts/forge-root.sh +102 -14
- package/adapters/cursor/scripts/forge-session.py +68 -9
- package/adapters/cursor/skills/forge/references/shared-conventions.md +12 -0
- package/adapters/cursor/skills/forge-0-epic/references/shared-conventions.md +12 -0
- package/adapters/cursor/skills/forge-1-prd/forge-1-prd.mdc +2 -0
- package/adapters/cursor/skills/forge-1-prd/references/shared-conventions.md +12 -0
- package/adapters/cursor/skills/forge-2-tech/forge-2-tech.mdc +2 -0
- package/adapters/cursor/skills/forge-2-tech/references/shared-conventions.md +12 -0
- package/adapters/cursor/skills/forge-2-tech/references/stacks/_generic.md +21 -0
- package/adapters/cursor/skills/forge-2-tech/references/stacks/go.md +19 -0
- package/adapters/cursor/skills/forge-2-tech/references/stacks/python.md +21 -0
- package/adapters/cursor/skills/forge-2-tech/references/stacks/rust.md +19 -0
- package/adapters/cursor/skills/forge-2-tech/references/stacks/typescript.md +23 -0
- package/adapters/cursor/skills/forge-3-specs/forge-3-specs.mdc +2 -0
- package/adapters/cursor/skills/forge-3-specs/references/shared-conventions.md +12 -0
- package/adapters/cursor/skills/forge-3-specs/references/stacks/_generic.md +21 -0
- package/adapters/cursor/skills/forge-3-specs/references/stacks/go.md +19 -0
- package/adapters/cursor/skills/forge-3-specs/references/stacks/python.md +21 -0
- package/adapters/cursor/skills/forge-3-specs/references/stacks/rust.md +19 -0
- package/adapters/cursor/skills/forge-3-specs/references/stacks/typescript.md +23 -0
- package/adapters/cursor/skills/forge-4-backlog/forge-4-backlog.mdc +5 -0
- package/adapters/cursor/skills/forge-4-backlog/references/forge-config-schema.json +2 -2
- package/adapters/cursor/skills/forge-4-backlog/references/shared-conventions.md +12 -0
- package/adapters/cursor/skills/forge-5-loop/forge-5-loop.mdc +7 -9
- package/adapters/cursor/skills/forge-5-loop/references/forge-config-schema.json +2 -2
- package/adapters/cursor/skills/forge-5-loop/references/runner-contract.md +41 -0
- package/adapters/cursor/skills/forge-5-loop/references/shared-conventions.md +12 -0
- package/adapters/cursor/skills/forge-6-docs/references/shared-conventions.md +12 -0
- package/adapters/cursor/skills/forge-fix/references/shared-conventions.md +12 -0
- package/adapters/cursor/skills/forge-guide/references/forge-config-schema.json +2 -2
- package/adapters/cursor/skills/forge-guide/references/shared-conventions.md +12 -0
- package/adapters/cursor/skills/forge-guide/references/stacks/_generic.md +21 -0
- package/adapters/cursor/skills/forge-guide/references/stacks/go.md +19 -0
- package/adapters/cursor/skills/forge-guide/references/stacks/python.md +21 -0
- package/adapters/cursor/skills/forge-guide/references/stacks/rust.md +19 -0
- package/adapters/cursor/skills/forge-guide/references/stacks/typescript.md +23 -0
- package/adapters/cursor/skills/forge-verify/forge-verify.mdc +3 -3
- package/adapters/cursor/skills/forge-verify/references/shared-conventions.md +12 -0
- package/adapters/cursor/skills/forge-verify/references/verification-checklists.md +82 -3
- package/adapters/gemini/.feature-forge-bundle.json +1 -1
- package/adapters/gemini/gemini-extension.json +1 -1
- package/adapters/gemini/references/epic-manifest-schema.json +5 -0
- package/adapters/gemini/references/forge-config-schema.json +2 -2
- package/adapters/gemini/references/shared-conventions.md +12 -0
- package/adapters/gemini/references/stacks/_generic.md +21 -0
- package/adapters/gemini/references/stacks/go.md +19 -0
- package/adapters/gemini/references/stacks/python.md +21 -0
- package/adapters/gemini/references/stacks/rust.md +19 -0
- package/adapters/gemini/references/stacks/typescript.md +23 -0
- package/adapters/gemini/scripts/epic-manifest.py +75 -5
- package/adapters/gemini/scripts/forge-root.sh +102 -14
- package/adapters/gemini/scripts/forge-session.py +68 -9
- package/adapters/gemini/skills/forge/references/shared-conventions.md +12 -0
- package/adapters/gemini/skills/forge-0-epic/references/shared-conventions.md +12 -0
- package/adapters/gemini/skills/forge-1-prd/forge-1-prd.md +2 -0
- package/adapters/gemini/skills/forge-1-prd/references/shared-conventions.md +12 -0
- package/adapters/gemini/skills/forge-2-tech/forge-2-tech.md +2 -0
- package/adapters/gemini/skills/forge-2-tech/references/shared-conventions.md +12 -0
- package/adapters/gemini/skills/forge-2-tech/references/stacks/_generic.md +21 -0
- package/adapters/gemini/skills/forge-2-tech/references/stacks/go.md +19 -0
- package/adapters/gemini/skills/forge-2-tech/references/stacks/python.md +21 -0
- package/adapters/gemini/skills/forge-2-tech/references/stacks/rust.md +19 -0
- package/adapters/gemini/skills/forge-2-tech/references/stacks/typescript.md +23 -0
- package/adapters/gemini/skills/forge-3-specs/forge-3-specs.md +2 -0
- package/adapters/gemini/skills/forge-3-specs/references/shared-conventions.md +12 -0
- package/adapters/gemini/skills/forge-3-specs/references/stacks/_generic.md +21 -0
- package/adapters/gemini/skills/forge-3-specs/references/stacks/go.md +19 -0
- package/adapters/gemini/skills/forge-3-specs/references/stacks/python.md +21 -0
- package/adapters/gemini/skills/forge-3-specs/references/stacks/rust.md +19 -0
- package/adapters/gemini/skills/forge-3-specs/references/stacks/typescript.md +23 -0
- package/adapters/gemini/skills/forge-4-backlog/forge-4-backlog.md +5 -0
- package/adapters/gemini/skills/forge-4-backlog/references/forge-config-schema.json +2 -2
- package/adapters/gemini/skills/forge-4-backlog/references/shared-conventions.md +12 -0
- package/adapters/gemini/skills/forge-5-loop/forge-5-loop.md +7 -9
- package/adapters/gemini/skills/forge-5-loop/references/forge-config-schema.json +2 -2
- package/adapters/gemini/skills/forge-5-loop/references/runner-contract.md +41 -0
- package/adapters/gemini/skills/forge-5-loop/references/shared-conventions.md +12 -0
- package/adapters/gemini/skills/forge-6-docs/references/shared-conventions.md +12 -0
- package/adapters/gemini/skills/forge-fix/references/shared-conventions.md +12 -0
- package/adapters/gemini/skills/forge-guide/references/forge-config-schema.json +2 -2
- package/adapters/gemini/skills/forge-guide/references/shared-conventions.md +12 -0
- package/adapters/gemini/skills/forge-guide/references/stacks/_generic.md +21 -0
- package/adapters/gemini/skills/forge-guide/references/stacks/go.md +19 -0
- package/adapters/gemini/skills/forge-guide/references/stacks/python.md +21 -0
- package/adapters/gemini/skills/forge-guide/references/stacks/rust.md +19 -0
- package/adapters/gemini/skills/forge-guide/references/stacks/typescript.md +23 -0
- package/adapters/gemini/skills/forge-verify/forge-verify.md +3 -3
- package/adapters/gemini/skills/forge-verify/references/shared-conventions.md +12 -0
- package/adapters/gemini/skills/forge-verify/references/verification-checklists.md +82 -3
- 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/pi/references/forge-config-schema.json +236 -0
- package/adapters/pi/references/pipeline-state-schema.json +191 -0
- 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 +295 -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 +258 -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 +1694 -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 +1888 -0
- package/adapters/pi/scripts/validate-traceability.py +150 -0
- package/adapters/pi/skills/forge/SKILL.md +243 -0
- package/adapters/pi/skills/forge/references/pipeline-state-schema.json +191 -0
- package/adapters/pi/skills/forge/references/process-overview.md +143 -0
- package/adapters/pi/skills/forge/references/shared-conventions.md +295 -0
- package/adapters/pi/skills/forge/references/stage-exit-protocol.md +258 -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/pi/skills/forge-0-epic/references/pipeline-state-schema.json +191 -0
- package/adapters/pi/skills/forge-0-epic/references/portable-root.md +71 -0
- package/adapters/pi/skills/forge-0-epic/references/shared-conventions.md +295 -0
- package/adapters/pi/skills/forge-0-epic/references/stage-exit-protocol.md +258 -0
- package/adapters/pi/skills/forge-1-prd/SKILL.md +164 -0
- package/adapters/pi/skills/forge-1-prd/references/pipeline-state-schema.json +191 -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 +295 -0
- package/adapters/pi/skills/forge-1-prd/references/stage-exit-protocol.md +258 -0
- package/adapters/pi/skills/forge-2-tech/SKILL.md +225 -0
- package/adapters/pi/skills/forge-2-tech/references/pipeline-state-schema.json +191 -0
- package/adapters/pi/skills/forge-2-tech/references/shared-conventions.md +295 -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 +258 -0
- package/adapters/pi/skills/forge-3-specs/SKILL.md +178 -0
- package/adapters/pi/skills/forge-3-specs/references/pipeline-state-schema.json +191 -0
- package/adapters/pi/skills/forge-3-specs/references/shared-conventions.md +295 -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 +258 -0
- package/adapters/pi/skills/forge-4-backlog/SKILL.md +175 -0
- package/adapters/pi/skills/forge-4-backlog/references/forge-config-schema.json +236 -0
- package/adapters/pi/skills/forge-4-backlog/references/pipeline-state-schema.json +191 -0
- package/adapters/pi/skills/forge-4-backlog/references/shared-conventions.md +295 -0
- package/adapters/pi/skills/forge-4-backlog/references/stage-exit-protocol.md +258 -0
- package/adapters/pi/skills/forge-5-loop/SKILL.md +314 -0
- package/adapters/pi/skills/forge-5-loop/references/forge-config-schema.json +236 -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 +341 -0
- package/adapters/pi/skills/forge-5-loop/references/shared-conventions.md +295 -0
- package/adapters/pi/skills/forge-5-loop/references/stage-exit-protocol.md +258 -0
- package/adapters/pi/skills/forge-6-docs/SKILL.md +202 -0
- package/adapters/pi/skills/forge-6-docs/references/doc-conventions.md +126 -0
- package/adapters/pi/skills/forge-6-docs/references/pipeline-state-schema.json +191 -0
- package/adapters/pi/skills/forge-6-docs/references/shared-conventions.md +295 -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 +295 -0
- package/adapters/pi/skills/forge-fix/references/stage-exit-protocol.md +258 -0
- package/adapters/pi/skills/forge-guide/SKILL.md +192 -0
- package/adapters/pi/skills/forge-guide/references/forge-config-schema.json +236 -0
- 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 +295 -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 +273 -0
- package/adapters/pi/skills/forge-verify/references/pipeline-state-schema.json +191 -0
- package/adapters/pi/skills/forge-verify/references/shared-conventions.md +295 -0
- package/adapters/pi/skills/forge-verify/references/verification-checklists.md +477 -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
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
// GENERATED — DO NOT EDIT. Source: adapter-src/pi/extensions/ask-user-question/ask-user-question.ts
|
|
2
|
+
// Regenerate with: python3 scripts/build-adapters.py
|
|
3
|
+
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
4
|
+
import { isKeyRelease, isKeyRepeat, matchesKey } from "@earendil-works/pi-tui";
|
|
5
|
+
import { loadConfig, resolveCollapseKey, validateGuidanceFields } from "./config.js";
|
|
6
|
+
import {
|
|
7
|
+
ASK_USER_BLOCKED_EVENT,
|
|
8
|
+
ASK_USER_PROMPT_EVENT,
|
|
9
|
+
type AskUserBlockedEventPayload,
|
|
10
|
+
type AskUserPromptEventPayload,
|
|
11
|
+
} from "./events.js";
|
|
12
|
+
// Static import is fine — rpc-fallback pulls only types + the i18n bridge,
|
|
13
|
+
// none of the ~560ms TUI render graph that QuestionnaireSession lazy-loads.
|
|
14
|
+
import { hasDialogUI, runRpcQuestionnaire } from "./rpc-fallback.js";
|
|
15
|
+
import { displayLabel } from "./state/i18n-bridge.js";
|
|
16
|
+
import { sentinelsToAppend } from "./state/row-intent.js";
|
|
17
|
+
import { buildQuestionnaireResponse, buildToolResult } from "./tool/response-envelope.js";
|
|
18
|
+
import {
|
|
19
|
+
MAX_OPTIONS,
|
|
20
|
+
MAX_QUESTIONS,
|
|
21
|
+
MIN_OPTIONS,
|
|
22
|
+
type QuestionData,
|
|
23
|
+
type QuestionnaireError,
|
|
24
|
+
type QuestionnaireResult,
|
|
25
|
+
type QuestionParams,
|
|
26
|
+
QuestionParamsSchema,
|
|
27
|
+
} from "./tool/types.js";
|
|
28
|
+
import { validateQuestionnaire } from "./tool/validate-questionnaire.js";
|
|
29
|
+
import type { WrappingSelectItem } from "./view/components/wrapping-select.js";
|
|
30
|
+
|
|
31
|
+
function emitAskUserPromptEvent(pi: ExtensionAPI, params: QuestionParams): void {
|
|
32
|
+
const payload: AskUserPromptEventPayload = {
|
|
33
|
+
questions: params.questions.map((q) => ({
|
|
34
|
+
question: q.question,
|
|
35
|
+
header: q.header,
|
|
36
|
+
multiSelect: q.multiSelect ?? false,
|
|
37
|
+
options: q.options.map((o) => ({
|
|
38
|
+
label: o.label,
|
|
39
|
+
description: o.description,
|
|
40
|
+
hasPreview: typeof o.preview === "string" && o.preview.length > 0,
|
|
41
|
+
})),
|
|
42
|
+
})),
|
|
43
|
+
};
|
|
44
|
+
pi.events.emit(ASK_USER_PROMPT_EVENT, payload);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function emitAskUserBlockedEvent(pi: ExtensionAPI, active: boolean): void {
|
|
48
|
+
const payload: AskUserBlockedEventPayload = { active };
|
|
49
|
+
pi.events.emit(ASK_USER_BLOCKED_EVENT, payload);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** Canonical tool name — single source of truth shared with the reconcile module. */
|
|
53
|
+
export const ASK_USER_QUESTION_TOOL_NAME = "AskUserQuestion"; // FEATURE-FORGE VENDOR PATCH: Claude-parity name
|
|
54
|
+
|
|
55
|
+
const ERROR_NO_UI = "Error: UI not available (running in non-interactive mode)";
|
|
56
|
+
|
|
57
|
+
const ERROR_NO_CUSTOM_UI =
|
|
58
|
+
"Error: this client cannot render the questionnaire (custom UI is unavailable, e.g. RPC/ACP hosts such as Zed or Paseo). The user never saw the questions — do NOT treat this as a decline. Ask the questions as plain chat text instead, without using this tool.";
|
|
59
|
+
|
|
60
|
+
const ERROR_SESSION_LOAD_FAILED =
|
|
61
|
+
"Error: the questionnaire UI failed to load — the host's installed dependencies were likely replaced or removed on disk while Pi was running (e.g. a package-manager install touched the store). The user never saw the questions — do NOT treat this as a decline. Ask the questions as plain chat text instead, and tell the user that restoring this tool requires repairing the install if needed and restarting Pi.";
|
|
62
|
+
|
|
63
|
+
const ERROR_STALE_MODULE_CACHE =
|
|
64
|
+
"Error: the questionnaire UI cannot load — the host's module cache went stale after an earlier failed load (typically dependencies replaced on disk mid-session). This is unrecoverable within the current Pi process. The user never saw the questions — do NOT treat this as a decline. Ask the questions as plain chat text instead, and tell the user to restart Pi to restore this tool.";
|
|
65
|
+
|
|
66
|
+
/** Delay before the background session-graph pre-warm; mirrors rpiv-workflow's /wf prewarm. */
|
|
67
|
+
export const PREWARM_DELAY_MS = 2000;
|
|
68
|
+
|
|
69
|
+
type SessionModule = typeof import("./state/questionnaire-session.js");
|
|
70
|
+
|
|
71
|
+
type SessionLoad =
|
|
72
|
+
| { ok: true; module: SessionModule }
|
|
73
|
+
| { ok: false; error: Extract<QuestionnaireError, "session_load_failed" | "stale_module_cache">; message: string };
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Lazy-load the ~560ms QuestionnaireSession view/TUI render graph, guarding
|
|
77
|
+
* the two failure shapes of issue #107. Pi's jiti loader registers a module in
|
|
78
|
+
* its graph cache BEFORE evaluating the body and does not evict it when
|
|
79
|
+
* evaluation throws (jiti 2.7.0), so one failed load — e.g. `pnpm install
|
|
80
|
+
* --force` replacing the store entry mid-session — leaves every later import
|
|
81
|
+
* of this specifier resolving to a namespace without the class. That state is
|
|
82
|
+
* unrecoverable in-process (cache-busting specifiers fail jiti resolution);
|
|
83
|
+
* both branches therefore return an LLM-facing envelope that names the restart
|
|
84
|
+
* requirement instead of leaking a bare "not a constructor" TypeError.
|
|
85
|
+
*/
|
|
86
|
+
export async function loadQuestionnaireSession(): Promise<SessionLoad> {
|
|
87
|
+
let mod: SessionModule;
|
|
88
|
+
try {
|
|
89
|
+
mod = await import("./state/questionnaire-session.js");
|
|
90
|
+
} catch (e) {
|
|
91
|
+
const cause = e instanceof Error ? e.message : String(e);
|
|
92
|
+
return { ok: false, error: "session_load_failed", message: `${ERROR_SESSION_LOAD_FAILED} (cause: ${cause})` };
|
|
93
|
+
}
|
|
94
|
+
if (typeof mod.QuestionnaireSession !== "function") {
|
|
95
|
+
const keys = JSON.stringify(Object.keys(mod));
|
|
96
|
+
return {
|
|
97
|
+
ok: false,
|
|
98
|
+
error: "stale_module_cache",
|
|
99
|
+
message: `${ERROR_STALE_MODULE_CACHE} (resolved namespace keys: ${keys})`,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
return { ok: true, module: mod };
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export function buildItemsForQuestion(question: QuestionData): WrappingSelectItem[] {
|
|
106
|
+
const items: WrappingSelectItem[] = question.options.map((o) => ({
|
|
107
|
+
kind: "option",
|
|
108
|
+
label: o.label,
|
|
109
|
+
description: o.description,
|
|
110
|
+
}));
|
|
111
|
+
for (const kind of sentinelsToAppend(question)) {
|
|
112
|
+
items.push({ kind, label: displayLabel(kind) });
|
|
113
|
+
}
|
|
114
|
+
return items;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export const DEFAULT_PROMPT_SNIPPET = `Ask the user up to ${MAX_QUESTIONS} structured questions (${MIN_OPTIONS}-${MAX_OPTIONS} options each) when requirements are ambiguous`;
|
|
118
|
+
export const DEFAULT_PROMPT_GUIDELINES: string[] = [
|
|
119
|
+
`Use ask_user_question whenever the user's request is underspecified and you cannot proceed without concrete decisions — you can ask up to ${MAX_QUESTIONS} questions per invocation.`,
|
|
120
|
+
`Each question MUST have ${MIN_OPTIONS}-${MAX_OPTIONS} options. Every option requires a concise label (1-5 words) and a description explaining what the choice means or its trade-offs. The user can additionally type a custom answer via the automatically appended "Type something." row on every question, or press Esc to abandon the questionnaire. Do NOT author "Other" or "Type something." labels yourself — reserved labels are rejected at runtime.`,
|
|
121
|
+
`Set multiSelect: true when multiple answers are valid. Provide an options[].preview markdown string when an option benefits from richer side-by-side context (mockups, code snippets, diagrams, configs) — single-select only. The "Type something." row is appended to every question; in preview mode it expands to the full pane width while typing so the custom answer is not cramped into the narrow options column. If you recommend a specific option, make that the first option and append "(Recommended)" to its label.`,
|
|
122
|
+
"Do not stack multiple ask_user_question calls back-to-back — group all clarifying questions into one invocation.",
|
|
123
|
+
];
|
|
124
|
+
|
|
125
|
+
export function registerAskUserQuestionTool(pi: ExtensionAPI): void {
|
|
126
|
+
const guidance = validateGuidanceFields(loadConfig().guidance);
|
|
127
|
+
pi.registerTool({
|
|
128
|
+
name: ASK_USER_QUESTION_TOOL_NAME,
|
|
129
|
+
label: "Ask User Question",
|
|
130
|
+
description: `Ask the user one or more structured questions during execution. Use when you need to:
|
|
131
|
+
1. Gather user preferences or requirements
|
|
132
|
+
2. Clarify ambiguous instructions
|
|
133
|
+
3. Get decisions on implementation choices as you work
|
|
134
|
+
4. Offer choices to the user about what direction to take
|
|
135
|
+
|
|
136
|
+
Usage notes:
|
|
137
|
+
- Users can type a custom answer via the automatically appended "Type something." row on every question or press Esc to abandon the questionnaire. Do NOT author "Other" or "Type something." labels yourself — reserved labels are rejected at runtime.
|
|
138
|
+
- Use multiSelect: true when multiple answers are valid. The "Type something." row is available on every question, including when options carry a \`preview\`; in preview mode it expands to the full pane width while typing so the custom answer is not cramped into the narrow options column.
|
|
139
|
+
- If you recommend a specific option, make that the first option in the list and add "(Recommended)" at the end of the label.
|
|
140
|
+
|
|
141
|
+
Preview feature:
|
|
142
|
+
Use the optional \`preview\` field on options when presenting concrete artifacts that users need to visually compare:
|
|
143
|
+
- ASCII mockups of UI layouts or components
|
|
144
|
+
- Code snippets showing different implementations
|
|
145
|
+
- Diagram variations
|
|
146
|
+
- Configuration examples
|
|
147
|
+
|
|
148
|
+
Preview content is rendered as markdown in a monospace box. Multi-line text with newlines is supported. When any option has a preview, the UI switches to a side-by-side layout with a vertical option list on the left and preview on the right. Do not use previews for simple preference questions where labels and descriptions suffice. Note: previews are only supported for single-select questions (not multiSelect).`,
|
|
149
|
+
promptSnippet: guidance.promptSnippet ?? DEFAULT_PROMPT_SNIPPET,
|
|
150
|
+
promptGuidelines: guidance.promptGuidelines ?? DEFAULT_PROMPT_GUIDELINES,
|
|
151
|
+
parameters: QuestionParamsSchema,
|
|
152
|
+
|
|
153
|
+
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
154
|
+
const typed = params as unknown as QuestionParams;
|
|
155
|
+
if (!ctx.hasUI) return buildToolResult(ERROR_NO_UI, { answers: [], cancelled: true, error: "no_ui" });
|
|
156
|
+
|
|
157
|
+
const validation = validateQuestionnaire(typed);
|
|
158
|
+
if (!validation.ok) {
|
|
159
|
+
return buildToolResult(validation.message, {
|
|
160
|
+
answers: [],
|
|
161
|
+
cancelled: true,
|
|
162
|
+
error: validation.error,
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Emit event for external listeners (e.g., notification plugins)
|
|
167
|
+
emitAskUserPromptEvent(pi, typed);
|
|
168
|
+
|
|
169
|
+
// RPC hosts (VSCode pendant, ACP clients like Zed/Paseo — issue #78):
|
|
170
|
+
// ui.custom() cannot render there, but the select/input dialog
|
|
171
|
+
// sub-protocol works. Hosts that advertise ctx.mode (pi ≥0.79) route to
|
|
172
|
+
// the sequential dialog walker up front, skipping the TUI render-graph
|
|
173
|
+
// import entirely; RPC builds that predate ctx.mode are caught by the
|
|
174
|
+
// custom()-resolved-undefined backstop below. See ./rpc-fallback.ts.
|
|
175
|
+
if ((ctx as { mode?: string }).mode === "rpc" && hasDialogUI(ctx.ui)) {
|
|
176
|
+
emitAskUserBlockedEvent(pi, true);
|
|
177
|
+
try {
|
|
178
|
+
return buildQuestionnaireResponse(await runRpcQuestionnaire(ctx.ui, typed), typed);
|
|
179
|
+
} finally {
|
|
180
|
+
emitAskUserBlockedEvent(pi, false);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
const itemsByTab: WrappingSelectItem[][] = typed.questions.map((q) => buildItemsForQuestion(q));
|
|
185
|
+
|
|
186
|
+
// Lazy — QuestionnaireSession pulls the ~560ms view/TUI render graph;
|
|
187
|
+
// load it only when the tool runs, not at extension registration.
|
|
188
|
+
const sessionLoad = await loadQuestionnaireSession();
|
|
189
|
+
if (!sessionLoad.ok) {
|
|
190
|
+
return buildToolResult(sessionLoad.message, { answers: [], cancelled: true, error: sessionLoad.error });
|
|
191
|
+
}
|
|
192
|
+
const { QuestionnaireSession } = sessionLoad.module;
|
|
193
|
+
// Resolve the collapse/expand key spec from config. Default is `ctrl+]`; users
|
|
194
|
+
// with non-US layouts (e.g. Latin American, where `]` is shifted) can override
|
|
195
|
+
// via the `collapseKey` config field. `resolveCollapseKey` also accepts the
|
|
196
|
+
// sentinel value `"off"` to disable the shortcut entirely.
|
|
197
|
+
const collapseKey = resolveCollapseKey(loadConfig());
|
|
198
|
+
|
|
199
|
+
// Capture the overlay handle so the session can call `setHidden()` when the
|
|
200
|
+
// user toggles collapse, and register a raw terminal input listener for the
|
|
201
|
+
// same key so the toggle still works while the overlay is hidden (pi-tui does
|
|
202
|
+
// not route input to a hidden overlay's `component.handleInput`).
|
|
203
|
+
const sessionRef: {
|
|
204
|
+
current: import("./state/questionnaire-session.js").QuestionnaireSession | null;
|
|
205
|
+
} = { current: null };
|
|
206
|
+
const overlayHandleRef: { current: import("@earendil-works/pi-tui").OverlayHandle | undefined } = {
|
|
207
|
+
current: undefined,
|
|
208
|
+
};
|
|
209
|
+
let hasAnnouncedHide = false;
|
|
210
|
+
let removeOverlayInputListener: (() => void) | undefined;
|
|
211
|
+
|
|
212
|
+
if (collapseKey !== "off" && typeof ctx.ui.onTerminalInput === "function") {
|
|
213
|
+
removeOverlayInputListener = ctx.ui.onTerminalInput((data) => {
|
|
214
|
+
const handle = overlayHandleRef.current;
|
|
215
|
+
if (!handle) return undefined;
|
|
216
|
+
// Only act while the questionnaire is hidden (its handleInput is
|
|
217
|
+
// unreachable) or actually focused. When some other overlay is on
|
|
218
|
+
// top (e.g. `/btw`), leave the keystroke to that overlay instead of
|
|
219
|
+
// toggling the questionnaire from underneath it.
|
|
220
|
+
if (!handle.isHidden() && !handle.isFocused()) return undefined;
|
|
221
|
+
if (!matchesKey(data, collapseKey as Parameters<typeof matchesKey>[1])) return undefined;
|
|
222
|
+
// Kitty-protocol terminals report press, repeat, and release separately.
|
|
223
|
+
// Toggle only on the initial press so a tap does not immediately reopen
|
|
224
|
+
// the overlay and a held key does not toggle it repeatedly.
|
|
225
|
+
if (isKeyRelease(data) || isKeyRepeat(data)) return { consume: true };
|
|
226
|
+
sessionRef.current?.toggleCollapsedExternal();
|
|
227
|
+
if (handle.isHidden() && !hasAnnouncedHide) {
|
|
228
|
+
hasAnnouncedHide = true;
|
|
229
|
+
ctx.ui.notify?.(`ask_user_question hidden — press ${collapseKey} to reopen`, "info");
|
|
230
|
+
}
|
|
231
|
+
return { consume: true };
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
emitAskUserBlockedEvent(pi, true);
|
|
236
|
+
try {
|
|
237
|
+
const result = await ctx.ui.custom<QuestionnaireResult>(
|
|
238
|
+
(tui, theme, _kb, done) => {
|
|
239
|
+
const session = new QuestionnaireSession({
|
|
240
|
+
tui,
|
|
241
|
+
theme,
|
|
242
|
+
params: typed,
|
|
243
|
+
itemsByTab,
|
|
244
|
+
done,
|
|
245
|
+
collapseKey,
|
|
246
|
+
});
|
|
247
|
+
sessionRef.current = session;
|
|
248
|
+
return session.component;
|
|
249
|
+
},
|
|
250
|
+
{
|
|
251
|
+
overlay: true,
|
|
252
|
+
overlayOptions: {
|
|
253
|
+
anchor: "bottom-center",
|
|
254
|
+
width: "100%",
|
|
255
|
+
maxHeight: "100%",
|
|
256
|
+
margin: { left: 0, right: 0, bottom: 0 },
|
|
257
|
+
},
|
|
258
|
+
onHandle: (handle) => {
|
|
259
|
+
overlayHandleRef.current = handle;
|
|
260
|
+
sessionRef.current?.setOverlayHandle(handle);
|
|
261
|
+
},
|
|
262
|
+
},
|
|
263
|
+
);
|
|
264
|
+
|
|
265
|
+
// A TUI questionnaire ALWAYS resolves a QuestionnaireResult (cancel
|
|
266
|
+
// included — state-reducer emits `{ answers, cancelled }`), so
|
|
267
|
+
// `undefined` uniquely means "host cannot render", never "user
|
|
268
|
+
// declined". RPC builds that predate ctx.mode land here: run the
|
|
269
|
+
// dialog walker when the host has the primitives; otherwise tell the
|
|
270
|
+
// model the user never saw the questions.
|
|
271
|
+
if (result === undefined) {
|
|
272
|
+
if (hasDialogUI(ctx.ui)) {
|
|
273
|
+
return buildQuestionnaireResponse(await runRpcQuestionnaire(ctx.ui, typed), typed);
|
|
274
|
+
}
|
|
275
|
+
return buildToolResult(ERROR_NO_CUSTOM_UI, { answers: [], cancelled: true, error: "no_custom_ui" });
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
return buildQuestionnaireResponse(result, typed);
|
|
279
|
+
} finally {
|
|
280
|
+
removeOverlayInputListener?.();
|
|
281
|
+
emitAskUserBlockedEvent(pi, false);
|
|
282
|
+
}
|
|
283
|
+
},
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
// Pre-warm the lazy session graph once startup settles (#107). A graph
|
|
287
|
+
// evaluated while the paths Pi resolved at boot still exist stays in memory
|
|
288
|
+
// for the process lifetime, so later on-disk dependency churn (e.g. `pnpm
|
|
289
|
+
// install --force` replacing the store mid-session) can no longer poison
|
|
290
|
+
// jiti's graph cache. Swallowed failure is safe: the first real call
|
|
291
|
+
// re-imports and surfaces it through loadQuestionnaireSession's structured
|
|
292
|
+
// envelope. unref keeps the timer from holding a non-TUI embedder's process
|
|
293
|
+
// open.
|
|
294
|
+
const timer = setTimeout(() => void loadQuestionnaireSession().catch(() => undefined), PREWARM_DELAY_MS);
|
|
295
|
+
timer.unref?.();
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
export { buildQuestionnaireResponse, buildToolResult };
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
// GENERATED — DO NOT EDIT. Source: adapter-src/pi/extensions/ask-user-question/config.ts
|
|
2
|
+
// Regenerate with: python3 scripts/build-adapters.py
|
|
3
|
+
// FEATURE-FORGE VENDOR PATCH: upstream imports these from @juicesharp/rpiv-config.
|
|
4
|
+
import type { GuidanceFields } from "./vendor-config-shim.js";
|
|
5
|
+
import { loadJsonConfigWithLegacyFallback, validateGuidanceFields } from "./vendor-config-shim.js";
|
|
6
|
+
|
|
7
|
+
/** Key spec for the overlay collapse/expand shortcut, e.g. `"ctrl+]"` or `"alt+o"`. */
|
|
8
|
+
export type CollapseKeySpec = string;
|
|
9
|
+
|
|
10
|
+
export const DEFAULT_COLLAPSE_KEY: CollapseKeySpec = "ctrl+]";
|
|
11
|
+
export const COLLAPSE_KEY_OFF: CollapseKeySpec = "off";
|
|
12
|
+
|
|
13
|
+
export interface AskUserQuestionConfig {
|
|
14
|
+
guidance?: GuidanceFields;
|
|
15
|
+
/**
|
|
16
|
+
* Key spec for the collapse/expand shortcut, in the same format as pi-coding-agent
|
|
17
|
+
* keybinding ids (`modifier+key`, e.g. `ctrl+]`, `alt+o`, `ctrl+shift+h`). Defaults
|
|
18
|
+
* to `"ctrl+]"`. Set this to a key that is reachable on your keyboard layout — Latin
|
|
19
|
+
* American layouts (where `]` is on the shifted layer) often want `"ctrl+}"` instead.
|
|
20
|
+
* Pass `"off"` to disable the collapse shortcut entirely.
|
|
21
|
+
*/
|
|
22
|
+
collapseKey?: CollapseKeySpec;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// Named keys accepted by pi-tui's `matchesKey` (keys.js switch on the parsed base key).
|
|
26
|
+
// parseKeyId lowercases the id before matching, so lowercase spellings are canonical.
|
|
27
|
+
const SPECIAL_KEYS = new Set([
|
|
28
|
+
"escape",
|
|
29
|
+
"esc",
|
|
30
|
+
"enter",
|
|
31
|
+
"return",
|
|
32
|
+
"tab",
|
|
33
|
+
"space",
|
|
34
|
+
"backspace",
|
|
35
|
+
"delete",
|
|
36
|
+
"insert",
|
|
37
|
+
"clear",
|
|
38
|
+
"home",
|
|
39
|
+
"end",
|
|
40
|
+
"pageup",
|
|
41
|
+
"pagedown",
|
|
42
|
+
"up",
|
|
43
|
+
"down",
|
|
44
|
+
"left",
|
|
45
|
+
"right",
|
|
46
|
+
...Array.from({ length: 12 }, (_, i) => `f${i + 1}`),
|
|
47
|
+
]);
|
|
48
|
+
|
|
49
|
+
const MODIFIERS = new Set(["ctrl", "shift", "alt", "super"]);
|
|
50
|
+
|
|
51
|
+
function isValidCollapseKeySpec(spec: string): boolean {
|
|
52
|
+
// Mirror pi-tui's KeyId grammar strictly: zero or more distinct modifiers, then a
|
|
53
|
+
// base key that is a single printable character or a named special key. A loose
|
|
54
|
+
// check is not enough — pi-tui's `parseKeyId` takes the LAST `+`-part as the key
|
|
55
|
+
// and ignores unknown parts, so a typo like `ctr+]` would silently match every
|
|
56
|
+
// bare `]` keypress (and the raw terminal listener would consume them globally).
|
|
57
|
+
if (!spec) return false;
|
|
58
|
+
if (spec.startsWith("+") || spec.endsWith("+") || spec.includes("++")) return false;
|
|
59
|
+
const parts = spec.split("+");
|
|
60
|
+
const base = parts[parts.length - 1] ?? "";
|
|
61
|
+
const modifiers = parts.slice(0, -1);
|
|
62
|
+
if (modifiers.length !== new Set(modifiers).size) return false;
|
|
63
|
+
if (!modifiers.every((m) => MODIFIERS.has(m))) return false;
|
|
64
|
+
return base.length === 1 ? /[a-z0-9_\-!@#$%^&*()|~`'":;,./<>?[\]{}=\\]/.test(base) : SPECIAL_KEYS.has(base);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function resolveCollapseKey(config: Pick<AskUserQuestionConfig, "collapseKey">): CollapseKeySpec {
|
|
68
|
+
const raw = config.collapseKey?.trim().toLowerCase();
|
|
69
|
+
if (raw === undefined || raw === "") return DEFAULT_COLLAPSE_KEY;
|
|
70
|
+
if (raw === COLLAPSE_KEY_OFF) return COLLAPSE_KEY_OFF;
|
|
71
|
+
return isValidCollapseKeySpec(raw) ? raw : DEFAULT_COLLAPSE_KEY;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export function loadConfig(): AskUserQuestionConfig {
|
|
75
|
+
return loadJsonConfigWithLegacyFallback<AskUserQuestionConfig>("rpiv-ask-user-question");
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export { validateGuidanceFields };
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
// GENERATED — DO NOT EDIT. Source: adapter-src/pi/extensions/ask-user-question/events.ts
|
|
2
|
+
// Regenerate with: python3 scripts/build-adapters.py
|
|
3
|
+
/**
|
|
4
|
+
* Public event contract for @juicesharp/rpiv-ask-user-question.
|
|
5
|
+
*
|
|
6
|
+
* STABILITY POLICY — applies to every event in the `rpiv:*` namespace.
|
|
7
|
+
*
|
|
8
|
+
* 1. Channel names are immutable. Once shipped, never rename.
|
|
9
|
+
* 2. Payload changes are append-only. Listeners MUST tolerate unknown
|
|
10
|
+
* fields. New fields ship as optional (`?:`).
|
|
11
|
+
* 3. Breaking changes (rename, retype, remove a field; change emission
|
|
12
|
+
* semantics) require a NEW channel, e.g. `rpiv:ask-user:prompt.v2`,
|
|
13
|
+
* with dual-emit during a deprecation window.
|
|
14
|
+
* 4. No `version` field inside payloads. Version via channel name only.
|
|
15
|
+
* 5. Payloads must be JSON-safe: primitives, arrays, plain objects.
|
|
16
|
+
* No Set/Map/Date/class instances — payloads must survive JSON
|
|
17
|
+
* serialization when listeners forward them across process or
|
|
18
|
+
* network boundaries.
|
|
19
|
+
*
|
|
20
|
+
* Naming: `rpiv:<package-or-tool>:<phase>`, lowercase, hyphen-separated.
|
|
21
|
+
* Aligns with Pi's `"my-extension:status"` example and UniPi's `unipi:*`.
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
export const ASK_USER_PROMPT_EVENT = "rpiv:ask-user:prompt" as const;
|
|
25
|
+
|
|
26
|
+
export interface AskUserPromptEventPayload {
|
|
27
|
+
questions: ReadonlyArray<AskUserPromptQuestion>;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Emitted while the questionnaire is awaiting user input (TUI `ui.custom` and
|
|
32
|
+
* RPC dialog walker). Cleared with `{ active: false }` in `finally` so listeners
|
|
33
|
+
* can distinguish blocked-on-human from working.
|
|
34
|
+
*/
|
|
35
|
+
export const ASK_USER_BLOCKED_EVENT = "rpiv:ask-user:blocked" as const;
|
|
36
|
+
|
|
37
|
+
export interface AskUserBlockedEventPayload {
|
|
38
|
+
/** True while input is awaited; false when the wait ends (answer, cancel, or error). */
|
|
39
|
+
active: boolean;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export interface AskUserPromptQuestion {
|
|
43
|
+
/** The full question text, exactly as the agent authored it. */
|
|
44
|
+
question: string;
|
|
45
|
+
/** The short chip/tag shown next to the question. */
|
|
46
|
+
header: string;
|
|
47
|
+
/** True iff the user may pick multiple options. Normalized from optional. */
|
|
48
|
+
multiSelect: boolean;
|
|
49
|
+
options: ReadonlyArray<AskUserPromptOption>;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export interface AskUserPromptOption {
|
|
53
|
+
label: string;
|
|
54
|
+
description: string;
|
|
55
|
+
/** True iff the option carries rich preview content (content not shipped). */
|
|
56
|
+
hasPreview: boolean;
|
|
57
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
// GENERATED — DO NOT EDIT. Source: adapter-src/pi/extensions/ask-user-question/index.ts
|
|
2
|
+
// Regenerate with: python3 scripts/build-adapters.py
|
|
3
|
+
/**
|
|
4
|
+
* rpiv-ask-user-question — Pi extension. Registers the `ask_user_question`
|
|
5
|
+
* tool: a structured option selector with an automatically appended
|
|
6
|
+
* `Type something.` custom-answer row.
|
|
7
|
+
*
|
|
8
|
+
* Sentinel labels and TUI chrome strings localize at render time via the i18n
|
|
9
|
+
* bridge. Strings are registered with rpiv-i18n here, once, at module init —
|
|
10
|
+
* but only when the SDK is actually installed. If `@juicesharp/rpiv-i18n` is
|
|
11
|
+
* missing (standalone install of just this package), the dynamic-load shim
|
|
12
|
+
* no-ops and the bridge's `t(key, fallback)` returns the inline English literal
|
|
13
|
+
* at every call site. The extension stays online either way.
|
|
14
|
+
*
|
|
15
|
+
* Adding a locale: drop `locales/<code>.json` next to en.json (mirroring the
|
|
16
|
+
* key set). No edit needed here — `registerLocalesFromDir` iterates
|
|
17
|
+
* `SUPPORTED_LOCALES` from the SDK. See `@juicesharp/rpiv-i18n` README →
|
|
18
|
+
* "Contributing translations" for the full convention.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
22
|
+
import { dirname } from "node:path"; // FEATURE-FORGE VENDOR PATCH
|
|
23
|
+
import { fileURLToPath } from "node:url"; // FEATURE-FORGE VENDOR PATCH
|
|
24
|
+
import { registerAskUserQuestionTool } from "./ask-user-question.js";
|
|
25
|
+
import { registerAskUserQuestionReconciler } from "./reconcile.js";
|
|
26
|
+
import { I18N_NAMESPACE } from "./state/i18n-bridge.js";
|
|
27
|
+
|
|
28
|
+
type I18nLoader = {
|
|
29
|
+
registerLocalesFromDir: (namespace: string, packageUrl: string, options?: { label?: string }) => void;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
// Dynamic import keeps `@juicesharp/rpiv-i18n` a soft optional peer: when the
|
|
33
|
+
// SDK is installed alongside this package the strings register and
|
|
34
|
+
// `/languages` flips them live; when it isn't, the import rejects here, we
|
|
35
|
+
// no-op, and the bridge's English-fallback shim keeps the extension online.
|
|
36
|
+
//
|
|
37
|
+
// The `/loader` subpath is used instead of the SDK entry so the i18n-ui +
|
|
38
|
+
// pi-tui modules are not pulled into our load graph just to register strings.
|
|
39
|
+
try {
|
|
40
|
+
const sdk = (await import("@juicesharp/rpiv-i18n/loader")) as I18nLoader;
|
|
41
|
+
sdk.registerLocalesFromDir(I18N_NAMESPACE, import.meta.url, { label: "rpiv-ask-user-question" });
|
|
42
|
+
} catch {
|
|
43
|
+
// SDK absent — extension still loads with English-only UI.
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export {
|
|
47
|
+
ASK_USER_BLOCKED_EVENT,
|
|
48
|
+
ASK_USER_PROMPT_EVENT,
|
|
49
|
+
type AskUserBlockedEventPayload,
|
|
50
|
+
type AskUserPromptEventPayload,
|
|
51
|
+
type AskUserPromptOption,
|
|
52
|
+
type AskUserPromptQuestion,
|
|
53
|
+
} from "./events.js";
|
|
54
|
+
|
|
55
|
+
export default function (pi: ExtensionAPI) {
|
|
56
|
+
// FEATURE-FORGE VENDOR PATCH: seed the bundle root so generated forge shell
|
|
57
|
+
// snippets prefer this active Pi adapter over unrelated local installs.
|
|
58
|
+
process.env.FEATURE_FORGE_ROOT ||= dirname(dirname(dirname(fileURLToPath(import.meta.url))));
|
|
59
|
+
registerAskUserQuestionTool(pi);
|
|
60
|
+
registerAskUserQuestionReconciler(pi);
|
|
61
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"_meta.notes": "Auto-translated draft. Native-speaker review welcome via PR. TUI symbols (↑/↓, ⚠) and key names (Enter, Esc, Tab, Space, n) are universal CLI conventions and stay untranslated.",
|
|
3
|
+
|
|
4
|
+
"sentinel.other": "Schreibe etwas.",
|
|
5
|
+
"sentinel.next": "Weiter",
|
|
6
|
+
|
|
7
|
+
"submit.label": "Antworten senden",
|
|
8
|
+
"submit.cancel": "Abbrechen",
|
|
9
|
+
|
|
10
|
+
"hint.enter": "Enter zum Auswählen",
|
|
11
|
+
"hint.navigate": "↑/↓ zur Navigation",
|
|
12
|
+
"hint.toggle": "Leertaste zum Umschalten",
|
|
13
|
+
"hint.notes": "n für Notizen",
|
|
14
|
+
"hint.tab": "Tab wechselt die Frage",
|
|
15
|
+
"hint.cancel": "Esc zum Abbrechen",
|
|
16
|
+
|
|
17
|
+
"review.heading": "Antworten überprüfen",
|
|
18
|
+
"review.ready": "Bereit, deine Antworten zu senden?",
|
|
19
|
+
"review.incomplete": "⚠ Beantworte die verbleibenden Fragen vor dem Senden:",
|
|
20
|
+
|
|
21
|
+
"preview.no_preview": "Keine Vorschau verfügbar",
|
|
22
|
+
"preview.notes_affordance": "Notizen: drücke n, um Notizen hinzuzufügen",
|
|
23
|
+
"notes.header": "Notizen:",
|
|
24
|
+
|
|
25
|
+
"rpc.multi_instructions": "Gib die Nummern aller zutreffenden Optionen durch Komma getrennt ein (z. B. \"1,3\") oder tippe eine eigene Antwort als Text.",
|
|
26
|
+
"rpc.custom_answer_title": "Gib deine Antwort ein:"
|
|
27
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"sentinel.other": "Type something.",
|
|
3
|
+
"sentinel.next": "Next",
|
|
4
|
+
|
|
5
|
+
"submit.label": "Submit answers",
|
|
6
|
+
"submit.cancel": "Cancel",
|
|
7
|
+
|
|
8
|
+
"hint.enter": "Enter to select",
|
|
9
|
+
"hint.navigate": "↑/↓ to navigate",
|
|
10
|
+
"hint.toggle": "Space to toggle",
|
|
11
|
+
"hint.notes": "n to add notes",
|
|
12
|
+
"hint.tab": "Tab to switch questions",
|
|
13
|
+
"hint.collapse": "Ctrl+] to collapse",
|
|
14
|
+
"hint.expand_line": "Ctrl+] to expand · Esc to cancel",
|
|
15
|
+
"hint.cancel": "Esc to cancel",
|
|
16
|
+
|
|
17
|
+
"review.heading": "Review your answers",
|
|
18
|
+
"review.ready": "Ready to submit your answers?",
|
|
19
|
+
"review.incomplete": "⚠ Answer remaining questions before submitting:",
|
|
20
|
+
|
|
21
|
+
"preview.no_preview": "No preview available",
|
|
22
|
+
"preview.notes_affordance": "Notes: press n to add notes",
|
|
23
|
+
"notes.header": "Notes:",
|
|
24
|
+
|
|
25
|
+
"rpc.multi_instructions": "Enter the numbers of all that apply, comma-separated (e.g. \"1,3\"), or type a custom answer as plain text.",
|
|
26
|
+
"rpc.custom_answer_title": "Type your answer:"
|
|
27
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"_meta.notes": "Auto-translated draft. Native-speaker review welcome via PR. TUI symbols (↑/↓, ⚠) and key names (Enter, Esc, Tab, Space, n) are universal CLI conventions and stay untranslated.",
|
|
3
|
+
|
|
4
|
+
"sentinel.other": "Escribe algo.",
|
|
5
|
+
"sentinel.next": "Siguiente",
|
|
6
|
+
|
|
7
|
+
"submit.label": "Enviar respuestas",
|
|
8
|
+
"submit.cancel": "Cancelar",
|
|
9
|
+
|
|
10
|
+
"hint.enter": "Enter para seleccionar",
|
|
11
|
+
"hint.navigate": "↑/↓ para navegar",
|
|
12
|
+
"hint.toggle": "Espacio para alternar",
|
|
13
|
+
"hint.notes": "n para añadir notas",
|
|
14
|
+
"hint.tab": "Tab para cambiar de pregunta",
|
|
15
|
+
"hint.cancel": "Esc para cancelar",
|
|
16
|
+
|
|
17
|
+
"review.heading": "Revisa tus respuestas",
|
|
18
|
+
"review.ready": "¿Listo para enviar tus respuestas?",
|
|
19
|
+
"review.incomplete": "⚠ Responde las preguntas restantes antes de enviar:",
|
|
20
|
+
|
|
21
|
+
"preview.no_preview": "Vista previa no disponible",
|
|
22
|
+
"preview.notes_affordance": "Notas: pulsa n para añadir notas",
|
|
23
|
+
"notes.header": "Notas:",
|
|
24
|
+
|
|
25
|
+
"rpc.multi_instructions": "Introduce los números de todas las opciones que apliquen, separados por comas (p. ej. \"1,3\"), o escribe una respuesta propia como texto.",
|
|
26
|
+
"rpc.custom_answer_title": "Escribe tu respuesta:"
|
|
27
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"_meta.notes": "Auto-translated draft. Native-speaker review welcome via PR. TUI symbols (↑/↓, ⚠) and key names (Enter, Esc, Tab, Space, n) are universal CLI conventions and stay untranslated.",
|
|
3
|
+
|
|
4
|
+
"sentinel.other": "Écrivez quelque chose.",
|
|
5
|
+
"sentinel.next": "Suivant",
|
|
6
|
+
|
|
7
|
+
"submit.label": "Envoyer les réponses",
|
|
8
|
+
"submit.cancel": "Annuler",
|
|
9
|
+
|
|
10
|
+
"hint.enter": "Entrée pour sélectionner",
|
|
11
|
+
"hint.navigate": "↑/↓ pour naviguer",
|
|
12
|
+
"hint.toggle": "Espace pour basculer",
|
|
13
|
+
"hint.notes": "n pour ajouter des notes",
|
|
14
|
+
"hint.tab": "Tab pour changer de question",
|
|
15
|
+
"hint.cancel": "Échap pour annuler",
|
|
16
|
+
|
|
17
|
+
"review.heading": "Vérifiez vos réponses",
|
|
18
|
+
"review.ready": "Prêt à envoyer vos réponses ?",
|
|
19
|
+
"review.incomplete": "⚠ Répondez aux questions restantes avant d'envoyer :",
|
|
20
|
+
|
|
21
|
+
"preview.no_preview": "Aucun aperçu disponible",
|
|
22
|
+
"preview.notes_affordance": "Notes : appuyez sur n pour ajouter des notes",
|
|
23
|
+
"notes.header": "Notes :",
|
|
24
|
+
|
|
25
|
+
"rpc.multi_instructions": "Saisissez les numéros de toutes les options applicables, séparés par des virgules (p. ex. « 1,3 »), ou tapez une réponse libre en texte.",
|
|
26
|
+
"rpc.custom_answer_title": "Tapez votre réponse :"
|
|
27
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"_meta.notes": "Auto-translated draft. Native-speaker review welcome via PR. TUI symbols (↑/↓, ⚠) and key names (Enter, Esc, Tab, Space, n) are universal CLI conventions and stay untranslated.",
|
|
3
|
+
|
|
4
|
+
"sentinel.other": "Digite algo.",
|
|
5
|
+
"sentinel.next": "Próximo",
|
|
6
|
+
|
|
7
|
+
"submit.label": "Enviar respostas",
|
|
8
|
+
"submit.cancel": "Cancelar",
|
|
9
|
+
|
|
10
|
+
"hint.enter": "Enter para selecionar",
|
|
11
|
+
"hint.navigate": "↑/↓ para navegar",
|
|
12
|
+
"hint.toggle": "Espaço para alternar",
|
|
13
|
+
"hint.notes": "n para adicionar notas",
|
|
14
|
+
"hint.tab": "Tab para trocar de pergunta",
|
|
15
|
+
"hint.cancel": "Esc para cancelar",
|
|
16
|
+
|
|
17
|
+
"review.heading": "Revise suas respostas",
|
|
18
|
+
"review.ready": "Pronto para enviar suas respostas?",
|
|
19
|
+
"review.incomplete": "⚠ Responda as perguntas restantes antes de enviar:",
|
|
20
|
+
|
|
21
|
+
"preview.no_preview": "Pré-visualização indisponível",
|
|
22
|
+
"preview.notes_affordance": "Notas: pressione n para adicionar notas",
|
|
23
|
+
"notes.header": "Notas:",
|
|
24
|
+
|
|
25
|
+
"rpc.multi_instructions": "Digite os números de todas as opções aplicáveis, separados por vírgula (ex.: \"1,3\") ou digite uma resposta própria em texto.",
|
|
26
|
+
"rpc.custom_answer_title": "Digite sua resposta:"
|
|
27
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"_meta.notes": "European Portuguese (Portugal). Auto-translated draft. Native-speaker review welcome via PR. Distinct from pt-BR (Brasil): differs in lexicon (utilizador / você), conjugation, and some terms. TUI symbols (↑/↓, ⚠) and key names (Enter, Esc, Tab, Space, n) are universal CLI conventions and stay untranslated.",
|
|
3
|
+
|
|
4
|
+
"sentinel.other": "Escreva algo.",
|
|
5
|
+
"sentinel.next": "Seguinte",
|
|
6
|
+
|
|
7
|
+
"submit.label": "Enviar respostas",
|
|
8
|
+
"submit.cancel": "Cancelar",
|
|
9
|
+
|
|
10
|
+
"hint.enter": "Enter para selecionar",
|
|
11
|
+
"hint.navigate": "↑/↓ para navegar",
|
|
12
|
+
"hint.toggle": "Espaço para alternar",
|
|
13
|
+
"hint.notes": "n para adicionar notas",
|
|
14
|
+
"hint.tab": "Tab para mudar de pergunta",
|
|
15
|
+
"hint.cancel": "Esc para cancelar",
|
|
16
|
+
|
|
17
|
+
"review.heading": "Reveja as suas respostas",
|
|
18
|
+
"review.ready": "Pronto para enviar as suas respostas?",
|
|
19
|
+
"review.incomplete": "⚠ Responda às perguntas restantes antes de enviar:",
|
|
20
|
+
|
|
21
|
+
"preview.no_preview": "Pré-visualização indisponível",
|
|
22
|
+
"preview.notes_affordance": "Notas: prima n para adicionar notas",
|
|
23
|
+
"notes.header": "Notas:",
|
|
24
|
+
|
|
25
|
+
"rpc.multi_instructions": "Introduza os números de todas as opções aplicáveis, separados por vírgulas (ex.: \"1,3\") ou escreva uma resposta própria em texto.",
|
|
26
|
+
"rpc.custom_answer_title": "Escreva a sua resposta:"
|
|
27
|
+
}
|