@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
|
@@ -21,14 +21,56 @@ is_root() { # $1 = candidate dir
|
|
|
21
21
|
[ -f "$1/.feature-forge-bundle.json" ] || [ -f "$1/.claude-plugin/plugin.json" ]
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
+
# Completeness gate (#152). A dir can carry the sentinel yet be a partial/stale install —
|
|
25
|
+
# a skill-only extraction, or an install predating the shared-reference fan-out — where the
|
|
26
|
+
# scripts/references the skills load at every stage are absent. Such a root looks usable but
|
|
27
|
+
# runs DEGRADED silently (hand-improvised state schema, skipped Mint Guard + scripted exit).
|
|
28
|
+
# These are the assets a complete install MUST carry beyond the sentinel; a resolved root
|
|
29
|
+
# missing any of them is reported as degraded rather than handed back as if it were whole.
|
|
30
|
+
CORE_ASSETS=(
|
|
31
|
+
"scripts/forge-session.py"
|
|
32
|
+
"references/pipeline-state-schema.json"
|
|
33
|
+
"references/stage-exit-protocol.md"
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
# Echo the first missing core asset (relative path) for $1, or nothing when complete.
|
|
37
|
+
first_missing_asset() { # $1 = candidate dir
|
|
38
|
+
local a
|
|
39
|
+
for a in "${CORE_ASSETS[@]}"; do
|
|
40
|
+
[ -f "$1/$a" ] || { printf '%s' "$a"; return 0; }
|
|
41
|
+
done
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
# A sentinel-bearing candidate that lacks a core asset is remembered here (first one wins)
|
|
45
|
+
# so a COMPLETE root found later in the probe order still takes precedence; only if the probe
|
|
46
|
+
# ends with no complete root do we report this degraded install (step 4).
|
|
47
|
+
partial_root=""
|
|
48
|
+
partial_missing=""
|
|
49
|
+
|
|
50
|
+
# Given a candidate that already passed is_root: print + exit 0 if it is complete; otherwise
|
|
51
|
+
# record it as the degraded fallback and return so probing continues. Always returns 0 on the
|
|
52
|
+
# fall-through path so `set -e` never aborts the resolver on a partial candidate.
|
|
53
|
+
accept_root() { # $1 = candidate dir (already is_root)
|
|
54
|
+
local miss
|
|
55
|
+
miss="$(first_missing_asset "$1")"
|
|
56
|
+
if [ -z "$miss" ]; then
|
|
57
|
+
printf '%s\n' "$1"
|
|
58
|
+
exit 0
|
|
59
|
+
fi
|
|
60
|
+
if [ -z "$partial_root" ]; then
|
|
61
|
+
partial_root="$1"
|
|
62
|
+
partial_missing="$miss"
|
|
63
|
+
fi
|
|
64
|
+
return 0
|
|
65
|
+
}
|
|
66
|
+
|
|
24
67
|
# ── Step 1: self-location — parent of this script's dir is the install root. ─────────────
|
|
25
68
|
# This is the PRIMARY path: a bundle ships its own scripts/forge-root.sh, so the parent of
|
|
26
69
|
# this script's dir is that bundle's root under any agent's layout.
|
|
27
70
|
self_dir="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd -P)"
|
|
28
71
|
root="$(cd -- "$self_dir/.." && pwd -P)"
|
|
29
72
|
if is_root "$root"; then
|
|
30
|
-
|
|
31
|
-
exit 0
|
|
73
|
+
accept_root "$root"
|
|
32
74
|
fi
|
|
33
75
|
|
|
34
76
|
# ── Step 2a: Claude marketplace-cache installs — ~/.claude/plugins/cache/<mp>/<plugin>/<ver>/.
|
|
@@ -42,8 +84,7 @@ fi
|
|
|
42
84
|
while IFS= read -r manifest; do
|
|
43
85
|
candidate="${manifest%/.claude-plugin/plugin.json}"
|
|
44
86
|
if is_root "$candidate"; then
|
|
45
|
-
|
|
46
|
-
exit 0
|
|
87
|
+
accept_root "$candidate"
|
|
47
88
|
fi
|
|
48
89
|
done < <(ls -t "$HOME"/.claude/plugins/cache/*/feature-forge/*/.claude-plugin/plugin.json 2>/dev/null || true)
|
|
49
90
|
|
|
@@ -51,9 +92,24 @@ done < <(ls -t "$HOME"/.claude/plugins/cache/*/feature-forge/*/.claude-plugin/pl
|
|
|
51
92
|
# Globs that match nothing expand to themselves; the is_root test rejects such literals. Covers
|
|
52
93
|
# every supported agent's install destination under BOTH global ($HOME) and project ($PWD) scope,
|
|
53
94
|
# matching the installer's per-agent layout: claude .claude/skills, codex .agents/skills, copilot
|
|
54
|
-
# .github/feature-forge, cursor .cursor/rules, gemini .gemini/extensions
|
|
55
|
-
# step 2a's path for a cache install that
|
|
56
|
-
# plugin.json for ls -t to key on).
|
|
95
|
+
# .github/feature-forge, cursor .cursor/rules, gemini .gemini/extensions, pi .pi/skills or
|
|
96
|
+
# $PI_CODING_AGENT_DIR/skills. The cache glob repeats step 2a's path for a cache install that
|
|
97
|
+
# carries only the neutral bundle sentinel (no plugin.json for ls -t to key on).
|
|
98
|
+
if [ -n "${PI_CODING_AGENT_DIR:-}" ]; then
|
|
99
|
+
for candidate in \
|
|
100
|
+
"$PI_CODING_AGENT_DIR/skills/feature-forge" \
|
|
101
|
+
"$PI_CODING_AGENT_DIR"/git/*/feature-forge/adapters/pi \
|
|
102
|
+
"$PI_CODING_AGENT_DIR"/git/*/*/feature-forge/adapters/pi \
|
|
103
|
+
"$PI_CODING_AGENT_DIR"/packages/*/feature-forge/adapters/pi \
|
|
104
|
+
"$PI_CODING_AGENT_DIR"/npm/*/@garygentry/feature-forge/adapters/pi \
|
|
105
|
+
"$PI_CODING_AGENT_DIR"/node_modules/@garygentry/feature-forge/adapters/pi \
|
|
106
|
+
; do
|
|
107
|
+
if is_root "$candidate"; then
|
|
108
|
+
accept_root "$candidate"
|
|
109
|
+
fi
|
|
110
|
+
done
|
|
111
|
+
fi
|
|
112
|
+
|
|
57
113
|
for candidate in \
|
|
58
114
|
"$HOME/.claude/skills/feature-forge" \
|
|
59
115
|
"$PWD/.claude/skills/feature-forge" \
|
|
@@ -67,25 +123,57 @@ for candidate in \
|
|
|
67
123
|
"$PWD/.cursor/rules/feature-forge" \
|
|
68
124
|
"$HOME/.gemini/extensions/feature-forge" \
|
|
69
125
|
"$PWD/.gemini/extensions/feature-forge" \
|
|
126
|
+
"$HOME/.pi/agent/skills/feature-forge" \
|
|
127
|
+
"$PWD/.pi/skills/feature-forge" \
|
|
128
|
+
"$HOME"/.pi/agent/git/*/feature-forge/adapters/pi \
|
|
129
|
+
"$HOME"/.pi/agent/git/*/*/feature-forge/adapters/pi \
|
|
130
|
+
"$HOME"/.pi/agent/packages/*/feature-forge/adapters/pi \
|
|
131
|
+
"$HOME"/.pi/agent/npm/*/@garygentry/feature-forge/adapters/pi \
|
|
132
|
+
"$HOME"/.pi/agent/node_modules/@garygentry/feature-forge/adapters/pi \
|
|
133
|
+
"$PWD"/.pi/git/*/feature-forge/adapters/pi \
|
|
134
|
+
"$PWD"/.pi/git/*/*/feature-forge/adapters/pi \
|
|
135
|
+
"$PWD"/.pi/packages/*/feature-forge/adapters/pi \
|
|
136
|
+
"$PWD"/.pi/npm/*/@garygentry/feature-forge/adapters/pi \
|
|
137
|
+
"$PWD"/.pi/node_modules/@garygentry/feature-forge/adapters/pi \
|
|
70
138
|
; do
|
|
71
139
|
if is_root "$candidate"; then
|
|
72
|
-
|
|
73
|
-
exit 0
|
|
140
|
+
accept_root "$candidate"
|
|
74
141
|
fi
|
|
75
142
|
done
|
|
76
143
|
|
|
144
|
+
# Project-scoped Pi installs may be discovered from a subdirectory of the repository. Probe
|
|
145
|
+
# ancestor .pi roots up to the filesystem root; this is bounded by path depth and avoids
|
|
146
|
+
# recursive globs. Scoped to .pi ONLY — every other agent's project layout is probed at $PWD
|
|
147
|
+
# in the fixed list above, and widening those to ancestors here would silently change
|
|
148
|
+
# established discovery behaviour for agents this bundle did not introduce.
|
|
149
|
+
probe_dir="$PWD"
|
|
150
|
+
while :; do
|
|
151
|
+
candidate="$probe_dir/.pi/skills/feature-forge"
|
|
152
|
+
if is_root "$candidate"; then
|
|
153
|
+
accept_root "$candidate"
|
|
154
|
+
fi
|
|
155
|
+
[ "$probe_dir" = "/" ] && break
|
|
156
|
+
next_probe_dir="$(dirname -- "$probe_dir")"
|
|
157
|
+
[ "$next_probe_dir" = "$probe_dir" ] && break
|
|
158
|
+
probe_dir="$next_probe_dir"
|
|
159
|
+
done
|
|
160
|
+
|
|
77
161
|
# ── Step 3: env fallback — neutral FEATURE_FORGE_ROOT, then the legacy CLAUDE_PLUGIN_ROOT. ─
|
|
78
162
|
# The neutral override works for every agent; CLAUDE_PLUGIN_ROOT is kept only for backwards
|
|
79
163
|
# compatibility with existing Claude installs (C-4).
|
|
80
164
|
if [ -n "${FEATURE_FORGE_ROOT:-}" ] && is_root "$FEATURE_FORGE_ROOT"; then
|
|
81
|
-
|
|
82
|
-
exit 0
|
|
165
|
+
accept_root "$FEATURE_FORGE_ROOT"
|
|
83
166
|
fi
|
|
84
167
|
if [ -n "${CLAUDE_PLUGIN_ROOT:-}" ] && is_root "$CLAUDE_PLUGIN_ROOT"; then
|
|
85
|
-
|
|
86
|
-
exit 0
|
|
168
|
+
accept_root "$CLAUDE_PLUGIN_ROOT"
|
|
87
169
|
fi
|
|
88
170
|
|
|
89
|
-
# ── Step 4: failure
|
|
171
|
+
# ── Step 4: failure. A sentinel-bearing but asset-incomplete root found along the way is a
|
|
172
|
+
# DEGRADED install (#152) — report it distinctly and actionably rather than the generic
|
|
173
|
+
# cannot-locate message, so the operator knows to reinstall/update rather than reconfigure. ─
|
|
174
|
+
if [ -n "$partial_root" ]; then
|
|
175
|
+
echo "feature-forge: install incomplete/degraded at $partial_root (missing $partial_missing) — reinstall with 'npx @garygentry/feature-forge' (or 'feature-forge update' for a stale install)." >&2
|
|
176
|
+
exit 1
|
|
177
|
+
fi
|
|
90
178
|
echo "feature-forge: cannot locate install root. Set FEATURE_FORGE_ROOT to the bundle dir, or run from an installed skill dir." >&2
|
|
91
179
|
exit 1
|
|
@@ -117,8 +117,20 @@ VERIFY_TOKEN_BY_STAGE: Final[dict[str, str]] = {
|
|
|
117
117
|
|
|
118
118
|
#: A production stage status that counts as "done" for next-stage selection.
|
|
119
119
|
_DONE_STATUS: Final = "complete"
|
|
120
|
-
#:
|
|
120
|
+
#: The authoritative forge-verify status vocabulary. SOURCE OF TRUTH:
|
|
121
|
+
#: references/pipeline-state-schema.json (definitions.verifyEntry.properties.status.enum).
|
|
122
|
+
#: A status outside this set is unrecognized and must not be silently interpreted (#148).
|
|
123
|
+
#: NOTE: epic-manifest.py keeps a byte-identical copy — flat, self-contained scripts have
|
|
124
|
+
#: no shared import module (each is copied verbatim into per-agent adapter bundles).
|
|
125
|
+
KNOWN_VERIFY_STATUSES: Final = frozenset(
|
|
126
|
+
{"pending", "passed", "findings-reported", "findings-applied", "skipped"}
|
|
127
|
+
)
|
|
128
|
+
#: Verify statuses that count as "resolved" (no outstanding verify needed). A STRICT
|
|
129
|
+
#: subset of KNOWN_VERIFY_STATUSES — not collapsible into it (different meaning).
|
|
121
130
|
_VERIFY_RESOLVED: Final = frozenset({"passed", "findings-applied", "skipped"})
|
|
131
|
+
#: Per-process dedupe for the unknown-verify-status diagnostic (#148) so a single
|
|
132
|
+
#: bogus status is flagged once, not once per verify_state() call in a command.
|
|
133
|
+
_UNKNOWN_VERIFY_WARNED: set[str] = set()
|
|
122
134
|
|
|
123
135
|
#: Default context window when the model can't be inferred and config is silent.
|
|
124
136
|
_DEFAULT_WINDOW: Final = 200_000
|
|
@@ -257,6 +269,25 @@ def _verify_entry(state: dict, verify_key: str) -> dict:
|
|
|
257
269
|
return entry if isinstance(entry, dict) else {}
|
|
258
270
|
|
|
259
271
|
|
|
272
|
+
def _warn_unknown_verify_status(stage_name: str, status: object) -> None:
|
|
273
|
+
"""Emit a one-time stderr diagnostic for an out-of-vocabulary verify status (#148).
|
|
274
|
+
|
|
275
|
+
The freshness classifier maps an unrecognized status to "never verified" — correct,
|
|
276
|
+
but silent, so a typo poisons the downstream gate (e.g. forge-5-loop's dependency
|
|
277
|
+
check) with no clue. Flagging it here makes the bad value visible where it is read.
|
|
278
|
+
"""
|
|
279
|
+
key = f"{stage_name}={status!r}"
|
|
280
|
+
if key in _UNKNOWN_VERIFY_WARNED:
|
|
281
|
+
return
|
|
282
|
+
_UNKNOWN_VERIFY_WARNED.add(key)
|
|
283
|
+
known = ", ".join(sorted(KNOWN_VERIFY_STATUSES))
|
|
284
|
+
print(
|
|
285
|
+
f"feature-forge: unknown {stage_name} status {status!r} "
|
|
286
|
+
f"(treated as unverified; expected one of {known})",
|
|
287
|
+
file=sys.stderr,
|
|
288
|
+
)
|
|
289
|
+
|
|
290
|
+
|
|
260
291
|
def verify_state(state: dict) -> tuple[str | None, str]:
|
|
261
292
|
"""Classify verify freshness for the most-recently-completed stage.
|
|
262
293
|
|
|
@@ -299,6 +330,12 @@ def verify_state(state: dict) -> tuple[str | None, str]:
|
|
|
299
330
|
if status not in _VERIFY_RESOLVED:
|
|
300
331
|
if status == "findings-reported":
|
|
301
332
|
return stage, "failing"
|
|
333
|
+
# An unrecognized status (outside KNOWN_VERIFY_STATUSES) is treated as
|
|
334
|
+
# "never verified" — defensible, but flag it once so a typo (e.g. the
|
|
335
|
+
# eye-slip 'findings-resolved') doesn't silently poison the gate that
|
|
336
|
+
# reads this label (#148). ``pending``/``None`` are known/absent → quiet.
|
|
337
|
+
if status is not None and status not in KNOWN_VERIFY_STATUSES:
|
|
338
|
+
_warn_unknown_verify_status(f"forge-verify-{token}", status)
|
|
302
339
|
return stage, "never"
|
|
303
340
|
verified_version = entry.get("verifiedStageVersion")
|
|
304
341
|
stage_version = _stage_version(state, stage)
|
|
@@ -1397,6 +1434,17 @@ def _resolve_feature_dir(specs_dir: Path, feature: str, epic: str | None) -> Pat
|
|
|
1397
1434
|
return flat
|
|
1398
1435
|
|
|
1399
1436
|
|
|
1437
|
+
def _host_command(command: str, host: str) -> str:
|
|
1438
|
+
"""Rewrite a `/feature-forge:` slash command to the host's surface.
|
|
1439
|
+
|
|
1440
|
+
Pi's slash-command surface is `/skill:` (matching the adapter body's
|
|
1441
|
+
`/feature-forge:` -> `/skill:` translation). The scripted stage-exit output bypasses
|
|
1442
|
+
that body translation, so it rewrites the commands it emits here. No-op for
|
|
1443
|
+
claude/generic, which keep the canonical `/feature-forge:` form.
|
|
1444
|
+
"""
|
|
1445
|
+
return command.replace("/feature-forge:", "/skill:") if host == "pi" else command
|
|
1446
|
+
|
|
1447
|
+
|
|
1400
1448
|
def _next_steps_block(
|
|
1401
1449
|
next_command: str, host: str, reconcile: dict | None = None
|
|
1402
1450
|
) -> str:
|
|
@@ -1426,6 +1474,18 @@ def _next_steps_block(
|
|
|
1426
1474
|
"2. Then start a fresh session and run the next stage below — or "
|
|
1427
1475
|
"re-run `/feature-forge:forge` to let the navigator resume from disk."
|
|
1428
1476
|
)
|
|
1477
|
+
elif host == "pi":
|
|
1478
|
+
# Pi's fresh-session command is `/new` (not `/clear`); its slash-command
|
|
1479
|
+
# surface is `/skill:` (the fenced command below is rewritten to match).
|
|
1480
|
+
clear_line = (
|
|
1481
|
+
"1. `/new` — recommended unconditionally at this stage boundary; every "
|
|
1482
|
+
"artifact is on disk, so the work survives starting a fresh session. "
|
|
1483
|
+
"I can't run `/new` for you — you have to run it yourself."
|
|
1484
|
+
)
|
|
1485
|
+
next_line = (
|
|
1486
|
+
"2. Then, in the new session, run the next stage below — or re-run "
|
|
1487
|
+
"`/skill:forge` to let the navigator resume from disk."
|
|
1488
|
+
)
|
|
1429
1489
|
else:
|
|
1430
1490
|
clear_line = (
|
|
1431
1491
|
"1. Clear your session / start a fresh session — recommended "
|
|
@@ -1442,7 +1502,7 @@ def _next_steps_block(
|
|
|
1442
1502
|
# epic-change request the primary is the reconcile command; otherwise it is the
|
|
1443
1503
|
# normal next-stage command. The fence sits before the sentinel, so the
|
|
1444
1504
|
# sentinel remains the absolute last line.
|
|
1445
|
-
fenced_command = reconcile["command"] if blocking else next_command
|
|
1505
|
+
fenced_command = _host_command(reconcile["command"] if blocking else next_command, host)
|
|
1446
1506
|
lines = ["**Next steps**", clear_line]
|
|
1447
1507
|
if blocking:
|
|
1448
1508
|
count = reconcile["count"]
|
|
@@ -1458,15 +1518,14 @@ def _next_steps_block(
|
|
|
1458
1518
|
lines.append("")
|
|
1459
1519
|
lines.append(f"```\n{fenced_command}\n```")
|
|
1460
1520
|
if blocking and reconcile.get("deferred"):
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
)
|
|
1521
|
+
deferred_cmd = _host_command(reconcile["deferred"], host)
|
|
1522
|
+
lines.append(f"After reconciling, continue the pipeline with: `{deferred_cmd}`")
|
|
1464
1523
|
elif reconcile and reconcile.get("reminder"):
|
|
1465
1524
|
count = reconcile["count"]
|
|
1466
1525
|
plural = "s" if count != 1 else ""
|
|
1467
1526
|
lines.append(
|
|
1468
1527
|
f"You also flagged {count} epic change{plural} to reconcile when "
|
|
1469
|
-
f"convenient: `{reconcile['command']}`"
|
|
1528
|
+
f"convenient: `{_host_command(reconcile['command'], host)}`"
|
|
1470
1529
|
)
|
|
1471
1530
|
lines.append(NEXT_STEPS_SENTINEL)
|
|
1472
1531
|
return "\n".join(lines)
|
|
@@ -1593,10 +1652,10 @@ def stage_exit(
|
|
|
1593
1652
|
"verifyGate": verify_gate,
|
|
1594
1653
|
"autoFixEligible": auto_fix_eligible,
|
|
1595
1654
|
"verifyState": verify_label,
|
|
1596
|
-
"verifyCommand": f"/feature-forge:forge-verify {feature}",
|
|
1655
|
+
"verifyCommand": _host_command(f"/feature-forge:forge-verify {feature}", host),
|
|
1597
1656
|
"autoVerifyEffective": effective_auto_verify,
|
|
1598
1657
|
"nextStage": next_stage_id,
|
|
1599
|
-
"nextCommand": next_command,
|
|
1658
|
+
"nextCommand": _host_command(next_command, host) if next_command else next_command,
|
|
1600
1659
|
"invalidAutoVerifyKeys": invalid_auto_verify_keys(config),
|
|
1601
1660
|
"gitRepo": git_repo,
|
|
1602
1661
|
"cleanTree": clean_tree,
|
|
@@ -1722,7 +1781,7 @@ def main() -> int:
|
|
|
1722
1781
|
p_exit.add_argument("--epic", default=None, help="Epic name for a nested member")
|
|
1723
1782
|
p_exit.add_argument("--next-feature", default=None, dest="next_feature",
|
|
1724
1783
|
help="First actionable feature (epic handoff next-command arg)")
|
|
1725
|
-
p_exit.add_argument("--host", default="claude", choices=("claude", "generic"),
|
|
1784
|
+
p_exit.add_argument("--host", default="claude", choices=("claude", "generic", "pi"),
|
|
1726
1785
|
help="Host wording for the NEXT-STEPS block")
|
|
1727
1786
|
p_exit.add_argument("--json", action="store_true", dest="json_output")
|
|
1728
1787
|
|
|
@@ -274,6 +274,18 @@ This write is **left uncommitted**: it is staged and committed as part of this s
|
|
|
274
274
|
|
|
275
275
|
**Incremental artifact tracking:** When a stage writes multiple files (e.g. forge-3-specs writing a suite of spec documents), update the `stages.{stage}.artifacts` array in `.pipeline-state.json` after writing each file — not just at stage completion. This is what makes the Interrupted inventory above precise about which files were successfully written.
|
|
276
276
|
|
|
277
|
+
## Stage-Completion Re-check
|
|
278
|
+
|
|
279
|
+
Invoke this block **at the head of any post-entry step that writes a stage artifact or runs the Scripted Stage Exit** — the Stage-Entry Guard runs only once, at the top of the skill. A **resumed or pasted mid-stage instruction** (e.g. "continue {stage}: write TRACEABILITY.md, run the stage exit") enters *below* the entry guard, so nothing re-checks completion before it overwrites a committed artifact and re-fires a finished exit — data-destructive if followed literally. This re-check is the idempotency backstop for that path. `{stage}` is the invoking skill's id.
|
|
280
|
+
|
|
281
|
+
**Re-read** `stages.{stage}` in `{resolvedFeatureDir}/.pipeline-state.json`, then classify by **provenance** — a legitimate completion runs in the same session that applied this stage's Entry Stamp; a replayed continuation finds a finished stage it did not produce:
|
|
282
|
+
|
|
283
|
+
1. **Proceed** when `stages.{stage}.status` is `"in-progress"` (this session's Entry Stamp — you are finishing the run you started) or absent/`pending`. Run the write / exit normally.
|
|
284
|
+
|
|
285
|
+
2. **Detect-and-refuse** when ALL of these hold: `stages.{stage}.status ∈ {"complete", "stale"}` **AND** the stage's artifacts (incl. `TRACEABILITY.md` for forge-3-specs) exist on disk **AND** a `commitHash` is recorded for the stage **AND** you did **not** author this stage earlier in the current session. This is a stale/replayed continuation of an already-finished, committed stage. Do **not** overwrite the artifact or re-run the exit. Route instead to the **Stage-Entry Guard**'s *Re-authoring* path: surface the same `AskUserQuestion` warning ("A completed {stage} artifact already exists for '{feature}' (v{n}{, marked stale}). Continuing will create a new version. Proceed?"). Only on explicit confirmation re-enter from the Entry Stamp (the version bumps at exit); otherwise **stop** and report that the stage is already complete — cite the recorded `commitHash` and offer `/feature-forge:forge {feature}` to see true state.
|
|
286
|
+
|
|
287
|
+
When you cannot confirm you authored the current run, treat it as a replay and refuse: a false refuse costs one confirmation click; a false proceed overwrites a committed artifact and re-churns a stage version. `--force` follows Force Mode (skip the gate, treat as a deliberate re-author).
|
|
288
|
+
|
|
277
289
|
## Force Mode
|
|
278
290
|
|
|
279
291
|
If the user passes `--force` as an argument, skip prerequisite validation with a warning:
|
|
@@ -274,6 +274,18 @@ This write is **left uncommitted**: it is staged and committed as part of this s
|
|
|
274
274
|
|
|
275
275
|
**Incremental artifact tracking:** When a stage writes multiple files (e.g. forge-3-specs writing a suite of spec documents), update the `stages.{stage}.artifacts` array in `.pipeline-state.json` after writing each file — not just at stage completion. This is what makes the Interrupted inventory above precise about which files were successfully written.
|
|
276
276
|
|
|
277
|
+
## Stage-Completion Re-check
|
|
278
|
+
|
|
279
|
+
Invoke this block **at the head of any post-entry step that writes a stage artifact or runs the Scripted Stage Exit** — the Stage-Entry Guard runs only once, at the top of the skill. A **resumed or pasted mid-stage instruction** (e.g. "continue {stage}: write TRACEABILITY.md, run the stage exit") enters *below* the entry guard, so nothing re-checks completion before it overwrites a committed artifact and re-fires a finished exit — data-destructive if followed literally. This re-check is the idempotency backstop for that path. `{stage}` is the invoking skill's id.
|
|
280
|
+
|
|
281
|
+
**Re-read** `stages.{stage}` in `{resolvedFeatureDir}/.pipeline-state.json`, then classify by **provenance** — a legitimate completion runs in the same session that applied this stage's Entry Stamp; a replayed continuation finds a finished stage it did not produce:
|
|
282
|
+
|
|
283
|
+
1. **Proceed** when `stages.{stage}.status` is `"in-progress"` (this session's Entry Stamp — you are finishing the run you started) or absent/`pending`. Run the write / exit normally.
|
|
284
|
+
|
|
285
|
+
2. **Detect-and-refuse** when ALL of these hold: `stages.{stage}.status ∈ {"complete", "stale"}` **AND** the stage's artifacts (incl. `TRACEABILITY.md` for forge-3-specs) exist on disk **AND** a `commitHash` is recorded for the stage **AND** you did **not** author this stage earlier in the current session. This is a stale/replayed continuation of an already-finished, committed stage. Do **not** overwrite the artifact or re-run the exit. Route instead to the **Stage-Entry Guard**'s *Re-authoring* path: surface the same `AskUserQuestion` warning ("A completed {stage} artifact already exists for '{feature}' (v{n}{, marked stale}). Continuing will create a new version. Proceed?"). Only on explicit confirmation re-enter from the Entry Stamp (the version bumps at exit); otherwise **stop** and report that the stage is already complete — cite the recorded `commitHash` and offer `/feature-forge:forge {feature}` to see true state.
|
|
286
|
+
|
|
287
|
+
When you cannot confirm you authored the current run, treat it as a replay and refuse: a false refuse costs one confirmation click; a false proceed overwrites a committed artifact and re-churns a stage version. `--force` follows Force Mode (skip the gate, treat as a deliberate re-author).
|
|
288
|
+
|
|
277
289
|
## Force Mode
|
|
278
290
|
|
|
279
291
|
If the user passes `--force` as an argument, skip prerequisite validation with a warning:
|
|
@@ -121,6 +121,8 @@ Iterate until the user confirms the PRD is complete.
|
|
|
121
121
|
|
|
122
122
|
## Step 6: Update Pipeline State and Commit
|
|
123
123
|
|
|
124
|
+
Before writing state or running the stage exit, invoke the **Stage-Completion Re-check** block in `references/shared-conventions.md` with `{stage}` = `forge-1-prd` — a resumed mid-stage continuation must not overwrite a committed `PRD.md` or re-fire a finished exit.
|
|
125
|
+
|
|
124
126
|
Write pipeline state conforming to `references/pipeline-state-schema.json`.
|
|
125
127
|
|
|
126
128
|
1. Create or update `{resolvedFeatureDir}/.pipeline-state.json`:
|
|
@@ -274,6 +274,18 @@ This write is **left uncommitted**: it is staged and committed as part of this s
|
|
|
274
274
|
|
|
275
275
|
**Incremental artifact tracking:** When a stage writes multiple files (e.g. forge-3-specs writing a suite of spec documents), update the `stages.{stage}.artifacts` array in `.pipeline-state.json` after writing each file — not just at stage completion. This is what makes the Interrupted inventory above precise about which files were successfully written.
|
|
276
276
|
|
|
277
|
+
## Stage-Completion Re-check
|
|
278
|
+
|
|
279
|
+
Invoke this block **at the head of any post-entry step that writes a stage artifact or runs the Scripted Stage Exit** — the Stage-Entry Guard runs only once, at the top of the skill. A **resumed or pasted mid-stage instruction** (e.g. "continue {stage}: write TRACEABILITY.md, run the stage exit") enters *below* the entry guard, so nothing re-checks completion before it overwrites a committed artifact and re-fires a finished exit — data-destructive if followed literally. This re-check is the idempotency backstop for that path. `{stage}` is the invoking skill's id.
|
|
280
|
+
|
|
281
|
+
**Re-read** `stages.{stage}` in `{resolvedFeatureDir}/.pipeline-state.json`, then classify by **provenance** — a legitimate completion runs in the same session that applied this stage's Entry Stamp; a replayed continuation finds a finished stage it did not produce:
|
|
282
|
+
|
|
283
|
+
1. **Proceed** when `stages.{stage}.status` is `"in-progress"` (this session's Entry Stamp — you are finishing the run you started) or absent/`pending`. Run the write / exit normally.
|
|
284
|
+
|
|
285
|
+
2. **Detect-and-refuse** when ALL of these hold: `stages.{stage}.status ∈ {"complete", "stale"}` **AND** the stage's artifacts (incl. `TRACEABILITY.md` for forge-3-specs) exist on disk **AND** a `commitHash` is recorded for the stage **AND** you did **not** author this stage earlier in the current session. This is a stale/replayed continuation of an already-finished, committed stage. Do **not** overwrite the artifact or re-run the exit. Route instead to the **Stage-Entry Guard**'s *Re-authoring* path: surface the same `AskUserQuestion` warning ("A completed {stage} artifact already exists for '{feature}' (v{n}{, marked stale}). Continuing will create a new version. Proceed?"). Only on explicit confirmation re-enter from the Entry Stamp (the version bumps at exit); otherwise **stop** and report that the stage is already complete — cite the recorded `commitHash` and offer `/feature-forge:forge {feature}` to see true state.
|
|
286
|
+
|
|
287
|
+
When you cannot confirm you authored the current run, treat it as a replay and refuse: a false refuse costs one confirmation click; a false proceed overwrites a committed artifact and re-churns a stage version. `--force` follows Force Mode (skip the gate, treat as a deliberate re-author).
|
|
288
|
+
|
|
277
289
|
## Force Mode
|
|
278
290
|
|
|
279
291
|
If the user passes `--force` as an argument, skip prerequisite validation with a warning:
|
|
@@ -183,6 +183,8 @@ Use the host's question mechanism to collect this feedback.
|
|
|
183
183
|
|
|
184
184
|
## Step 7: Update Pipeline State and Commit
|
|
185
185
|
|
|
186
|
+
Before writing state or running the stage exit, invoke the **Stage-Completion Re-check** block in `references/shared-conventions.md` with `{stage}` = `forge-2-tech` — a resumed mid-stage continuation must not overwrite a committed `tech-spec.md` or re-fire a finished exit.
|
|
187
|
+
|
|
186
188
|
Write pipeline state conforming to `references/pipeline-state-schema.json`.
|
|
187
189
|
|
|
188
190
|
1. Update `{resolvedFeatureDir}/.pipeline-state.json`:
|
|
@@ -274,6 +274,18 @@ This write is **left uncommitted**: it is staged and committed as part of this s
|
|
|
274
274
|
|
|
275
275
|
**Incremental artifact tracking:** When a stage writes multiple files (e.g. forge-3-specs writing a suite of spec documents), update the `stages.{stage}.artifacts` array in `.pipeline-state.json` after writing each file — not just at stage completion. This is what makes the Interrupted inventory above precise about which files were successfully written.
|
|
276
276
|
|
|
277
|
+
## Stage-Completion Re-check
|
|
278
|
+
|
|
279
|
+
Invoke this block **at the head of any post-entry step that writes a stage artifact or runs the Scripted Stage Exit** — the Stage-Entry Guard runs only once, at the top of the skill. A **resumed or pasted mid-stage instruction** (e.g. "continue {stage}: write TRACEABILITY.md, run the stage exit") enters *below* the entry guard, so nothing re-checks completion before it overwrites a committed artifact and re-fires a finished exit — data-destructive if followed literally. This re-check is the idempotency backstop for that path. `{stage}` is the invoking skill's id.
|
|
280
|
+
|
|
281
|
+
**Re-read** `stages.{stage}` in `{resolvedFeatureDir}/.pipeline-state.json`, then classify by **provenance** — a legitimate completion runs in the same session that applied this stage's Entry Stamp; a replayed continuation finds a finished stage it did not produce:
|
|
282
|
+
|
|
283
|
+
1. **Proceed** when `stages.{stage}.status` is `"in-progress"` (this session's Entry Stamp — you are finishing the run you started) or absent/`pending`. Run the write / exit normally.
|
|
284
|
+
|
|
285
|
+
2. **Detect-and-refuse** when ALL of these hold: `stages.{stage}.status ∈ {"complete", "stale"}` **AND** the stage's artifacts (incl. `TRACEABILITY.md` for forge-3-specs) exist on disk **AND** a `commitHash` is recorded for the stage **AND** you did **not** author this stage earlier in the current session. This is a stale/replayed continuation of an already-finished, committed stage. Do **not** overwrite the artifact or re-run the exit. Route instead to the **Stage-Entry Guard**'s *Re-authoring* path: surface the same `AskUserQuestion` warning ("A completed {stage} artifact already exists for '{feature}' (v{n}{, marked stale}). Continuing will create a new version. Proceed?"). Only on explicit confirmation re-enter from the Entry Stamp (the version bumps at exit); otherwise **stop** and report that the stage is already complete — cite the recorded `commitHash` and offer `/feature-forge:forge {feature}` to see true state.
|
|
286
|
+
|
|
287
|
+
When you cannot confirm you authored the current run, treat it as a replay and refuse: a false refuse costs one confirmation click; a false proceed overwrites a committed artifact and re-churns a stage version. `--force` follows Force Mode (skip the gate, treat as a deliberate re-author).
|
|
288
|
+
|
|
277
289
|
## Force Mode
|
|
278
290
|
|
|
279
291
|
If the user passes `--force` as an argument, skip prerequisite validation with a warning:
|
|
@@ -79,6 +79,27 @@ Replace stack-specific checks with these generic equivalents:
|
|
|
79
79
|
| "JSDoc on every field" | "Documentation comments on every field" |
|
|
80
80
|
| "tsconfig.json extends root" | "Build configuration follows project conventions" |
|
|
81
81
|
|
|
82
|
+
### Runtime Entrypoints & Bootstrap-Wiring Sites
|
|
83
|
+
|
|
84
|
+
Used by `CHECK-I22` (a runtime-required bootstrap needs a **non-test** caller on one of these) and
|
|
85
|
+
`CHECK-I23` (a heavy init wired into a **universal** bootstrap entry should move to a lazier site).
|
|
86
|
+
Since no dedicated profile applies, identify these by role rather than exact filename:
|
|
87
|
+
|
|
88
|
+
- **Runtime entrypoints (a legitimate non-test call site):** the process/main entry the build's
|
|
89
|
+
run command actually launches (from the CI/`Makefile`/manifest "start" target), an HTTP/RPC handler
|
|
90
|
+
or route, a scheduled/worker task, or a CLI subcommand — **not** a file in the project's test
|
|
91
|
+
directory or matching its test-file convention.
|
|
92
|
+
- **Universal bootstrap entries (run on every startup — the `CHECK-I23` risk site):** any
|
|
93
|
+
module/hook the framework runs **once per process before serving** — a startup/lifecycle hook, an
|
|
94
|
+
import-time initializer, a global preload, or a shared test-setup module that bootstraps production
|
|
95
|
+
graphs. Side effects here run on every process start (and, under a dev/watch runtime, on every
|
|
96
|
+
reload).
|
|
97
|
+
- **Heavy server-only import markers (what makes an init "heavy" for `CHECK-I23`):** database/ORM
|
|
98
|
+
clients and connection pools, message/queue clients, telemetry/observability SDKs, or a broad
|
|
99
|
+
whole-service-layer import. An init pulling any of these into a universal bootstrap entry is the
|
|
100
|
+
CHECK-I23 pattern — recommend lazy initialization at the first handler/worker that needs the graph,
|
|
101
|
+
not eagerly at process start.
|
|
102
|
+
|
|
82
103
|
## Acceptance Criteria Patterns
|
|
83
104
|
|
|
84
105
|
Use these placeholder patterns in backlog items. Replace `{typeCheckCommand}`, `{testCommand}`, and `{module}` with values from `forge.config.json` and the project structure:
|
|
@@ -84,6 +84,25 @@ When examining a Go project, check for:
|
|
|
84
84
|
- **Formatting**: `gofmt -l .` or `goimports -l .` (should produce no output)
|
|
85
85
|
- **Module tidiness**: `go mod tidy` (ensures `go.mod` and `go.sum` are consistent)
|
|
86
86
|
|
|
87
|
+
### Runtime Entrypoints & Bootstrap-Wiring Sites
|
|
88
|
+
|
|
89
|
+
Used by `CHECK-I22` (a runtime-required bootstrap needs a **non-test** caller on one of these) and
|
|
90
|
+
`CHECK-I23` (a heavy init wired into a **universal** bootstrap entry should move to a lazier site).
|
|
91
|
+
|
|
92
|
+
- **Runtime entrypoints (a legitimate non-test call site):** `func main()` in a `package main` under
|
|
93
|
+
`cmd/…` or the module root, an HTTP handler registered on a `*http.ServeMux` / router, a gRPC service
|
|
94
|
+
registration, or a worker/consumer goroutine started from `main` — not a `*_test.go` file.
|
|
95
|
+
- **Universal bootstrap entries (run on every startup — the `CHECK-I23` risk site):** a package-level
|
|
96
|
+
`func init()` that constructs heavy clients, package-level `var` initializers that dial/connect at
|
|
97
|
+
import time, or a single `bootstrap`/`wire` module `main` calls before serving. `init()` and
|
|
98
|
+
package-var side effects run on **every** binary start, before `main` gets control.
|
|
99
|
+
- **Heavy server-only import markers (what makes an init "heavy" for `CHECK-I23`):** DB drivers/pools
|
|
100
|
+
(`database/sql` + a driver, `pgx`, `gorm`, `mongo-driver`), message/queue clients (`sarama`/Kafka,
|
|
101
|
+
`amqp`, `go-redis`), telemetry SDKs (`go.opentelemetry.io/*`, `sentry-go`), or a broad internal
|
|
102
|
+
service package. An `init()` or package-var that dials any of these is the CHECK-I23 pattern —
|
|
103
|
+
recommend a `sync.Once` lazy constructor invoked from the first handler that needs it, not an
|
|
104
|
+
eager package-level connect.
|
|
105
|
+
|
|
87
106
|
## Testing
|
|
88
107
|
|
|
89
108
|
- **Framework**: `testing` stdlib package
|
|
@@ -111,6 +111,27 @@ async def refresh_session_token(
|
|
|
111
111
|
- **Import validation**: `mypy` with `--strict` or `--disallow-untyped-defs` catches missing type annotations
|
|
112
112
|
- **Module export validation**: `__all__` lists in `__init__.py` match spec's public API
|
|
113
113
|
|
|
114
|
+
### Runtime Entrypoints & Bootstrap-Wiring Sites
|
|
115
|
+
|
|
116
|
+
Used by `CHECK-I22` (a runtime-required bootstrap needs a **non-test** caller on one of these) and
|
|
117
|
+
`CHECK-I23` (a heavy init wired into a **universal** bootstrap entry should move to a lazier site).
|
|
118
|
+
|
|
119
|
+
- **Runtime entrypoints (a legitimate non-test call site):** a `if __name__ == "__main__":` block, a
|
|
120
|
+
`[project.scripts]` console-script target in `pyproject.toml`, an ASGI/WSGI app object
|
|
121
|
+
(`app = FastAPI()` / Django `wsgi.py` / `asgi.py`), a route/view/handler, a Celery/RQ task module, or
|
|
122
|
+
a management command — not a `test_*.py` / `conftest.py`.
|
|
123
|
+
- **Universal bootstrap entries (run on every startup — the `CHECK-I23` risk site):** a package
|
|
124
|
+
`__init__.py` that eagerly instantiates heavy clients at import time, a framework startup hook
|
|
125
|
+
(FastAPI `lifespan` / `@app.on_event("startup")`, Django `AppConfig.ready()`, a Gunicorn/uvicorn
|
|
126
|
+
`--preload` module), or a `conftest.py` that bootstraps production graphs. Import-time side effects
|
|
127
|
+
here run on every process start.
|
|
128
|
+
- **Heavy server-only import markers (what makes an init "heavy" for `CHECK-I23`):** DB/ORM engines
|
|
129
|
+
(`sqlalchemy.create_engine`, `psycopg`, Django ORM, `pymongo`, `redis`), task queues (`celery`,
|
|
130
|
+
`rq`, `kafka`), telemetry SDKs (`opentelemetry`, `sentry_sdk`), or a whole-service-layer package
|
|
131
|
+
import. An init pulling any of these at a universal entry is the CHECK-I23 pattern — recommend lazy
|
|
132
|
+
init (module-level `@lru_cache` factory, `Depends()` provider, or first-use lazy import) at the
|
|
133
|
+
handler that needs it.
|
|
134
|
+
|
|
114
135
|
## Testing
|
|
115
136
|
|
|
116
137
|
- **Framework**: pytest (with `conftest.py` for fixtures)
|
|
@@ -90,6 +90,25 @@ When examining a Rust project, check for:
|
|
|
90
90
|
- **Formatting**: `cargo fmt --check` (ensures code matches `rustfmt` style)
|
|
91
91
|
- **Unsafe audit**: `cargo geiger` (if security-sensitive — counts unsafe blocks)
|
|
92
92
|
|
|
93
|
+
### Runtime Entrypoints & Bootstrap-Wiring Sites
|
|
94
|
+
|
|
95
|
+
Used by `CHECK-I22` (a runtime-required bootstrap needs a **non-test** caller on one of these) and
|
|
96
|
+
`CHECK-I23` (a heavy init wired into a **universal** bootstrap entry should move to a lazier site).
|
|
97
|
+
|
|
98
|
+
- **Runtime entrypoints (a legitimate non-test call site):** `fn main()` in `main.rs` or a `[[bin]]`
|
|
99
|
+
target, an async runtime entry (`#[tokio::main]`), an HTTP handler registered on an axum/actix/warp
|
|
100
|
+
router, or a worker task spawned from `main` — not a `#[cfg(test)]` module or a `tests/` integration
|
|
101
|
+
file.
|
|
102
|
+
- **Universal bootstrap entries (run on every startup — the `CHECK-I23` risk site):** a `lazy_static!`
|
|
103
|
+
/ `once_cell::sync::Lazy` static that eagerly constructs heavy clients, a single `bootstrap`/`setup`
|
|
104
|
+
fn `main` calls before serving, or a `#[ctor]`-style pre-`main` initializer. A `Lazy` static is only
|
|
105
|
+
a risk when it is *forced* at startup rather than on first use.
|
|
106
|
+
- **Heavy server-only import markers (what makes an init "heavy" for `CHECK-I23`):** DB pools
|
|
107
|
+
(`sqlx::Pool`, `diesel`, `deadpool`, `mongodb`), message/queue clients (`rdkafka`, `lapin`,
|
|
108
|
+
`redis`), telemetry SDKs (`opentelemetry`, `sentry`), or a broad internal service crate. Constructing
|
|
109
|
+
any of these eagerly at a universal entry is the CHECK-I23 pattern — recommend a `OnceCell`/`Lazy`
|
|
110
|
+
forced on **first use** by the handler that needs it, not at process start.
|
|
111
|
+
|
|
93
112
|
## Testing
|
|
94
113
|
|
|
95
114
|
- **Framework**: Built-in test harness (`#[test]`, `#[cfg(test)]`)
|
|
@@ -64,6 +64,29 @@ When examining a TypeScript project, check for:
|
|
|
64
64
|
- **Cross-package type checks**: `bun run typecheck` (or equivalent) passes for both the feature package AND packages that depend on it
|
|
65
65
|
- **Import path validation**: All import paths resolve correctly per the `exports` map in `package.json`
|
|
66
66
|
|
|
67
|
+
### Runtime Entrypoints & Bootstrap-Wiring Sites
|
|
68
|
+
|
|
69
|
+
Used by `CHECK-I22` (a runtime-required bootstrap needs a **non-test** caller on one of these) and
|
|
70
|
+
`CHECK-I23` (a heavy init wired into a **universal** bootstrap entry should move to a lazier site).
|
|
71
|
+
|
|
72
|
+
- **Runtime entrypoints (a legitimate non-test call site):** a `package.json` `bin` / CLI `main`; a
|
|
73
|
+
server entry that actually starts listening (`src/server.ts`, `src/index.ts` invoking `listen`); a
|
|
74
|
+
worker/consumer file; and for Next.js — `middleware.ts`, `app/**/route.ts` route handlers,
|
|
75
|
+
`app/**/{page,layout,template}.tsx`, server actions, and `instrumentation.ts`. Express/Hono/Fastify:
|
|
76
|
+
the file that constructs the app and calls `.listen()`.
|
|
77
|
+
- **Universal bootstrap entries (run on every startup — the `CHECK-I23` risk site):** Next.js
|
|
78
|
+
`instrumentation.ts` / `instrumentation.js` (its `register()` runs once per server process before
|
|
79
|
+
any request), an app-server preload/`register`/`--import` hook, a root `app/layout.tsx` that
|
|
80
|
+
eagerly imports server singletons, and global test setup (`vitest.setup.ts`, `jest.setup.ts`) if it
|
|
81
|
+
bootstraps production graphs. Wiring a heavy init here loads it on **every** cold start (and, under
|
|
82
|
+
the dev server, on every module re-evaluation).
|
|
83
|
+
- **Heavy server-only import markers (what makes an init "heavy" for `CHECK-I23`):** DB/ORM clients
|
|
84
|
+
(`drizzle-orm`, `@prisma/client`, `pg`, `mongoose`, `kysely`), queue/worker libs (`bullmq`, `bull`,
|
|
85
|
+
`kafkajs`, `ioredis`), telemetry/observability SDKs (`@opentelemetry/*`, `@sentry/node`), and a
|
|
86
|
+
whole-service-layer barrel (`import * as services from "@repo/services"`). An init that pulls any of
|
|
87
|
+
these into a universal bootstrap entry is the CHECK-I23 pattern — recommend lazy init at the first
|
|
88
|
+
route/handler/worker that needs it.
|
|
89
|
+
|
|
67
90
|
## Testing
|
|
68
91
|
|
|
69
92
|
- **Framework**: Vitest (most common in modern TS), Jest, or testing-library
|
|
@@ -116,6 +116,8 @@ do not reload everything. This keeps quality up under context pressure.
|
|
|
116
116
|
|
|
117
117
|
## Step 5: Cross-Reference Validation
|
|
118
118
|
|
|
119
|
+
Before writing `TRACEABILITY.md` or running the stage exit, invoke the **Stage-Completion Re-check** block in `references/shared-conventions.md` with `{stage}` = `forge-3-specs` — a resumed mid-stage continuation must not overwrite a committed `TRACEABILITY.md` or re-fire a finished exit.
|
|
120
|
+
|
|
119
121
|
After writing all documents, verify:
|
|
120
122
|
|
|
121
123
|
1. Every PRD requirement has coverage in at least one spec document
|
|
@@ -274,6 +274,18 @@ This write is **left uncommitted**: it is staged and committed as part of this s
|
|
|
274
274
|
|
|
275
275
|
**Incremental artifact tracking:** When a stage writes multiple files (e.g. forge-3-specs writing a suite of spec documents), update the `stages.{stage}.artifacts` array in `.pipeline-state.json` after writing each file — not just at stage completion. This is what makes the Interrupted inventory above precise about which files were successfully written.
|
|
276
276
|
|
|
277
|
+
## Stage-Completion Re-check
|
|
278
|
+
|
|
279
|
+
Invoke this block **at the head of any post-entry step that writes a stage artifact or runs the Scripted Stage Exit** — the Stage-Entry Guard runs only once, at the top of the skill. A **resumed or pasted mid-stage instruction** (e.g. "continue {stage}: write TRACEABILITY.md, run the stage exit") enters *below* the entry guard, so nothing re-checks completion before it overwrites a committed artifact and re-fires a finished exit — data-destructive if followed literally. This re-check is the idempotency backstop for that path. `{stage}` is the invoking skill's id.
|
|
280
|
+
|
|
281
|
+
**Re-read** `stages.{stage}` in `{resolvedFeatureDir}/.pipeline-state.json`, then classify by **provenance** — a legitimate completion runs in the same session that applied this stage's Entry Stamp; a replayed continuation finds a finished stage it did not produce:
|
|
282
|
+
|
|
283
|
+
1. **Proceed** when `stages.{stage}.status` is `"in-progress"` (this session's Entry Stamp — you are finishing the run you started) or absent/`pending`. Run the write / exit normally.
|
|
284
|
+
|
|
285
|
+
2. **Detect-and-refuse** when ALL of these hold: `stages.{stage}.status ∈ {"complete", "stale"}` **AND** the stage's artifacts (incl. `TRACEABILITY.md` for forge-3-specs) exist on disk **AND** a `commitHash` is recorded for the stage **AND** you did **not** author this stage earlier in the current session. This is a stale/replayed continuation of an already-finished, committed stage. Do **not** overwrite the artifact or re-run the exit. Route instead to the **Stage-Entry Guard**'s *Re-authoring* path: surface the same `AskUserQuestion` warning ("A completed {stage} artifact already exists for '{feature}' (v{n}{, marked stale}). Continuing will create a new version. Proceed?"). Only on explicit confirmation re-enter from the Entry Stamp (the version bumps at exit); otherwise **stop** and report that the stage is already complete — cite the recorded `commitHash` and offer `/feature-forge:forge {feature}` to see true state.
|
|
286
|
+
|
|
287
|
+
When you cannot confirm you authored the current run, treat it as a replay and refuse: a false refuse costs one confirmation click; a false proceed overwrites a committed artifact and re-churns a stage version. `--force` follows Force Mode (skip the gate, treat as a deliberate re-author).
|
|
288
|
+
|
|
277
289
|
## Force Mode
|
|
278
290
|
|
|
279
291
|
If the user passes `--force` as an argument, skip prerequisite validation with a warning:
|
|
@@ -79,6 +79,27 @@ Replace stack-specific checks with these generic equivalents:
|
|
|
79
79
|
| "JSDoc on every field" | "Documentation comments on every field" |
|
|
80
80
|
| "tsconfig.json extends root" | "Build configuration follows project conventions" |
|
|
81
81
|
|
|
82
|
+
### Runtime Entrypoints & Bootstrap-Wiring Sites
|
|
83
|
+
|
|
84
|
+
Used by `CHECK-I22` (a runtime-required bootstrap needs a **non-test** caller on one of these) and
|
|
85
|
+
`CHECK-I23` (a heavy init wired into a **universal** bootstrap entry should move to a lazier site).
|
|
86
|
+
Since no dedicated profile applies, identify these by role rather than exact filename:
|
|
87
|
+
|
|
88
|
+
- **Runtime entrypoints (a legitimate non-test call site):** the process/main entry the build's
|
|
89
|
+
run command actually launches (from the CI/`Makefile`/manifest "start" target), an HTTP/RPC handler
|
|
90
|
+
or route, a scheduled/worker task, or a CLI subcommand — **not** a file in the project's test
|
|
91
|
+
directory or matching its test-file convention.
|
|
92
|
+
- **Universal bootstrap entries (run on every startup — the `CHECK-I23` risk site):** any
|
|
93
|
+
module/hook the framework runs **once per process before serving** — a startup/lifecycle hook, an
|
|
94
|
+
import-time initializer, a global preload, or a shared test-setup module that bootstraps production
|
|
95
|
+
graphs. Side effects here run on every process start (and, under a dev/watch runtime, on every
|
|
96
|
+
reload).
|
|
97
|
+
- **Heavy server-only import markers (what makes an init "heavy" for `CHECK-I23`):** database/ORM
|
|
98
|
+
clients and connection pools, message/queue clients, telemetry/observability SDKs, or a broad
|
|
99
|
+
whole-service-layer import. An init pulling any of these into a universal bootstrap entry is the
|
|
100
|
+
CHECK-I23 pattern — recommend lazy initialization at the first handler/worker that needs the graph,
|
|
101
|
+
not eagerly at process start.
|
|
102
|
+
|
|
82
103
|
## Acceptance Criteria Patterns
|
|
83
104
|
|
|
84
105
|
Use these placeholder patterns in backlog items. Replace `{typeCheckCommand}`, `{testCommand}`, and `{module}` with values from `forge.config.json` and the project structure:
|