@guanlin4924/devflow-pi 0.1.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 +164 -0
- package/docs/OMP-NATIVE-ARCHITECTURE.md +104 -0
- package/package.json +40 -0
- package/plugins/devflow-core/extensions/devflow-core.ts +1642 -0
- package/plugins/devflow-core/package.json +14 -0
- package/plugins/devflow-core/runtime/hooks/context_sync_gate.py +174 -0
- package/plugins/devflow-core/runtime/hooks/hook_common.py +696 -0
- package/plugins/devflow-core/runtime/hooks/index_gate.py +63 -0
- package/plugins/devflow-core/runtime/hooks/injection_code_specification.py +7 -0
- package/plugins/devflow-core/runtime/hooks/post_tool.py +44 -0
- package/plugins/devflow-core/runtime/hooks/start.py +288 -0
- package/plugins/devflow-core/skills/workflow-orchestrator/SKILL.md +265 -0
- package/plugins/devflow-core/skills/workflow-orchestrator/agents/openai.yaml +4 -0
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/advance_state.rb +520 -0
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/control_io.rb +42 -0
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/init_state.rb +138 -0
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/init_workflow.rb +121 -0
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/inspect_state.rb +553 -0
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/manage_lessons.rb +219 -0
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/sync_artifacts.rb +168 -0
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/update_triage_route.rb +110 -0
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/validate_state.rb +565 -0
- package/plugins/devflow-core/skills/workflow-orchestrator/templates/feature-development.yaml +783 -0
- package/plugins/devflow-core/skills/workflow-orchestrator/templates/uat-remediation.yaml +143 -0
- package/plugins/devflow-core/skills/workflow-orchestrator/templates/workflows-README.md +10 -0
- package/plugins/devflow-core/skills/workflow-pipeline/SKILL.md +117 -0
- package/plugins/devflow-core/skills/workflow-pipeline/references/pipeline-flow.md +167 -0
- package/plugins/devflow-core/skills/workflow-pipeline/references/slice-safety-guide.md +125 -0
- package/plugins/devflow-core/skills/workflow-project-context/SKILL.md +819 -0
- package/plugins/devflow-core/skills/workflow-project-context/assets/agents-md-template.md +25 -0
- package/plugins/devflow-core/skills/workflow-project-context/assets/codebase-backend-spec-template.md +68 -0
- package/plugins/devflow-core/skills/workflow-project-context/assets/codebase-frontend-spec-template.md +64 -0
- package/plugins/devflow-core/skills/workflow-project-context/assets/codebase-navigation-template.md +168 -0
- package/plugins/devflow-core/skills/workflow-project-context/assets/context-domain-index-template.md +43 -0
- package/plugins/devflow-core/skills/workflow-project-context/assets/context-spec-index-template.md +45 -0
- package/plugins/devflow-core/skills/workflow-project-context/assets/execution-contract-template.md +57 -0
- package/plugins/devflow-core/skills/workflow-project-context/assets/navigation-index-template.md +40 -0
- package/plugins/devflow-core/skills/workflow-project-context/assets/project-initialization-template.md +109 -0
- package/plugins/devflow-core/skills/workflow-project-context/assets/rules-index-template.md +80 -0
- package/plugins/devflow-core/skills/workflow-project-context/assets/run-manifest-template.json +40 -0
- package/plugins/devflow-core/skills/workflow-project-context/assets/spec-templates/backend/directory-structure.md +46 -0
- package/plugins/devflow-core/skills/workflow-project-context/assets/spec-templates/backend/engine.md +46 -0
- package/plugins/devflow-core/skills/workflow-project-context/assets/spec-templates/backend/errors.md +46 -0
- package/plugins/devflow-core/skills/workflow-project-context/assets/spec-templates/backend/locator.md +46 -0
- package/plugins/devflow-core/skills/workflow-project-context/assets/spec-templates/backend/model.md +46 -0
- package/plugins/devflow-core/skills/workflow-project-context/assets/spec-templates/backend/repository.md +46 -0
- package/plugins/devflow-core/skills/workflow-project-context/assets/spec-templates/backend/router.md +46 -0
- package/plugins/devflow-core/skills/workflow-project-context/assets/spec-templates/backend/scheduler.md +46 -0
- package/plugins/devflow-core/skills/workflow-project-context/assets/spec-templates/backend/schema.md +46 -0
- package/plugins/devflow-core/skills/workflow-project-context/assets/spec-templates/backend/service.md +46 -0
- package/plugins/devflow-core/skills/workflow-project-context/assets/spec-templates/backend/testing.md +46 -0
- package/plugins/devflow-core/skills/workflow-project-context/assets/spec-templates/frontend/api-client.md +46 -0
- package/plugins/devflow-core/skills/workflow-project-context/assets/spec-templates/frontend/case-editor.md +46 -0
- package/plugins/devflow-core/skills/workflow-project-context/assets/spec-templates/frontend/components.md +46 -0
- package/plugins/devflow-core/skills/workflow-project-context/assets/spec-templates/frontend/directory-structure.md +46 -0
- package/plugins/devflow-core/skills/workflow-project-context/assets/spec-templates/frontend/forms.md +46 -0
- package/plugins/devflow-core/skills/workflow-project-context/assets/spec-templates/frontend/routing.md +46 -0
- package/plugins/devflow-core/skills/workflow-project-context/assets/spec-templates/frontend/state.md +46 -0
- package/plugins/devflow-core/skills/workflow-project-context/assets/spec-templates/frontend/testing.md +46 -0
- package/plugins/devflow-core/skills/workflow-project-context/assets/stack-spec-template.md +106 -0
- package/plugins/devflow-core/skills/workflow-project-context/assets/state-template.md +77 -0
- package/plugins/devflow-core/skills/workflow-project-context/assets/toolchain-template.md +37 -0
- package/plugins/devflow-core/skills/workflow-project-context/references/navigation-guide.md +262 -0
- package/plugins/devflow-core/skills/workflow-project-context/scripts/validate_initialization.py +545 -0
- package/plugins/devflow-design/agents/contract-auditor.md +18 -0
- package/plugins/devflow-design/extensions/devflow-design.ts +47 -0
- package/plugins/devflow-design/package.json +14 -0
- package/plugins/devflow-design/skills/workflow-api-call-guide/SKILL.md +142 -0
- package/plugins/devflow-design/skills/workflow-api-contract/SKILL.md +150 -0
- package/plugins/devflow-design/skills/workflow-api-supplement/SKILL.md +121 -0
- package/plugins/devflow-design/skills/workflow-backend-tech-spec/SKILL.md +257 -0
- package/plugins/devflow-design/skills/workflow-backend-tech-spec/assets/adr-template.md +57 -0
- package/plugins/devflow-design/skills/workflow-backend-tech-spec/assets/backend-spec-template.md +205 -0
- package/plugins/devflow-design/skills/workflow-backend-tech-spec/references/affected-module-exploration.md +59 -0
- package/plugins/devflow-design/skills/workflow-backend-tech-spec/references/backend-conventions.md +30 -0
- package/plugins/devflow-design/skills/workflow-backend-tech-spec/references/code-explore-guide.md +40 -0
- package/plugins/devflow-design/skills/workflow-backend-tech-spec/references/project-rule-contract.md +66 -0
- package/plugins/devflow-design/skills/workflow-design-rule-pack/SKILL.md +91 -0
- package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/index.md +71 -0
- package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/recommendations/accessibility.md +31 -0
- package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/recommendations/component-library.md +31 -0
- package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/recommendations/design-systems.md +47 -0
- package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/recommendations/responsive-grid.md +29 -0
- package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/recommendations/stack-guidelines.md +31 -0
- package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/recommendations/ux-patterns.md +40 -0
- package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/tokens/project-tokens.md +19 -0
- package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/tools/ui-ux-pro-max/SKILL.md +377 -0
- package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/tools/ui-ux-pro-max/data/charts.csv +26 -0
- package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/tools/ui-ux-pro-max/data/colors.csv +97 -0
- package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/tools/ui-ux-pro-max/data/icons.csv +101 -0
- package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/tools/ui-ux-pro-max/data/landing.csv +31 -0
- package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/tools/ui-ux-pro-max/data/products.csv +97 -0
- package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/tools/ui-ux-pro-max/data/react-performance.csv +45 -0
- package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/tools/ui-ux-pro-max/data/stacks/astro.csv +54 -0
- package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/tools/ui-ux-pro-max/data/stacks/flutter.csv +53 -0
- package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/tools/ui-ux-pro-max/data/stacks/html-tailwind.csv +56 -0
- package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/tools/ui-ux-pro-max/data/stacks/jetpack-compose.csv +53 -0
- package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/tools/ui-ux-pro-max/data/stacks/nextjs.csv +53 -0
- package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/tools/ui-ux-pro-max/data/stacks/nuxt-ui.csv +51 -0
- package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/tools/ui-ux-pro-max/data/stacks/nuxtjs.csv +59 -0
- package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/tools/ui-ux-pro-max/data/stacks/react-native.csv +52 -0
- package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/tools/ui-ux-pro-max/data/stacks/react.csv +54 -0
- package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/tools/ui-ux-pro-max/data/stacks/shadcn.csv +61 -0
- package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/tools/ui-ux-pro-max/data/stacks/svelte.csv +54 -0
- package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/tools/ui-ux-pro-max/data/stacks/swiftui.csv +51 -0
- package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/tools/ui-ux-pro-max/data/stacks/vue.csv +50 -0
- package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/tools/ui-ux-pro-max/data/styles.csv +68 -0
- package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/tools/ui-ux-pro-max/data/typography.csv +58 -0
- package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/tools/ui-ux-pro-max/data/ui-reasoning.csv +101 -0
- package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/tools/ui-ux-pro-max/data/ux-guidelines.csv +100 -0
- package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/tools/ui-ux-pro-max/data/web-interface.csv +31 -0
- package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/tools/ui-ux-pro-max/scripts/core.py +253 -0
- package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/tools/ui-ux-pro-max/scripts/design_system.py +1067 -0
- package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/tools/ui-ux-pro-max/scripts/search.py +114 -0
- package/plugins/devflow-design/skills/workflow-design-rule-pack/scripts/install.py +67 -0
- package/plugins/devflow-design/skills/workflow-feature-breakdown/SKILL.md +370 -0
- package/plugins/devflow-design/skills/workflow-feature-breakdown/assets/admin-system-template.md +57 -0
- package/plugins/devflow-design/skills/workflow-feature-breakdown/assets/api-service-template.md +42 -0
- package/plugins/devflow-design/skills/workflow-feature-breakdown/assets/c-end-system-template.md +25 -0
- package/plugins/devflow-design/skills/workflow-feature-breakdown/assets/output-template.md +139 -0
- package/plugins/devflow-design/skills/workflow-feature-breakdown/references/bug-rules.md +12 -0
- package/plugins/devflow-design/skills/workflow-feature-breakdown/references/exception-checklist.md +31 -0
- package/plugins/devflow-design/skills/workflow-feature-breakdown/references/trace-integrity-guide.md +153 -0
- package/plugins/devflow-design/skills/workflow-feature-breakdown/references/writing-guide.md +92 -0
- package/plugins/devflow-design/skills/workflow-frontend-tech-spec/SKILL.md +223 -0
- package/plugins/devflow-design/skills/workflow-frontend-tech-spec/assets/frontend-spec-template.md +204 -0
- package/plugins/devflow-design/skills/workflow-frontend-tech-spec/references/affected-module-exploration.md +58 -0
- package/plugins/devflow-design/skills/workflow-frontend-tech-spec/references/component-patterns.md +42 -0
- package/plugins/devflow-design/skills/workflow-frontend-tech-spec/references/frontend-conventions.md +28 -0
- package/plugins/devflow-design/skills/workflow-frontend-tech-spec/references/frontend-stack-slots/common-web.md +53 -0
- package/plugins/devflow-design/skills/workflow-frontend-tech-spec/references/frontend-stack-slots/next.md +40 -0
- package/plugins/devflow-design/skills/workflow-frontend-tech-spec/references/frontend-stack-slots/react.md +41 -0
- package/plugins/devflow-design/skills/workflow-frontend-tech-spec/references/frontend-stack-slots/vue.md +41 -0
- package/plugins/devflow-design/skills/workflow-frontend-tech-spec/references/project-rule-contract.md +95 -0
- package/plugins/devflow-design/skills/workflow-integration-verify/SKILL.md +172 -0
- package/plugins/devflow-design/skills/workflow-ui-spec/SKILL.md +302 -0
- package/plugins/devflow-design/skills/workflow-ui-spec/assets/ui-spec-template.md +244 -0
- package/plugins/devflow-design/skills/workflow-ui-spec/references/affected-module-exploration.md +55 -0
- package/plugins/devflow-implementation/agents/implementation-worker.md +20 -0
- package/plugins/devflow-implementation/package.json +6 -0
- package/plugins/devflow-implementation/skills/workflow-bug-fix/SKILL.md +124 -0
- package/plugins/devflow-implementation/skills/workflow-bug-fix/references/INDEX.md +13 -0
- package/plugins/devflow-implementation/skills/workflow-bug-fix/references/adversarial-review.md +35 -0
- package/plugins/devflow-implementation/skills/workflow-bug-fix/references/first-principles.md +26 -0
- package/plugins/devflow-implementation/skills/workflow-bug-fix/references/lesson-format.md +28 -0
- package/plugins/devflow-implementation/skills/workflow-bug-fix/references/root-cause-ladder.md +51 -0
- package/plugins/devflow-implementation/skills/workflow-bug-fix/references/seam-analysis.md +30 -0
- package/plugins/devflow-implementation/skills/workflow-change-plan/SKILL.md +160 -0
- package/plugins/devflow-implementation/skills/workflow-change-plan/references/code-conventions.md +33 -0
- package/plugins/devflow-implementation/skills/workflow-change-plan/references/ddl-guidelines.md +60 -0
- package/plugins/devflow-implementation/skills/workflow-change-plan/references/output-template.md +217 -0
- package/plugins/devflow-implementation/skills/workflow-change-plan/references/project-rule-contract.md +55 -0
- package/plugins/devflow-implementation/skills/workflow-execute-phase/SKILL.md +271 -0
- package/plugins/devflow-implementation/skills/workflow-execute-phase/references/execute-phase.md +1251 -0
- package/plugins/devflow-implementation/skills/workflow-execute-phase/references/ui-brand.md +160 -0
- package/plugins/devflow-intel/agents/project-scout.md +27 -0
- package/plugins/devflow-intel/extensions/devflow-intel.ts +104 -0
- package/plugins/devflow-intel/package.json +14 -0
- package/plugins/devflow-intel/skills/code-index-query/SKILL.md +37 -0
- package/plugins/devflow-intel/skills/code-index-query/references/query-patterns.md +27 -0
- package/plugins/devflow-intel/skills/workflow-code-index/SKILL.md +68 -0
- package/plugins/devflow-intel/skills/workflow-code-index/references/adapter-contract.md +38 -0
- package/plugins/devflow-intel/skills/workflow-code-index/references/audit-checklist.md +10 -0
- package/plugins/devflow-intel/skills/workflow-code-index/references/confidence-rules.md +43 -0
- package/plugins/devflow-intel/skills/workflow-code-index/references/data-model.md +74 -0
- package/plugins/devflow-intel/skills/workflow-code-index/references/discovery.md +24 -0
- package/plugins/devflow-intel/skills/workflow-code-index/references/query-guide.md +20 -0
- package/plugins/devflow-intel/skills/workflow-code-index/scripts/adapters/__init__.py +1 -0
- package/plugins/devflow-intel/skills/workflow-code-index/scripts/adapters/base.py +30 -0
- package/plugins/devflow-intel/skills/workflow-code-index/scripts/adapters/generic_text.py +287 -0
- package/plugins/devflow-intel/skills/workflow-code-index/scripts/adapters/registry.py +17 -0
- package/plugins/devflow-intel/skills/workflow-code-index/scripts/code_index.py +437 -0
- package/plugins/devflow-intel/skills/workflow-code-index/scripts/core/__init__.py +1 -0
- package/plugins/devflow-intel/skills/workflow-code-index/scripts/core/discovery.py +139 -0
- package/plugins/devflow-intel/skills/workflow-code-index/scripts/core/hashing.py +11 -0
- package/plugins/devflow-intel/skills/workflow-code-index/scripts/core/scanner.py +115 -0
- package/plugins/devflow-intel/skills/workflow-code-index/scripts/core/schema.py +123 -0
- package/plugins/devflow-intel/skills/workflow-code-index/scripts/validators/__init__.py +1 -0
- package/plugins/devflow-intel/skills/workflow-code-index/scripts/validators/project_binding_check.py +66 -0
- package/plugins/devflow-intel/skills/workflow-code-index/scripts/validators/relation_check.py +36 -0
- package/plugins/devflow-intel/skills/workflow-code-index/scripts/validators/schema_validate.py +11 -0
- package/plugins/devflow-intel/skills/workflow-code-index/scripts/validators/stale_check.py +42 -0
- package/plugins/devflow-intel/skills/workflow-code-index/scripts/writers/__init__.py +1 -0
- package/plugins/devflow-intel/skills/workflow-code-index/scripts/writers/jsonl_writer.py +25 -0
- package/plugins/devflow-intel/skills/workflow-code-index/scripts/writers/markdown_writer.py +106 -0
- package/plugins/devflow-intel/skills/workflow-code-index/scripts/writers/sqlite_writer.py +143 -0
- package/plugins/devflow-intel/skills/workflow-context-sync/SKILL.md +381 -0
- package/plugins/devflow-intel/skills/workflow-context-sync/agents/openai.yaml +4 -0
- package/plugins/devflow-intel/skills/workflow-context-sync/scripts/context_sync_cursor.py +241 -0
- package/plugins/devflow-intel/skills/workflow-update-navigation/SKILL.md +186 -0
- package/plugins/devflow-intel/skills/workflow-update-navigation/references/incremental-update-guide.md +47 -0
- package/plugins/devflow-quality/agents/code-reviewer.md +18 -0
- package/plugins/devflow-quality/agents/verification-runner.md +21 -0
- package/plugins/devflow-quality/extensions/devflow-quality.ts +59 -0
- package/plugins/devflow-quality/package.json +14 -0
- package/plugins/devflow-quality/skills/code-review/SKILL.md +288 -0
- package/plugins/devflow-quality/skills/code-review/references/cross-layer-checklist.md +70 -0
- package/plugins/devflow-quality/skills/code-review/references/dao-checklist.md +70 -0
- package/plugins/devflow-quality/skills/code-review/references/handler-checklist.md +48 -0
- package/plugins/devflow-quality/skills/code-review/references/repository-checklist.md +44 -0
- package/plugins/devflow-quality/skills/code-review/references/service-checklist.md +57 -0
- package/plugins/devflow-quality/skills/code-review/references/spec-checklist.md +34 -0
- package/plugins/devflow-quality/skills/code-review/references/vo-checklist.md +26 -0
- package/plugins/devflow-quality/skills/workflow-audit-milestone/SKILL.md +31 -0
- package/plugins/devflow-quality/skills/workflow-audit-milestone/references/audit-milestone.md +328 -0
- package/plugins/devflow-quality/skills/workflow-complete-milestone/SKILL.md +132 -0
- package/plugins/devflow-quality/skills/workflow-complete-milestone/assets/milestone-archive.md +123 -0
- package/plugins/devflow-quality/skills/workflow-complete-milestone/references/complete-milestone.md +775 -0
- package/plugins/devflow-quality/skills/workflow-complete-milestone/references/milestone-archive.md +123 -0
- package/plugins/devflow-quality/skills/workflow-generate-mainflow-cases/SKILL.md +126 -0
- package/plugins/devflow-quality/skills/workflow-generate-mainflow-cases/references/api-mainflow-rules.md +27 -0
- package/plugins/devflow-quality/skills/workflow-generate-mainflow-cases/references/codebase-discovery.md +54 -0
- package/plugins/devflow-quality/skills/workflow-generate-mainflow-cases/references/intermediate-format.md +244 -0
- package/plugins/devflow-quality/skills/workflow-generate-mainflow-cases/references/mainflow-selection.md +36 -0
- package/plugins/devflow-quality/skills/workflow-generate-mainflow-cases/references/project-dsl-contract.md +190 -0
- package/plugins/devflow-quality/skills/workflow-generate-mainflow-cases/references/ui-mainflow-rules.md +110 -0
- package/plugins/devflow-quality/skills/workflow-generate-mainflow-cases/scripts/compile_dsl.py +583 -0
- package/plugins/devflow-quality/skills/workflow-generate-mainflow-cases/scripts/discover_codebases.py +199 -0
- package/plugins/devflow-quality/skills/workflow-generate-mainflow-cases/scripts/normalize_case_payloads.py +177 -0
- package/plugins/devflow-quality/skills/workflow-generate-mainflow-cases/scripts/validate_case_payloads.py +370 -0
- package/plugins/devflow-quality/skills/workflow-verify-work/SKILL.md +106 -0
- package/plugins/devflow-quality/skills/workflow-verify-work/assets/UAT.md +265 -0
- package/plugins/devflow-quality/skills/workflow-verify-work/references/verify-work.md +759 -0
- package/plugins/devflow-requirements/agents/requirements-auditor.md +20 -0
- package/plugins/devflow-requirements/package.json +6 -0
- package/plugins/devflow-requirements/skills/requirement-feasibility-review/SKILL.md +219 -0
- package/plugins/devflow-requirements/skills/requirement-feasibility-review/agents/openai.yaml +4 -0
- package/plugins/devflow-requirements/skills/requirement-feasibility-review/references/review-method.md +257 -0
- package/plugins/devflow-requirements/skills/requirement-feasibility-review/references/review-template.md +80 -0
- package/plugins/devflow-requirements/skills/workflow-demand-clarify/SKILL.md +325 -0
- package/plugins/devflow-requirements/skills/workflow-domain-modeling/SKILL.md +163 -0
- package/plugins/devflow-requirements/skills/workflow-requirement-baseline/SKILL.md +748 -0
- package/plugins/devflow-requirements/skills/workflow-requirement-baseline/assets/baseline-template.md +281 -0
- package/plugins/devflow-requirements/skills/workflow-requirement-baseline/references/antipatterns.md +69 -0
- package/plugins/devflow-requirements/skills/workflow-requirement-baseline/references/challenge-review-guide.md +158 -0
- package/plugins/devflow-requirements/skills/workflow-requirement-baseline/references/decomposition-guide.md +115 -0
- package/plugins/devflow-requirements/skills/workflow-requirement-baseline/references/project-context-guide.md +119 -0
- package/plugins/devflow-requirements/skills/workflow-requirement-baseline/references/questioning.md +76 -0
- package/plugins/devflow-requirements/skills/workflow-requirement-baseline/references/requirement-review-checklist.md +115 -0
- package/plugins/devflow-requirements/skills/workflow-requirement-triage/SKILL.md +204 -0
- package/plugins/devflow-requirements/skills/workflow-wayfinder/SKILL.md +183 -0
- package/src/cli.ts +76 -0
- package/src/constants.ts +15 -0
- package/src/doctor.ts +66 -0
- package/src/paths.ts +37 -0
- package/src/platform-extension.ts +46 -0
- package/src/project-context.ts +165 -0
- package/src/runtime.ts +167 -0
- package/src/usage-stats.ts +101 -0
- package/templates/commands/start.md +58 -0
- package/templates/omp/AGENTS.md +36 -0
- package/templates/omp/config.yml +112 -0
- package/templates/omp/hook-config.json +18 -0
- package/templates/omp/index-policy.json +57 -0
package/plugins/devflow-core/skills/workflow-project-context/scripts/validate_initialization.py
ADDED
|
@@ -0,0 +1,545 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Validate that project-context outputs belong to the current initialization run."""
|
|
3
|
+
|
|
4
|
+
from __future__ import annotations
|
|
5
|
+
|
|
6
|
+
import argparse
|
|
7
|
+
import hashlib
|
|
8
|
+
import json
|
|
9
|
+
import sys
|
|
10
|
+
from collections import Counter
|
|
11
|
+
from datetime import datetime
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
from typing import Any
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
SKILL_ROOT = Path(__file__).resolve().parents[1]
|
|
17
|
+
SPEC_TEMPLATE_ROOT = SKILL_ROOT / "assets" / "spec-templates"
|
|
18
|
+
|
|
19
|
+
CODE_INDEX_FILES = (
|
|
20
|
+
".planning/code-index/index.sqlite",
|
|
21
|
+
".planning/code-index/files.jsonl",
|
|
22
|
+
".planning/code-index/symbols.jsonl",
|
|
23
|
+
".planning/code-index/relations.jsonl",
|
|
24
|
+
".planning/code-index/AUDIT.md",
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
DESIGN_RULE_PACK_FILES = (
|
|
28
|
+
".context/spec/design/tokens/project-tokens.md",
|
|
29
|
+
".context/spec/design/recommendations/accessibility.md",
|
|
30
|
+
".context/spec/design/recommendations/component-library.md",
|
|
31
|
+
".context/spec/design/tools/ui-ux-pro-max/SKILL.md",
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
STATUS_FILES = (
|
|
35
|
+
".planning/STATE.md",
|
|
36
|
+
".planning/PROJECT.md",
|
|
37
|
+
".planning/navigation/INDEX.md",
|
|
38
|
+
".planning/rules/INDEX.md",
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def parse_args() -> argparse.Namespace:
|
|
43
|
+
parser = argparse.ArgumentParser()
|
|
44
|
+
parser.add_argument("--root", default=".")
|
|
45
|
+
parser.add_argument(
|
|
46
|
+
"--manifest",
|
|
47
|
+
default=".planning/project-context-run.json",
|
|
48
|
+
)
|
|
49
|
+
return parser.parse_args()
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def parse_started_at(value: str) -> float:
|
|
53
|
+
normalized = value.replace("Z", "+00:00")
|
|
54
|
+
return datetime.fromisoformat(normalized).timestamp()
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def resolve_project_path(root: Path, relative_path: str) -> Path:
|
|
58
|
+
candidate = (root / relative_path).resolve()
|
|
59
|
+
try:
|
|
60
|
+
candidate.relative_to(root)
|
|
61
|
+
except ValueError as error:
|
|
62
|
+
raise ValueError(f"path escapes project root: {relative_path}") from error
|
|
63
|
+
return candidate
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def resolve_codebase_root(project_root: Path, value: str) -> Path:
|
|
67
|
+
path = Path(value)
|
|
68
|
+
return path.resolve() if path.is_absolute() else (project_root / path).resolve()
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def resolve_source_path(codebase_root: Path, relative_path: str) -> Path:
|
|
72
|
+
candidate = (codebase_root / relative_path).resolve()
|
|
73
|
+
try:
|
|
74
|
+
candidate.relative_to(codebase_root)
|
|
75
|
+
except ValueError as error:
|
|
76
|
+
raise ValueError(f"source path escapes codebase root: {relative_path}") from error
|
|
77
|
+
return candidate
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def source_fingerprint(codebase_root: Path, source_paths: list[str]) -> str:
|
|
81
|
+
digest = hashlib.sha256()
|
|
82
|
+
for relative_path in sorted(set(source_paths)):
|
|
83
|
+
path = resolve_source_path(codebase_root, relative_path)
|
|
84
|
+
if not path.is_file():
|
|
85
|
+
raise ValueError(f"source file missing: {relative_path}")
|
|
86
|
+
file_hash = hashlib.sha256(path.read_bytes()).hexdigest()
|
|
87
|
+
digest.update(relative_path.encode("utf-8"))
|
|
88
|
+
digest.update(b"\0")
|
|
89
|
+
digest.update(file_hash.encode("ascii"))
|
|
90
|
+
digest.update(b"\n")
|
|
91
|
+
return f"sha256:{digest.hexdigest()}"
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def load_manifest(path: Path) -> dict[str, Any]:
|
|
95
|
+
value = json.loads(path.read_text(encoding="utf-8"))
|
|
96
|
+
if not isinstance(value, dict):
|
|
97
|
+
raise ValueError("manifest root must be an object")
|
|
98
|
+
return value
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def contains_placeholder(value: Any) -> bool:
|
|
102
|
+
if isinstance(value, str):
|
|
103
|
+
return "{{" in value or "}}" in value
|
|
104
|
+
if isinstance(value, list):
|
|
105
|
+
return any(contains_placeholder(item) for item in value)
|
|
106
|
+
if isinstance(value, dict):
|
|
107
|
+
return any(contains_placeholder(item) for item in value.values())
|
|
108
|
+
return False
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def require_fresh_file(path: Path, started_at: float, errors: list[str]) -> None:
|
|
112
|
+
if not path.is_file():
|
|
113
|
+
errors.append(f"missing file: {path}")
|
|
114
|
+
return
|
|
115
|
+
if path.stat().st_mtime + 1 < started_at:
|
|
116
|
+
errors.append(f"stale file from before this run: {path}")
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def validate_status_markers(
|
|
120
|
+
root: Path,
|
|
121
|
+
run_id: str,
|
|
122
|
+
code_index_status: str,
|
|
123
|
+
code_index_skip_reason: str,
|
|
124
|
+
errors: list[str],
|
|
125
|
+
) -> None:
|
|
126
|
+
marker = (
|
|
127
|
+
f"project_context_run_id: {run_id}; "
|
|
128
|
+
f"code_index_status: {code_index_status}; "
|
|
129
|
+
f"code_index_skip_reason: {code_index_skip_reason}"
|
|
130
|
+
)
|
|
131
|
+
for relative_path in STATUS_FILES:
|
|
132
|
+
path = resolve_project_path(root, relative_path)
|
|
133
|
+
if not path.is_file():
|
|
134
|
+
errors.append(f"status file missing: {relative_path}")
|
|
135
|
+
continue
|
|
136
|
+
content = path.read_text(encoding="utf-8")
|
|
137
|
+
if marker not in content:
|
|
138
|
+
errors.append(f"current-run status marker missing: {relative_path}")
|
|
139
|
+
if relative_path == ".planning/STATE.md" and "PENDING_TEMPLATE" in content:
|
|
140
|
+
errors.append("STATE.md contains an unresolved PENDING_TEMPLATE blocker")
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def validate_code_index(
|
|
144
|
+
root: Path,
|
|
145
|
+
manifest: dict[str, Any],
|
|
146
|
+
started_at: float,
|
|
147
|
+
errors: list[str],
|
|
148
|
+
) -> None:
|
|
149
|
+
mode = manifest.get("mode")
|
|
150
|
+
status = manifest.get("code_index_status")
|
|
151
|
+
if mode == "full":
|
|
152
|
+
if status != "complete":
|
|
153
|
+
errors.append("full mode requires code_index_status=complete")
|
|
154
|
+
if manifest.get("code_index_skip_reason") != "none":
|
|
155
|
+
errors.append("full mode requires code_index_skip_reason=none")
|
|
156
|
+
for relative_path in CODE_INDEX_FILES:
|
|
157
|
+
require_fresh_file(
|
|
158
|
+
resolve_project_path(root, relative_path),
|
|
159
|
+
started_at,
|
|
160
|
+
errors,
|
|
161
|
+
)
|
|
162
|
+
elif mode == "fast":
|
|
163
|
+
if status != "skipped":
|
|
164
|
+
errors.append("fast mode requires code_index_status=skipped")
|
|
165
|
+
if manifest.get("code_index_skip_reason") not in {
|
|
166
|
+
"--fast",
|
|
167
|
+
"--skip-code-index",
|
|
168
|
+
}:
|
|
169
|
+
errors.append("fast mode requires an explicit code-index skip flag")
|
|
170
|
+
else:
|
|
171
|
+
errors.append("mode must be full or fast")
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
def validate_design_rule_pack(manifest: dict[str, Any], root: Path, errors: list[str]) -> None:
|
|
175
|
+
pack = manifest.get("design_rule_pack")
|
|
176
|
+
if not isinstance(pack, dict):
|
|
177
|
+
errors.append("design_rule_pack must be an object")
|
|
178
|
+
return
|
|
179
|
+
|
|
180
|
+
status = pack.get("status")
|
|
181
|
+
reason = pack.get("reason")
|
|
182
|
+
has_frontend = any(
|
|
183
|
+
isinstance(item, dict) and item.get("domain") == "frontend"
|
|
184
|
+
for item in manifest.get("topic_inventory", [])
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
if has_frontend:
|
|
188
|
+
if status != "installed":
|
|
189
|
+
errors.append("frontend projects require design_rule_pack.status=installed")
|
|
190
|
+
return
|
|
191
|
+
assets = pack.get("assets")
|
|
192
|
+
if not isinstance(assets, list):
|
|
193
|
+
errors.append("installed design rule pack requires an assets list")
|
|
194
|
+
for relative_path in DESIGN_RULE_PACK_FILES:
|
|
195
|
+
if not resolve_project_path(root, relative_path).is_file():
|
|
196
|
+
errors.append(f"missing design rule pack asset: {relative_path}")
|
|
197
|
+
elif status != "not_applicable":
|
|
198
|
+
errors.append("non-frontend projects require design_rule_pack.status=not_applicable")
|
|
199
|
+
elif not isinstance(reason, str) or not reason:
|
|
200
|
+
errors.append("not_applicable design rule pack requires a reason")
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
def validate_depth_specs(
|
|
204
|
+
root: Path,
|
|
205
|
+
manifest: dict[str, Any],
|
|
206
|
+
started_at: float,
|
|
207
|
+
errors: list[str],
|
|
208
|
+
) -> set[tuple[str, str, str]]:
|
|
209
|
+
specs = manifest.get("depth_specs")
|
|
210
|
+
if not isinstance(specs, list):
|
|
211
|
+
errors.append("depth_specs must be an array")
|
|
212
|
+
return set()
|
|
213
|
+
|
|
214
|
+
seen_keys: set[tuple[str, str, str]] = set()
|
|
215
|
+
seen_paths: set[str] = set()
|
|
216
|
+
run_id = str(manifest.get("run_id", ""))
|
|
217
|
+
|
|
218
|
+
for index, entry in enumerate(specs):
|
|
219
|
+
if not isinstance(entry, dict):
|
|
220
|
+
errors.append(f"depth_specs[{index}] must be an object")
|
|
221
|
+
continue
|
|
222
|
+
codebase = str(entry.get("codebase", ""))
|
|
223
|
+
codebase_root_value = str(entry.get("codebase_root", ""))
|
|
224
|
+
domain = str(entry.get("domain", ""))
|
|
225
|
+
topic = str(entry.get("topic", ""))
|
|
226
|
+
relative_path = str(entry.get("path", ""))
|
|
227
|
+
key = (codebase, domain, topic)
|
|
228
|
+
|
|
229
|
+
if not all(key) or not codebase_root_value or domain not in {"backend", "frontend"}:
|
|
230
|
+
errors.append(f"invalid depth spec identity at index {index}: {key}")
|
|
231
|
+
continue
|
|
232
|
+
if key in seen_keys:
|
|
233
|
+
errors.append(f"duplicate depth spec identity: {key}")
|
|
234
|
+
seen_keys.add(key)
|
|
235
|
+
if relative_path in seen_paths:
|
|
236
|
+
errors.append(f"multiple depth specs share one output path: {relative_path}")
|
|
237
|
+
seen_paths.add(relative_path)
|
|
238
|
+
|
|
239
|
+
source_paths = entry.get("source_paths")
|
|
240
|
+
if (
|
|
241
|
+
not isinstance(source_paths, list)
|
|
242
|
+
or not source_paths
|
|
243
|
+
or not all(isinstance(path, str) and path for path in source_paths)
|
|
244
|
+
):
|
|
245
|
+
errors.append(f"depth spec has no source_paths: {key}")
|
|
246
|
+
continue
|
|
247
|
+
try:
|
|
248
|
+
codebase_root = resolve_codebase_root(root, codebase_root_value)
|
|
249
|
+
if not codebase_root.is_dir():
|
|
250
|
+
raise ValueError(f"codebase root missing: {codebase_root_value}")
|
|
251
|
+
actual_fingerprint = source_fingerprint(codebase_root, source_paths)
|
|
252
|
+
except ValueError as error:
|
|
253
|
+
errors.append(f"{key}: {error}")
|
|
254
|
+
continue
|
|
255
|
+
expected_fingerprint = entry.get("source_fingerprint")
|
|
256
|
+
if actual_fingerprint != expected_fingerprint:
|
|
257
|
+
errors.append(f"source fingerprint mismatch: {key}")
|
|
258
|
+
|
|
259
|
+
try:
|
|
260
|
+
path = resolve_project_path(root, relative_path)
|
|
261
|
+
except ValueError as error:
|
|
262
|
+
errors.append(str(error))
|
|
263
|
+
continue
|
|
264
|
+
require_fresh_file(path, started_at, errors)
|
|
265
|
+
if not path.is_file():
|
|
266
|
+
continue
|
|
267
|
+
content = path.read_text(encoding="utf-8")
|
|
268
|
+
if f"Run ID: `{run_id}`" not in content:
|
|
269
|
+
errors.append(f"run ID missing from depth spec: {relative_path}")
|
|
270
|
+
if f"Source fingerprint: `{actual_fingerprint}`" not in content:
|
|
271
|
+
errors.append(f"source fingerprint missing from depth spec: {relative_path}")
|
|
272
|
+
return seen_keys
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
def validate_not_applicable_topics(
|
|
276
|
+
manifest: dict[str, Any],
|
|
277
|
+
depth_spec_keys: set[tuple[str, str, str]],
|
|
278
|
+
errors: list[str],
|
|
279
|
+
) -> set[tuple[str, str, str]]:
|
|
280
|
+
entries = manifest.get("not_applicable_topics")
|
|
281
|
+
if not isinstance(entries, list):
|
|
282
|
+
errors.append("not_applicable_topics must be an array")
|
|
283
|
+
return set()
|
|
284
|
+
|
|
285
|
+
seen: set[tuple[str, str, str]] = set()
|
|
286
|
+
for index, entry in enumerate(entries):
|
|
287
|
+
if not isinstance(entry, dict):
|
|
288
|
+
errors.append(f"not_applicable_topics[{index}] must be an object")
|
|
289
|
+
continue
|
|
290
|
+
key = (
|
|
291
|
+
str(entry.get("codebase", "")),
|
|
292
|
+
str(entry.get("domain", "")),
|
|
293
|
+
str(entry.get("topic", "")),
|
|
294
|
+
)
|
|
295
|
+
if not all(key) or key[1] not in {"backend", "frontend"}:
|
|
296
|
+
errors.append(f"invalid not-applicable identity at index {index}: {key}")
|
|
297
|
+
continue
|
|
298
|
+
if key in seen:
|
|
299
|
+
errors.append(f"duplicate not-applicable identity: {key}")
|
|
300
|
+
if key in depth_spec_keys:
|
|
301
|
+
errors.append(f"topic is both generated and not applicable: {key}")
|
|
302
|
+
seen.add(key)
|
|
303
|
+
return seen
|
|
304
|
+
|
|
305
|
+
|
|
306
|
+
def template_topics(domain: str) -> set[str]:
|
|
307
|
+
template_dir = SPEC_TEMPLATE_ROOT / domain
|
|
308
|
+
return {path.stem for path in template_dir.glob("*.md") if path.is_file()}
|
|
309
|
+
|
|
310
|
+
|
|
311
|
+
def validate_topic_inventory(
|
|
312
|
+
manifest: dict[str, Any],
|
|
313
|
+
depth_spec_keys: set[tuple[str, str, str]],
|
|
314
|
+
not_applicable_keys: set[tuple[str, str, str]],
|
|
315
|
+
errors: list[str],
|
|
316
|
+
) -> None:
|
|
317
|
+
entries = manifest.get("topic_inventory")
|
|
318
|
+
if not isinstance(entries, list):
|
|
319
|
+
errors.append("topic_inventory must be an array")
|
|
320
|
+
return
|
|
321
|
+
|
|
322
|
+
seen_identities: set[tuple[str, str]] = set()
|
|
323
|
+
accounted_keys: set[tuple[str, str, str]] = set()
|
|
324
|
+
|
|
325
|
+
for index, entry in enumerate(entries):
|
|
326
|
+
if not isinstance(entry, dict):
|
|
327
|
+
errors.append(f"topic_inventory[{index}] must be an object")
|
|
328
|
+
continue
|
|
329
|
+
codebase = str(entry.get("codebase", ""))
|
|
330
|
+
domain = str(entry.get("domain", ""))
|
|
331
|
+
identity = (codebase, domain)
|
|
332
|
+
if not codebase or domain not in {"backend", "frontend"}:
|
|
333
|
+
errors.append(f"invalid topic inventory identity at index {index}: {identity}")
|
|
334
|
+
continue
|
|
335
|
+
if identity in seen_identities:
|
|
336
|
+
errors.append(f"duplicate topic inventory identity: {identity}")
|
|
337
|
+
seen_identities.add(identity)
|
|
338
|
+
|
|
339
|
+
candidates_value = entry.get("candidate_topics")
|
|
340
|
+
discovered_value = entry.get("discovered_topics")
|
|
341
|
+
if (
|
|
342
|
+
not isinstance(candidates_value, list)
|
|
343
|
+
or not all(isinstance(topic, str) and topic for topic in candidates_value)
|
|
344
|
+
):
|
|
345
|
+
errors.append(f"invalid candidate_topics for: {identity}")
|
|
346
|
+
continue
|
|
347
|
+
if (
|
|
348
|
+
not isinstance(discovered_value, list)
|
|
349
|
+
or not all(isinstance(topic, str) and topic for topic in discovered_value)
|
|
350
|
+
):
|
|
351
|
+
errors.append(f"invalid discovered_topics for: {identity}")
|
|
352
|
+
continue
|
|
353
|
+
|
|
354
|
+
candidate_counts = Counter(candidates_value)
|
|
355
|
+
discovered_counts = Counter(discovered_value)
|
|
356
|
+
duplicate_candidates = sorted(
|
|
357
|
+
topic for topic, count in candidate_counts.items() if count > 1
|
|
358
|
+
)
|
|
359
|
+
duplicate_discovered = sorted(
|
|
360
|
+
topic for topic, count in discovered_counts.items() if count > 1
|
|
361
|
+
)
|
|
362
|
+
if duplicate_candidates:
|
|
363
|
+
errors.append(
|
|
364
|
+
f"duplicate candidate topics for {identity}: {duplicate_candidates}"
|
|
365
|
+
)
|
|
366
|
+
if duplicate_discovered:
|
|
367
|
+
errors.append(
|
|
368
|
+
f"duplicate discovered topics for {identity}: {duplicate_discovered}"
|
|
369
|
+
)
|
|
370
|
+
|
|
371
|
+
candidates = set(candidates_value)
|
|
372
|
+
discovered = set(discovered_value)
|
|
373
|
+
expected_candidates = template_topics(domain)
|
|
374
|
+
if candidates != expected_candidates:
|
|
375
|
+
errors.append(
|
|
376
|
+
f"candidate topics do not match current templates for {identity}: "
|
|
377
|
+
f"expected={sorted(expected_candidates)} actual={sorted(candidates)}"
|
|
378
|
+
)
|
|
379
|
+
unexpected_discovered = discovered - candidates
|
|
380
|
+
if unexpected_discovered:
|
|
381
|
+
errors.append(
|
|
382
|
+
f"discovered topics are not candidates for {identity}: "
|
|
383
|
+
f"{sorted(unexpected_discovered)}"
|
|
384
|
+
)
|
|
385
|
+
|
|
386
|
+
expected_generated = {
|
|
387
|
+
(codebase, domain, topic) for topic in discovered
|
|
388
|
+
}
|
|
389
|
+
expected_not_applicable = {
|
|
390
|
+
(codebase, domain, topic) for topic in candidates - discovered
|
|
391
|
+
}
|
|
392
|
+
actual_generated = {
|
|
393
|
+
key for key in depth_spec_keys if key[:2] == identity
|
|
394
|
+
}
|
|
395
|
+
actual_not_applicable = {
|
|
396
|
+
key for key in not_applicable_keys if key[:2] == identity
|
|
397
|
+
}
|
|
398
|
+
if actual_generated != expected_generated:
|
|
399
|
+
errors.append(
|
|
400
|
+
f"generated topic partition mismatch for {identity}: "
|
|
401
|
+
f"expected={sorted(expected_generated)} actual={sorted(actual_generated)}"
|
|
402
|
+
)
|
|
403
|
+
if actual_not_applicable != expected_not_applicable:
|
|
404
|
+
errors.append(
|
|
405
|
+
f"not-applicable topic partition mismatch for {identity}: "
|
|
406
|
+
f"expected={sorted(expected_not_applicable)} "
|
|
407
|
+
f"actual={sorted(actual_not_applicable)}"
|
|
408
|
+
)
|
|
409
|
+
accounted_keys.update(expected_generated)
|
|
410
|
+
accounted_keys.update(expected_not_applicable)
|
|
411
|
+
|
|
412
|
+
unaccounted_keys = (depth_spec_keys | not_applicable_keys) - accounted_keys
|
|
413
|
+
if unaccounted_keys:
|
|
414
|
+
errors.append(
|
|
415
|
+
"topics exist without a topic_inventory entry: "
|
|
416
|
+
f"{sorted(unaccounted_keys)}"
|
|
417
|
+
)
|
|
418
|
+
|
|
419
|
+
|
|
420
|
+
def validate_domain_indexes(
|
|
421
|
+
root: Path,
|
|
422
|
+
manifest: dict[str, Any],
|
|
423
|
+
started_at: float,
|
|
424
|
+
errors: list[str],
|
|
425
|
+
) -> None:
|
|
426
|
+
run_id = str(manifest.get("run_id", ""))
|
|
427
|
+
expected_by_domain: dict[str, set[str]] = {}
|
|
428
|
+
|
|
429
|
+
for entry in manifest.get("depth_specs", []):
|
|
430
|
+
if not isinstance(entry, dict):
|
|
431
|
+
continue
|
|
432
|
+
codebase = str(entry.get("codebase", ""))
|
|
433
|
+
domain = str(entry.get("domain", ""))
|
|
434
|
+
topic = str(entry.get("topic", ""))
|
|
435
|
+
path = str(entry.get("path", ""))
|
|
436
|
+
if not codebase or domain not in {"backend", "frontend"} or not topic or not path:
|
|
437
|
+
continue
|
|
438
|
+
expected_by_domain.setdefault(domain, set()).add(
|
|
439
|
+
f"<!-- depth_spec: codebase={codebase}; domain={domain}; "
|
|
440
|
+
f"topic={topic}; status=present; path={path} -->"
|
|
441
|
+
)
|
|
442
|
+
|
|
443
|
+
for entry in manifest.get("not_applicable_topics", []):
|
|
444
|
+
if not isinstance(entry, dict):
|
|
445
|
+
continue
|
|
446
|
+
codebase = str(entry.get("codebase", ""))
|
|
447
|
+
domain = str(entry.get("domain", ""))
|
|
448
|
+
topic = str(entry.get("topic", ""))
|
|
449
|
+
if not codebase or domain not in {"backend", "frontend"} or not topic:
|
|
450
|
+
continue
|
|
451
|
+
expected_by_domain.setdefault(domain, set()).add(
|
|
452
|
+
f"<!-- depth_spec: codebase={codebase}; domain={domain}; "
|
|
453
|
+
f"topic={topic}; status=not_applicable; path=none -->"
|
|
454
|
+
)
|
|
455
|
+
|
|
456
|
+
for domain, expected_markers in expected_by_domain.items():
|
|
457
|
+
relative_path = f".context/spec/{domain}/index.md"
|
|
458
|
+
path = resolve_project_path(root, relative_path)
|
|
459
|
+
require_fresh_file(path, started_at, errors)
|
|
460
|
+
if not path.is_file():
|
|
461
|
+
continue
|
|
462
|
+
content = path.read_text(encoding="utf-8")
|
|
463
|
+
if f"Run ID: `{run_id}`" not in content:
|
|
464
|
+
errors.append(f"run ID missing from domain index: {relative_path}")
|
|
465
|
+
marker_lines = [
|
|
466
|
+
line.strip()
|
|
467
|
+
for line in content.splitlines()
|
|
468
|
+
if line.strip().startswith("<!-- depth_spec:")
|
|
469
|
+
]
|
|
470
|
+
if len(marker_lines) != len(set(marker_lines)):
|
|
471
|
+
errors.append(f"duplicate depth-spec markers in domain index: {relative_path}")
|
|
472
|
+
actual_markers = set(marker_lines)
|
|
473
|
+
missing = sorted(expected_markers - actual_markers)
|
|
474
|
+
stale = sorted(actual_markers - expected_markers)
|
|
475
|
+
if missing:
|
|
476
|
+
errors.append(f"domain index missing markers in {relative_path}: {missing}")
|
|
477
|
+
if stale:
|
|
478
|
+
errors.append(f"domain index has stale markers in {relative_path}: {stale}")
|
|
479
|
+
|
|
480
|
+
|
|
481
|
+
def main() -> int:
|
|
482
|
+
args = parse_args()
|
|
483
|
+
root = Path(args.root).resolve()
|
|
484
|
+
manifest_path = resolve_project_path(root, args.manifest)
|
|
485
|
+
errors: list[str] = []
|
|
486
|
+
|
|
487
|
+
try:
|
|
488
|
+
manifest = load_manifest(manifest_path)
|
|
489
|
+
if manifest.get("version") != 1:
|
|
490
|
+
raise ValueError("manifest version must be 1")
|
|
491
|
+
if contains_placeholder(manifest):
|
|
492
|
+
raise ValueError("manifest contains unresolved template placeholders")
|
|
493
|
+
run_id = str(manifest.get("run_id", ""))
|
|
494
|
+
if not run_id:
|
|
495
|
+
raise ValueError("run_id is required")
|
|
496
|
+
started_at = parse_started_at(str(manifest.get("started_at", "")))
|
|
497
|
+
code_index_status = str(manifest.get("code_index_status", ""))
|
|
498
|
+
code_index_skip_reason = (
|
|
499
|
+
str(manifest.get("code_index_skip_reason"))
|
|
500
|
+
if manifest.get("code_index_skip_reason")
|
|
501
|
+
else "none"
|
|
502
|
+
)
|
|
503
|
+
except (OSError, ValueError, json.JSONDecodeError) as error:
|
|
504
|
+
print(f"Initialization validation failed: {error}", file=sys.stderr)
|
|
505
|
+
return 1
|
|
506
|
+
|
|
507
|
+
validate_status_markers(
|
|
508
|
+
root,
|
|
509
|
+
run_id,
|
|
510
|
+
code_index_status,
|
|
511
|
+
code_index_skip_reason,
|
|
512
|
+
errors,
|
|
513
|
+
)
|
|
514
|
+
validate_code_index(root, manifest, started_at, errors)
|
|
515
|
+
validate_design_rule_pack(manifest, root, errors)
|
|
516
|
+
depth_spec_keys = validate_depth_specs(root, manifest, started_at, errors)
|
|
517
|
+
not_applicable_keys = validate_not_applicable_topics(
|
|
518
|
+
manifest,
|
|
519
|
+
depth_spec_keys,
|
|
520
|
+
errors,
|
|
521
|
+
)
|
|
522
|
+
validate_topic_inventory(
|
|
523
|
+
manifest,
|
|
524
|
+
depth_spec_keys,
|
|
525
|
+
not_applicable_keys,
|
|
526
|
+
errors,
|
|
527
|
+
)
|
|
528
|
+
validate_domain_indexes(root, manifest, started_at, errors)
|
|
529
|
+
|
|
530
|
+
if errors:
|
|
531
|
+
print("Initialization validation failed:", file=sys.stderr)
|
|
532
|
+
for error in errors:
|
|
533
|
+
print(f"- {error}", file=sys.stderr)
|
|
534
|
+
return 1
|
|
535
|
+
|
|
536
|
+
print(
|
|
537
|
+
"Initialization validation passed: "
|
|
538
|
+
f"run_id={run_id} depth_specs={len(manifest['depth_specs'])} "
|
|
539
|
+
f"code_index={code_index_status}"
|
|
540
|
+
)
|
|
541
|
+
return 0
|
|
542
|
+
|
|
543
|
+
|
|
544
|
+
if __name__ == "__main__":
|
|
545
|
+
raise SystemExit(main())
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: contract-auditor
|
|
3
|
+
description: Read-only cross-layer auditor for API, UI, frontend, backend, data, and integration design consistency.
|
|
4
|
+
tools:
|
|
5
|
+
- read
|
|
6
|
+
- grep
|
|
7
|
+
- find
|
|
8
|
+
- lsp
|
|
9
|
+
model: "@slow"
|
|
10
|
+
thinkingLevel: high
|
|
11
|
+
autoloadSkills:
|
|
12
|
+
- workflow-api-contract
|
|
13
|
+
- workflow-integration-verify
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
Audit contracts across requirement slices, API schemas, UI states, frontend calls, backend handlers, persistence, and verification cases.
|
|
17
|
+
|
|
18
|
+
Look for divergent names and types, missing error states, ownership ambiguity, unhandled compatibility, premature implementation of later slices, and claims not supported by code. Return a compact trace matrix plus severity-ordered gaps. Do not edit artifacts or workflow state.
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
|
|
5
|
+
import type { ExtensionAPI } from "@oh-my-pi/pi-coding-agent";
|
|
6
|
+
|
|
7
|
+
export default function devflowDesign(pi: ExtensionAPI) {
|
|
8
|
+
const { z } = pi.zod;
|
|
9
|
+
pi.registerTool({
|
|
10
|
+
name: "devflow_design_rule",
|
|
11
|
+
label: "Devflow Design Rule Pack",
|
|
12
|
+
description: "Install the versioned Devflow design rule pack into the current project.",
|
|
13
|
+
parameters: z.object({ args: z.array(z.string()).default([]) }),
|
|
14
|
+
approval: "write",
|
|
15
|
+
async execute(_id, params, _signal, _onUpdate, ctx) {
|
|
16
|
+
const moduleDirectory = path.dirname(fileURLToPath(import.meta.url));
|
|
17
|
+
const roots = [
|
|
18
|
+
process.env.DEVFLOW_KIT_ROOT,
|
|
19
|
+
path.join(ctx.cwd, ".skills"),
|
|
20
|
+
path.resolve(moduleDirectory, "../skills"),
|
|
21
|
+
path.resolve(moduleDirectory, "../../.."),
|
|
22
|
+
].filter(Boolean) as string[];
|
|
23
|
+
const skillRoot = roots.find(root =>
|
|
24
|
+
existsSync(path.join(root, "workflow-design-rule-pack/scripts/install.py")),
|
|
25
|
+
);
|
|
26
|
+
if (!skillRoot) throw new Error("Devflow design skills not found");
|
|
27
|
+
const script = path.join(skillRoot, "workflow-design-rule-pack/scripts/install.py");
|
|
28
|
+
const child = Bun.spawn(["python3", script, ...params.args], {
|
|
29
|
+
cwd: ctx.cwd,
|
|
30
|
+
stdout: "pipe",
|
|
31
|
+
stderr: "pipe",
|
|
32
|
+
});
|
|
33
|
+
const [exitCode, stdout, stderr] = await Promise.all([
|
|
34
|
+
child.exited,
|
|
35
|
+
new Response(child.stdout).text(),
|
|
36
|
+
new Response(child.stderr).text(),
|
|
37
|
+
]);
|
|
38
|
+
const out = stdout.trim();
|
|
39
|
+
const err = stderr.trim();
|
|
40
|
+
return {
|
|
41
|
+
content: [{ type: "text" as const, text: out || err || `Process exited with ${exitCode}` }],
|
|
42
|
+
details: { exitCode, stderr: err || undefined },
|
|
43
|
+
isError: exitCode !== 0,
|
|
44
|
+
};
|
|
45
|
+
},
|
|
46
|
+
});
|
|
47
|
+
}
|