@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
|
@@ -34,11 +34,11 @@ def _run_light_sync(root: Path, files: list[str], timeout: int) -> tuple[bool, s
|
|
|
34
34
|
"--root",
|
|
35
35
|
str(root),
|
|
36
36
|
"--output",
|
|
37
|
-
".planning/code-index",
|
|
37
|
+
".devflow/planning/code-index",
|
|
38
38
|
"--changed-files",
|
|
39
39
|
*files,
|
|
40
40
|
],
|
|
41
|
-
[sys.executable, str(script), "validate", "--index", ".planning/code-index"],
|
|
41
|
+
[sys.executable, str(script), "validate", "--index", ".devflow/planning/code-index"],
|
|
42
42
|
[
|
|
43
43
|
sys.executable,
|
|
44
44
|
str(script),
|
|
@@ -46,7 +46,7 @@ def _run_light_sync(root: Path, files: list[str], timeout: int) -> tuple[bool, s
|
|
|
46
46
|
"--root",
|
|
47
47
|
str(root),
|
|
48
48
|
"--index",
|
|
49
|
-
".planning/code-index",
|
|
49
|
+
".devflow/planning/code-index",
|
|
50
50
|
],
|
|
51
51
|
]
|
|
52
52
|
output = []
|
|
@@ -11,6 +11,7 @@ import re
|
|
|
11
11
|
import subprocess
|
|
12
12
|
import tempfile
|
|
13
13
|
import time
|
|
14
|
+
from datetime import datetime
|
|
14
15
|
from contextlib import contextmanager
|
|
15
16
|
from pathlib import Path
|
|
16
17
|
from typing import Any, Iterator
|
|
@@ -26,16 +27,16 @@ DEFAULT_POLICY: dict[str, Any] = {
|
|
|
26
27
|
"mode": "strict",
|
|
27
28
|
"protected_roots": [],
|
|
28
29
|
"required_evidence": [
|
|
29
|
-
".planning/rules/INDEX.md",
|
|
30
|
-
".context/spec/index.md",
|
|
31
|
-
".planning/navigation/INDEX.md",
|
|
30
|
+
".devflow/planning/rules/INDEX.md",
|
|
31
|
+
".devflow/context/spec/index.md",
|
|
32
|
+
".devflow/planning/navigation/INDEX.md",
|
|
32
33
|
],
|
|
33
|
-
"optional_evidence": [".planning/code-index/INDEX.md"],
|
|
34
|
+
"optional_evidence": [".devflow/planning/code-index/INDEX.md"],
|
|
34
35
|
"allowed_before_gate": [
|
|
35
36
|
"AGENTS.md",
|
|
36
37
|
"README.md",
|
|
37
|
-
".planning/**",
|
|
38
|
-
".context/**",
|
|
38
|
+
".devflow/planning/**",
|
|
39
|
+
".devflow/context/**",
|
|
39
40
|
".agent-gates/**",
|
|
40
41
|
".omp/**",
|
|
41
42
|
".skills/**",
|
|
@@ -46,6 +47,8 @@ DEFAULT_POLICY: dict[str, Any] = {
|
|
|
46
47
|
"light_timeout_seconds": 120,
|
|
47
48
|
"full_file_threshold": 30,
|
|
48
49
|
"ignore": [
|
|
50
|
+
".devflow/planning/**",
|
|
51
|
+
".devflow/context/**",
|
|
49
52
|
".planning/**",
|
|
50
53
|
".context/**",
|
|
51
54
|
".agent-gates/**",
|
|
@@ -122,18 +125,69 @@ def cli_dir_name() -> str:
|
|
|
122
125
|
return ".omp"
|
|
123
126
|
|
|
124
127
|
|
|
128
|
+
def assert_project_layout_ready(root: Path) -> None:
|
|
129
|
+
legacy_planning = root / ".planning"
|
|
130
|
+
legacy_context = root / ".context"
|
|
131
|
+
planning_markers = ("STATE.md", "PROJECT.md", ".devflow.lock", "navigation/INDEX.md", "code-index/INDEX.md", "workflows", "contracts", "evidence", "review-runs", "requirements", "features", "handoffs", "artifacts", "phase-ownership.yaml")
|
|
132
|
+
context_markers = ("spec/index.md", "index.md", "project/index.md", "knowledge/index.md")
|
|
133
|
+
legacy_markers = [legacy_planning / item for item in planning_markers] + [legacy_context / item for item in context_markers]
|
|
134
|
+
if not any(item.exists() for item in legacy_markers):
|
|
135
|
+
return
|
|
136
|
+
try:
|
|
137
|
+
manifest = json.loads((root / ".devflow/project.json").read_text(encoding="utf-8"))
|
|
138
|
+
created_at = str(manifest.get("createdAt", "")).replace("Z", "+00:00")
|
|
139
|
+
datetime.fromisoformat(created_at)
|
|
140
|
+
valid_manifest = (
|
|
141
|
+
manifest.get("schemaVersion") == 1
|
|
142
|
+
and re.fullmatch(r"[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}", str(manifest.get("projectId", "")), re.I)
|
|
143
|
+
and bool(str(manifest.get("name", "")).strip())
|
|
144
|
+
and manifest.get("layoutVersion") in (None, 1, 2)
|
|
145
|
+
)
|
|
146
|
+
except (OSError, ValueError, TypeError, json.JSONDecodeError):
|
|
147
|
+
valid_manifest = False
|
|
148
|
+
manifest = {}
|
|
149
|
+
if not valid_manifest:
|
|
150
|
+
raise RuntimeError("DEVFLOW_LEGACY_LAYOUT_CONFIRMATION_REQUIRED: valid project manifest required")
|
|
151
|
+
try:
|
|
152
|
+
marker = json.loads((root / ".devflow/layout-migration.json").read_text(encoding="utf-8"))
|
|
153
|
+
migration_complete = marker.get("schemaVersion") == 1 and marker.get("status") == "complete" and isinstance(marker.get("migrated"), list)
|
|
154
|
+
except (OSError, TypeError, json.JSONDecodeError):
|
|
155
|
+
migration_complete = False
|
|
156
|
+
for relative in ("STATE.md", "workflows", "contracts", "evidence", "review-runs", "requirements", "features", "handoffs", "artifacts", "phase-ownership.yaml"):
|
|
157
|
+
if (legacy_planning / relative).exists() and not migration_complete:
|
|
158
|
+
raise RuntimeError(f"DEVFLOW_ACTIVE_LEGACY_LAYOUT: .planning/{relative} requires dedicated control-plane migration")
|
|
159
|
+
canonical_exists = (root / ".devflow/planning").exists() or (root / ".devflow/context").exists()
|
|
160
|
+
if manifest.get("layoutVersion") == 2 and not migration_complete:
|
|
161
|
+
raise RuntimeError("DEVFLOW_LEGACY_REINTRODUCTION: v2 project cannot import legacy layout")
|
|
162
|
+
if manifest.get("layoutVersion") == 2 and migration_complete:
|
|
163
|
+
planning_legacy = any((legacy_planning / item).exists() for item in planning_markers)
|
|
164
|
+
context_legacy = any((legacy_context / item).exists() for item in context_markers)
|
|
165
|
+
if (planning_legacy and not (root / ".devflow/planning").exists()) or (context_legacy and not (root / ".devflow/context").exists()):
|
|
166
|
+
raise RuntimeError("DEVFLOW_LEGACY_REINTRODUCTION: v2 project will not backfill a missing canonical directory")
|
|
167
|
+
if canonical_exists and not migration_complete:
|
|
168
|
+
raise RuntimeError("DEVFLOW_LAYOUT_CONFLICT: canonical and legacy layouts coexist without migration marker")
|
|
169
|
+
if not canonical_exists:
|
|
170
|
+
raise RuntimeError("DEVFLOW_LAYOUT_MIGRATION_REQUIRED: run project initialization")
|
|
171
|
+
|
|
172
|
+
|
|
125
173
|
def project_root(event: dict[str, Any] | None = None) -> Path:
|
|
126
174
|
event = event or {}
|
|
127
175
|
explicit = os.environ.get("OMP_PROJECT_DIR")
|
|
128
176
|
candidate = Path(explicit or event.get("cwd") or os.getcwd()).expanduser().resolve()
|
|
129
177
|
if candidate.is_file():
|
|
130
178
|
candidate = candidate.parent
|
|
179
|
+
# The project manifest is the authoritative root marker. Generated
|
|
180
|
+
# directories are deliberately ignored because a nested business module
|
|
181
|
+
# may legitimately use the same names.
|
|
131
182
|
for current in (candidate, *candidate.parents):
|
|
132
|
-
if
|
|
133
|
-
(current
|
|
134
|
-
for marker in (".omp", ".agent-gates", ".planning", ".skills")
|
|
135
|
-
):
|
|
183
|
+
if (current / ".devflow" / "project.json").is_file():
|
|
184
|
+
assert_project_layout_ready(current)
|
|
136
185
|
return current
|
|
186
|
+
for current in (candidate, *candidate.parents):
|
|
187
|
+
if (current / ".git").exists():
|
|
188
|
+
assert_project_layout_ready(current)
|
|
189
|
+
return current
|
|
190
|
+
assert_project_layout_ready(candidate)
|
|
137
191
|
return candidate
|
|
138
192
|
|
|
139
193
|
|
|
@@ -274,7 +328,7 @@ def path_matches(path: str, patterns: list[str]) -> bool:
|
|
|
274
328
|
|
|
275
329
|
|
|
276
330
|
def _navigation_codebase_roots(root: Path) -> list[str]:
|
|
277
|
-
path = root / ".planning/navigation/INDEX.md"
|
|
331
|
+
path = root / ".devflow/planning/navigation/INDEX.md"
|
|
278
332
|
try:
|
|
279
333
|
text = path.read_text(encoding="utf-8")
|
|
280
334
|
except (FileNotFoundError, PermissionError):
|
|
@@ -388,6 +442,275 @@ def tool_requests_protected_source(
|
|
|
388
442
|
return False, []
|
|
389
443
|
|
|
390
444
|
|
|
445
|
+
# Core control store protection (approval records live in control.db). This is
|
|
446
|
+
# misuse prevention, not a defence against a hostile same-user process. It is
|
|
447
|
+
# always on: neither DEVFLOW_SOFT_GATES, the policy mode nor hook-config can
|
|
448
|
+
# disable it; hook-config may only add extra protected path globs.
|
|
449
|
+
CONTROL_STORE_NAME_RE = re.compile(r"^control\.db(?:$|[-.])", re.IGNORECASE)
|
|
450
|
+
CANONICAL_ACCEPTANCE_RE = re.compile(
|
|
451
|
+
r"(?:^|/)\.devflow/planning/test-runs/[^/]+/acceptance-results(?:\.meta)?\.json$",
|
|
452
|
+
re.IGNORECASE,
|
|
453
|
+
)
|
|
454
|
+
CANONICAL_ACCEPTANCE_COMMAND_RE = re.compile(
|
|
455
|
+
r"\.devflow/planning/test-runs/(?:[^\s/'\"`]+|\$\{?[^\s}/]+\}?)/acceptance-results(?:\.meta)?\.json\b",
|
|
456
|
+
re.IGNORECASE,
|
|
457
|
+
)
|
|
458
|
+
_CONTROL_TABLE = r"[\"'`\[]?(?:main\.)?(?:approval_proposals|approvals|authority_state)\b[\"'`\]]?"
|
|
459
|
+
APPROVAL_SQL_RE = re.compile(
|
|
460
|
+
r"\b(?:insert\s+(?:or\s+\w+\s+)?into|replace\s+into|delete\s+from|drop\s+table(?:\s+if\s+exists)?|alter\s+table)\s+"
|
|
461
|
+
+ _CONTROL_TABLE
|
|
462
|
+
+ r"|\bupdate\s+(?:or\s+\w+\s+)?"
|
|
463
|
+
+ _CONTROL_TABLE
|
|
464
|
+
+ r"\s+set\b",
|
|
465
|
+
re.IGNORECASE,
|
|
466
|
+
)
|
|
467
|
+
|
|
468
|
+
|
|
469
|
+
def devflow_home() -> Path:
|
|
470
|
+
"""DEVFLOW_HOME rule shared with src/paths.ts: unset/empty/whitespace-only -> ~/.devflow-pi,
|
|
471
|
+
otherwise expand a leading ``~`` and make absolute (no symlink resolution, existence not required)."""
|
|
472
|
+
configured = os.environ.get("DEVFLOW_HOME")
|
|
473
|
+
if configured is None or not configured.strip():
|
|
474
|
+
return Path(os.path.abspath(str(Path.home() / ".devflow-pi")))
|
|
475
|
+
if configured == "~" or configured.startswith("~/"):
|
|
476
|
+
configured = str(Path.home()) + configured[1:]
|
|
477
|
+
return Path(os.path.abspath(configured))
|
|
478
|
+
|
|
479
|
+
|
|
480
|
+
def _raw_tool_paths(event: dict[str, Any]) -> list[str]:
|
|
481
|
+
tool_input = event.get("tool_input", {})
|
|
482
|
+
values = list(_walk_path_values(tool_input))
|
|
483
|
+
if isinstance(tool_input, dict):
|
|
484
|
+
for key in ("patch", "input"):
|
|
485
|
+
patch = tool_input.get(key)
|
|
486
|
+
if isinstance(patch, str):
|
|
487
|
+
values.extend(re.findall(r"^\*\*\* (?:Add|Update|Delete|Move) (?:File|to):\s*(.+)$", patch, re.MULTILINE))
|
|
488
|
+
elif isinstance(tool_input, str):
|
|
489
|
+
values.extend(re.findall(r"^\*\*\* (?:Add|Update|Delete|Move) (?:File|to):\s*(.+)$", tool_input, re.MULTILINE))
|
|
490
|
+
return [str(value).strip().strip("'\"") for value in values if str(value).strip()]
|
|
491
|
+
|
|
492
|
+
|
|
493
|
+
def _extra_control_store_globs(root: Path) -> list[str]:
|
|
494
|
+
config = load_hook_config(root).get("gates", {})
|
|
495
|
+
section = config.get("control_store", {}) if isinstance(config, dict) else {}
|
|
496
|
+
extra = section.get("extra_protected_paths", []) if isinstance(section, dict) else []
|
|
497
|
+
return [str(item) for item in extra if isinstance(item, str) and item.strip()] if isinstance(extra, list) else []
|
|
498
|
+
|
|
499
|
+
|
|
500
|
+
def _under(item: Path, base: Path) -> bool:
|
|
501
|
+
try:
|
|
502
|
+
item.relative_to(base)
|
|
503
|
+
return True
|
|
504
|
+
except ValueError:
|
|
505
|
+
return False
|
|
506
|
+
|
|
507
|
+
|
|
508
|
+
def _data_home_project_roots() -> list[Path]:
|
|
509
|
+
"""Every spelling of the Devflow ``projects`` tree (configured home, default home, symlink-resolved)."""
|
|
510
|
+
homes = [devflow_home(), Path(os.path.abspath(str(Path.home() / ".devflow-pi")))]
|
|
511
|
+
roots: list[Path] = []
|
|
512
|
+
for home in homes:
|
|
513
|
+
for base in (home, Path(os.path.realpath(str(home)))):
|
|
514
|
+
root = base / "projects"
|
|
515
|
+
if root not in roots:
|
|
516
|
+
roots.append(root)
|
|
517
|
+
return roots
|
|
518
|
+
|
|
519
|
+
|
|
520
|
+
def is_pure_read_tool(event: dict[str, Any]) -> bool:
|
|
521
|
+
"""True for file-reader tools (Read/Grep/Glob/...) that cannot mutate anything."""
|
|
522
|
+
name = tool_name(event)
|
|
523
|
+
return (
|
|
524
|
+
any(marker in name for marker in READ_TOOL_MARKERS)
|
|
525
|
+
and not is_mutation_tool(event)
|
|
526
|
+
and not is_command_tool(event)
|
|
527
|
+
)
|
|
528
|
+
|
|
529
|
+
|
|
530
|
+
def path_is_control_store(
|
|
531
|
+
raw: str, cwd: Path, extra_globs: list[str] | None = None, allow_acceptance_read: bool = False
|
|
532
|
+
) -> bool:
|
|
533
|
+
"""``allow_acceptance_read`` opens canonical acceptance-results*.json for pure read tools only;
|
|
534
|
+
control.db, the data-home projects tree and extra globs stay denied for every access."""
|
|
535
|
+
candidate = Path(raw).expanduser()
|
|
536
|
+
if not candidate.is_absolute():
|
|
537
|
+
candidate = cwd / candidate
|
|
538
|
+
lexical = Path(os.path.normpath(str(candidate)))
|
|
539
|
+
resolved = Path(os.path.realpath(str(candidate)))
|
|
540
|
+
project_roots = _data_home_project_roots()
|
|
541
|
+
for item in (lexical, resolved):
|
|
542
|
+
if not allow_acceptance_read and CANONICAL_ACCEPTANCE_RE.search(item.as_posix()):
|
|
543
|
+
return True
|
|
544
|
+
if CONTROL_STORE_NAME_RE.match(item.name):
|
|
545
|
+
return True
|
|
546
|
+
if any(_under(item, root) for root in project_roots):
|
|
547
|
+
return True
|
|
548
|
+
if any(fnmatch.fnmatch(item.as_posix(), pattern) for pattern in extra_globs or []):
|
|
549
|
+
return True
|
|
550
|
+
return False
|
|
551
|
+
|
|
552
|
+
|
|
553
|
+
# Programs that can open a SQLite file (or run arbitrary code that can) from their arguments.
|
|
554
|
+
DB_CAPABLE_PROGRAM_RE = re.compile(
|
|
555
|
+
r"^(?:sqlite3?|python[\d.]*|pypy[\d.]*|bun|bunx|node|deno|ruby|perl|php|lua|litecli|duckdb|datasette|sqlite-utils|sqlitebrowser)$",
|
|
556
|
+
re.IGNORECASE,
|
|
557
|
+
)
|
|
558
|
+
# Programs that read/copy/delete their file arguments, so a bare ``control.db`` operand is a real file target.
|
|
559
|
+
FILE_OPERAND_PROGRAMS = {
|
|
560
|
+
"cat", "less", "more", "head", "tail", "strings", "xxd", "od", "hexdump", "file", "stat", "cp", "mv", "rm",
|
|
561
|
+
"tee", "ln", "dd", "install", "touch", "truncate", "rsync", "scp", "sha256sum", "shasum", "md5sum", "md5",
|
|
562
|
+
"cksum", "base64", "open", "tar", "zip", "gzip", "gunzip", "bzip2", "xz", "unlink", "shred", "chmod", "chown",
|
|
563
|
+
}
|
|
564
|
+
WRAPPER_PROGRAMS = {"sudo", "env", "command", "time", "nohup", "exec", "nice", "xargs", "builtin", "stdbuf", "timeout"}
|
|
565
|
+
SHELL_PROGRAMS = {"sh", "bash", "zsh", "dash", "ksh", "fish"}
|
|
566
|
+
CONTROL_OPERATORS = {";", "&&", "||", "|", "&", "|&", "(", ")", "\n"}
|
|
567
|
+
REDIRECT_OPERATORS = {">", ">>", ">|", "<", "<>", "&>", ">&", "<&", "&>>"}
|
|
568
|
+
ASSIGNMENT_RE = re.compile(r"^[A-Za-z_][A-Za-z0-9_]*=")
|
|
569
|
+
|
|
570
|
+
|
|
571
|
+
def _split_unquoted_newlines(command: str) -> str:
|
|
572
|
+
out: list[str] = []
|
|
573
|
+
quote = ""
|
|
574
|
+
escaped = False
|
|
575
|
+
for ch in command:
|
|
576
|
+
if escaped:
|
|
577
|
+
escaped = False
|
|
578
|
+
elif ch == "\\" and quote != "'":
|
|
579
|
+
escaped = True
|
|
580
|
+
elif quote:
|
|
581
|
+
if ch == quote:
|
|
582
|
+
quote = ""
|
|
583
|
+
elif ch in "'\"":
|
|
584
|
+
quote = ch
|
|
585
|
+
elif ch == "\n":
|
|
586
|
+
out.append(" ; ")
|
|
587
|
+
continue
|
|
588
|
+
out.append(ch)
|
|
589
|
+
return "".join(out)
|
|
590
|
+
|
|
591
|
+
|
|
592
|
+
def _shell_tokens(command: str) -> list[str]:
|
|
593
|
+
import shlex
|
|
594
|
+
|
|
595
|
+
prepared = _split_unquoted_newlines(command)
|
|
596
|
+
try:
|
|
597
|
+
lexer = shlex.shlex(prepared, posix=True, punctuation_chars=True)
|
|
598
|
+
lexer.whitespace_split = True
|
|
599
|
+
lexer.commenters = ""
|
|
600
|
+
return list(lexer)
|
|
601
|
+
except ValueError:
|
|
602
|
+
return [item.strip("'\"") for item in prepared.split()]
|
|
603
|
+
|
|
604
|
+
|
|
605
|
+
def _expand_shell_path(token: str) -> str:
|
|
606
|
+
home = devflow_home().as_posix()
|
|
607
|
+
user_home = str(Path.home())
|
|
608
|
+
for name, value in (("DEVFLOW_HOME", home), ("HOME", user_home)):
|
|
609
|
+
token = re.sub(r"\$\{" + name + r"(?::-[^}]*)?\}|\$" + name + r"\b", lambda _m, v=value: v, token)
|
|
610
|
+
if token == "~" or token.startswith("~/"):
|
|
611
|
+
token = user_home + token[1:]
|
|
612
|
+
return token
|
|
613
|
+
|
|
614
|
+
|
|
615
|
+
def _token_is_control_target(token: str, cwd: Path, *, bare_name_is_target: bool) -> bool:
|
|
616
|
+
if not token or any(ch.isspace() for ch in token):
|
|
617
|
+
return False
|
|
618
|
+
if token.startswith("-") and "=" in token:
|
|
619
|
+
token = token.split("=", 1)[1]
|
|
620
|
+
elif token.startswith("-"):
|
|
621
|
+
return False
|
|
622
|
+
expanded = _expand_shell_path(token).replace("\\", "/")
|
|
623
|
+
candidate = Path(expanded)
|
|
624
|
+
if not candidate.is_absolute():
|
|
625
|
+
candidate = cwd / candidate
|
|
626
|
+
lexical = Path(os.path.normpath(str(candidate)))
|
|
627
|
+
resolved = Path(os.path.realpath(str(candidate)))
|
|
628
|
+
project_roots = _data_home_project_roots()
|
|
629
|
+
for item in (lexical, resolved):
|
|
630
|
+
if any(_under(item, root) for root in project_roots):
|
|
631
|
+
return True
|
|
632
|
+
if ".devflow-pi/projects" in expanded:
|
|
633
|
+
return True
|
|
634
|
+
for item in (lexical, resolved):
|
|
635
|
+
if not CONTROL_STORE_NAME_RE.match(item.name):
|
|
636
|
+
continue
|
|
637
|
+
# ``rg control.db src/`` names a pattern, not a file: a bare name only counts when it is
|
|
638
|
+
# a real file, is redirected/handed to a file-operating program, or carries a directory part.
|
|
639
|
+
if "/" in expanded or bare_name_is_target or item.exists() or resolved.exists():
|
|
640
|
+
return True
|
|
641
|
+
return False
|
|
642
|
+
|
|
643
|
+
|
|
644
|
+
def _segments(tokens: list[str]) -> list[list[str]]:
|
|
645
|
+
segments: list[list[str]] = [[]]
|
|
646
|
+
for token in tokens:
|
|
647
|
+
if token in CONTROL_OPERATORS:
|
|
648
|
+
segments.append([])
|
|
649
|
+
else:
|
|
650
|
+
segments[-1].append(token)
|
|
651
|
+
return [segment for segment in segments if segment]
|
|
652
|
+
|
|
653
|
+
|
|
654
|
+
def _analyze_command(command: str, cwd: Path, depth: int = 0) -> bool:
|
|
655
|
+
tokens = _shell_tokens(command)
|
|
656
|
+
for segment in _segments(tokens):
|
|
657
|
+
index = 0
|
|
658
|
+
while index < len(segment) and (ASSIGNMENT_RE.match(segment[index]) or segment[index] in WRAPPER_PROGRAMS):
|
|
659
|
+
index += 1
|
|
660
|
+
if index >= len(segment):
|
|
661
|
+
continue
|
|
662
|
+
program = os.path.basename(segment[index]).lower()
|
|
663
|
+
operands = segment[index + 1 :]
|
|
664
|
+
db_program = bool(DB_CAPABLE_PROGRAM_RE.match(program))
|
|
665
|
+
if program in SHELL_PROGRAMS and depth < 3:
|
|
666
|
+
for pos, operand in enumerate(operands):
|
|
667
|
+
if operand.startswith("-") and "c" in operand[1:] and pos + 1 < len(operands):
|
|
668
|
+
if _analyze_command(operands[pos + 1], cwd, depth + 1):
|
|
669
|
+
return True
|
|
670
|
+
previous = ""
|
|
671
|
+
for operand in [*segment[:index], *operands]:
|
|
672
|
+
after_redirect = previous in REDIRECT_OPERATORS or bool(re.match(r"^\d*(?:>>?|<)$", previous))
|
|
673
|
+
bare_ok = db_program or after_redirect or program in FILE_OPERAND_PROGRAMS
|
|
674
|
+
if operand not in REDIRECT_OPERATORS:
|
|
675
|
+
if db_program and (
|
|
676
|
+
re.search(r"control\.db", operand, re.IGNORECASE) or ".devflow-pi/projects" in operand
|
|
677
|
+
):
|
|
678
|
+
return True
|
|
679
|
+
if _token_is_control_target(operand, cwd, bare_name_is_target=bare_ok):
|
|
680
|
+
return True
|
|
681
|
+
glued = re.sub(r"^\d*[<>]+", "", operand)
|
|
682
|
+
if glued != operand and _token_is_control_target(glued, cwd, bare_name_is_target=True):
|
|
683
|
+
return True
|
|
684
|
+
previous = operand
|
|
685
|
+
return False
|
|
686
|
+
|
|
687
|
+
|
|
688
|
+
def command_touches_control_store(command: str, cwd: Path | None = None) -> bool:
|
|
689
|
+
"""Deny shell commands that target the real control store or write approval tables.
|
|
690
|
+
|
|
691
|
+
Merely mentioning the text ``control.db`` (rg patterns, commit messages, echo) is allowed;
|
|
692
|
+
this is a mistake-prevention guard, not a sandbox."""
|
|
693
|
+
normalized = command.replace("\\", "/")
|
|
694
|
+
if APPROVAL_SQL_RE.search(normalized) or CANONICAL_ACCEPTANCE_COMMAND_RE.search(normalized):
|
|
695
|
+
return True
|
|
696
|
+
return _analyze_command(command, cwd or Path.cwd())
|
|
697
|
+
|
|
698
|
+
|
|
699
|
+
def tool_touches_control_store(event: dict[str, Any], root: Path) -> tuple[bool, list[str]]:
|
|
700
|
+
"""Deny non-Core access to control.db and the Devflow project data dir; canonical
|
|
701
|
+
acceptance results are additionally readable by pure read tools (never writable)."""
|
|
702
|
+
cwd = Path(str(event.get("cwd") or root)).expanduser()
|
|
703
|
+
extra = _extra_control_store_globs(root)
|
|
704
|
+
allow_read = is_pure_read_tool(event)
|
|
705
|
+
blocked = [raw for raw in _raw_tool_paths(event) if path_is_control_store(raw, cwd, extra, allow_read)]
|
|
706
|
+
if blocked:
|
|
707
|
+
return True, sorted(dict.fromkeys(blocked))
|
|
708
|
+
command = command_text(event)
|
|
709
|
+
if command and command_touches_control_store(command, cwd):
|
|
710
|
+
return True, ["<shell command>"]
|
|
711
|
+
return False, []
|
|
712
|
+
|
|
713
|
+
|
|
391
714
|
def evidence_observed(event: dict[str, Any], root: Path, artifacts: list[str]) -> list[str]:
|
|
392
715
|
name = tool_name(event)
|
|
393
716
|
if not (any(marker in name for marker in READ_TOOL_MARKERS) or is_command_tool(event)):
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
|
-
"""PreToolUse hook: block protected source access until indexes were observed."""
|
|
2
|
+
"""PreToolUse hook: deny control-store access and block protected source access until indexes were observed."""
|
|
3
3
|
|
|
4
4
|
from __future__ import annotations
|
|
5
5
|
|
|
@@ -16,12 +16,39 @@ from hook_common import (
|
|
|
16
16
|
record_prechange_fingerprints,
|
|
17
17
|
required_evidence,
|
|
18
18
|
tool_requests_protected_source,
|
|
19
|
+
tool_touches_control_store,
|
|
19
20
|
)
|
|
20
21
|
|
|
21
22
|
|
|
23
|
+
def deny(reason: str) -> int:
|
|
24
|
+
print(
|
|
25
|
+
json.dumps(
|
|
26
|
+
{
|
|
27
|
+
"hookSpecificOutput": {
|
|
28
|
+
"hookEventName": "PreToolUse",
|
|
29
|
+
"permissionDecision": "deny",
|
|
30
|
+
"permissionDecisionReason": reason,
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
ensure_ascii=False,
|
|
34
|
+
)
|
|
35
|
+
)
|
|
36
|
+
return 0
|
|
37
|
+
|
|
38
|
+
|
|
22
39
|
def main() -> int:
|
|
23
40
|
event = read_event()
|
|
24
41
|
root = project_root(event)
|
|
42
|
+
# Hard protection, evaluated before any soft/strict policy handling.
|
|
43
|
+
control_blocked, control_paths = tool_touches_control_store(event, root)
|
|
44
|
+
if control_blocked:
|
|
45
|
+
return deny(
|
|
46
|
+
"CONTROL_STORE_PROTECTED: Devflow control.db, the Devflow data-home projects tree and writes to canonical "
|
|
47
|
+
"acceptance results are reserved for Core runtime tools; this misuse-prevention hook denies ordinary agent file and "
|
|
48
|
+
"shell access to them regardless of DEVFLOW_SOFT_GATES, but is not a same-user process sandbox. "
|
|
49
|
+
"Canonical acceptance-results*.json may be read with the Read/Grep file tools. "
|
|
50
|
+
f"Use devflow_approval(action=\"propose\"|\"list\") for approvals. Blocked target: {', '.join(control_paths)}."
|
|
51
|
+
)
|
|
25
52
|
policy = load_policy(root)
|
|
26
53
|
session_id = ensure_session(root, event)
|
|
27
54
|
required = required_evidence(root, policy)
|
|
@@ -34,24 +61,11 @@ def main() -> int:
|
|
|
34
61
|
missing = [path for path in required if path not in observed]
|
|
35
62
|
strict = str(policy.get("mode", "strict")).lower() == "strict"
|
|
36
63
|
if strict and required and missing and blocked:
|
|
37
|
-
|
|
64
|
+
return deny(
|
|
38
65
|
"INDEX_GATE_BLOCKED: protected source access requires observed index evidence. "
|
|
39
66
|
f"Read these files first, in order: {', '.join(missing)}. "
|
|
40
67
|
f"Blocked target: {', '.join(paths)}. The gate records successful tool reads, not assistant promises."
|
|
41
68
|
)
|
|
42
|
-
print(
|
|
43
|
-
json.dumps(
|
|
44
|
-
{
|
|
45
|
-
"hookSpecificOutput": {
|
|
46
|
-
"hookEventName": "PreToolUse",
|
|
47
|
-
"permissionDecision": "deny",
|
|
48
|
-
"permissionDecisionReason": reason,
|
|
49
|
-
}
|
|
50
|
-
},
|
|
51
|
-
ensure_ascii=False,
|
|
52
|
-
)
|
|
53
|
-
)
|
|
54
|
-
return 0
|
|
55
69
|
|
|
56
70
|
if is_mutation_tool(event):
|
|
57
71
|
record_prechange_fingerprints(root, session_id, direct_tool_paths(event, root))
|
|
@@ -60,4 +74,3 @@ def main() -> int:
|
|
|
60
74
|
|
|
61
75
|
if __name__ == "__main__":
|
|
62
76
|
raise SystemExit(main())
|
|
63
|
-
|
|
@@ -29,15 +29,15 @@ def detect_cli_dir(project_dir: Path) -> str:
|
|
|
29
29
|
def load_config(project_dir: Path, cli_dir: str) -> dict:
|
|
30
30
|
defaults = {
|
|
31
31
|
"sources": {
|
|
32
|
-
"state": ".planning/STATE.md",
|
|
33
|
-
"workflow": ".context/workflow.md",
|
|
32
|
+
"state": ".devflow/planning/STATE.md",
|
|
33
|
+
"workflow": ".devflow/context/workflow.md",
|
|
34
34
|
"indexes": [
|
|
35
|
-
".planning/rules/INDEX.md",
|
|
36
|
-
".context/spec/index.md",
|
|
37
|
-
".planning/navigation/INDEX.md",
|
|
38
|
-
".planning/code-index/INDEX.md",
|
|
35
|
+
".devflow/planning/rules/INDEX.md",
|
|
36
|
+
".devflow/context/spec/index.md",
|
|
37
|
+
".devflow/planning/navigation/INDEX.md",
|
|
38
|
+
".devflow/planning/code-index/INDEX.md",
|
|
39
39
|
],
|
|
40
|
-
"lessons": ".context/lessons/README.md",
|
|
40
|
+
"lessons": ".devflow/context/lessons/README.md",
|
|
41
41
|
"commands": f"{cli_dir}/commands/start.md",
|
|
42
42
|
}
|
|
43
43
|
}
|
|
@@ -196,7 +196,7 @@ def main():
|
|
|
196
196
|
|
|
197
197
|
# 项目身份
|
|
198
198
|
project_name = project_dir.name
|
|
199
|
-
project_md = read_file(project_dir / ".planning" / "PROJECT.md")
|
|
199
|
+
project_md = read_file(project_dir / ".devflow/planning" / "PROJECT.md")
|
|
200
200
|
for line in project_md.split("\n"):
|
|
201
201
|
if line.startswith("- **Name**:"):
|
|
202
202
|
project_name = line.split(":")[-1].strip()
|
|
@@ -205,13 +205,13 @@ def main():
|
|
|
205
205
|
output.write(
|
|
206
206
|
"<session-context>\n"
|
|
207
207
|
f"你正在 {project_name} 项目中进行研发工作。\n"
|
|
208
|
-
"该项目使用 .planning/ 跟踪研发流水线进度,状态写入和上下文同步由 OMP extension 强制执行。\n"
|
|
208
|
+
"该项目使用 .devflow/planning/ 跟踪研发流水线进度,状态写入和上下文同步由 OMP extension 强制执行。\n"
|
|
209
209
|
"索引只用于加速定位;发现索引缺失或过期时,直接回退到 LSP、搜索和源码,并报告降级状态。\n"
|
|
210
210
|
"</session-context>\n\n"
|
|
211
211
|
)
|
|
212
212
|
|
|
213
213
|
# 跨 clear 意图
|
|
214
|
-
intent_path = project_dir / ".planning" / ".next-intent"
|
|
214
|
+
intent_path = project_dir / ".devflow/planning" / ".next-intent"
|
|
215
215
|
intent = {}
|
|
216
216
|
if intent_path.exists():
|
|
217
217
|
try:
|
|
@@ -229,7 +229,7 @@ def main():
|
|
|
229
229
|
output.write("\n</intent>\n\n")
|
|
230
230
|
|
|
231
231
|
# Pipeline 状态
|
|
232
|
-
state_path = sources.get("state", ".planning/STATE.md")
|
|
232
|
+
state_path = sources.get("state", ".devflow/planning/STATE.md")
|
|
233
233
|
state_text = load_state_section(project_dir, state_path)
|
|
234
234
|
if state_text:
|
|
235
235
|
output.write("<pipeline-state>\n")
|
|
@@ -237,7 +237,7 @@ def main():
|
|
|
237
237
|
output.write("\n</pipeline-state>\n\n")
|
|
238
238
|
|
|
239
239
|
# 研发流程
|
|
240
|
-
workflow_path = sources.get("workflow", ".context/workflow.md")
|
|
240
|
+
workflow_path = sources.get("workflow", ".devflow/context/workflow.md")
|
|
241
241
|
workflow_text = read_file(project_dir / workflow_path)
|
|
242
242
|
if workflow_text:
|
|
243
243
|
output.write("<workflow>\n")
|
|
@@ -254,7 +254,7 @@ def main():
|
|
|
254
254
|
output.write("</index-entrypoints>\n\n")
|
|
255
255
|
|
|
256
256
|
# 经验教训
|
|
257
|
-
lessons_path = sources.get("lessons", ".context/lessons/README.md")
|
|
257
|
+
lessons_path = sources.get("lessons", ".devflow/context/lessons/README.md")
|
|
258
258
|
lessons_text = read_file(project_dir / lessons_path)
|
|
259
259
|
if lessons_text and lessons_text.strip():
|
|
260
260
|
output.write("<lessons>\n")
|
|
@@ -7,8 +7,8 @@ description: Generate or revise a low-fidelity wireframe proposal from controlle
|
|
|
7
7
|
|
|
8
8
|
Read the controlled requirement baseline and the wireframe schema/registry. Produce exactly two candidate files:
|
|
9
9
|
|
|
10
|
-
- .planning/features/{feature}/proposal.yaml
|
|
11
|
-
- .planning/features/{feature}/questions.yaml
|
|
10
|
+
- .devflow/planning/features/{feature}/proposal.yaml
|
|
11
|
+
- .devflow/planning/features/{feature}/questions.yaml
|
|
12
12
|
|
|
13
13
|
Use only registered element types and screen-level requirement_refs. Keep IDs stable during revision. Do not add API fields, coordinates, CSS, nested children, or approval fields. Emit valid YAML only and never claim that the proposal is validated or approved. The validator and Core decide legality, fingerprints, and approval.
|
|
14
14
|
|
|
@@ -11,10 +11,10 @@ Run the bundled validator through Core's `devflow_skill_script` tool:
|
|
|
11
11
|
devflow_skill_script(
|
|
12
12
|
script="wireframe-validate",
|
|
13
13
|
args=[
|
|
14
|
-
"--proposal", ".planning/features/<feature>/proposal.yaml",
|
|
15
|
-
"--traceability", ".planning/requirements/<feature>/traceability.json",
|
|
16
|
-
"--questions", ".planning/features/<feature>/questions.yaml",
|
|
17
|
-
"--canonical-out", ".planning/features/<feature>/canonical.json"
|
|
14
|
+
"--proposal", ".devflow/planning/features/<feature>/proposal.yaml",
|
|
15
|
+
"--traceability", ".devflow/planning/requirements/<feature>/traceability.json",
|
|
16
|
+
"--questions", ".devflow/planning/features/<feature>/questions.yaml",
|
|
17
|
+
"--canonical-out", ".devflow/planning/features/<feature>/canonical.json"
|
|
18
18
|
]
|
|
19
19
|
)
|
|
20
20
|
```
|