@guanlin4924/devflow-pi 0.1.93 → 0.1.95
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 +10 -10
- package/node_modules/@playwright/test/LICENSE +202 -0
- package/node_modules/@playwright/test/NOTICE +5 -0
- package/node_modules/@playwright/test/README.md +318 -0
- package/node_modules/@playwright/test/cli.js +19 -0
- package/node_modules/@playwright/test/index.d.ts +18 -0
- package/node_modules/@playwright/test/index.js +17 -0
- package/node_modules/@playwright/test/index.mjs +18 -0
- package/node_modules/@playwright/test/package.json +35 -0
- package/node_modules/@playwright/test/reporter.d.ts +17 -0
- package/node_modules/@playwright/test/reporter.js +17 -0
- package/node_modules/@playwright/test/reporter.mjs +17 -0
- package/node_modules/playwright/LICENSE +202 -0
- package/node_modules/playwright/NOTICE +5 -0
- package/node_modules/playwright/README.md +318 -0
- package/node_modules/playwright/ThirdPartyNotices.txt +14 -0
- package/node_modules/playwright/cli.js +19 -0
- package/node_modules/playwright/index.d.ts +17 -0
- package/node_modules/playwright/index.js +17 -0
- package/node_modules/playwright/index.mjs +18 -0
- package/node_modules/playwright/jsx-runtime.js +42 -0
- package/node_modules/playwright/jsx-runtime.mjs +21 -0
- package/node_modules/playwright/lib/agents/agentParser.js +89 -0
- package/node_modules/playwright/lib/agents/copilot-setup-steps.yml +34 -0
- package/node_modules/playwright/lib/agents/generateAgents.js +395 -0
- package/node_modules/playwright/lib/agents/playwright-test-coverage.prompt.md +31 -0
- package/node_modules/playwright/lib/agents/playwright-test-generate.prompt.md +8 -0
- package/node_modules/playwright/lib/agents/playwright-test-generator.agent.md +88 -0
- package/node_modules/playwright/lib/agents/playwright-test-heal.prompt.md +6 -0
- package/node_modules/playwright/lib/agents/playwright-test-healer.agent.md +56 -0
- package/node_modules/playwright/lib/agents/playwright-test-plan.prompt.md +9 -0
- package/node_modules/playwright/lib/agents/playwright-test-planner.agent.md +74 -0
- package/node_modules/playwright/lib/cli/reportActions.js +78 -0
- package/node_modules/playwright/lib/cli/testActions.js +214 -0
- package/node_modules/playwright/lib/common/index.js +2923 -0
- package/node_modules/playwright/lib/common/index.js.txt +34 -0
- package/node_modules/playwright/lib/errorContext.js +129 -0
- package/node_modules/playwright/lib/globals.js +58 -0
- package/node_modules/playwright/lib/index.js +815 -0
- package/node_modules/playwright/lib/isomorphic.js +260 -0
- package/node_modules/playwright/lib/isomorphic.js.txt +9 -0
- package/node_modules/playwright/lib/loader/loaderProcessEntry.js +34 -0
- package/node_modules/playwright/lib/loader/loaderProcessEntry.js.txt +9 -0
- package/node_modules/playwright/lib/matchers/expect.js +13490 -0
- package/node_modules/playwright/lib/matchers/expect.js.LICENSE +640 -0
- package/node_modules/playwright/lib/matchers/expect.js.txt +67 -0
- package/node_modules/playwright/lib/mcp/test/browserBackend.js +135 -0
- package/node_modules/playwright/lib/mcp/test/generatorTools.js +122 -0
- package/node_modules/playwright/lib/mcp/test/plannerTools.js +150 -0
- package/node_modules/playwright/lib/mcp/test/seed.js +82 -0
- package/node_modules/playwright/lib/mcp/test/streams.js +44 -0
- package/node_modules/playwright/lib/mcp/test/testBackend.js +99 -0
- package/node_modules/playwright/lib/mcp/test/testContext.js +306 -0
- package/node_modules/playwright/lib/mcp/test/testTool.js +30 -0
- package/node_modules/playwright/lib/mcp/test/testTools.js +98 -0
- package/node_modules/playwright/lib/package.js +47 -0
- package/node_modules/playwright/lib/program.js +241 -0
- package/node_modules/playwright/lib/runner/index.js +8527 -0
- package/node_modules/playwright/lib/runner/index.js.txt +61 -0
- package/node_modules/playwright/lib/transform/babelBundle.js +72274 -0
- package/node_modules/playwright/lib/transform/babelBundle.js.LICENSE +2384 -0
- package/node_modules/playwright/lib/transform/babelBundle.js.txt +325 -0
- package/node_modules/playwright/lib/transform/esmLoader.js +8054 -0
- package/node_modules/playwright/lib/transform/esmLoader.js.LICENSE +355 -0
- package/node_modules/playwright/lib/transform/esmLoader.js.txt +60 -0
- package/node_modules/playwright/lib/util.js +373 -0
- package/node_modules/playwright/lib/worker/workerProcessEntry.js +1861 -0
- package/node_modules/playwright/lib/worker/workerProcessEntry.js.txt +19 -0
- package/node_modules/playwright/package.json +55 -0
- package/node_modules/playwright/test.d.ts +18 -0
- package/node_modules/playwright/test.js +24 -0
- package/node_modules/playwright/test.mjs +35 -0
- package/node_modules/playwright/types/test.d.ts +11074 -0
- package/node_modules/playwright/types/testReporter.d.ts +950 -0
- package/node_modules/playwright-core/LICENSE +202 -0
- package/node_modules/playwright-core/NOTICE +5 -0
- package/node_modules/playwright-core/README.md +3 -0
- package/node_modules/playwright-core/ThirdPartyNotices.txt +13 -0
- package/node_modules/playwright-core/bin/install_media_pack.ps1 +5 -0
- package/node_modules/playwright-core/bin/install_webkit_wsl.ps1 +33 -0
- package/node_modules/playwright-core/bin/reinstall_chrome_beta_linux.sh +42 -0
- package/node_modules/playwright-core/bin/reinstall_chrome_beta_mac.sh +13 -0
- package/node_modules/playwright-core/bin/reinstall_chrome_beta_win.ps1 +24 -0
- package/node_modules/playwright-core/bin/reinstall_chrome_stable_linux.sh +42 -0
- package/node_modules/playwright-core/bin/reinstall_chrome_stable_mac.sh +12 -0
- package/node_modules/playwright-core/bin/reinstall_chrome_stable_win.ps1 +24 -0
- package/node_modules/playwright-core/bin/reinstall_msedge_beta_linux.sh +48 -0
- package/node_modules/playwright-core/bin/reinstall_msedge_beta_mac.sh +11 -0
- package/node_modules/playwright-core/bin/reinstall_msedge_beta_win.ps1 +23 -0
- package/node_modules/playwright-core/bin/reinstall_msedge_dev_linux.sh +48 -0
- package/node_modules/playwright-core/bin/reinstall_msedge_dev_mac.sh +11 -0
- package/node_modules/playwright-core/bin/reinstall_msedge_dev_win.ps1 +23 -0
- package/node_modules/playwright-core/bin/reinstall_msedge_stable_linux.sh +48 -0
- package/node_modules/playwright-core/bin/reinstall_msedge_stable_mac.sh +11 -0
- package/node_modules/playwright-core/bin/reinstall_msedge_stable_win.ps1 +24 -0
- package/node_modules/playwright-core/browsers.json +52 -0
- package/node_modules/playwright-core/cli.js +21 -0
- package/node_modules/playwright-core/index.d.ts +17 -0
- package/node_modules/playwright-core/index.js +17 -0
- package/node_modules/playwright-core/index.mjs +28 -0
- package/node_modules/playwright-core/lib/bootstrap.js +88 -0
- package/node_modules/playwright-core/lib/coreBundle.js +75813 -0
- package/node_modules/playwright-core/lib/entry/cliDaemon.js +5 -0
- package/node_modules/playwright-core/lib/entry/dashboardApp.js +3 -0
- package/node_modules/playwright-core/lib/entry/mcp.js +10 -0
- package/node_modules/playwright-core/lib/entry/oopBrowserDownload.js +3 -0
- package/node_modules/playwright-core/lib/package.js +50 -0
- package/node_modules/playwright-core/lib/server/chromium/appIcon.png +0 -0
- package/node_modules/playwright-core/lib/server/electron/loader.js +116 -0
- package/node_modules/playwright-core/lib/serverRegistry.js +1939 -0
- package/node_modules/playwright-core/lib/serverRegistry.js.LICENSE +65 -0
- package/node_modules/playwright-core/lib/tools/cli-client/channelSessions.js +141 -0
- package/node_modules/playwright-core/lib/tools/cli-client/cli.js +6 -0
- package/node_modules/playwright-core/lib/tools/cli-client/help.json +721 -0
- package/node_modules/playwright-core/lib/tools/cli-client/minimist.js +128 -0
- package/node_modules/playwright-core/lib/tools/cli-client/output.js +351 -0
- package/node_modules/playwright-core/lib/tools/cli-client/program.js +418 -0
- package/node_modules/playwright-core/lib/tools/cli-client/registry.js +180 -0
- package/node_modules/playwright-core/lib/tools/cli-client/session.js +259 -0
- package/node_modules/playwright-core/lib/tools/dashboard/appIcon.png +0 -0
- package/node_modules/playwright-core/lib/tools/skills/playwright-cli/SKILL.md +425 -0
- package/node_modules/playwright-core/lib/tools/skills/playwright-cli/references/element-attributes.md +23 -0
- package/node_modules/playwright-core/lib/tools/skills/playwright-cli/references/playwright-tests.md +39 -0
- package/node_modules/playwright-core/lib/tools/skills/playwright-cli/references/request-mocking.md +87 -0
- package/node_modules/playwright-core/lib/tools/skills/playwright-cli/references/running-code.md +241 -0
- package/node_modules/playwright-core/lib/tools/skills/playwright-cli/references/session-management.md +225 -0
- package/node_modules/playwright-core/lib/tools/skills/playwright-cli/references/storage-state.md +275 -0
- package/node_modules/playwright-core/lib/tools/skills/playwright-cli/references/test-generation.md +433 -0
- package/node_modules/playwright-core/lib/tools/skills/playwright-cli/references/tracing.md +139 -0
- package/node_modules/playwright-core/lib/tools/skills/playwright-cli/references/video-recording.md +143 -0
- package/node_modules/playwright-core/lib/tools/skills/playwright-component-testing/SKILL.md +136 -0
- package/node_modules/playwright-core/lib/tools/skills/playwright-component-testing/references/gallery-spec.md +144 -0
- package/node_modules/playwright-core/lib/tools/skills/playwright-component-testing/references/migration.md +89 -0
- package/node_modules/playwright-core/lib/tools/skills/playwright-component-testing/references/react.md +69 -0
- package/node_modules/playwright-core/lib/tools/skills/playwright-component-testing/references/typing.md +173 -0
- package/node_modules/playwright-core/lib/tools/skills/playwright-component-testing/references/vue.md +77 -0
- package/node_modules/playwright-core/lib/tools/skills/playwright-trace/SKILL.md +174 -0
- package/node_modules/playwright-core/lib/tools/utils/extension.js +112 -0
- package/node_modules/playwright-core/lib/tools/utils/socketConnection.js +108 -0
- package/node_modules/playwright-core/lib/utilsBundle.js +85357 -0
- package/node_modules/playwright-core/lib/utilsBundle.js.LICENSE +1890 -0
- package/node_modules/playwright-core/lib/vite/dashboard/assets/codeMirrorModule--QdMvsKi.css +1 -0
- package/node_modules/playwright-core/lib/vite/dashboard/assets/codeMirrorModule-CQ8RZGBm.js +32 -0
- package/node_modules/playwright-core/lib/vite/dashboard/assets/codicon-DCmgc-ay.ttf +0 -0
- package/node_modules/playwright-core/lib/vite/dashboard/assets/firefox-1bWoP6pv.svg +1 -0
- package/node_modules/playwright-core/lib/vite/dashboard/assets/firefox-beta-k3eOH_eK.svg +1 -0
- package/node_modules/playwright-core/lib/vite/dashboard/assets/firefox-nightly-Cp5nfeDT.svg +1 -0
- package/node_modules/playwright-core/lib/vite/dashboard/assets/index-AwgwcYie.css +1 -0
- package/node_modules/playwright-core/lib/vite/dashboard/assets/index-hRvO4yU2.js +12 -0
- package/node_modules/playwright-core/lib/vite/dashboard/assets/safari-na3_-uQk.svg +1 -0
- package/node_modules/playwright-core/lib/vite/dashboard/index.html +29 -0
- package/node_modules/playwright-core/lib/vite/dashboard/playwright-logo.svg +24 -0
- package/node_modules/playwright-core/lib/vite/htmlReport/index.html +16 -0
- package/node_modules/playwright-core/lib/vite/htmlReport/report.css +2 -0
- package/node_modules/playwright-core/lib/vite/htmlReport/report.js +32 -0
- package/node_modules/playwright-core/lib/vite/recorder/assets/codeMirrorModule--QdMvsKi.css +1 -0
- package/node_modules/playwright-core/lib/vite/recorder/assets/codeMirrorModule-CVQWJZAA.js +32 -0
- package/node_modules/playwright-core/lib/vite/recorder/assets/codicon-DCmgc-ay.ttf +0 -0
- package/node_modules/playwright-core/lib/vite/recorder/assets/index-BZpYJZ-P.css +1 -0
- package/node_modules/playwright-core/lib/vite/recorder/assets/index-hrlLqLtq.js +129 -0
- package/node_modules/playwright-core/lib/vite/recorder/index.html +29 -0
- package/node_modules/playwright-core/lib/vite/recorder/playwright-logo.svg +9 -0
- package/node_modules/playwright-core/lib/vite/traceViewer/assets/codeMirrorModule-BbkfBe3n.js +32 -0
- package/node_modules/playwright-core/lib/vite/traceViewer/assets/defaultSettingsView-Ds6CBOo0.js +182 -0
- package/node_modules/playwright-core/lib/vite/traceViewer/assets/urlMatch-L3liM589.js +1 -0
- package/node_modules/playwright-core/lib/vite/traceViewer/assets/xtermModule-DywYcAf8.js +7 -0
- package/node_modules/playwright-core/lib/vite/traceViewer/codeMirrorModule.-QdMvsKi.css +1 -0
- package/node_modules/playwright-core/lib/vite/traceViewer/codicon.DCmgc-ay.ttf +0 -0
- package/node_modules/playwright-core/lib/vite/traceViewer/defaultSettingsView.Bqk9acqE.css +1 -0
- package/node_modules/playwright-core/lib/vite/traceViewer/index.B4cLoZK3.js +1 -0
- package/node_modules/playwright-core/lib/vite/traceViewer/index.B_TqY17P.css +1 -0
- package/node_modules/playwright-core/lib/vite/traceViewer/index.html +44 -0
- package/node_modules/playwright-core/lib/vite/traceViewer/manifest.webmanifest +16 -0
- package/node_modules/playwright-core/lib/vite/traceViewer/playwright-logo.svg +9 -0
- package/node_modules/playwright-core/lib/vite/traceViewer/snapshot.B_Jk1wbt.js +1 -0
- package/node_modules/playwright-core/lib/vite/traceViewer/snapshot.html +10 -0
- package/node_modules/playwright-core/lib/vite/traceViewer/sw.bundle.js +4 -0
- package/node_modules/playwright-core/lib/vite/traceViewer/uiMode.CU5KtEkS.js +5 -0
- package/node_modules/playwright-core/lib/vite/traceViewer/uiMode.CyMfwkXJ.css +1 -0
- package/node_modules/playwright-core/lib/vite/traceViewer/uiMode.html +18 -0
- package/node_modules/playwright-core/lib/vite/traceViewer/xtermModule.kHJ-D0s7.css +1 -0
- package/node_modules/playwright-core/lib/webp_codec.LICENSE +173 -0
- package/node_modules/playwright-core/lib/webp_codec.wasm +0 -0
- package/node_modules/playwright-core/lib/xdg-open +1267 -0
- package/node_modules/playwright-core/package.json +34 -0
- package/node_modules/playwright-core/types/protocol.d.ts +24645 -0
- package/node_modules/playwright-core/types/structs.d.ts +52 -0
- package/node_modules/playwright-core/types/types.d.ts +26632 -0
- package/package.json +12 -2
- package/plugins/devflow-core/extensions/devflow-core.ts +518 -40
- package/plugins/devflow-core/runtime/hooks/context_sync_gate.py +3 -3
- package/plugins/devflow-core/runtime/hooks/hook_common.py +334 -11
- package/plugins/devflow-core/runtime/hooks/index_gate.py +29 -16
- package/plugins/devflow-core/runtime/hooks/start.py +13 -13
- package/plugins/devflow-core/skills/wireframe-proposal/SKILL.md +2 -2
- package/plugins/devflow-core/skills/wireframe-validate/SKILL.md +4 -4
- package/plugins/devflow-core/skills/workflow-orchestrator/SKILL.md +19 -19
- package/plugins/devflow-core/skills/workflow-orchestrator/agents/openai.yaml +2 -2
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/acceptance_test_runner.py +412 -76
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/advance_state.rb +60 -9
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/api_test_matrix.py +2 -2
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/approval_pins.py +433 -0
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/approval_store.py +137 -0
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/architecture_assessment.rb +1 -1
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/architecture_brief.rb +1 -1
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/architecture_feasibility.rb +1 -1
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/business_invalidation.rb +5 -5
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/business_model_commit.rb +4 -4
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/business_model_validate.py +1 -1
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/business_source_resolver.rb +4 -4
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/checker_adapter.rb +7 -7
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/control_io.rb +51 -7
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/cross_track_consistency_check.rb +1 -1
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/dsl_coverage.py +87 -0
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/dsl_v1.py +318 -0
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/environment_profile.py +134 -0
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/execution_contract.rb +7 -6
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/execution_surface.py +138 -0
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/gate_runtime.rb +3 -3
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/init_state.rb +5 -5
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/init_workflow.rb +5 -5
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/inspect_state.rb +13 -13
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/machine_evidence.rb +3 -3
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/manage_lessons.rb +7 -7
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/parallel_recover.rb +2 -2
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/parallel_run.rb +3 -3
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/phase_ownership.rb +6 -6
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/playwright_adapter.py +515 -0
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/repair_control_plane.rb +1 -1
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/requirement_coverage.rb +1 -1
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/requirement_graph.rb +3 -3
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/review_preflight.py +3 -3
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/review_run.py +18 -18
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/runtime_context_collector.rb +3 -3
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/session_rollover.rb +4 -4
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/static_runtime_context_collector.rb +2 -2
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/sync_artifacts.rb +5 -5
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/tc_hash.py +132 -0
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/tdd_evidence.py +3 -3
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/test_command_policy.py +104 -10
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/test_task_binding_check.py +3 -3
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/update_triage_route.rb +3 -3
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/validate_state.rb +19 -6
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/wireframe_commit.rb +5 -5
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/wireframe_validate.py +1 -1
- package/plugins/devflow-core/skills/workflow-orchestrator/templates/acceptance-remediation.yaml +12 -12
- package/plugins/devflow-core/skills/workflow-orchestrator/templates/feature-development.yaml +201 -222
- package/plugins/devflow-core/skills/workflow-pipeline/SKILL.md +6 -4
- package/plugins/devflow-core/skills/workflow-pipeline/references/pipeline-flow.md +68 -140
- package/plugins/devflow-core/skills/workflow-project-context/SKILL.md +14 -14
- package/plugins/devflow-core/skills/workflow-project-context/assets/agents-md-template.md +7 -7
- package/plugins/devflow-core/skills/workflow-project-context/assets/codebase-backend-spec-template.md +4 -4
- package/plugins/devflow-core/skills/workflow-project-context/assets/codebase-frontend-spec-template.md +4 -4
- package/plugins/devflow-core/skills/workflow-project-context/assets/codebase-navigation-template.md +1 -1
- package/plugins/devflow-core/skills/workflow-project-context/assets/context-domain-index-template.md +4 -4
- package/plugins/devflow-core/skills/workflow-project-context/assets/context-spec-index-template.md +10 -10
- package/plugins/devflow-core/skills/workflow-project-context/assets/execution-contract-template.md +2 -2
- package/plugins/devflow-core/skills/workflow-project-context/assets/navigation-index-template.md +18 -18
- package/plugins/devflow-core/skills/workflow-project-context/assets/project-initialization-template.md +32 -32
- package/plugins/devflow-core/skills/workflow-project-context/assets/rules-index-template.md +30 -30
- package/plugins/devflow-core/skills/workflow-project-context/assets/state-template.md +7 -7
- package/plugins/devflow-core/skills/workflow-project-context/references/navigation-guide.md +37 -37
- package/plugins/devflow-core/skills/workflow-project-context/scripts/validate_initialization.py +16 -16
- package/plugins/devflow-core/skills/workflow-project-context/scripts/validate_initialization_database.py +1 -1
- package/plugins/devflow-design/skills/workflow-api-call-guide/SKILL.md +4 -4
- package/plugins/devflow-design/skills/workflow-api-contract/SKILL.md +8 -8
- package/plugins/devflow-design/skills/workflow-api-supplement/SKILL.md +5 -5
- package/plugins/devflow-design/skills/workflow-architecture-feasibility/SKILL.md +1 -1
- package/plugins/devflow-design/skills/workflow-backend-tech-spec/SKILL.md +39 -39
- package/plugins/devflow-design/skills/workflow-backend-tech-spec/assets/backend-spec-template.md +10 -10
- package/plugins/devflow-design/skills/workflow-backend-tech-spec/references/affected-module-exploration.md +2 -2
- package/plugins/devflow-design/skills/workflow-backend-tech-spec/references/code-explore-guide.md +1 -1
- package/plugins/devflow-design/skills/workflow-backend-tech-spec/references/project-rule-contract.md +20 -20
- package/plugins/devflow-design/skills/workflow-design-rule-pack/SKILL.md +8 -8
- package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/index.md +3 -3
- package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/recommendations/accessibility.md +2 -2
- package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/recommendations/component-library.md +2 -2
- package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/recommendations/design-systems.md +1 -1
- package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/recommendations/responsive-grid.md +2 -2
- package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/recommendations/stack-guidelines.md +6 -6
- package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/recommendations/ux-patterns.md +2 -2
- package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/tokens/project-tokens.md +1 -1
- package/plugins/devflow-design/skills/workflow-design-rule-pack/assets/design/tools/ui-ux-pro-max/SKILL.md +12 -12
- package/plugins/devflow-design/skills/workflow-design-rule-pack/scripts/install.py +2 -2
- package/plugins/devflow-design/skills/workflow-feature-breakdown/SKILL.md +30 -30
- package/plugins/devflow-design/skills/workflow-feature-breakdown/assets/output-template.md +2 -2
- package/plugins/devflow-design/skills/workflow-frontend-tech-spec/SKILL.md +41 -41
- package/plugins/devflow-design/skills/workflow-frontend-tech-spec/assets/frontend-spec-template.md +15 -15
- package/plugins/devflow-design/skills/workflow-frontend-tech-spec/references/affected-module-exploration.md +2 -2
- package/plugins/devflow-design/skills/workflow-frontend-tech-spec/references/project-rule-contract.md +25 -25
- package/plugins/devflow-design/skills/workflow-integration-verify/SKILL.md +13 -13
- package/plugins/devflow-design/skills/workflow-ui-spec/SKILL.md +23 -23
- package/plugins/devflow-design/skills/workflow-ui-spec/assets/ui-spec-template.md +3 -3
- package/plugins/devflow-implementation/agents/implementation-worker.md +2 -2
- package/plugins/devflow-implementation/skills/workflow-bug-fix/SKILL.md +9 -9
- package/plugins/devflow-implementation/skills/workflow-bug-fix/references/lesson-format.md +2 -2
- package/plugins/devflow-implementation/skills/workflow-bug-fix/references/root-cause-ladder.md +1 -1
- package/plugins/devflow-implementation/skills/workflow-change-plan/SKILL.md +17 -17
- package/plugins/devflow-implementation/skills/workflow-change-plan/references/code-conventions.md +1 -1
- package/plugins/devflow-implementation/skills/workflow-change-plan/references/output-template.md +3 -3
- package/plugins/devflow-implementation/skills/workflow-change-plan/references/project-rule-contract.md +16 -16
- package/plugins/devflow-implementation/skills/workflow-execute-phase/SKILL.md +38 -38
- package/plugins/devflow-implementation/skills/workflow-execute-phase/references/execute-phase.md +4 -2
- package/plugins/devflow-intel/agents/project-scout.md +1 -1
- package/plugins/devflow-intel/extensions/devflow-intel.ts +20 -19
- package/plugins/devflow-intel/skills/code-index-query/SKILL.md +6 -6
- package/plugins/devflow-intel/skills/workflow-code-index/SKILL.md +12 -12
- package/plugins/devflow-intel/skills/workflow-code-index/references/discovery.md +2 -2
- package/plugins/devflow-intel/skills/workflow-code-index/references/query-guide.md +1 -1
- package/plugins/devflow-intel/skills/workflow-code-index/scripts/code_index.py +31 -12
- package/plugins/devflow-intel/skills/workflow-code-index/scripts/core/discovery.py +2 -2
- package/plugins/devflow-intel/skills/workflow-code-index/scripts/core/scanner.py +4 -1
- package/plugins/devflow-intel/skills/workflow-code-index/scripts/validators/project_binding_check.py +4 -4
- package/plugins/devflow-intel/skills/workflow-context-sync/SKILL.md +14 -14
- package/plugins/devflow-intel/skills/workflow-context-sync/scripts/context_sync_cursor.py +2 -2
- package/plugins/devflow-intel/skills/workflow-update-navigation/SKILL.md +26 -26
- package/plugins/devflow-intel/skills/workflow-update-navigation/references/incremental-update-guide.md +2 -2
- package/plugins/devflow-quality/runtime/playwright/devflow-test-dsl-v1.schema.json +872 -0
- package/plugins/devflow-quality/runtime/playwright/playwright.config.mjs +46 -0
- package/plugins/devflow-quality/runtime/playwright/reporter.mjs +311 -0
- package/plugins/devflow-quality/runtime/playwright/runner.spec.mjs +1308 -0
- package/plugins/devflow-quality/runtime/playwright/runtime-manifest.json +11 -0
- package/plugins/devflow-quality/skills/code-review/SKILL.md +12 -12
- package/plugins/devflow-quality/skills/code-review/references/spec-checklist.md +1 -1
- package/plugins/devflow-quality/skills/workflow-acceptance-test-design/SKILL.md +11 -8
- package/plugins/devflow-quality/skills/workflow-gen-test-guide/SKILL.md +6 -6
- package/plugins/devflow-quality/skills/workflow-gen-test-guide/legacy/SKILL.md +14 -14
- package/plugins/devflow-quality/skills/workflow-generate-mainflow-cases/SKILL.md +82 -69
- package/plugins/devflow-quality/skills/workflow-generate-mainflow-cases/references/api-mainflow-rules.md +20 -15
- package/plugins/devflow-quality/skills/workflow-generate-mainflow-cases/references/codebase-discovery.md +12 -10
- package/plugins/devflow-quality/skills/workflow-generate-mainflow-cases/references/intermediate-format.md +115 -192
- package/plugins/devflow-quality/skills/workflow-generate-mainflow-cases/references/mainflow-selection.md +27 -23
- package/plugins/devflow-quality/skills/workflow-generate-mainflow-cases/references/project-dsl-contract.md +78 -153
- package/plugins/devflow-quality/skills/workflow-generate-mainflow-cases/references/ui-mainflow-rules.md +36 -83
- package/plugins/devflow-quality/skills/workflow-generate-mainflow-cases/scripts/compile_dsl.py +497 -556
- package/plugins/devflow-quality/skills/workflow-generate-mainflow-cases/scripts/discover_codebases.py +2 -2
- package/plugins/devflow-quality/skills/workflow-generate-mainflow-cases/scripts/export_legacy_testagent.py +647 -0
- package/plugins/devflow-quality/skills/workflow-generate-mainflow-cases/scripts/normalize_case_payloads.py +10 -3
- package/plugins/devflow-quality/skills/workflow-generate-mainflow-cases/scripts/validate_case_payloads.py +165 -275
- package/plugins/devflow-quality/skills/workflow-human-acceptance/SKILL.md +61 -0
- package/plugins/devflow-quality/skills/workflow-release-closeout/SKILL.md +18 -18
- package/plugins/devflow-quality/skills/workflow-run-acceptance-tests/SKILL.md +20 -14
- package/plugins/devflow-requirements/skills/requirement-feasibility-review/SKILL.md +1 -1
- package/plugins/devflow-requirements/skills/workflow-demand-clarify/SKILL.md +10 -10
- package/plugins/devflow-requirements/skills/workflow-domain-modeling/SKILL.md +25 -25
- package/plugins/devflow-requirements/skills/workflow-requirement-baseline/SKILL.md +49 -49
- package/plugins/devflow-requirements/skills/workflow-requirement-baseline/assets/baseline-template.md +22 -22
- package/plugins/devflow-requirements/skills/workflow-requirement-baseline/references/antipatterns.md +3 -3
- package/plugins/devflow-requirements/skills/workflow-requirement-baseline/references/challenge-review-guide.md +3 -3
- package/plugins/devflow-requirements/skills/workflow-requirement-baseline/references/project-context-guide.md +11 -11
- package/plugins/devflow-requirements/skills/workflow-requirement-baseline/references/questioning.md +1 -1
- package/plugins/devflow-requirements/skills/workflow-requirement-baseline/references/requirement-review-checklist.md +4 -4
- package/plugins/devflow-requirements/skills/workflow-requirement-triage/SKILL.md +16 -16
- package/plugins/devflow-requirements/skills/workflow-wayfinder/SKILL.md +6 -6
- package/src/approval-store.ts +340 -0
- package/src/cli.ts +15 -0
- package/src/constants.ts +1 -1
- package/src/doctor.ts +259 -2
- package/src/initialization-store.ts +51 -3
- package/src/paths.ts +12 -1
- package/src/project-context.ts +60 -15
- package/src/project-documents.ts +61 -61
- package/src/project-initializer.ts +9 -8
- package/src/project-layout.ts +217 -0
- package/src/runtime.ts +3 -3
- package/templates/commands/start.md +4 -4
- package/templates/omp/AGENTS.md +1 -1
- package/templates/omp/hook-config.json +13 -7
- package/templates/omp/index-policy.json +8 -8
|
@@ -109,7 +109,7 @@ def validate_authority(root: Path, feature: str, expectations: list) -> tuple[li
|
|
|
109
109
|
issues.append(f"{item['id']}: authority_ref must identify a Core graph node and revision")
|
|
110
110
|
continue
|
|
111
111
|
node_id, revision = ref[len("core-graph:"):].rsplit("@", 1)
|
|
112
|
-
graph_path = f".planning/requirements/{feature}/governance.json"
|
|
112
|
+
graph_path = f".devflow/planning/requirements/{feature}/governance.json"
|
|
113
113
|
graph_file = safe_file(root, graph_path)
|
|
114
114
|
authority = read_json(graph_file)
|
|
115
115
|
node = next((n for n in authority.get("nodes", []) if isinstance(n, dict) and n.get("id") == node_id), None)
|
|
@@ -132,7 +132,7 @@ def validate_authority(root: Path, feature: str, expectations: list) -> tuple[li
|
|
|
132
132
|
|
|
133
133
|
|
|
134
134
|
def db_open(root: Path) -> sqlite3.Connection:
|
|
135
|
-
planning = root / ".planning"
|
|
135
|
+
planning = root / ".devflow/planning"
|
|
136
136
|
if planning.is_symlink():
|
|
137
137
|
raise ValueError("unsafe planning directory")
|
|
138
138
|
directory = planning / "review-runs"
|
|
@@ -174,7 +174,7 @@ def response(status: str, chain_id: str | None, round_no: int, **details: Any) -
|
|
|
174
174
|
|
|
175
175
|
def locate_index(root: Path, accepted: list, target_paths: list[str], questions: list[str]) -> dict:
|
|
176
176
|
"""Ask the index for bounded leads, never for authoritative conclusions."""
|
|
177
|
-
index = root / ".planning" / "code-index"
|
|
177
|
+
index = root / ".devflow/planning" / "code-index"
|
|
178
178
|
script = Path(__file__).resolve().parents[3].parent / "devflow-intel" / "skills" / "workflow-code-index" / "scripts" / "code_index.py"
|
|
179
179
|
if not index.exists() or not script.exists():
|
|
180
180
|
return {"status": "unavailable", "reason": "No local code-index snapshot; source evidence is independent"}
|
|
@@ -218,7 +218,7 @@ def verify_core_result(root: Path, feature: str, evidence: Any, expected_status:
|
|
|
218
218
|
"""Accept only a Core-owned TC result bound to the feature and frozen suite."""
|
|
219
219
|
if not isinstance(evidence, dict):
|
|
220
220
|
return False, "missing Core acceptance-test result reference"
|
|
221
|
-
relative = f".planning/test-runs/{feature}/acceptance-results.json"
|
|
221
|
+
relative = f".devflow/planning/test-runs/{feature}/acceptance-results.json"
|
|
222
222
|
if evidence.get("path") != relative or not isinstance(evidence.get("tc_id"), str):
|
|
223
223
|
return False, "result must reference a Core acceptance TC for this feature"
|
|
224
224
|
try:
|
|
@@ -226,7 +226,7 @@ def verify_core_result(root: Path, feature: str, evidence: Any, expected_status:
|
|
|
226
226
|
if digest(result_file.read_bytes()) != evidence.get("sha256"):
|
|
227
227
|
return False, "acceptance result hash mismatch"
|
|
228
228
|
payload = read_json(result_file)
|
|
229
|
-
suite = read_json(safe_file(root, f".planning/requirements/{feature}/tests.json"))
|
|
229
|
+
suite = read_json(safe_file(root, f".devflow/planning/requirements/{feature}/tests.json"))
|
|
230
230
|
if payload.get("origin") != "core_acceptance_test_runner" or payload.get("feature") != feature:
|
|
231
231
|
return False, "not a Core acceptance-test run"
|
|
232
232
|
if payload.get("test_suite") != {"graph_revision": suite.get("graph_revision"), "fingerprint": suite.get("view_meta", {}).get("fingerprint")}:
|
|
@@ -252,7 +252,7 @@ def verify_core_result(root: Path, feature: str, evidence: Any, expected_status:
|
|
|
252
252
|
def verify_core_impact(root: Path, feature: str, evidence: dict, impact: str, trigger: str) -> tuple[bool, str]:
|
|
253
253
|
"""A failed TC alone does not establish the reviewer's causal/impact label."""
|
|
254
254
|
try:
|
|
255
|
-
suite = read_json(safe_file(root, f".planning/requirements/{feature}/tests.json"))
|
|
255
|
+
suite = read_json(safe_file(root, f".devflow/planning/requirements/{feature}/tests.json"))
|
|
256
256
|
node = next((n for n in suite.get("nodes", []) if isinstance(n, dict) and n.get("id") == evidence.get("tc_id")), None)
|
|
257
257
|
data = node.get("data", {}) if node else {}
|
|
258
258
|
if data.get("review_impact") == impact and data.get("review_trigger") == trigger:
|
|
@@ -263,7 +263,7 @@ def verify_core_impact(root: Path, feature: str, evidence: dict, impact: str, tr
|
|
|
263
263
|
|
|
264
264
|
|
|
265
265
|
def declared_change_paths(root: Path, feature: str) -> tuple[set[str], str, str]:
|
|
266
|
-
relative = f".planning/features/{feature}/变更清单.md"
|
|
266
|
+
relative = f".devflow/planning/features/{feature}/变更清单.md"
|
|
267
267
|
source = safe_file(root, relative)
|
|
268
268
|
declarations = re.findall(r"^\s*-\s*\*\*文件\*\*\s*[::]\s*(.+)$", source.read_text(encoding="utf-8"), re.MULTILINE)
|
|
269
269
|
paths = set()
|
|
@@ -295,7 +295,7 @@ def verify_coverage(root: Path, feature: str, required: list[str], coverage_evid
|
|
|
295
295
|
if not valid:
|
|
296
296
|
issues.append(f"{tag}: {reason}")
|
|
297
297
|
continue
|
|
298
|
-
suite = read_json(safe_file(root, f".planning/requirements/{feature}/tests.json"))
|
|
298
|
+
suite = read_json(safe_file(root, f".devflow/planning/requirements/{feature}/tests.json"))
|
|
299
299
|
node = next((n for n in suite.get("nodes", []) if isinstance(n, dict) and n.get("id") == ref["tc_id"]), None)
|
|
300
300
|
types = {"scenario:normal": {"api", "page"}, "scenario:unauthorized": {"permission"}, "scenario:failure_rollback": {"resilience", "boundary"}, "scenario:compatibility": {"migration"}}
|
|
301
301
|
data = node.get("data", {}) if node else {}
|
|
@@ -310,7 +310,7 @@ def verify_coverage(root: Path, feature: str, required: list[str], coverage_evid
|
|
|
310
310
|
|
|
311
311
|
def suite_has_failures(root: Path, feature: str) -> bool:
|
|
312
312
|
try:
|
|
313
|
-
payload = read_json(safe_file(root, f".planning/test-runs/{feature}/acceptance-results.json"))
|
|
313
|
+
payload = read_json(safe_file(root, f".devflow/planning/test-runs/{feature}/acceptance-results.json"))
|
|
314
314
|
return any(isinstance(item, dict) and item.get("status") != "passed" for item in payload.get("results", []))
|
|
315
315
|
except (OSError, ValueError, TypeError, json.JSONDecodeError):
|
|
316
316
|
return True
|
|
@@ -322,13 +322,13 @@ def gate_status(root: Path, feature: str, contract_id: str | None = None) -> dic
|
|
|
322
322
|
if not contract_id:
|
|
323
323
|
return {"status": "human_confirmation", "reason": "Current Core review contract identity is required"}
|
|
324
324
|
try:
|
|
325
|
-
contract = read_json(safe_file(root, f".planning/contracts/{feature}/{contract_id}.json"))
|
|
325
|
+
contract = read_json(safe_file(root, f".devflow/planning/contracts/{feature}/{contract_id}.json"))
|
|
326
326
|
if contract.get("origin") != "core_execution_contract" or contract.get("step") != "code-review" or contract.get("feature") != feature or contract.get("contract_id") != contract_id:
|
|
327
327
|
return {"status": "core_contract_conflict", "reason": "Review contract identity is not a frozen Core code-review contract"}
|
|
328
328
|
sys.path.insert(0, str(Path(__file__).resolve().parent))
|
|
329
329
|
from review_preflight import load_state
|
|
330
|
-
state = load_state(safe_file(root, ".planning/STATE.md"))
|
|
331
|
-
graph = read_json(safe_file(root, f".planning/requirements/{feature}/governance.json"))
|
|
330
|
+
state = load_state(safe_file(root, ".devflow/planning/STATE.md"))
|
|
331
|
+
graph = read_json(safe_file(root, f".devflow/planning/requirements/{feature}/governance.json"))
|
|
332
332
|
workflow = safe_file(root, contract["workflow_path"])
|
|
333
333
|
if (state.get("current_feature") != feature or state.get("current_step") != "code-review"
|
|
334
334
|
or state.get("revision") != contract.get("state_revision")
|
|
@@ -337,7 +337,7 @@ def gate_status(root: Path, feature: str, contract_id: str | None = None) -> dic
|
|
|
337
337
|
return {"status": "stale_evidence", "reason": "Review contract differs from current Core state, graph, or workflow"}
|
|
338
338
|
except (OSError, ValueError, KeyError, TypeError, ImportError, json.JSONDecodeError) as exc:
|
|
339
339
|
return {"status": "human_confirmation", "reason": f"Current Core review contract cannot be verified: {exc}"}
|
|
340
|
-
database = root / ".planning" / "review-runs" / "review-runs.sqlite"
|
|
340
|
+
database = root / ".devflow/planning" / "review-runs" / "review-runs.sqlite"
|
|
341
341
|
if not database.is_file() or database.is_symlink():
|
|
342
342
|
return {"status": "human_confirmation", "reason": "No Core review round exists"}
|
|
343
343
|
db = sqlite3.connect(f"file:{database}?mode=ro", uri=True)
|
|
@@ -366,7 +366,7 @@ def gate_status(root: Path, feature: str, contract_id: str | None = None) -> dic
|
|
|
366
366
|
index_generation = fixed.get("code_index_generation")
|
|
367
367
|
if index_generation is not None:
|
|
368
368
|
try:
|
|
369
|
-
snapshot = read_json(safe_file(root, ".planning/code-index/SNAPSHOT.json"))
|
|
369
|
+
snapshot = read_json(safe_file(root, ".devflow/planning/code-index/SNAPSHOT.json"))
|
|
370
370
|
if snapshot.get("generation") != index_generation:
|
|
371
371
|
return {"status": "stale_evidence", "reason": "Code-index generation changed after review", "chain_id": result.get("chain_id")}
|
|
372
372
|
except (OSError, ValueError, json.JSONDecodeError):
|
|
@@ -415,11 +415,11 @@ def review_markdown(result: dict) -> str:
|
|
|
415
415
|
|
|
416
416
|
def render_review(root: Path, feature: str, contract_id: str) -> dict:
|
|
417
417
|
root = root.resolve(strict=True)
|
|
418
|
-
contract = read_json(safe_file(root, f".planning/contracts/{feature}/{contract_id}.json"))
|
|
418
|
+
contract = read_json(safe_file(root, f".devflow/planning/contracts/{feature}/{contract_id}.json"))
|
|
419
419
|
path = next((item for item in contract.get("allowed_paths", []) if isinstance(item, str) and item.endswith("/REVIEW.md")), None)
|
|
420
420
|
if not path:
|
|
421
421
|
return {"status": "core_contract_conflict", "reason": "Core contract has no REVIEW.md output"}
|
|
422
|
-
database = root / ".planning/review-runs/review-runs.sqlite"
|
|
422
|
+
database = root / ".devflow/planning/review-runs/review-runs.sqlite"
|
|
423
423
|
if not database.is_file():
|
|
424
424
|
return {"status": "human_confirmation", "reason": "No Core review round exists"}
|
|
425
425
|
db = sqlite3.connect(f"file:{database}?mode=ro", uri=True)
|
|
@@ -616,7 +616,7 @@ def run(root: Path, request: dict) -> dict:
|
|
|
616
616
|
db.commit()
|
|
617
617
|
return result
|
|
618
618
|
if index_discovery.get("generation"):
|
|
619
|
-
current_snapshot = root / ".planning" / "code-index" / "SNAPSHOT.json"
|
|
619
|
+
current_snapshot = root / ".devflow/planning" / "code-index" / "SNAPSHOT.json"
|
|
620
620
|
if not current_snapshot.exists() or read_json(current_snapshot).get("generation") != index_discovery["generation"]:
|
|
621
621
|
result = response("stale_evidence", chain_id, round_no, questions=["Code-index generation changed during review"])
|
|
622
622
|
db.execute("INSERT INTO events(chain_id,status,detail_json) VALUES(?,?,?)", (chain_id, result["status"], canonical(result)))
|
|
@@ -645,7 +645,7 @@ def run(root: Path, request: dict) -> dict:
|
|
|
645
645
|
db.commit()
|
|
646
646
|
return result
|
|
647
647
|
status = "terminated_p0" if round_no == 3 and summary["P0"] else ("findings" if open_findings else "clean")
|
|
648
|
-
core_results = {rel: digest(safe_file(root, rel).read_bytes()) for rel in (f".planning/requirements/{target['feature']}/tests.json", f".planning/test-runs/{target['feature']}/acceptance-results.json")}
|
|
648
|
+
core_results = {rel: digest(safe_file(root, rel).read_bytes()) for rel in (f".devflow/planning/requirements/{target['feature']}/tests.json", f".devflow/planning/test-runs/{target['feature']}/acceptance-results.json")}
|
|
649
649
|
result = response(status, chain_id, round_no, fixed_versions={"source": versions, "authority": accepted, "core_results": core_results, "change_plan": {"path": change_plan_path, "sha256": change_plan_hash, "declared_paths": sorted(declared_paths)}, "code_index_generation": index_discovery.get("generation")}, index_discovery=index_discovery, coverage={"covered": sorted(covered), "gaps": gaps, "index_gap": index_discovery.get("reason") if index_discovery["status"] != "located" else None}, findings=findings, risk_summary=summary, improvement_plan=[{"finding_id": f["finding_id"], "severity": f["severity"], "action": f["improvement"]} for f in sorted(open_findings, key=lambda x: x["severity"])], all_p0_resolved=summary["P0"] == 0, severity_source="independent_reviewer_core_evidence_bound", semantic_causality_verified=True, automatic_release_allowed=status == "clean", termination_scope="current_task_only" if status == "terminated_p0" else None, reviewer_task={key: binding[key] for key in ("agent", "feature", "contract_id", "task_call_id", "report_sha256")}, history=[{"round": r, "status": json.loads(raw)["status"]} for r, raw in db.execute("SELECT round,result_json FROM rounds WHERE chain_id=? ORDER BY round", (chain_id,))])
|
|
650
650
|
db.execute("INSERT INTO reviewer_tasks(task_call_id,chain_id,round,report_sha256) VALUES(?,?,?,?)", (binding["task_call_id"], chain_id, round_no, binding["report_sha256"]))
|
|
651
651
|
db.execute("INSERT INTO rounds(chain_id,round,result_json) VALUES(?,?,?)", (chain_id, round_no, canonical(result)))
|
package/plugins/devflow-core/skills/workflow-orchestrator/scripts/runtime_context_collector.rb
CHANGED
|
@@ -14,8 +14,8 @@ require_relative "control_io"
|
|
|
14
14
|
|
|
15
15
|
module RuntimeContextCollector
|
|
16
16
|
SCHEMA_VERSION = 1
|
|
17
|
-
HISTORY_DIR = File.join(".context", "runtime-context", "revisions")
|
|
18
|
-
POINTER = File.join(".context", "runtime-context.json")
|
|
17
|
+
HISTORY_DIR = File.join(".devflow/context", "runtime-context", "revisions")
|
|
18
|
+
POINTER = File.join(".devflow/context", "runtime-context.json")
|
|
19
19
|
EXTRACTORS = {
|
|
20
20
|
"package.json" => :extract_package_json,
|
|
21
21
|
"requirements.txt" => :extract_requirements_txt,
|
|
@@ -170,7 +170,7 @@ module RuntimeContextCollector
|
|
|
170
170
|
history = File.join(root, HISTORY_DIR, "#{revision}.json")
|
|
171
171
|
DevflowControlIO.atomic_create(history, JSON.pretty_generate(snapshot) + "\n")
|
|
172
172
|
DevflowControlIO.atomic_write(File.join(root, POINTER), JSON.pretty_generate({ "current_revision" => revision, "path" => history.sub("#{root}/", "") }) + "\n")
|
|
173
|
-
DevflowControlIO.append_audit(File.join(root, ".context", "runtime-context", "audit.jsonl"), {
|
|
173
|
+
DevflowControlIO.append_audit(File.join(root, ".devflow/context", "runtime-context", "audit.jsonl"), {
|
|
174
174
|
"event" => "snapshot_collected", "snapshot_revision" => revision,
|
|
175
175
|
"repository_revision" => repository_revision, "coverage_status" => coverage_status
|
|
176
176
|
})
|
|
@@ -69,7 +69,7 @@ def lease_expiry(seconds)
|
|
|
69
69
|
end
|
|
70
70
|
|
|
71
71
|
root = Dir.pwd
|
|
72
|
-
state_path, = DevflowControlIO.resolve_control_path(root, ".planning/STATE.md", :state)
|
|
72
|
+
state_path, = DevflowControlIO.resolve_control_path(root, ".devflow/planning/STATE.md", :state)
|
|
73
73
|
result = catch(:transition_done) do
|
|
74
74
|
lock = DevflowControlIO.acquire_project_lock(root)
|
|
75
75
|
begin
|
|
@@ -129,7 +129,7 @@ result = catch(:transition_done) do
|
|
|
129
129
|
throw :transition_done, result
|
|
130
130
|
end
|
|
131
131
|
rollover_id = "ROL-#{SecureRandom.uuid}"
|
|
132
|
-
relative_path = ".planning/handoffs/#{state.fetch("current_feature")}/#{rollover_id}.json"
|
|
132
|
+
relative_path = ".devflow/planning/handoffs/#{state.fetch("current_feature")}/#{rollover_id}.json"
|
|
133
133
|
absolute_path, = DevflowControlIO.resolve_control_path(root, relative_path, :handoff)
|
|
134
134
|
payload = {
|
|
135
135
|
"schema_version" => 1,
|
|
@@ -144,9 +144,9 @@ result = catch(:transition_done) do
|
|
|
144
144
|
"status" => state["status"], "completed_steps" => state["completed_steps"], "pending_steps" => state["pending_steps"]
|
|
145
145
|
},
|
|
146
146
|
"references" => {
|
|
147
|
-
"state_path" => ".planning/STATE.md",
|
|
147
|
+
"state_path" => ".devflow/planning/STATE.md",
|
|
148
148
|
"workflow_path" => state["workflow_config"],
|
|
149
|
-
"artifact_registry" => ".planning/artifacts/index.yaml"
|
|
149
|
+
"artifact_registry" => ".devflow/planning/artifacts/index.yaml"
|
|
150
150
|
}
|
|
151
151
|
}
|
|
152
152
|
serialized = JSON.generate(payload) + "\n"
|
|
@@ -17,9 +17,9 @@ require_relative "control_io"
|
|
|
17
17
|
module StaticRuntimeContextCollector
|
|
18
18
|
SCHEMA_VERSION = 2
|
|
19
19
|
COLLECTOR_VERSION = "static-runtime-context-v2.1"
|
|
20
|
-
ROOT_DIR = File.join(".context", "static-runtime-context")
|
|
20
|
+
ROOT_DIR = File.join(".devflow/context", "static-runtime-context")
|
|
21
21
|
HISTORY_DIR = File.join(ROOT_DIR, "revisions")
|
|
22
|
-
POINTER = ".context/static-runtime-context.json"
|
|
22
|
+
POINTER = ".devflow/context/static-runtime-context.json"
|
|
23
23
|
AUDIT_PATH = File.join(ROOT_DIR, "audit.jsonl")
|
|
24
24
|
MAX_COMPOSE_BYTES = 1_048_576
|
|
25
25
|
EXCLUDED_ROOTS = %w[node_modules vendor dist build .git].freeze
|
|
@@ -11,7 +11,7 @@ require_relative "control_io"
|
|
|
11
11
|
require_relative "phase_ownership"
|
|
12
12
|
|
|
13
13
|
options = {
|
|
14
|
-
state: ".planning/STATE.md",
|
|
14
|
+
state: ".devflow/planning/STATE.md",
|
|
15
15
|
workflow: nil,
|
|
16
16
|
output: nil,
|
|
17
17
|
write: false,
|
|
@@ -72,10 +72,10 @@ unless ownership["ok"]
|
|
|
72
72
|
puts JSON.pretty_generate(ownership.merge("written" => false))
|
|
73
73
|
exit 0
|
|
74
74
|
end
|
|
75
|
-
workflow_source = options[:workflow] || state["workflow_config"] || ".planning/workflows/#{state.fetch("current_flow")}.yaml"
|
|
75
|
+
workflow_source = options[:workflow] || state["workflow_config"] || ".devflow/planning/workflows/#{state.fetch("current_flow")}.yaml"
|
|
76
76
|
workflow_path, = DevflowControlIO.resolve_control_path(root, workflow_source, :workflow)
|
|
77
77
|
workflow = load_yaml_file(workflow_path)
|
|
78
|
-
registry_source = options[:output] || workflow.dig("artifact_registry", "source") || ".planning/artifacts/index.yaml"
|
|
78
|
+
registry_source = options[:output] || workflow.dig("artifact_registry", "source") || ".devflow/planning/artifacts/index.yaml"
|
|
79
79
|
existing_registry_path, registry_path = DevflowControlIO.resolve_control_path(root, registry_source, :registry)
|
|
80
80
|
existing_by_path = {}
|
|
81
81
|
if options[:preserve] && File.exist?(existing_registry_path)
|
|
@@ -112,7 +112,7 @@ end
|
|
|
112
112
|
|
|
113
113
|
def questions_registry_entry(root, state, existing_by_path)
|
|
114
114
|
feature = state.fetch("current_feature", "").to_s
|
|
115
|
-
path = ".planning/features/#{feature}/questions.yaml"
|
|
115
|
+
path = ".devflow/planning/features/#{feature}/questions.yaml"
|
|
116
116
|
absolute, = DevflowControlIO.resolve_control_path(root, path, :artifact)
|
|
117
117
|
exists = File.exist?(absolute)
|
|
118
118
|
entry = {
|
|
@@ -180,7 +180,7 @@ artifacts = collect_outputs(workflow).map do |step, output|
|
|
|
180
180
|
}.reject { |_, value| value.nil? || value == [] }
|
|
181
181
|
end
|
|
182
182
|
|
|
183
|
-
questions_path = ".planning/features/#{state.fetch("current_feature", "")}/questions.yaml"
|
|
183
|
+
questions_path = ".devflow/planning/features/#{state.fetch("current_feature", "")}/questions.yaml"
|
|
184
184
|
questions_entry = questions_registry_entry(root, state, existing_by_path)
|
|
185
185
|
question_index = artifacts.index { |artifact| artifact["path"] == questions_path }
|
|
186
186
|
if question_index
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""RFC 8785 JSON Canonicalization Scheme (JCS) and the single tc_sha256 implementation.
|
|
3
|
+
|
|
4
|
+
tc_sha256 = lowercase hex SHA-256 of JCS(node.data). Generators, validators and
|
|
5
|
+
approval pins must call this module; the Runtime only echoes the value back.
|
|
6
|
+
"""
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import argparse
|
|
10
|
+
import hashlib
|
|
11
|
+
import json
|
|
12
|
+
import math
|
|
13
|
+
import sys
|
|
14
|
+
from typing import Any
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
_ESCAPES = {'"': '\\"', "\\": "\\\\", "\b": "\\b", "\f": "\\f", "\n": "\\n", "\r": "\\r", "\t": "\\t"}
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def _string(value: str) -> str:
|
|
21
|
+
out = ['"']
|
|
22
|
+
for char in value:
|
|
23
|
+
if char in _ESCAPES:
|
|
24
|
+
out.append(_ESCAPES[char])
|
|
25
|
+
elif ord(char) < 0x20:
|
|
26
|
+
out.append(f"\\u{ord(char):04x}")
|
|
27
|
+
elif 0xD800 <= ord(char) <= 0xDFFF:
|
|
28
|
+
raise ValueError("lone surrogate cannot be canonicalized")
|
|
29
|
+
else:
|
|
30
|
+
out.append(char)
|
|
31
|
+
out.append('"')
|
|
32
|
+
return "".join(out)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def _number(value: int | float) -> str:
|
|
36
|
+
"""ECMAScript Number.prototype.toString for an IEEE-754 double (RFC 8785 §3.2.2.3)."""
|
|
37
|
+
if isinstance(value, int):
|
|
38
|
+
converted = float(value)
|
|
39
|
+
if int(converted) != value:
|
|
40
|
+
raise ValueError(f"integer {value} is not exactly representable as an IEEE-754 double")
|
|
41
|
+
value = converted
|
|
42
|
+
if math.isnan(value) or math.isinf(value):
|
|
43
|
+
raise ValueError("NaN and Infinity are not valid JSON numbers")
|
|
44
|
+
if value == 0:
|
|
45
|
+
return "0"
|
|
46
|
+
sign = "-" if value < 0 else ""
|
|
47
|
+
text = repr(abs(value)) # shortest round-trip digits
|
|
48
|
+
mantissa, _, exponent = text.partition("e")
|
|
49
|
+
integer, _, fraction = mantissa.partition(".")
|
|
50
|
+
raw = integer + fraction
|
|
51
|
+
leading = len(raw) - len(raw.lstrip("0"))
|
|
52
|
+
digits = raw.lstrip("0").rstrip("0")
|
|
53
|
+
point = len(integer) + int(exponent or 0) - leading # value = 0.digits * 10**point
|
|
54
|
+
count = len(digits)
|
|
55
|
+
if count <= point <= 21:
|
|
56
|
+
body = digits + "0" * (point - count)
|
|
57
|
+
elif 0 < point <= 21:
|
|
58
|
+
body = digits[:point] + "." + digits[point:]
|
|
59
|
+
elif -6 < point <= 0:
|
|
60
|
+
body = "0." + "0" * (-point) + digits
|
|
61
|
+
else:
|
|
62
|
+
power = point - 1
|
|
63
|
+
suffix = f"e{'+' if power >= 0 else '-'}{abs(power)}"
|
|
64
|
+
body = (digits if count == 1 else digits[0] + "." + digits[1:]) + suffix
|
|
65
|
+
return sign + body
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def _utf16_key(key: str) -> list[int]:
|
|
69
|
+
encoded = key.encode("utf-16-be")
|
|
70
|
+
return [int.from_bytes(encoded[index:index + 2], "big") for index in range(0, len(encoded), 2)]
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def _serialize(value: Any, out: list[str]) -> None:
|
|
74
|
+
if value is None:
|
|
75
|
+
out.append("null")
|
|
76
|
+
elif value is True:
|
|
77
|
+
out.append("true")
|
|
78
|
+
elif value is False:
|
|
79
|
+
out.append("false")
|
|
80
|
+
elif isinstance(value, (int, float)):
|
|
81
|
+
out.append(_number(value))
|
|
82
|
+
elif isinstance(value, str):
|
|
83
|
+
out.append(_string(value))
|
|
84
|
+
elif isinstance(value, (list, tuple)):
|
|
85
|
+
out.append("[")
|
|
86
|
+
for index, item in enumerate(value):
|
|
87
|
+
if index:
|
|
88
|
+
out.append(",")
|
|
89
|
+
_serialize(item, out)
|
|
90
|
+
out.append("]")
|
|
91
|
+
elif isinstance(value, dict):
|
|
92
|
+
if not all(isinstance(key, str) for key in value):
|
|
93
|
+
raise ValueError("object keys must be strings")
|
|
94
|
+
out.append("{")
|
|
95
|
+
for index, key in enumerate(sorted(value, key=_utf16_key)):
|
|
96
|
+
if index:
|
|
97
|
+
out.append(",")
|
|
98
|
+
out.append(_string(key))
|
|
99
|
+
out.append(":")
|
|
100
|
+
_serialize(value[key], out)
|
|
101
|
+
out.append("}")
|
|
102
|
+
else:
|
|
103
|
+
raise ValueError(f"unsupported JSON value type: {type(value).__name__}")
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def canonicalize(value: Any) -> bytes:
|
|
107
|
+
out: list[str] = []
|
|
108
|
+
_serialize(value, out)
|
|
109
|
+
return "".join(out).encode("utf-8")
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def jcs_sha256(value: Any) -> str:
|
|
113
|
+
return hashlib.sha256(canonicalize(value)).hexdigest()
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def tc_sha256(data: Any) -> str:
|
|
117
|
+
if not isinstance(data, dict):
|
|
118
|
+
raise ValueError("TC data must be an object")
|
|
119
|
+
return jcs_sha256(data)
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def main() -> int:
|
|
123
|
+
parser = argparse.ArgumentParser(description="Print tc_sha256 (JCS SHA-256) of a JSON document read from a file or stdin.")
|
|
124
|
+
parser.add_argument("path", nargs="?")
|
|
125
|
+
args = parser.parse_args()
|
|
126
|
+
text = open(args.path, encoding="utf-8").read() if args.path else sys.stdin.read()
|
|
127
|
+
print(jcs_sha256(json.loads(text)))
|
|
128
|
+
return 0
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
if __name__ == "__main__":
|
|
132
|
+
raise SystemExit(main())
|
|
@@ -92,7 +92,7 @@ def task_binding(root: Path, feature: str, task_id: str) -> tuple[dict[str, Any]
|
|
|
92
92
|
validation = validate_bindings(root, feature)
|
|
93
93
|
if not validation.get("ok"):
|
|
94
94
|
return None, [str(item) for item in validation.get("errors", ["invalid test bindings"])]
|
|
95
|
-
bindings = read_json(root / ".planning" / "features" / feature / "test-bindings.json")
|
|
95
|
+
bindings = read_json(root / ".devflow/planning" / "features" / feature / "test-bindings.json")
|
|
96
96
|
if bindings is None:
|
|
97
97
|
return None, ["missing test bindings"]
|
|
98
98
|
matches = [item for item in bindings.get("tasks", []) if isinstance(item, dict) and item.get("id") == task_id]
|
|
@@ -105,7 +105,7 @@ def task_binding(root: Path, feature: str, task_id: str) -> tuple[dict[str, Any]
|
|
|
105
105
|
|
|
106
106
|
|
|
107
107
|
def evidence_path(root: Path, feature: str, task_id: str) -> Path:
|
|
108
|
-
return root / ".planning" / "test-runs" / feature / "tdd" / f"{task_id}.json"
|
|
108
|
+
return root / ".devflow/planning" / "test-runs" / feature / "tdd" / f"{task_id}.json"
|
|
109
109
|
|
|
110
110
|
|
|
111
111
|
def command_hash(argv: list[str]) -> str:
|
|
@@ -233,7 +233,7 @@ def validate_feature(root: Path, feature: str) -> dict[str, Any]:
|
|
|
233
233
|
errors = [str(item) for item in binding_result.get("errors", [])]
|
|
234
234
|
if errors:
|
|
235
235
|
return response(False, feature=feature, errors=errors)
|
|
236
|
-
bindings = read_json(root / ".planning" / "features" / feature / "test-bindings.json")
|
|
236
|
+
bindings = read_json(root / ".devflow/planning" / "features" / feature / "test-bindings.json")
|
|
237
237
|
assert bindings is not None
|
|
238
238
|
checked: list[str] = []
|
|
239
239
|
for task in bindings.get("tasks", []):
|
|
@@ -6,18 +6,25 @@ from pathlib import Path
|
|
|
6
6
|
from typing import Any
|
|
7
7
|
import json
|
|
8
8
|
import os
|
|
9
|
+
import re
|
|
9
10
|
import sqlite3
|
|
10
11
|
|
|
12
|
+
from approval_store import devflow_home
|
|
11
13
|
|
|
12
|
-
|
|
14
|
+
|
|
15
|
+
PACKAGE_RUNNERS = {"npm", "pnpm", "yarn"}
|
|
16
|
+
RUNTIME_MARKERS = ("devflow-quality/runtime/playwright", "runtime-manifest.json", "runner.spec.mjs", "devflow-test-dsl-v1.schema.json")
|
|
17
|
+
MARKDOWN_ROW_RE = re.compile(r"^\|(.+)\|\s*$")
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def database_toolchain_facts(root: Path) -> list[dict[str, Any]] | None:
|
|
13
21
|
manifest_path = root / ".devflow" / "project.json"
|
|
14
22
|
if not manifest_path.is_file():
|
|
15
23
|
return None
|
|
16
24
|
try:
|
|
17
25
|
project_id = json.loads(manifest_path.read_text(encoding="utf-8"))["projectId"]
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
connection = sqlite3.connect(f"file:{database}?mode=ro", uri=True)
|
|
26
|
+
database = devflow_home() / "projects" / project_id / "control.db"
|
|
27
|
+
connection = sqlite3.connect(f"{database.as_uri()}?mode=ro", uri=True)
|
|
21
28
|
connection.row_factory = sqlite3.Row
|
|
22
29
|
try:
|
|
23
30
|
authority = connection.execute("SELECT authority FROM authority_state WHERE project_id=?", (project_id,)).fetchone()
|
|
@@ -32,13 +39,87 @@ def database_toolchain(root: Path) -> list[str] | None:
|
|
|
32
39
|
ORDER BY c.revision DESC""",
|
|
33
40
|
(project_id, str(root.resolve())),
|
|
34
41
|
).fetchall()
|
|
35
|
-
|
|
42
|
+
facts = [json.loads(row["value_json"]) for row in rows]
|
|
43
|
+
return [fact for fact in facts if isinstance(fact, dict)]
|
|
36
44
|
finally:
|
|
37
45
|
connection.close()
|
|
38
46
|
except (OSError, KeyError, ValueError, json.JSONDecodeError, sqlite3.Error):
|
|
39
47
|
return None
|
|
40
48
|
|
|
41
49
|
|
|
50
|
+
def database_toolchain(root: Path) -> list[str] | None:
|
|
51
|
+
facts = database_toolchain_facts(root)
|
|
52
|
+
return None if facts is None else [str(fact.get("command", "")) for fact in facts]
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def _root_directory(value: Any) -> bool:
|
|
56
|
+
return value in (None, "", ".", "./")
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def registered_scripts(root: Path, facts: list[dict[str, Any]] | None) -> tuple[set[str], str]:
|
|
60
|
+
"""Package script names Core may run from the project root, and their source.
|
|
61
|
+
|
|
62
|
+
Toolchain facts (package-json@1) carry {name, command, workingDirectory};
|
|
63
|
+
the compatibility toolchain.md projects them as a 名称/工作目录 table. A
|
|
64
|
+
legacy free-form toolchain.md has no script names, so only then fall back
|
|
65
|
+
to the root package.json scripts.
|
|
66
|
+
"""
|
|
67
|
+
if facts is not None:
|
|
68
|
+
return {str(fact["name"]) for fact in facts if isinstance(fact.get("name"), str) and "command" in fact and _root_directory(fact.get("workingDirectory"))}, "toolchain facts"
|
|
69
|
+
names: set[str] = set()
|
|
70
|
+
toolchain = root / ".devflow/planning" / "toolchain.md"
|
|
71
|
+
header: list[str] | None = None
|
|
72
|
+
if toolchain.is_file():
|
|
73
|
+
for line in toolchain.read_text(encoding="utf-8").splitlines():
|
|
74
|
+
match = MARKDOWN_ROW_RE.match(line.strip())
|
|
75
|
+
if not match:
|
|
76
|
+
header = None
|
|
77
|
+
continue
|
|
78
|
+
cells = [cell.strip() for cell in match.group(1).split("|")]
|
|
79
|
+
if header is None:
|
|
80
|
+
header = cells
|
|
81
|
+
elif "名称" in header and "命令" in header and not set("".join(cells)) <= set("-: "):
|
|
82
|
+
row = dict(zip(header, cells))
|
|
83
|
+
if row.get("名称") not in (None, "", "undefined") and row.get("命令") not in (None, "", "undefined") and _root_directory(row.get("工作目录")):
|
|
84
|
+
names.add(row["名称"])
|
|
85
|
+
if names:
|
|
86
|
+
return names, "toolchain.md"
|
|
87
|
+
try:
|
|
88
|
+
scripts = json.loads((root / "package.json").read_text(encoding="utf-8")).get("scripts", {})
|
|
89
|
+
return ({name for name in scripts if isinstance(name, str)} if isinstance(scripts, dict) else set()), "package.json"
|
|
90
|
+
except (OSError, ValueError, AttributeError):
|
|
91
|
+
return set(), "package.json"
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def package_script(argv: list[str]) -> tuple[str | None, str | None]:
|
|
95
|
+
"""Return (script name, error) for npm/pnpm/yarn test|run argv."""
|
|
96
|
+
if argv[1] == "test":
|
|
97
|
+
rest, name = argv[2:], "test"
|
|
98
|
+
else:
|
|
99
|
+
if len(argv) < 3 or argv[2].startswith("-"):
|
|
100
|
+
return None, f"{Path(argv[0]).name} run must name a script immediately after 'run' (options before the script name are rejected)"
|
|
101
|
+
rest, name = argv[3:], argv[2]
|
|
102
|
+
if rest and rest[0] != "--":
|
|
103
|
+
return None, f"{Path(argv[0]).name} {argv[1]} extra arguments must follow '--'"
|
|
104
|
+
return name, None
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def reserved_reference(root: Path, argv: list[str]) -> str | None:
|
|
108
|
+
runtime_dirs: list[str] = []
|
|
109
|
+
try:
|
|
110
|
+
from dsl_v1 import runtime_dir_candidates
|
|
111
|
+
runtime_dirs = [str(path) for path in runtime_dir_candidates()]
|
|
112
|
+
except ImportError:
|
|
113
|
+
pass
|
|
114
|
+
for token in argv:
|
|
115
|
+
if "DEVFLOW_" in token:
|
|
116
|
+
return "test command must not reference DEVFLOW_ reserved variables"
|
|
117
|
+
normalized = token.replace("\\", "/")
|
|
118
|
+
if any(marker in normalized for marker in RUNTIME_MARKERS) or any(directory and directory in token for directory in runtime_dirs):
|
|
119
|
+
return "test command must not reference the Devflow Playwright Runtime; use the devflow_playwright adapter"
|
|
120
|
+
return None
|
|
121
|
+
|
|
122
|
+
|
|
42
123
|
def runner_marker(argv: list[str]) -> str | None:
|
|
43
124
|
if not argv:
|
|
44
125
|
return None
|
|
@@ -73,18 +154,31 @@ def runner_marker(argv: list[str]) -> str | None:
|
|
|
73
154
|
def validate_test_command(root: Path, argv: Any) -> str | None:
|
|
74
155
|
if not isinstance(argv, list) or not argv or not all(isinstance(token, str) and token and "\x00" not in token for token in argv):
|
|
75
156
|
return "test command must be a non-empty argv array"
|
|
157
|
+
reserved = reserved_reference(root, argv)
|
|
158
|
+
if reserved:
|
|
159
|
+
return reserved
|
|
76
160
|
marker = runner_marker(argv)
|
|
77
161
|
if marker is None:
|
|
162
|
+
if Path(argv[0]).name in PACKAGE_RUNNERS and len(argv) >= 2 and argv[1].startswith("-"):
|
|
163
|
+
return f"{Path(argv[0]).name} global options before the command are rejected (they can switch to another package)"
|
|
78
164
|
return "test command runner is not in the Core allowlist"
|
|
79
|
-
|
|
80
|
-
if
|
|
81
|
-
toolchain = root / ".planning" / "toolchain.md"
|
|
165
|
+
facts = database_toolchain_facts(root)
|
|
166
|
+
if facts is None:
|
|
167
|
+
toolchain = root / ".devflow/planning" / "toolchain.md"
|
|
82
168
|
if not toolchain.is_file():
|
|
83
|
-
return "initialized toolchain context (database or .planning/toolchain.md compatibility projection) is required before Core can execute a test command"
|
|
169
|
+
return "initialized toolchain context (database or .devflow/planning/toolchain.md compatibility projection) is required before Core can execute a test command"
|
|
84
170
|
content = toolchain.read_text(encoding="utf-8").lower()
|
|
85
171
|
else:
|
|
86
|
-
content = "\n".join(
|
|
172
|
+
content = "\n".join(str(fact.get("command", "")) for fact in facts).lower()
|
|
87
173
|
aliases = {"pytest": ("pytest",), "unittest": ("unittest",), "bun test": ("bun test",), "npm": ("npm",), "pnpm": ("pnpm",), "yarn": ("yarn",), "go test": ("go test",), "newman": ("newman",), "playwright": ("playwright",), "vitest": ("vitest",)}
|
|
174
|
+
if marker in PACKAGE_RUNNERS:
|
|
175
|
+
script, error = package_script(argv)
|
|
176
|
+
if error:
|
|
177
|
+
return error
|
|
178
|
+
names, source = registered_scripts(root, facts)
|
|
179
|
+
if script not in names:
|
|
180
|
+
return f"package script '{script}' is not registered in the initialization toolchain ({source})"
|
|
181
|
+
return None
|
|
88
182
|
if not any(alias in content for alias in aliases[marker]):
|
|
89
183
|
return f"test runner '{marker}' was not discovered in the initialization toolchain snapshot"
|
|
90
184
|
return None
|
package/plugins/devflow-core/skills/workflow-orchestrator/scripts/test_task_binding_check.py
CHANGED
|
@@ -74,7 +74,7 @@ def view_pin(suite: dict[str, Any]) -> dict[str, Any]:
|
|
|
74
74
|
|
|
75
75
|
|
|
76
76
|
def freeze_attestation_path(root: Path, feature: str) -> Path:
|
|
77
|
-
return root / ".planning" / "features" / feature / "test-suite-freeze.json"
|
|
77
|
+
return root / ".devflow/planning" / "features" / feature / "test-suite-freeze.json"
|
|
78
78
|
|
|
79
79
|
|
|
80
80
|
def validated_attestation(
|
|
@@ -108,8 +108,8 @@ def validated_attestation(
|
|
|
108
108
|
|
|
109
109
|
def validate(root: Path, feature: str, stage: str = "frozen") -> dict[str, Any]:
|
|
110
110
|
errors: list[str] = []
|
|
111
|
-
suite_path = root / ".planning" / "requirements" / feature / "tests.json"
|
|
112
|
-
binding_path = root / ".planning" / "features" / feature / "test-bindings.json"
|
|
111
|
+
suite_path = root / ".devflow/planning" / "requirements" / feature / "tests.json"
|
|
112
|
+
binding_path = root / ".devflow/planning" / "features" / feature / "test-bindings.json"
|
|
113
113
|
suite = read_json(suite_path, errors, "TC suite")
|
|
114
114
|
bindings = read_json(binding_path, errors, "test bindings")
|
|
115
115
|
if suite is None or bindings is None:
|
|
@@ -33,7 +33,7 @@ options = {
|
|
|
33
33
|
route: nil,
|
|
34
34
|
reason: nil,
|
|
35
35
|
blocking_question: nil,
|
|
36
|
-
state: ".planning/STATE.md",
|
|
36
|
+
state: ".devflow/planning/STATE.md",
|
|
37
37
|
write: false,
|
|
38
38
|
json: false
|
|
39
39
|
}
|
|
@@ -76,7 +76,7 @@ result = if !ROUTE_NEXT_SKILL.key?(options[:route].to_s)
|
|
|
76
76
|
if feature.to_s.empty?
|
|
77
77
|
fail_result("missing_feature", "message" => "Pass --feature or provide current_feature in STATE.md")
|
|
78
78
|
else
|
|
79
|
-
meta_path = File.join(root, ".planning", "requirements", feature, "入口分诊.meta.json")
|
|
79
|
+
meta_path = File.join(root, ".devflow/planning", "requirements", feature, "入口分诊.meta.json")
|
|
80
80
|
meta = File.exist?(meta_path) ? JSON.parse(File.read(meta_path)) : { "feature_name" => feature }
|
|
81
81
|
route = options[:route]
|
|
82
82
|
|
|
@@ -101,7 +101,7 @@ result = if !ROUTE_NEXT_SKILL.key?(options[:route].to_s)
|
|
|
101
101
|
{
|
|
102
102
|
"ok" => true,
|
|
103
103
|
"written" => options[:write],
|
|
104
|
-
"path" => ".planning/requirements/#{feature}/入口分诊.meta.json",
|
|
104
|
+
"path" => ".devflow/planning/requirements/#{feature}/入口分诊.meta.json",
|
|
105
105
|
"meta" => meta
|
|
106
106
|
}
|
|
107
107
|
end
|