@guanlin4924/devflow-pi 0.1.92 → 0.1.94
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -6
- package/package.json +1 -1
- package/plugins/devflow-core/extensions/devflow-core.ts +87 -33
- package/plugins/devflow-core/runtime/hooks/context_sync_gate.py +3 -3
- package/plugins/devflow-core/runtime/hooks/hook_common.py +65 -11
- 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 +5 -5
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/advance_state.rb +9 -9
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/api_test_matrix.py +2 -2
- 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/execution_contract.rb +6 -6
- 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/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/tdd_evidence.py +3 -3
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/test_command_policy.py +2 -2
- 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 +6 -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 +205 -205
- package/plugins/devflow-core/skills/workflow-pipeline/SKILL.md +3 -3
- package/plugins/devflow-core/skills/workflow-pipeline/references/pipeline-flow.md +10 -10
- 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 +22 -17
- 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 +1 -1
- package/plugins/devflow-intel/agents/project-scout.md +3 -1
- package/plugins/devflow-intel/extensions/devflow-intel.ts +20 -19
- package/plugins/devflow-intel/skills/code-index-query/SKILL.md +8 -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 +8 -8
- 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/skills/code-review/SKILL.md +13 -13
- package/plugins/devflow-quality/skills/code-review/references/spec-checklist.md +1 -1
- package/plugins/devflow-quality/skills/workflow-acceptance-test-design/SKILL.md +8 -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 +23 -23
- package/plugins/devflow-quality/skills/workflow-generate-mainflow-cases/references/codebase-discovery.md +9 -9
- package/plugins/devflow-quality/skills/workflow-generate-mainflow-cases/references/project-dsl-contract.md +1 -1
- package/plugins/devflow-quality/skills/workflow-generate-mainflow-cases/scripts/compile_dsl.py +2 -2
- package/plugins/devflow-quality/skills/workflow-generate-mainflow-cases/scripts/discover_codebases.py +2 -2
- package/plugins/devflow-quality/skills/workflow-release-closeout/SKILL.md +15 -15
- package/plugins/devflow-quality/skills/workflow-run-acceptance-tests/SKILL.md +5 -5
- 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/cli.ts +15 -0
- package/src/constants.ts +1 -1
- package/src/initialization-store.ts +3 -2
- package/src/project-context.ts +36 -14
- package/src/project-documents.ts +61 -61
- package/src/project-initializer.ts +23 -9
- 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 +7 -7
- package/templates/omp/index-policy.json +8 -8
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: workflow-orchestrator
|
|
3
|
-
description: Use when the user asks to continue, resume, advance, inspect, or route a .planning-based workflow; when the OMP development agent must decide the next workflow skill from project state; or when a checkpoint must be handled before proceeding.
|
|
3
|
+
description: Use when the user asks to continue, resume, advance, inspect, or route a .devflow/planning-based workflow; when the OMP development agent must decide the next workflow skill from project state; or when a checkpoint must be handled before proceeding.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Workflow Orchestrator
|
|
7
7
|
|
|
8
8
|
## Overview
|
|
9
9
|
|
|
10
|
-
Control-plane entrypoint for project workflows. Reads `.planning/STATE.md`, `.planning/workflows/*.yaml`, and the artifact registry, decides the next action, and preserves checkpoint gates. Pipeline delegates here after parameter parsing and breakpoint detection.
|
|
10
|
+
Control-plane entrypoint for project workflows. Reads `.devflow/planning/STATE.md`, `.devflow/planning/workflows/*.yaml`, and the artifact registry, decides the next action, and preserves checkpoint gates. Pipeline delegates here after parameter parsing and breakpoint detection.
|
|
11
11
|
|
|
12
12
|
This skill is the **single source of truth for all execution-time rules**: gate rules, CP protocol, failure branches, parallel windows, state writeback, lessons injection, and requirement writeback. Pipeline only handles entry (args + breakpoint).
|
|
13
13
|
|
|
@@ -51,7 +51,7 @@ When `blocked` includes a `recovery` command, run or propose that command before
|
|
|
51
51
|
|
|
52
52
|
`inspect_state.rb` runs `validate_state.rb` before dispatching normal actions. If validation fails, stop at `action: blocked` and fix the reported state/artifact inconsistency before continuing. Do not treat `status: completed` as authoritative unless `validate_state.rb --json` returns `ok: true`.
|
|
53
53
|
|
|
54
|
-
When `run_project_context` is returned, do not initialize workflow state manually first. Execute `workflow-project-context` with the user's provided codebase locations and project-init arguments, verify it writes `.planning/PROJECT.md`, `.planning/navigation/INDEX.md`, `.context/spec/index.md`, and `.planning/STATE.md`, then run `inspect_state.rb --json` again and continue from the returned action.
|
|
54
|
+
When `run_project_context` is returned, do not initialize workflow state manually first. Execute `workflow-project-context` with the user's provided codebase locations and project-init arguments, verify it writes `.devflow/planning/PROJECT.md`, `.devflow/planning/navigation/INDEX.md`, `.devflow/context/spec/index.md`, and `.devflow/planning/STATE.md`, then run `inspect_state.rb --json` again and continue from the returned action.
|
|
55
55
|
|
|
56
56
|
## Automatic Run Loop
|
|
57
57
|
|
|
@@ -63,7 +63,7 @@ When the invocation contains `<devflow-runtime-directive>`, run the workflow con
|
|
|
63
63
|
4. Stop only when the inspector returns `await_user_confirmation`, `blocked`, or `workflow_complete`; also stop on an explicit user interruption or an unrecoverable tool failure.
|
|
64
64
|
5. At `await_user_confirmation`, present the checkpoint and yield to the user. Resume the same loop only after an explicit confirmation and successful `devflow_transition`.
|
|
65
65
|
|
|
66
|
-
Do not interpret “automatic” as permission to cross a checkpoint, weaken a gate, retry a stale revision without re-inspection, or continue after a blocked action. If context pressure requires a new turn, preserve project truth in `.planning`, finish required context synchronization, and use `/devflow resume` rather than inventing state from the conversation.
|
|
66
|
+
Do not interpret “automatic” as permission to cross a checkpoint, weaken a gate, retry a stale revision without re-inspection, or continue after a blocked action. If context pressure requires a new turn, preserve project truth in `.devflow/planning`, finish required context synchronization, and use `/devflow resume` rather than inventing state from the conversation.
|
|
67
67
|
|
|
68
68
|
## Step Execution Protocol
|
|
69
69
|
|
|
@@ -105,7 +105,7 @@ When the inspector returns `await_user_confirmation`:
|
|
|
105
105
|
5. Check artifact registry content_valid status for the listed outputs.
|
|
106
106
|
6. Use `ask` to present the CP prompt, filling in the `summary_fields` from `.meta.json` data.
|
|
107
107
|
7. If the user confirms, inspect the current revision and call `devflow_transition(action="confirm-checkpoint", expectedRevision=<revision>)`.
|
|
108
|
-
8. If the user asks for fixes or rejects the checkpoint, keep `.planning/STATE.md` at `status: waiting_checkpoint`, inspect the current revision, call `devflow_transition(action="checkpoint-decision", decision="needs_fix", expectedRevision=<revision>)`, and route to the requested remediation.
|
|
108
|
+
8. If the user asks for fixes or rejects the checkpoint, keep `.devflow/planning/STATE.md` at `status: waiting_checkpoint`, inspect the current revision, call `devflow_transition(action="checkpoint-decision", decision="needs_fix", expectedRevision=<revision>)`, and route to the requested remediation.
|
|
109
109
|
|
|
110
110
|
CP skip rules:
|
|
111
111
|
- CP-1, CP-API, CP-2, CP-3, CP-4: **never skip**.
|
|
@@ -137,7 +137,7 @@ If `hard_gate_mode` is `core`, a gate failure requires re-execution. In the curr
|
|
|
137
137
|
|
|
138
138
|
When any later step discovers or introduces a change that alters external behavior, the requirement baseline must be updated first before downstream documents or code are modified.
|
|
139
139
|
|
|
140
|
-
Must writeback to `.planning/requirements/baseline.md` when:
|
|
140
|
+
Must writeback to `.devflow/planning/requirements/baseline.md` when:
|
|
141
141
|
- New or changed user-visible behavior, notifications, failure handling, retry policy, scheduling, permissions, API contracts, or data write rules
|
|
142
142
|
- Missing edge cases, compatibility requirements, historical impacts, or non-functional constraints found during execution
|
|
143
143
|
- User adds/modifies requirements during tech-spec, change-plan, execution, or verification
|
|
@@ -194,7 +194,7 @@ devflow_transition(action="enter-failure-branch", expectedRevision=<revision>)
|
|
|
194
194
|
Always obtain `<revision>` from a fresh `devflow_state(action="inspect")`. A stale
|
|
195
195
|
revision is rejected without changing state, registry, or next-intent files.
|
|
196
196
|
|
|
197
|
-
Checkpoint confirmation also writes the configured `.planning/.next-intent`.
|
|
197
|
+
Checkpoint confirmation also writes the configured `.devflow/planning/.next-intent`.
|
|
198
198
|
|
|
199
199
|
## Control-plane recovery
|
|
200
200
|
|
|
@@ -253,19 +253,19 @@ The `.meta.json` data feeds CP prompts — e.g., CP-1 reads `baseline.meta.json`
|
|
|
253
253
|
|
|
254
254
|
## Initialization Rules
|
|
255
255
|
|
|
256
|
-
This skill must be portable. Do not require manually-created `.planning` control files.
|
|
256
|
+
This skill must be portable. Do not require manually-created `.devflow/planning` control files.
|
|
257
257
|
|
|
258
|
-
If `.planning/STATE.md` is missing and project context files are also missing, route to `workflow-project-context` instead of asking for `init_state.rb`. If `.planning/STATE.md` is missing but project context files already exist, keep the existing `init_state.rb` recovery path.
|
|
258
|
+
If `.devflow/planning/STATE.md` is missing and project context files are also missing, route to `workflow-project-context` instead of asking for `init_state.rb`. If `.devflow/planning/STATE.md` is missing but project context files already exist, keep the existing `init_state.rb` recovery path.
|
|
259
259
|
|
|
260
|
-
If `.planning/STATE.md` contains blockers with `type: PENDING_TEMPLATE`, stop normal dispatch and report the missing depth spec template. The blocker must name the codebase, topic, matched path, missing template path, and impact.
|
|
260
|
+
If `.devflow/planning/STATE.md` contains blockers with `type: PENDING_TEMPLATE`, stop normal dispatch and report the missing depth spec template. The blocker must name the codebase, topic, matched path, missing template path, and impact.
|
|
261
261
|
|
|
262
262
|
Use these generators:
|
|
263
263
|
|
|
264
264
|
| Script | Generates |
|
|
265
265
|
|--------|-----------|
|
|
266
|
-
| `init_workflow.rb` | `.planning/workflows/*.yaml` and workflow README from bundled templates. |
|
|
267
|
-
| `init_state.rb` | `.planning/STATE.md` YAML front matter. |
|
|
268
|
-
| `sync_artifacts.rb` | `.planning/artifacts/index.yaml` from active workflow outputs. |
|
|
266
|
+
| `init_workflow.rb` | `.devflow/planning/workflows/*.yaml` and workflow README from bundled templates. |
|
|
267
|
+
| `init_state.rb` | `.devflow/planning/STATE.md` YAML front matter. |
|
|
268
|
+
| `sync_artifacts.rb` | `.devflow/planning/artifacts/index.yaml` from active workflow outputs. |
|
|
269
269
|
|
|
270
270
|
The generated files may be project-specific instances, but their creation path must remain inside this skill.
|
|
271
271
|
|
|
@@ -273,26 +273,26 @@ The generated files may be project-specific instances, but their creation path m
|
|
|
273
273
|
|
|
274
274
|
- Do not modify existing `workflow-*` skill behavior.
|
|
275
275
|
- Auto-execute only the parallel window returned by the inspector while the runtime loop is active. Use task agents when isolation is safe; otherwise use `serial_fallback_order`.
|
|
276
|
-
- Do not infer a missing workflow. If `.planning/STATE.md` has no machine-readable front matter, ask to initialize workflow state.
|
|
276
|
+
- Do not infer a missing workflow. If `.devflow/planning/STATE.md` has no machine-readable front matter, ask to initialize workflow state.
|
|
277
277
|
- Do not skip CP-1, CP-3, or CP-4. CP-2 can only be skipped if the active workflow config explicitly allows it.
|
|
278
|
-
- Do not treat `.planning/pipeline-state.md` as the primary state source when YAML front matter exists in `.planning/STATE.md`.
|
|
278
|
+
- Do not treat `.devflow/planning/pipeline-state.md` as the primary state source when YAML front matter exists in `.devflow/planning/STATE.md`.
|
|
279
279
|
- Do not advance a step if its `meta_output` `.meta.json` is missing or incomplete.
|
|
280
280
|
|
|
281
281
|
## Files
|
|
282
282
|
|
|
283
283
|
| File | Purpose |
|
|
284
284
|
|------|---------|
|
|
285
|
-
| `.planning/STATE.md` | Primary runtime state, YAML front matter + auto-generated Markdown body. |
|
|
286
|
-
| `.planning/workflows/<current_flow>.yaml` | Active workflow config: step topology, CP definitions, meta_output contracts. |
|
|
285
|
+
| `.devflow/planning/STATE.md` | Primary runtime state, YAML front matter + auto-generated Markdown body. |
|
|
286
|
+
| `.devflow/planning/workflows/<current_flow>.yaml` | Active workflow config: step topology, CP definitions, meta_output contracts. |
|
|
287
287
|
| `failure_branch.workflow_config` | Optional remediation workflow returned by the inspector. |
|
|
288
288
|
| active workflow `artifact_registry.source` | Artifact status registry with content validation. |
|
|
289
289
|
| `scripts/inspect_state.rb` | Deterministic state and next-action inspector. |
|
|
290
290
|
| `scripts/init_workflow.rb` | Creates required workflow YAML files from bundled templates. |
|
|
291
|
-
| `scripts/init_state.rb` | Creates or repairs `.planning/STATE.md` front matter. |
|
|
291
|
+
| `scripts/init_state.rb` | Creates or repairs `.devflow/planning/STATE.md` front matter. |
|
|
292
292
|
| `scripts/sync_artifacts.rb` | Generates artifact registry with content validation. |
|
|
293
293
|
| `scripts/validate_state.rb` | Verifies STATE.md, workflow steps, dependencies, outputs, meta outputs, and artifact statuses agree before dispatch or writeback. |
|
|
294
294
|
| `scripts/advance_state.rb` | State writeback + Markdown body auto-generation. |
|
|
295
295
|
| `scripts/parallel_recover.rb` | Audited, CAS-guarded recovery and join for legacy lost parallel lifecycle events. |
|
|
296
|
-
| `scripts/update_triage_route.rb` | Deterministically updates `.planning/requirements/{feature}/入口分诊.meta.json` route/status after clarify or wayfinder. |
|
|
296
|
+
| `scripts/update_triage_route.rb` | Deterministically updates `.devflow/planning/requirements/{feature}/入口分诊.meta.json` route/status after clarify or wayfinder. |
|
|
297
297
|
| `scripts/manage_lessons.rb` | Lesson candidate selector and evidence-based template writer. |
|
|
298
298
|
| `templates/` | Portable workflow templates used by `init_workflow.rb`. |
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
interface:
|
|
2
2
|
display_name: "Workflow Orchestrator"
|
|
3
|
-
short_description: "Route .planning workflows, checkpoints, remediation, and parallel windows"
|
|
4
|
-
default_prompt: "Inspect .planning/STATE.md and route the workflow safely"
|
|
3
|
+
short_description: "Route .devflow/planning workflows, checkpoints, remediation, and parallel windows"
|
|
4
|
+
default_prompt: "Inspect .devflow/planning/STATE.md and route the workflow safely"
|
|
@@ -134,9 +134,9 @@ def frozen_cases(suite: dict[str, Any], errors: list[str]) -> dict[str, dict[str
|
|
|
134
134
|
|
|
135
135
|
def paths(root: Path, feature: str) -> tuple[Path, Path, Path]:
|
|
136
136
|
return (
|
|
137
|
-
root / ".planning" / "requirements" / feature / "tests.json",
|
|
138
|
-
root / ".planning" / "features" / feature / "acceptance-test-bindings.json",
|
|
139
|
-
root / ".planning" / "test-runs" / feature / "acceptance-results.json",
|
|
137
|
+
root / ".devflow/planning" / "requirements" / feature / "tests.json",
|
|
138
|
+
root / ".devflow/planning" / "features" / feature / "acceptance-test-bindings.json",
|
|
139
|
+
root / ".devflow/planning" / "test-runs" / feature / "acceptance-results.json",
|
|
140
140
|
)
|
|
141
141
|
|
|
142
142
|
|
|
@@ -339,8 +339,8 @@ def run(root: Path, feature: str, write: bool) -> dict[str, Any]:
|
|
|
339
339
|
cases = frozen_cases(suite, [])
|
|
340
340
|
_, _, result_path = paths(root, feature)
|
|
341
341
|
previous = read_json(result_path, [], "previous acceptance-test results")
|
|
342
|
-
task_bindings_path = root / ".planning" / "features" / feature / "test-bindings.json"
|
|
343
|
-
execution_bindings_path = root / ".planning" / "features" / feature / "acceptance-test-bindings.json"
|
|
342
|
+
task_bindings_path = root / ".devflow/planning" / "features" / feature / "test-bindings.json"
|
|
343
|
+
execution_bindings_path = root / ".devflow/planning" / "features" / feature / "acceptance-test-bindings.json"
|
|
344
344
|
results: list[dict[str, Any]] = []
|
|
345
345
|
for entry in bindings["cases"]:
|
|
346
346
|
tc_id = entry["tc_id"]
|
|
@@ -59,7 +59,7 @@ OptionParser.new do |opts|
|
|
|
59
59
|
end.parse!
|
|
60
60
|
|
|
61
61
|
root = Dir.pwd
|
|
62
|
-
state_path, = DevflowControlIO.resolve_control_path(root, options[:state] || ".planning/STATE.md", :state)
|
|
62
|
+
state_path, = DevflowControlIO.resolve_control_path(root, options[:state] || ".devflow/planning/STATE.md", :state)
|
|
63
63
|
|
|
64
64
|
def front_matter(markdown)
|
|
65
65
|
match = markdown.match(/\A---\n(.*?)\n---\n/m)
|
|
@@ -71,7 +71,7 @@ def load_yaml_file(path)
|
|
|
71
71
|
end
|
|
72
72
|
|
|
73
73
|
def workflow_path_for(root, state)
|
|
74
|
-
state["workflow_config"] || File.join(".planning", "workflows", "#{state.fetch("current_flow")}.yaml")
|
|
74
|
+
state["workflow_config"] || File.join(".devflow/planning", "workflows", "#{state.fetch("current_flow")}.yaml")
|
|
75
75
|
end
|
|
76
76
|
|
|
77
77
|
def load_workflow(root, state)
|
|
@@ -384,7 +384,7 @@ def checkpoint_label(workflow, checkpoint_id)
|
|
|
384
384
|
end
|
|
385
385
|
|
|
386
386
|
def next_intent_path(root, workflow)
|
|
387
|
-
workflow.dig("resume_rules", "continue_keyword", "next_intent_path") || ".planning/.next-intent"
|
|
387
|
+
workflow.dig("resume_rules", "continue_keyword", "next_intent_path") || ".devflow/planning/.next-intent"
|
|
388
388
|
end
|
|
389
389
|
|
|
390
390
|
def write_next_intent(root, workflow)
|
|
@@ -635,16 +635,16 @@ end
|
|
|
635
635
|
|
|
636
636
|
def business_cross_model_check(root, feature)
|
|
637
637
|
script = File.join(__dir__, "business_cross_model_check.py")
|
|
638
|
-
business = ".planning/business-model/#{feature}/canonical.json"
|
|
639
|
-
wireframe = ".planning/features/#{feature}/canonical.json"
|
|
638
|
+
business = ".devflow/planning/business-model/#{feature}/canonical.json"
|
|
639
|
+
wireframe = ".devflow/planning/features/#{feature}/canonical.json"
|
|
640
640
|
unless File.file?(File.join(root, business))
|
|
641
641
|
return { "valid" => false, "errors" => [{ "code" => "BUSINESS_CANONICAL_MISSING", "path" => business }] }
|
|
642
642
|
end
|
|
643
643
|
command = ["python3", script, "--business-canonical", business]
|
|
644
644
|
command += ["--wireframe", wireframe] if File.file?(File.join(root, wireframe))
|
|
645
|
-
claims = ".planning/features/#{feature}/business-claims.yaml"
|
|
645
|
+
claims = ".devflow/planning/features/#{feature}/business-claims.yaml"
|
|
646
646
|
command += ["--claims", claims] if File.file?(File.join(root, claims))
|
|
647
|
-
traceability = ".planning/requirements/#{feature}/traceability.json"
|
|
647
|
+
traceability = ".devflow/planning/requirements/#{feature}/traceability.json"
|
|
648
648
|
command += ["--traceability", traceability] if File.file?(File.join(root, traceability))
|
|
649
649
|
stdout, stderr, status = Open3.capture3(*command, "--json", chdir: root)
|
|
650
650
|
payload = JSON.parse(stdout)
|
|
@@ -675,7 +675,7 @@ rescue JSON::ParserError => error
|
|
|
675
675
|
end
|
|
676
676
|
|
|
677
677
|
def test_suite_freeze_attestation_path(root, feature)
|
|
678
|
-
DevflowControlIO.resolve_control_path(root, ".planning/features/#{feature}/test-suite-freeze.json", :artifact)
|
|
678
|
+
DevflowControlIO.resolve_control_path(root, ".devflow/planning/features/#{feature}/test-suite-freeze.json", :artifact)
|
|
679
679
|
end
|
|
680
680
|
|
|
681
681
|
def frozen_test_suite_pin(freeze_result)
|
|
@@ -1218,7 +1218,7 @@ result =
|
|
|
1218
1218
|
prospective_owner = if changed
|
|
1219
1219
|
{
|
|
1220
1220
|
"phase" => state["current_phase"], "feature" => state["current_feature"],
|
|
1221
|
-
"flow" => state["current_flow"], "state_path" => ".planning/STATE.md",
|
|
1221
|
+
"flow" => state["current_flow"], "state_path" => ".devflow/planning/STATE.md",
|
|
1222
1222
|
"scope" => "global", "status" => "active"
|
|
1223
1223
|
}
|
|
1224
1224
|
end
|
|
@@ -72,8 +72,8 @@ def write_text(path: Path, value: str) -> None:
|
|
|
72
72
|
|
|
73
73
|
|
|
74
74
|
def paths(root: Path, feature: str) -> tuple[Path, Path, Path, Path]:
|
|
75
|
-
requirements = root / ".planning" / "requirements" / feature
|
|
76
|
-
feature_dir = root / ".planning" / "features" / feature
|
|
75
|
+
requirements = root / ".devflow/planning" / "requirements" / feature
|
|
76
|
+
feature_dir = root / ".devflow/planning" / "features" / feature
|
|
77
77
|
return (
|
|
78
78
|
requirements / "governance.json",
|
|
79
79
|
requirements / "api-test-matrix.json",
|
package/plugins/devflow-core/skills/workflow-orchestrator/scripts/architecture_assessment.rb
CHANGED
|
@@ -17,7 +17,7 @@ require_relative "runtime_context_collector"
|
|
|
17
17
|
module ArchitectureAssessment
|
|
18
18
|
SCHEMA_VERSION = 1
|
|
19
19
|
RULE_VERSION = 1
|
|
20
|
-
ROOT_DIR = File.join(".planning", "architecture-assessment")
|
|
20
|
+
ROOT_DIR = File.join(".devflow/planning", "architecture-assessment")
|
|
21
21
|
|
|
22
22
|
UNRESOLVED = {
|
|
23
23
|
DELTA_SET_BINDING_FAILED: "DELTA_SET_BINDING_FAILED",
|
package/plugins/devflow-core/skills/workflow-orchestrator/scripts/architecture_feasibility.rb
CHANGED
|
@@ -27,7 +27,7 @@ module ArchitectureFeasibility
|
|
|
27
27
|
|
|
28
28
|
pointer = JSON.parse(File.read(pointer_path))
|
|
29
29
|
relative = pointer.fetch("path")
|
|
30
|
-
raise ArgumentError, "static runtime-context pointer path is invalid" unless relative.is_a?(String) && relative.start_with?(".context/static-runtime-context/revisions/")
|
|
30
|
+
raise ArgumentError, "static runtime-context pointer path is invalid" unless relative.is_a?(String) && relative.start_with?(".devflow/context/static-runtime-context/revisions/")
|
|
31
31
|
|
|
32
32
|
absolute = File.expand_path(relative, root)
|
|
33
33
|
root_real = File.realpath(root)
|
|
@@ -11,7 +11,7 @@ require "time"
|
|
|
11
11
|
require "yaml"
|
|
12
12
|
require_relative "control_io"
|
|
13
13
|
|
|
14
|
-
options = { root: ".", feature: nil, canonical: nil, changed_source: [], registry: ".planning/artifacts/index.yaml", write: false, json: false }
|
|
14
|
+
options = { root: ".", feature: nil, canonical: nil, changed_source: [], registry: ".devflow/planning/artifacts/index.yaml", write: false, json: false }
|
|
15
15
|
OptionParser.new do |o|
|
|
16
16
|
o.on("--root PATH") { |v| options[:root] = v }
|
|
17
17
|
o.on("--feature NAME") { |v| options[:feature] = v }
|
|
@@ -42,7 +42,7 @@ lock = nil
|
|
|
42
42
|
begin
|
|
43
43
|
raise ArgumentError, "feature is required" if options[:feature].to_s.empty?
|
|
44
44
|
raise ArgumentError, "at least one changed source is required" if options[:changed_source].empty?
|
|
45
|
-
canonical_path = options[:canonical] || ".planning/business-model/#{options[:feature]}/canonical.json"
|
|
45
|
+
canonical_path = options[:canonical] || ".devflow/planning/business-model/#{options[:feature]}/canonical.json"
|
|
46
46
|
canonical_absolute, canonical_relative = DevflowControlIO.resolve_control_path(root, canonical_path, :artifact)
|
|
47
47
|
model = read_json(canonical_absolute)
|
|
48
48
|
changed = options[:changed_source].uniq
|
|
@@ -56,7 +56,7 @@ begin
|
|
|
56
56
|
end
|
|
57
57
|
end
|
|
58
58
|
affected_ids = affected.map { |item| item["id"].to_s }.to_set
|
|
59
|
-
wireframe_relative = ".planning/features/#{options[:feature]}/canonical.json"
|
|
59
|
+
wireframe_relative = ".devflow/planning/features/#{options[:feature]}/canonical.json"
|
|
60
60
|
wireframe_path, = DevflowControlIO.resolve_control_path(root, wireframe_relative, :artifact)
|
|
61
61
|
consumers = []
|
|
62
62
|
if File.file?(wireframe_path)
|
|
@@ -70,7 +70,7 @@ begin
|
|
|
70
70
|
if options[:write]
|
|
71
71
|
lock = DevflowControlIO.acquire_project_lock(root)
|
|
72
72
|
timestamp = Time.now.utc.iso8601
|
|
73
|
-
approval_relative = ".planning/features/#{options[:feature]}/approval.json"
|
|
73
|
+
approval_relative = ".devflow/planning/features/#{options[:feature]}/approval.json"
|
|
74
74
|
approval_path, = DevflowControlIO.resolve_control_path(root, approval_relative, :artifact)
|
|
75
75
|
if !consumers.empty? && File.file?(approval_path)
|
|
76
76
|
approval = read_json(approval_path)
|
|
@@ -93,7 +93,7 @@ begin
|
|
|
93
93
|
DevflowControlIO.atomic_write(registry_path, registry.to_yaml.sub(/\A---\n/, ""))
|
|
94
94
|
report["registry_path"] = registry_relative
|
|
95
95
|
end
|
|
96
|
-
report_path = File.join(root, ".planning", "business-model", options[:feature], "invalidation.json")
|
|
96
|
+
report_path = File.join(root, ".devflow/planning", "business-model", options[:feature], "invalidation.json")
|
|
97
97
|
DevflowControlIO.atomic_write(report_path, JSON.pretty_generate(report) + "\n")
|
|
98
98
|
report["written"] = true
|
|
99
99
|
else
|
|
@@ -43,7 +43,7 @@ module BusinessModelCommit
|
|
|
43
43
|
raise ArgumentError, "invalid feature" unless valid_feature?(feature)
|
|
44
44
|
|
|
45
45
|
root_real = File.realpath(root)
|
|
46
|
-
relative = File.join(".planning", "business-model", feature)
|
|
46
|
+
relative = File.join(".devflow/planning", "business-model", feature)
|
|
47
47
|
absolute = File.expand_path(relative, root_real)
|
|
48
48
|
raise ArgumentError, "business model path escapes project root" unless absolute.start_with?("#{root_real}#{File::SEPARATOR}")
|
|
49
49
|
|
|
@@ -67,7 +67,7 @@ module BusinessModelCommit
|
|
|
67
67
|
raise ArgumentError, "proposal path contains control characters" if value.match?(/[\x00-\x1F\x7F]/)
|
|
68
68
|
|
|
69
69
|
normalized = Pathname.new(value).cleanpath.to_s.tr("\\", "/")
|
|
70
|
-
prefix = File.join(".planning", "business-model", feature, "proposals").tr("\\", "/") + "/"
|
|
70
|
+
prefix = File.join(".devflow/planning", "business-model", feature, "proposals").tr("\\", "/") + "/"
|
|
71
71
|
raise ArgumentError, "proposal path is outside the feature proposal directory" unless normalized.start_with?(prefix)
|
|
72
72
|
absolute = File.expand_path(normalized, root_real)
|
|
73
73
|
raise ArgumentError, "proposal path escapes project root" unless absolute.start_with?("#{root_real}#{File::SEPARATOR}")
|
|
@@ -255,7 +255,7 @@ module BusinessModelCommit
|
|
|
255
255
|
def load_delta(root, feature, raw)
|
|
256
256
|
raise ArgumentError, "candidate delta path is required" if raw.to_s.empty?
|
|
257
257
|
path = File.expand_path(raw, root)
|
|
258
|
-
feature_root = File.expand_path(File.join(".planning", "business-model", feature, "candidates"), root)
|
|
258
|
+
feature_root = File.expand_path(File.join(".devflow/planning", "business-model", feature, "candidates"), root)
|
|
259
259
|
raise ArgumentError, "candidate delta is missing" unless File.file?(path)
|
|
260
260
|
path = File.realpath(path)
|
|
261
261
|
feature_root = File.realpath(feature_root)
|
|
@@ -290,7 +290,7 @@ module BusinessModelCommit
|
|
|
290
290
|
def source_registry_fingerprint(root, feature, aggregate)
|
|
291
291
|
registry_ref = aggregate.dig("merged", "source_registry_ref").to_s
|
|
292
292
|
return "" if registry_ref.empty?
|
|
293
|
-
path = if registry_ref.start_with?(".planning/")
|
|
293
|
+
path = if registry_ref.start_with?(".devflow/planning/")
|
|
294
294
|
File.expand_path(registry_ref, root)
|
|
295
295
|
else
|
|
296
296
|
File.expand_path(registry_ref, feature_dir(root, feature))
|
package/plugins/devflow-core/skills/workflow-orchestrator/scripts/business_model_validate.py
CHANGED
|
@@ -606,7 +606,7 @@ def load_json(path: Path) -> Any:
|
|
|
606
606
|
|
|
607
607
|
|
|
608
608
|
def requirement_nodes(root: Path, feature: str, violations: list[dict[str, Any]]) -> set[str]:
|
|
609
|
-
requirements_root = (root / ".planning" / "requirements").resolve()
|
|
609
|
+
requirements_root = (root / ".devflow/planning" / "requirements").resolve()
|
|
610
610
|
path = (requirements_root / feature / "governance.json").resolve()
|
|
611
611
|
if not path.is_relative_to(requirements_root):
|
|
612
612
|
add_violation(violations, "BUSINESS_REQUIREMENT_GRAPH_INVALID", feature, path=str(path), message="feature escapes requirements directory")
|
package/plugins/devflow-core/skills/workflow-orchestrator/scripts/business_source_resolver.rb
CHANGED
|
@@ -101,7 +101,7 @@ module BusinessSourceResolver
|
|
|
101
101
|
output = command(root, "git", "status", "--porcelain=v1", "--untracked-files=all")
|
|
102
102
|
lines = output.lines.map(&:rstrip).reject do |line|
|
|
103
103
|
path = line.length > 3 ? line[3..].to_s.strip : ""
|
|
104
|
-
path.start_with?(".planning/", ".context/")
|
|
104
|
+
path.start_with?(".devflow/planning/", ".devflow/context/")
|
|
105
105
|
end
|
|
106
106
|
"sha256:#{Digest::SHA256.hexdigest(lines.join("\n"))}"
|
|
107
107
|
end
|
|
@@ -237,7 +237,7 @@ module BusinessSourceResolver
|
|
|
237
237
|
current_signature = worktree_signature(root)
|
|
238
238
|
add(errors, "BUSINESS_WORKTREE_SIGNATURE_MISMATCH", "worktree signature is stale", source_id: id) unless source["worktree_signature"].to_s == current_signature
|
|
239
239
|
|
|
240
|
-
snapshot_path = File.join(root, ".planning", "code-index", "SNAPSHOT.json")
|
|
240
|
+
snapshot_path = File.join(root, ".devflow/planning", "code-index", "SNAPSHOT.json")
|
|
241
241
|
unless File.file?(snapshot_path)
|
|
242
242
|
add(errors, "BUSINESS_CODE_INDEX_STALE", "code index snapshot is missing", source_id: id, path: snapshot_path)
|
|
243
243
|
return
|
|
@@ -258,7 +258,7 @@ module BusinessSourceResolver
|
|
|
258
258
|
end
|
|
259
259
|
return if symbol.empty?
|
|
260
260
|
|
|
261
|
-
symbols_path = File.join(root, ".planning", "code-index", "symbols.jsonl")
|
|
261
|
+
symbols_path = File.join(root, ".devflow/planning", "code-index", "symbols.jsonl")
|
|
262
262
|
unless File.file?(symbols_path)
|
|
263
263
|
add(errors, "BUSINESS_CODE_SYMBOL_NOT_FOUND", "symbols index is missing", source_id: id, path: symbols_path)
|
|
264
264
|
return
|
|
@@ -318,7 +318,7 @@ module BusinessSourceResolver
|
|
|
318
318
|
raise ArgumentError, "invalid feature" unless valid_feature?(feature)
|
|
319
319
|
root = File.realpath(root)
|
|
320
320
|
schema = load_yaml(REGISTRY_SCHEMA)
|
|
321
|
-
raw_registry = registry_path || File.join(".planning", "business-model", feature, "source-registry.yaml")
|
|
321
|
+
raw_registry = registry_path || File.join(".devflow/planning", "business-model", feature, "source-registry.yaml")
|
|
322
322
|
registry_absolute, registry_relative = safe_path(root, raw_registry, "source registry")
|
|
323
323
|
registry = load_yaml(registry_absolute)
|
|
324
324
|
errors = []
|
|
@@ -60,22 +60,22 @@ module CheckerAdapter
|
|
|
60
60
|
when "cross-track-consistency-check"
|
|
61
61
|
["ruby", File.join(scripts, "cross_track_consistency_check.rb"), "--feature", feature, "--json"]
|
|
62
62
|
when "business-cross-model-check"
|
|
63
|
-
business = ".planning/business-model/#{feature}/canonical.json"
|
|
63
|
+
business = ".devflow/planning/business-model/#{feature}/canonical.json"
|
|
64
64
|
return nil unless File.file?(File.join(root, business))
|
|
65
65
|
command = ["python3", File.join(scripts, "business_cross_model_check.py"), "--business-canonical", business]
|
|
66
|
-
wireframe = ".planning/features/#{feature}/canonical.json"
|
|
67
|
-
claims = ".planning/features/#{feature}/business-claims.yaml"
|
|
68
|
-
traceability = ".planning/requirements/#{feature}/traceability.json"
|
|
66
|
+
wireframe = ".devflow/planning/features/#{feature}/canonical.json"
|
|
67
|
+
claims = ".devflow/planning/features/#{feature}/business-claims.yaml"
|
|
68
|
+
traceability = ".devflow/planning/requirements/#{feature}/traceability.json"
|
|
69
69
|
command += ["--wireframe", wireframe] if File.file?(File.join(root, wireframe))
|
|
70
70
|
command += ["--claims", claims] if File.file?(File.join(root, claims))
|
|
71
71
|
command += ["--traceability", traceability] if File.file?(File.join(root, traceability))
|
|
72
72
|
command + ["--json"]
|
|
73
73
|
when "business-claim-reference-check"
|
|
74
|
-
claims = ".planning/features/#{feature}/business-claims.yaml"
|
|
75
|
-
business = ".planning/business-model/#{feature}/canonical.json"
|
|
74
|
+
claims = ".devflow/planning/features/#{feature}/business-claims.yaml"
|
|
75
|
+
business = ".devflow/planning/business-model/#{feature}/canonical.json"
|
|
76
76
|
return nil unless File.file?(File.join(root, claims)) && File.file?(File.join(root, business))
|
|
77
77
|
command = ["python3", File.join(scripts, "business_claim_validate.py"), "--claims", claims, "--business-canonical", business]
|
|
78
|
-
traceability = ".planning/requirements/#{feature}/traceability.json"
|
|
78
|
+
traceability = ".devflow/planning/requirements/#{feature}/traceability.json"
|
|
79
79
|
command += ["--traceability", traceability] if File.file?(File.join(root, traceability))
|
|
80
80
|
command
|
|
81
81
|
end
|
|
@@ -5,6 +5,7 @@ require "fileutils"
|
|
|
5
5
|
require "json"
|
|
6
6
|
require "pathname"
|
|
7
7
|
require "securerandom"
|
|
8
|
+
require "time"
|
|
8
9
|
|
|
9
10
|
# Shared durability primitives for every writer in the Devflow control plane.
|
|
10
11
|
# The project lock serializes state, workflow, registry, and next-intent updates;
|
|
@@ -14,10 +15,52 @@ module DevflowControlIO
|
|
|
14
15
|
|
|
15
16
|
module_function
|
|
16
17
|
|
|
18
|
+
def assert_layout_ready(root)
|
|
19
|
+
root_path = File.realpath(root)
|
|
20
|
+
legacy_planning = File.join(root_path, ".planning")
|
|
21
|
+
legacy_context = File.join(root_path, ".context")
|
|
22
|
+
planning_markers = %w[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]
|
|
23
|
+
context_markers = %w[spec/index.md index.md project/index.md knowledge/index.md]
|
|
24
|
+
legacy_markers = planning_markers.map { |item| File.join(legacy_planning, item) } + context_markers.map { |item| File.join(legacy_context, item) }
|
|
25
|
+
return true unless legacy_markers.any? { |item| File.exist?(item) }
|
|
26
|
+
|
|
27
|
+
manifest = JSON.parse(File.read(File.join(root_path, ".devflow", "project.json")))
|
|
28
|
+
valid_manifest = manifest["schemaVersion"] == 1 &&
|
|
29
|
+
manifest["projectId"].to_s.match?(/\A[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}\z/i) &&
|
|
30
|
+
!manifest["name"].to_s.strip.empty? &&
|
|
31
|
+
!Time.iso8601(manifest["createdAt"].to_s).nil? &&
|
|
32
|
+
[nil, 1, 2].include?(manifest["layoutVersion"])
|
|
33
|
+
raise InvalidControlPath, "DEVFLOW_LEGACY_LAYOUT_CONFIRMATION_REQUIRED: valid project manifest required" unless valid_manifest
|
|
34
|
+
|
|
35
|
+
marker = JSON.parse(File.read(File.join(root_path, ".devflow", "layout-migration.json"))) rescue nil
|
|
36
|
+
migration_complete = marker.is_a?(Hash) && marker["schemaVersion"] == 1 && marker["status"] == "complete" && marker["migrated"].is_a?(Array)
|
|
37
|
+
active = %w[STATE.md workflows contracts evidence review-runs requirements features handoffs artifacts phase-ownership.yaml].find do |item|
|
|
38
|
+
File.exist?(File.join(legacy_planning, item))
|
|
39
|
+
end
|
|
40
|
+
raise InvalidControlPath, "DEVFLOW_ACTIVE_LEGACY_LAYOUT: .planning/#{active} requires dedicated control-plane migration" if active && !migration_complete
|
|
41
|
+
canonical_exists = File.exist?(File.join(root_path, ".devflow", "planning")) || File.exist?(File.join(root_path, ".devflow", "context"))
|
|
42
|
+
if manifest["layoutVersion"] == 2 && !migration_complete
|
|
43
|
+
raise InvalidControlPath, "DEVFLOW_LEGACY_REINTRODUCTION: v2 project cannot import legacy layout"
|
|
44
|
+
end
|
|
45
|
+
if manifest["layoutVersion"] == 2 && migration_complete
|
|
46
|
+
planning_legacy = planning_markers.any? { |item| File.exist?(File.join(legacy_planning, item)) }
|
|
47
|
+
context_legacy = context_markers.any? { |item| File.exist?(File.join(legacy_context, item)) }
|
|
48
|
+
missing_canonical = (planning_legacy && !File.exist?(File.join(root_path, ".devflow", "planning"))) ||
|
|
49
|
+
(context_legacy && !File.exist?(File.join(root_path, ".devflow", "context")))
|
|
50
|
+
raise InvalidControlPath, "DEVFLOW_LEGACY_REINTRODUCTION: v2 project will not backfill a missing canonical directory" if missing_canonical
|
|
51
|
+
end
|
|
52
|
+
raise InvalidControlPath, "DEVFLOW_LAYOUT_CONFLICT: canonical and legacy layouts coexist without migration marker" if canonical_exists && !migration_complete
|
|
53
|
+
raise InvalidControlPath, "DEVFLOW_LAYOUT_MIGRATION_REQUIRED: run project initialization" unless canonical_exists
|
|
54
|
+
true
|
|
55
|
+
rescue Errno::ENOENT, JSON::ParserError, ArgumentError
|
|
56
|
+
raise InvalidControlPath, "DEVFLOW_LEGACY_LAYOUT_CONFIRMATION_REQUIRED: valid project manifest required"
|
|
57
|
+
end
|
|
58
|
+
|
|
17
59
|
# Control-plane files are not general-purpose CLI file arguments. Keeping
|
|
18
60
|
# their location fixed prevents a crafted STATE/workflow/registry reference
|
|
19
61
|
# from turning recovery or synchronization into an out-of-project writer.
|
|
20
62
|
def resolve_control_path(root, raw, kind)
|
|
63
|
+
assert_layout_ready(root)
|
|
21
64
|
root_path = File.realpath(root)
|
|
22
65
|
value = raw.to_s
|
|
23
66
|
raise InvalidControlPath, "#{kind} path is required" if value.empty?
|
|
@@ -27,14 +70,14 @@ module DevflowControlIO
|
|
|
27
70
|
normalized = Pathname.new(value).cleanpath.to_s.tr("\\", "/")
|
|
28
71
|
raise InvalidControlPath, "#{kind} path cannot traverse parent directories" if normalized == ".." || normalized.start_with?("../")
|
|
29
72
|
allowed = case kind
|
|
30
|
-
when :state then normalized == ".planning/STATE.md"
|
|
31
|
-
when :workflow then normalized.match?(%r{\A\.planning/workflows/[A-Za-z0-9][A-Za-z0-9_-]*\.yaml\z})
|
|
32
|
-
when :registry then normalized == ".planning/artifacts/index.yaml"
|
|
33
|
-
when :artifact then normalized.start_with?(".planning/") || normalized.start_with?(".context/")
|
|
73
|
+
when :state then normalized == ".devflow/planning/STATE.md"
|
|
74
|
+
when :workflow then normalized.match?(%r{\A\.devflow/planning/workflows/[A-Za-z0-9][A-Za-z0-9_-]*\.yaml\z})
|
|
75
|
+
when :registry then normalized == ".devflow/planning/artifacts/index.yaml"
|
|
76
|
+
when :artifact then normalized.start_with?(".devflow/planning/") || normalized.start_with?(".devflow/context/")
|
|
34
77
|
# Feature names are user-facing and may be Unicode. `cleanpath`
|
|
35
78
|
# and the parent-traversal check above own containment; this
|
|
36
79
|
# matcher only fixes the handoff namespace and immutable name.
|
|
37
|
-
when :handoff then normalized.match?(%r{\A\.planning/handoffs/[^/]+/ROL-[0-9a-f-]+\.json\z})
|
|
80
|
+
when :handoff then normalized.match?(%r{\A\.devflow/planning/handoffs/[^/]+/ROL-[0-9a-f-]+\.json\z})
|
|
38
81
|
else false
|
|
39
82
|
end
|
|
40
83
|
raise InvalidControlPath, "invalid #{kind} control path" unless allowed
|
|
@@ -58,7 +101,8 @@ module DevflowControlIO
|
|
|
58
101
|
end
|
|
59
102
|
|
|
60
103
|
def acquire_project_lock(root)
|
|
61
|
-
|
|
104
|
+
assert_layout_ready(root)
|
|
105
|
+
planning_dir = File.join(root, ".devflow/planning")
|
|
62
106
|
FileUtils.mkdir_p(planning_dir)
|
|
63
107
|
handle = File.open(File.join(planning_dir, ".devflow.lock"), File::RDWR | File::CREAT, 0o644)
|
|
64
108
|
handle.flock(File::LOCK_EX)
|
|
@@ -122,7 +166,7 @@ module DevflowControlIO
|
|
|
122
166
|
# 独立受控工件登记:与 sync_artifacts 的 workflow-outputs registry 分开,
|
|
123
167
|
# 避免被 workflow 重建覆盖。按 path 去重,last-write-wins。
|
|
124
168
|
def register_control_artifact(root, entry)
|
|
125
|
-
path = File.join(root, ".planning", "artifacts", "control-artifacts.json")
|
|
169
|
+
path = File.join(root, ".devflow/planning", "artifacts", "control-artifacts.json")
|
|
126
170
|
existing = File.exist?(path) ? JSON.parse(File.read(path)) : { "schema_version" => 1, "artifacts" => [] }
|
|
127
171
|
existing["artifacts"] ||= []
|
|
128
172
|
existing["artifacts"].reject! { |item| item["path"] == entry["path"] }
|
package/plugins/devflow-core/skills/workflow-orchestrator/scripts/cross_track_consistency_check.rb
CHANGED
|
@@ -16,7 +16,7 @@ feature = options[:feature].to_s
|
|
|
16
16
|
raise ArgumentError, "feature contains path separators" if feature.include?("/") || feature.include?("\\")
|
|
17
17
|
|
|
18
18
|
root = Dir.pwd
|
|
19
|
-
base = File.join(root, ".planning", "features", feature)
|
|
19
|
+
base = File.join(root, ".devflow/planning", "features", feature)
|
|
20
20
|
files = {
|
|
21
21
|
"api_contract" => File.join(base, "api-contract.md"),
|
|
22
22
|
"api_call_guide" => File.join(base, "api-call-guide.md"),
|
|
@@ -43,7 +43,7 @@ OptionParser.new do |o|
|
|
|
43
43
|
end.parse!
|
|
44
44
|
|
|
45
45
|
def load_state(root)
|
|
46
|
-
document = File.read(File.join(root, ".planning/STATE.md"))
|
|
46
|
+
document = File.read(File.join(root, ".devflow/planning/STATE.md"))
|
|
47
47
|
front = document.match(/\A---\n(.*?)\n---/m)&.[](1)
|
|
48
48
|
raise "STATE.md has no YAML front matter" unless front
|
|
49
49
|
YAML.safe_load(front, permitted_classes: [], aliases: false)
|
|
@@ -57,7 +57,7 @@ def render_execution_contract_markdown(contract)
|
|
|
57
57
|
lines = [
|
|
58
58
|
"# Execution Contract",
|
|
59
59
|
"",
|
|
60
|
-
"> Core-generated derived view. The immutable contract JSON under `.planning/contracts/` is authoritative.",
|
|
60
|
+
"> Core-generated derived view. The immutable contract JSON under `.devflow/planning/contracts/` is authoritative.",
|
|
61
61
|
"",
|
|
62
62
|
"- Contract ID: `#{contract.fetch("contract_id")}`",
|
|
63
63
|
"- Feature: `#{contract.fetch("feature")}`",
|
|
@@ -106,7 +106,7 @@ begin
|
|
|
106
106
|
# omitting production_paths strands implementation workers in a contract
|
|
107
107
|
# that can write summaries but never code.
|
|
108
108
|
if options[:step] == "execute"
|
|
109
|
-
binding_path = File.join(root, ".planning/features", options[:feature], "test-bindings.json")
|
|
109
|
+
binding_path = File.join(root, ".devflow/planning/features", options[:feature], "test-bindings.json")
|
|
110
110
|
if File.file?(binding_path)
|
|
111
111
|
bindings = JSON.parse(File.read(binding_path))
|
|
112
112
|
Array(bindings["tasks"]).each do |task|
|
|
@@ -142,10 +142,10 @@ begin
|
|
|
142
142
|
result = { "ok" => true, "contract" => frozen }
|
|
143
143
|
else
|
|
144
144
|
raise ArgumentError, "--write is required" unless options[:write]
|
|
145
|
-
destination = File.join(root, ".planning/contracts", options[:feature], "#{contract_id}.json")
|
|
145
|
+
destination = File.join(root, ".devflow/planning/contracts", options[:feature], "#{contract_id}.json")
|
|
146
146
|
DevflowControlIO.atomic_write(destination, JSON.pretty_generate(frozen) + "\n")
|
|
147
|
-
DevflowControlIO.atomic_write(File.join(root, ".planning/execution-contract.md"), render_execution_contract_markdown(frozen) + "\n")
|
|
148
|
-
audit = File.join(root, ".planning/contracts", options[:feature], "control-events.jsonl")
|
|
147
|
+
DevflowControlIO.atomic_write(File.join(root, ".devflow/planning/execution-contract.md"), render_execution_contract_markdown(frozen) + "\n")
|
|
148
|
+
audit = File.join(root, ".devflow/planning/contracts", options[:feature], "control-events.jsonl")
|
|
149
149
|
existing = File.exist?(audit) ? File.read(audit) : ""
|
|
150
150
|
DevflowControlIO.atomic_write(audit, existing + JSON.generate({ "event" => "execution_contract_frozen", "contract_id" => contract_id, "state_revision" => state["revision"], "graph_revision" => graph["revision"], "frozen_hash" => frozen["frozen_hash"] }) + "\n")
|
|
151
151
|
result = { "ok" => true, "path" => destination.sub("#{root}/", ""), "contract" => frozen }
|
|
@@ -87,7 +87,7 @@ module GateRuntime
|
|
|
87
87
|
invalid_outputs = validate_declared_inputs(contract.dig("outputs", "required_inputs"), root, workflow_state, purpose: :completion)
|
|
88
88
|
return GateResult.block(**base, code: "REQUIRED_OUTPUT_INVALID", message: "required step input/output fact is invalid", details: { "invalid" => invalid_outputs }) unless invalid_outputs.empty?
|
|
89
89
|
if step_id == "code-review"
|
|
90
|
-
contract_view = File.join(root, ".planning/execution-contract.md")
|
|
90
|
+
contract_view = File.join(root, ".devflow/planning/execution-contract.md")
|
|
91
91
|
contract_id = if File.file?(contract_view) && !File.symlink?(contract_view)
|
|
92
92
|
File.read(contract_view).match(/^- Contract ID: `(EC-[0-9a-f]{16})`$/)&.[](1)
|
|
93
93
|
end
|
|
@@ -234,9 +234,9 @@ module GateRuntime
|
|
|
234
234
|
case validation
|
|
235
235
|
when "static-runtime-context"
|
|
236
236
|
pointer_path = payload.fetch("path")
|
|
237
|
-
raise "invalid pointer path" unless pointer_path.start_with?(".context/static-runtime-context/revisions/")
|
|
237
|
+
raise "invalid pointer path" unless pointer_path.start_with?(".devflow/context/static-runtime-context/revisions/")
|
|
238
238
|
root_real = File.realpath(root)
|
|
239
|
-
revisions_root = File.realpath(File.join(root, ".context/static-runtime-context/revisions"))
|
|
239
|
+
revisions_root = File.realpath(File.join(root, ".devflow/context/static-runtime-context/revisions"))
|
|
240
240
|
snapshot_real = File.realpath(File.expand_path(pointer_path, root))
|
|
241
241
|
raise "snapshot path escapes project root" unless snapshot_real.start_with?("#{root_real}#{File::SEPARATOR}")
|
|
242
242
|
raise "snapshot path escapes revisions directory" unless snapshot_real.start_with?("#{revisions_root}#{File::SEPARATOR}")
|