@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
|
@@ -17,7 +17,7 @@ options = {
|
|
|
17
17
|
step: nil,
|
|
18
18
|
status: "not_started",
|
|
19
19
|
track: nil,
|
|
20
|
-
state: ".planning/STATE.md",
|
|
20
|
+
state: ".devflow/planning/STATE.md",
|
|
21
21
|
write: false,
|
|
22
22
|
force: false,
|
|
23
23
|
json: false
|
|
@@ -58,7 +58,7 @@ unless PhaseOwnership.valid_slug?(phase)
|
|
|
58
58
|
puts JSON.pretty_generate({ "ok" => false, "reason" => "invalid_phase", "message" => "phase must be a safe non-empty slug" })
|
|
59
59
|
exit 0
|
|
60
60
|
end
|
|
61
|
-
workflow_config = ".planning/workflows/#{options[:flow]}.yaml"
|
|
61
|
+
workflow_config = ".devflow/planning/workflows/#{options[:flow]}.yaml"
|
|
62
62
|
workflow_path = File.expand_path(workflow_config, root)
|
|
63
63
|
unless options[:flow].is_a?(String) && options[:flow].match?(/\A[A-Za-z0-9][A-Za-z0-9_-]*\z/)
|
|
64
64
|
puts JSON.pretty_generate({
|
|
@@ -120,9 +120,9 @@ state = {
|
|
|
120
120
|
"completed_steps" => [],
|
|
121
121
|
"pending_steps" => pending_steps,
|
|
122
122
|
"active_outputs" => {
|
|
123
|
-
"requirement_baseline" => ".planning/requirements/baseline.md",
|
|
124
|
-
"feature_dir" => ".planning/features/#{feature}/",
|
|
125
|
-
"phase_dir" => ".planning/phases/#{phase}/"
|
|
123
|
+
"requirement_baseline" => ".devflow/planning/requirements/baseline.md",
|
|
124
|
+
"feature_dir" => ".devflow/planning/features/#{feature}/",
|
|
125
|
+
"phase_dir" => ".devflow/planning/phases/#{phase}/"
|
|
126
126
|
}
|
|
127
127
|
}
|
|
128
128
|
|
|
@@ -19,7 +19,7 @@ end.parse!
|
|
|
19
19
|
root = Dir.pwd
|
|
20
20
|
skill_root = File.expand_path("..", __dir__)
|
|
21
21
|
template_dir = File.join(skill_root, "templates")
|
|
22
|
-
state_path = File.join(root, ".planning", "STATE.md")
|
|
22
|
+
state_path = File.join(root, ".devflow/planning", "STATE.md")
|
|
23
23
|
|
|
24
24
|
def front_matter(markdown)
|
|
25
25
|
match = markdown.match(/\A---\n(.*?)\n---\n/m)
|
|
@@ -42,7 +42,7 @@ end
|
|
|
42
42
|
def active_workflow_target?(state, target_path)
|
|
43
43
|
return false unless state
|
|
44
44
|
|
|
45
|
-
active = state["workflow_config"] || ".planning/workflows/#{state["current_flow"]}.yaml"
|
|
45
|
+
active = state["workflow_config"] || ".devflow/planning/workflows/#{state["current_flow"]}.yaml"
|
|
46
46
|
active == target_path
|
|
47
47
|
end
|
|
48
48
|
|
|
@@ -57,9 +57,9 @@ def state_step_mismatch?(state, template_path)
|
|
|
57
57
|
end
|
|
58
58
|
|
|
59
59
|
targets = {
|
|
60
|
-
"feature-development.yaml" => ".planning/workflows/feature-development.yaml",
|
|
61
|
-
"acceptance-remediation.yaml" => ".planning/workflows/acceptance-remediation.yaml",
|
|
62
|
-
"workflows-README.md" => ".planning/workflows/README.md"
|
|
60
|
+
"feature-development.yaml" => ".devflow/planning/workflows/feature-development.yaml",
|
|
61
|
+
"acceptance-remediation.yaml" => ".devflow/planning/workflows/acceptance-remediation.yaml",
|
|
62
|
+
"workflows-README.md" => ".devflow/planning/workflows/README.md"
|
|
63
63
|
}
|
|
64
64
|
|
|
65
65
|
blocked_target_paths = if options[:force] && options[:write] && !options[:allow_state_mismatch]
|
|
@@ -15,7 +15,7 @@ OptionParser.new do |opts|
|
|
|
15
15
|
end.parse!
|
|
16
16
|
|
|
17
17
|
root = Dir.pwd
|
|
18
|
-
state_path = options[:state] ? File.expand_path(options[:state], root) : File.join(root, ".planning", "STATE.md")
|
|
18
|
+
state_path = options[:state] ? File.expand_path(options[:state], root) : File.join(root, ".devflow/planning", "STATE.md")
|
|
19
19
|
|
|
20
20
|
def fail_result(reason, details = {})
|
|
21
21
|
{
|
|
@@ -64,9 +64,9 @@ end
|
|
|
64
64
|
|
|
65
65
|
def project_context_missing?(root)
|
|
66
66
|
required_paths = [
|
|
67
|
-
File.join(root, ".planning", "PROJECT.md"),
|
|
68
|
-
File.join(root, ".planning", "navigation", "INDEX.md"),
|
|
69
|
-
File.join(root, ".context", "spec", "index.md")
|
|
67
|
+
File.join(root, ".devflow/planning", "PROJECT.md"),
|
|
68
|
+
File.join(root, ".devflow/planning", "navigation", "INDEX.md"),
|
|
69
|
+
File.join(root, ".devflow/context", "spec", "index.md")
|
|
70
70
|
]
|
|
71
71
|
|
|
72
72
|
required_paths.any? { |path| !File.exist?(path) }
|
|
@@ -325,10 +325,10 @@ result =
|
|
|
325
325
|
"missing_project_context",
|
|
326
326
|
path: state_path,
|
|
327
327
|
missing: [
|
|
328
|
-
".planning/STATE.md",
|
|
329
|
-
".planning/PROJECT.md",
|
|
330
|
-
".planning/navigation/INDEX.md",
|
|
331
|
-
".context/spec/index.md"
|
|
328
|
+
".devflow/planning/STATE.md",
|
|
329
|
+
".devflow/planning/PROJECT.md",
|
|
330
|
+
".devflow/planning/navigation/INDEX.md",
|
|
331
|
+
".devflow/context/spec/index.md"
|
|
332
332
|
]
|
|
333
333
|
)
|
|
334
334
|
else
|
|
@@ -367,9 +367,9 @@ result =
|
|
|
367
367
|
project_context_result(
|
|
368
368
|
"incomplete_project_context",
|
|
369
369
|
missing: [
|
|
370
|
-
".planning/PROJECT.md",
|
|
371
|
-
".planning/navigation/INDEX.md",
|
|
372
|
-
".context/spec/index.md"
|
|
370
|
+
".devflow/planning/PROJECT.md",
|
|
371
|
+
".devflow/planning/navigation/INDEX.md",
|
|
372
|
+
".devflow/context/spec/index.md"
|
|
373
373
|
]
|
|
374
374
|
)
|
|
375
375
|
else
|
|
@@ -385,7 +385,7 @@ result =
|
|
|
385
385
|
)
|
|
386
386
|
else
|
|
387
387
|
workflow_path = state["workflow_config"] ||
|
|
388
|
-
File.join(".planning", "workflows", "#{state["current_flow"]}.yaml")
|
|
388
|
+
File.join(".devflow/planning", "workflows", "#{state["current_flow"]}.yaml")
|
|
389
389
|
abs_workflow_path = File.join(root, workflow_path)
|
|
390
390
|
|
|
391
391
|
if !File.exist?(abs_workflow_path)
|
|
@@ -641,7 +641,7 @@ result =
|
|
|
641
641
|
missing_outputs: missing_outputs,
|
|
642
642
|
checkpoint_meta_errors: checkpoint_meta_errors,
|
|
643
643
|
resume_behavior: checkpoint && checkpoint["resume_behavior"],
|
|
644
|
-
next_intent: ".planning/.next-intent"
|
|
644
|
+
next_intent: ".devflow/planning/.next-intent"
|
|
645
645
|
)
|
|
646
646
|
elsif parallel_window
|
|
647
647
|
base.merge(action: "run_parallel_window")
|
|
@@ -30,7 +30,7 @@ abort "feature, step and --write are required" unless options[:feature] && optio
|
|
|
30
30
|
abort "invalid feature" unless RequirementGraph.valid_feature?(options[:feature])
|
|
31
31
|
|
|
32
32
|
def state_front_matter(root)
|
|
33
|
-
document = File.read(File.join(root, ".planning/STATE.md"))
|
|
33
|
+
document = File.read(File.join(root, ".devflow/planning/STATE.md"))
|
|
34
34
|
front = document.match(/\A---\n(.*?)\n---/m)&.[](1)
|
|
35
35
|
raise "STATE.md has no YAML front matter" unless front
|
|
36
36
|
YAML.safe_load(front, permitted_classes: [], aliases: false)
|
|
@@ -62,7 +62,7 @@ def independent_evidence(root, feature, step, state, workflow, graph, files, che
|
|
|
62
62
|
# cannot manufacture proof that an engine did not invoke AI.
|
|
63
63
|
binding_attempt = binding && binding["attempt"]
|
|
64
64
|
event_name = binding_attempt.nil? ? "#{step}.engine-events.jsonl" : "#{step}.attempt-#{binding_attempt}.engine-events.jsonl"
|
|
65
|
-
event_path = File.join(".planning", "evidence", feature, event_name)
|
|
65
|
+
event_path = File.join(".devflow/planning", "evidence", feature, event_name)
|
|
66
66
|
event_absolute, = DevflowControlIO.resolve_control_path(root, event_path, :artifact)
|
|
67
67
|
events = if File.file?(event_absolute)
|
|
68
68
|
File.foreach(event_absolute).first(10_000).each_with_object([]) do |line, parsed|
|
|
@@ -259,7 +259,7 @@ begin
|
|
|
259
259
|
"gate_mode" => gate.empty? ? "observe" : gate
|
|
260
260
|
}.compact
|
|
261
261
|
suffix = binding ? ".attempt-#{binding["attempt"]}.branch-#{Digest::SHA256.hexdigest(binding["branch_id"].to_s)[0, 12]}" : ""
|
|
262
|
-
destination = File.join(root, ".planning/evidence", options[:feature], "#{options[:step]}#{suffix}.machine.json")
|
|
262
|
+
destination = File.join(root, ".devflow/planning/evidence", options[:feature], "#{options[:step]}#{suffix}.machine.json")
|
|
263
263
|
DevflowControlIO.atomic_write(destination, JSON.pretty_generate(pack) + "\n")
|
|
264
264
|
result = { "ok" => true, "path" => destination.sub("#{root}/", ""), "complete" => pack["complete"], "state_revision" => pack["state_revision"], "graph_revision" => pack["graph_revision"], "checkers" => checker_results, "checkpoint_meta_errors" => checkpoint_meta_errors, "parallel_binding" => binding }
|
|
265
265
|
rescue StandardError => error
|
|
@@ -31,7 +31,7 @@ OptionParser.new do |opts|
|
|
|
31
31
|
end.parse!
|
|
32
32
|
|
|
33
33
|
root = Dir.pwd
|
|
34
|
-
state_path = options[:state] ? File.expand_path(options[:state], root) : File.join(root, ".planning", "STATE.md")
|
|
34
|
+
state_path = options[:state] ? File.expand_path(options[:state], root) : File.join(root, ".devflow/planning", "STATE.md")
|
|
35
35
|
|
|
36
36
|
def front_matter(markdown)
|
|
37
37
|
match = markdown.match(/\A---\n(.*?)\n---\n/m)
|
|
@@ -51,19 +51,19 @@ def load_state(path)
|
|
|
51
51
|
end
|
|
52
52
|
|
|
53
53
|
def workflow_path_for(state)
|
|
54
|
-
state["workflow_config"] || File.join(".planning", "workflows", "#{state.fetch("current_flow")}.yaml")
|
|
54
|
+
state["workflow_config"] || File.join(".devflow/planning", "workflows", "#{state.fetch("current_flow")}.yaml")
|
|
55
55
|
end
|
|
56
56
|
|
|
57
57
|
def configured_policy(workflow)
|
|
58
58
|
workflow["lessons_policy"] || {
|
|
59
59
|
"sources" => [
|
|
60
|
-
{ "path" => ".context/lessons/README.md", "required" => false },
|
|
61
|
-
{ "path" => ".planning/lessons/README.md", "required" => false }
|
|
60
|
+
{ "path" => ".devflow/context/lessons/README.md", "required" => false },
|
|
61
|
+
{ "path" => ".devflow/planning/lessons/README.md", "required" => false }
|
|
62
62
|
],
|
|
63
63
|
"selection" => { "max_candidates" => 5, "min_score" => 1 },
|
|
64
64
|
"write" => {
|
|
65
|
-
"default_dir" => ".context/lessons",
|
|
66
|
-
"index_path" => ".context/lessons/README.md"
|
|
65
|
+
"default_dir" => ".devflow/context/lessons",
|
|
66
|
+
"index_path" => ".devflow/context/lessons/README.md"
|
|
67
67
|
}
|
|
68
68
|
}
|
|
69
69
|
end
|
|
@@ -167,7 +167,7 @@ end
|
|
|
167
167
|
|
|
168
168
|
def write_template(root, policy, state, title, source, write)
|
|
169
169
|
write_config = policy["write"] || {}
|
|
170
|
-
dir = write_config["default_dir"] || ".context/lessons"
|
|
170
|
+
dir = write_config["default_dir"] || ".devflow/context/lessons"
|
|
171
171
|
index_path = write_config["index_path"] || File.join(dir, "README.md")
|
|
172
172
|
file_name = "#{Date.today}-#{slug_for(title)}.md"
|
|
173
173
|
rel_path = File.join(dir, file_name)
|
|
@@ -159,7 +159,7 @@ rescue JSON::ParserError => error
|
|
|
159
159
|
end
|
|
160
160
|
|
|
161
161
|
def audit_path(root, feature)
|
|
162
|
-
DevflowControlIO.resolve_control_path(root, ".planning/evidence/#{feature}/parallel-recovery.jsonl", :artifact).first
|
|
162
|
+
DevflowControlIO.resolve_control_path(root, ".devflow/planning/evidence/#{feature}/parallel-recovery.jsonl", :artifact).first
|
|
163
163
|
end
|
|
164
164
|
|
|
165
165
|
def append_audit(root, feature, payload, lock: nil)
|
|
@@ -233,7 +233,7 @@ begin
|
|
|
233
233
|
validation_records = []
|
|
234
234
|
project_lock = DevflowControlIO.acquire_project_lock(root)
|
|
235
235
|
begin
|
|
236
|
-
state_path, = DevflowControlIO.resolve_control_path(root, ".planning/STATE.md", :state)
|
|
236
|
+
state_path, = DevflowControlIO.resolve_control_path(root, ".devflow/planning/STATE.md", :state)
|
|
237
237
|
state_yaml = front_matter(File.read(state_path))
|
|
238
238
|
raise ArgumentError, "STATE.md has no YAML front matter" unless state_yaml
|
|
239
239
|
state = YAML.safe_load(state_yaml, permitted_classes: [Date, Time], aliases: false)
|
|
@@ -29,7 +29,7 @@ module ParallelRun
|
|
|
29
29
|
end
|
|
30
30
|
|
|
31
31
|
def path(root, feature)
|
|
32
|
-
File.join(root, ".planning", "parallel", safe_feature(feature), "branches.yaml")
|
|
32
|
+
File.join(root, ".devflow/planning", "parallel", safe_feature(feature), "branches.yaml")
|
|
33
33
|
end
|
|
34
34
|
|
|
35
35
|
def load(root, feature)
|
|
@@ -94,7 +94,7 @@ module ParallelRun
|
|
|
94
94
|
state
|
|
95
95
|
end
|
|
96
96
|
|
|
97
|
-
def prepare(root:, feature:, workflow_window:, state_revision:, branches:, task_ids: {}, state_path: ".planning/STATE.md")
|
|
97
|
+
def prepare(root:, feature:, workflow_window:, state_revision:, branches:, task_ids: {}, state_path: ".devflow/planning/STATE.md")
|
|
98
98
|
lock = DevflowControlIO.acquire_project_lock(root)
|
|
99
99
|
begin
|
|
100
100
|
raise ArgumentError, "parallel run already exists" if load(root, feature)
|
|
@@ -204,7 +204,7 @@ end
|
|
|
204
204
|
|
|
205
205
|
if $PROGRAM_NAME == __FILE__
|
|
206
206
|
begin
|
|
207
|
-
options = { action: nil, feature: nil, state_revision: nil, run_revision: nil, branch_id: nil, status: nil, workflow_window: nil, branches: [], state_path: ".planning/STATE.md", json: false }
|
|
207
|
+
options = { action: nil, feature: nil, state_revision: nil, run_revision: nil, branch_id: nil, status: nil, workflow_window: nil, branches: [], state_path: ".devflow/planning/STATE.md", json: false }
|
|
208
208
|
OptionParser.new do |opts|
|
|
209
209
|
opts.on("--action ACTION", %w[inspect prepare update retry rebase serial-fallback]) { |value| options[:action] = value }
|
|
210
210
|
opts.on("--feature FEATURE") { |value| options[:feature] = value }
|
|
@@ -11,7 +11,7 @@ require "yaml"
|
|
|
11
11
|
require_relative "control_io"
|
|
12
12
|
|
|
13
13
|
module PhaseOwnership
|
|
14
|
-
REGISTRY_PATH = ".planning/phase-ownership.yaml"
|
|
14
|
+
REGISTRY_PATH = ".devflow/planning/phase-ownership.yaml"
|
|
15
15
|
PHASE_SLUG = /\A[A-Za-z0-9][A-Za-z0-9_-]*\z/
|
|
16
16
|
module_function
|
|
17
17
|
|
|
@@ -45,11 +45,11 @@ module PhaseOwnership
|
|
|
45
45
|
def valid_owner?(owner, phase: nil)
|
|
46
46
|
owner.is_a?(Hash) && valid_slug?(owner["phase"]) && (phase.nil? || owner["phase"] == phase) &&
|
|
47
47
|
valid_feature?(owner["feature"]) && owner["flow"].is_a?(String) && !owner["flow"].empty? &&
|
|
48
|
-
owner["state_path"] == ".planning/STATE.md" && %w[active completed].include?(owner["status"])
|
|
48
|
+
owner["state_path"] == ".devflow/planning/STATE.md" && %w[active completed].include?(owner["status"])
|
|
49
49
|
end
|
|
50
50
|
|
|
51
51
|
def nonempty_phase_dirs(root)
|
|
52
|
-
Dir.glob(File.join(root, ".planning", "phases", "*")).select do |path|
|
|
52
|
+
Dir.glob(File.join(root, ".devflow/planning", "phases", "*")).select do |path|
|
|
53
53
|
File.directory?(path) && !Dir.children(path).empty?
|
|
54
54
|
end.map { |path| File.basename(path) }
|
|
55
55
|
end
|
|
@@ -84,8 +84,8 @@ module PhaseOwnership
|
|
|
84
84
|
return failure("phase_owned_by_another_feature", "requested phase is already owned by another feature", owner: current)
|
|
85
85
|
end
|
|
86
86
|
|
|
87
|
-
owner = current || { "phase" => phase, "feature" => feature, "flow" => flow, "state_path" => ".planning/STATE.md", "scope" => "global", "status" => "active" }
|
|
88
|
-
owner = owner.merge("phase" => phase, "feature" => feature, "flow" => flow, "state_path" => ".planning/STATE.md", "scope" => "global", "status" => "active")
|
|
87
|
+
owner = current || { "phase" => phase, "feature" => feature, "flow" => flow, "state_path" => ".devflow/planning/STATE.md", "scope" => "global", "status" => "active" }
|
|
88
|
+
owner = owner.merge("phase" => phase, "feature" => feature, "flow" => flow, "state_path" => ".devflow/planning/STATE.md", "scope" => "global", "status" => "active")
|
|
89
89
|
registry["owners"][phase] = owner
|
|
90
90
|
registry["updated_at"] = Date.today.to_s
|
|
91
91
|
DevflowControlIO.atomic_write(registry_path(root), registry.to_yaml) if write
|
|
@@ -114,7 +114,7 @@ module PhaseOwnership
|
|
|
114
114
|
return failure("invalid_phase", "STATE.md current_phase must be a safe non-empty slug") unless valid_slug?(phase)
|
|
115
115
|
owner = owner_override || registry["owners"][phase]
|
|
116
116
|
return failure("missing_phase_owner", "STATE.md phase has no ownership record", phase: phase) unless valid_owner?(owner, phase: phase)
|
|
117
|
-
unless owner["feature"] == feature && owner["flow"] == flow && owner["state_path"] == ".planning/STATE.md"
|
|
117
|
+
unless owner["feature"] == feature && owner["flow"] == flow && owner["state_path"] == ".devflow/planning/STATE.md"
|
|
118
118
|
return failure("phase_owner_mismatch", "STATE.md does not match phase ownership record", owner: owner)
|
|
119
119
|
end
|
|
120
120
|
conflicting = registry["owners"].values.find { |entry| valid_owner?(entry) && entry["status"] == "active" && entry["phase"] != phase }
|
|
@@ -9,7 +9,7 @@ require_relative "control_io"
|
|
|
9
9
|
require_relative "validate_state"
|
|
10
10
|
require_relative "phase_ownership"
|
|
11
11
|
|
|
12
|
-
options = { state: ".planning/STATE.md", expected_revision: nil, confirm: false, write: false, json: false }
|
|
12
|
+
options = { state: ".devflow/planning/STATE.md", expected_revision: nil, confirm: false, write: false, json: false }
|
|
13
13
|
OptionParser.new do |opts|
|
|
14
14
|
opts.banner = "Usage: repair_control_plane.rb --expected-revision N --confirm --write"
|
|
15
15
|
opts.on("--state PATH") { |value| options[:state] = value }
|
|
@@ -14,7 +14,7 @@ module RequirementCoverage
|
|
|
14
14
|
module_function
|
|
15
15
|
|
|
16
16
|
def generate(root:, feature:, source:)
|
|
17
|
-
state = YAML.safe_load(File.read(File.join(root, ".planning/STATE.md")).split(/^---\s*$/, 3)[1], permitted_classes: [Date], aliases: false)
|
|
17
|
+
state = YAML.safe_load(File.read(File.join(root, ".devflow/planning/STATE.md")).split(/^---\s*$/, 3)[1], permitted_classes: [Date], aliases: false)
|
|
18
18
|
raise ArgumentError, "source generation requires the active wayfinder step" unless state["current_feature"] == feature && state["current_step"] == "requirement-wayfinder"
|
|
19
19
|
source_path = File.realpath(File.expand_path(source, root))
|
|
20
20
|
raise ArgumentError, "source must be a project file" unless source_path.start_with?(File.realpath(root) + File::SEPARATOR)
|
|
@@ -18,7 +18,7 @@ module RequirementGraph
|
|
|
18
18
|
# graphs are migrated in memory and re-written only by this Core writer.
|
|
19
19
|
SCHEMA_VERSION = 5
|
|
20
20
|
SUPPORTED_SCHEMA_VERSIONS = [1, 2, 3, 4, SCHEMA_VERSION].freeze
|
|
21
|
-
ROOT = ".planning/requirements"
|
|
21
|
+
ROOT = ".devflow/planning/requirements"
|
|
22
22
|
KINDS = {
|
|
23
23
|
"source" => "SRC", "code" => "CODE", "term" => "TERM", "object" => "OBJECT",
|
|
24
24
|
"behavior" => "BEH", "requirement" => "REQ", "rule" => "BR", "boundary" => "BC",
|
|
@@ -56,7 +56,7 @@ module RequirementGraph
|
|
|
56
56
|
end
|
|
57
57
|
|
|
58
58
|
def active_feature(root)
|
|
59
|
-
state_path = File.join(root, ".planning", "STATE.md")
|
|
59
|
+
state_path = File.join(root, ".devflow/planning", "STATE.md")
|
|
60
60
|
return nil unless File.file?(state_path)
|
|
61
61
|
front = File.read(state_path).match(/\A---\n(.*?)\n---/m)&.[](1)
|
|
62
62
|
return nil unless front
|
|
@@ -553,7 +553,7 @@ module RequirementGraph
|
|
|
553
553
|
end
|
|
554
554
|
matrix["imported_graph_revision"] = graph["revision"]
|
|
555
555
|
DevflowControlIO.atomic_write(matrix_path, JSON.pretty_generate(matrix) + "\n")
|
|
556
|
-
template_path = File.join(root, ".planning", "features", graph["feature"], "api-acceptance-bindings.template.json")
|
|
556
|
+
template_path = File.join(root, ".devflow/planning", "features", graph["feature"], "api-acceptance-bindings.template.json")
|
|
557
557
|
template = {
|
|
558
558
|
"schema_version" => 1, "origin" => "core_api_test_matrix_template", "feature" => graph["feature"],
|
|
559
559
|
"case_set_fingerprint" => matrix["case_set_fingerprint"],
|
|
@@ -81,7 +81,7 @@ def preflight(root: Path, feature: str, step: str, contract_path: str,
|
|
|
81
81
|
return {"status": "human_confirmation", "evidence": evidence,
|
|
82
82
|
"issues": [{"code": "STALE_WORKFLOW_SNAPSHOT"}]}
|
|
83
83
|
workflow = load_workflow(workflow_path)
|
|
84
|
-
state = load_state(within(root, ".planning/STATE.md"))
|
|
84
|
+
state = load_state(within(root, ".devflow/planning/STATE.md"))
|
|
85
85
|
if state.get("revision") != current["state_revision"] or state.get("current_feature") != feature or state.get("current_step") != step:
|
|
86
86
|
return {"status": "human_confirmation", "evidence": evidence,
|
|
87
87
|
"issues": [{"code": "STALE_STATE_SNAPSHOT"}]}
|
|
@@ -100,7 +100,7 @@ def preflight(root: Path, feature: str, step: str, contract_path: str,
|
|
|
100
100
|
else:
|
|
101
101
|
issues.append({"code": "INVALID_WORKFLOW_INPUT", "detail": "unrecognized input obligation"})
|
|
102
102
|
continue
|
|
103
|
-
if required and relative != ".planning/execution-contract.md":
|
|
103
|
+
if required and relative != ".devflow/planning/execution-contract.md":
|
|
104
104
|
derived.append({"path": render(relative), "producer": "existing"})
|
|
105
105
|
for item in step_definition.get("outputs", []):
|
|
106
106
|
if isinstance(item, dict) and item.get("required") is True and isinstance(item.get("path"), str):
|
|
@@ -113,7 +113,7 @@ def preflight(root: Path, feature: str, step: str, contract_path: str,
|
|
|
113
113
|
"required_obligation_count": len(derived),
|
|
114
114
|
"checker_ids": current.get("checker_ids", [])})
|
|
115
115
|
if step == "code-review":
|
|
116
|
-
graph_relative = f".planning/requirements/{feature}/governance.json"
|
|
116
|
+
graph_relative = f".devflow/planning/requirements/{feature}/governance.json"
|
|
117
117
|
graph_path = within(root, graph_relative)
|
|
118
118
|
if not graph_path.is_file():
|
|
119
119
|
issues.append({"code": "CONFIRMED_EXPECTATIONS_UNAVAILABLE", "path": graph_relative})
|
|
@@ -109,7 +109,7 @@ def validate_authority(root: Path, feature: str, expectations: list) -> tuple[li
|
|
|
109
109
|
issues.append(f"{item['id']}: authority_ref must identify a Core graph node and revision")
|
|
110
110
|
continue
|
|
111
111
|
node_id, revision = ref[len("core-graph:"):].rsplit("@", 1)
|
|
112
|
-
graph_path = f".planning/requirements/{feature}/governance.json"
|
|
112
|
+
graph_path = f".devflow/planning/requirements/{feature}/governance.json"
|
|
113
113
|
graph_file = safe_file(root, graph_path)
|
|
114
114
|
authority = read_json(graph_file)
|
|
115
115
|
node = next((n for n in authority.get("nodes", []) if isinstance(n, dict) and n.get("id") == node_id), None)
|
|
@@ -132,7 +132,7 @@ def validate_authority(root: Path, feature: str, expectations: list) -> tuple[li
|
|
|
132
132
|
|
|
133
133
|
|
|
134
134
|
def db_open(root: Path) -> sqlite3.Connection:
|
|
135
|
-
planning = root / ".planning"
|
|
135
|
+
planning = root / ".devflow/planning"
|
|
136
136
|
if planning.is_symlink():
|
|
137
137
|
raise ValueError("unsafe planning directory")
|
|
138
138
|
directory = planning / "review-runs"
|
|
@@ -174,7 +174,7 @@ def response(status: str, chain_id: str | None, round_no: int, **details: Any) -
|
|
|
174
174
|
|
|
175
175
|
def locate_index(root: Path, accepted: list, target_paths: list[str], questions: list[str]) -> dict:
|
|
176
176
|
"""Ask the index for bounded leads, never for authoritative conclusions."""
|
|
177
|
-
index = root / ".planning" / "code-index"
|
|
177
|
+
index = root / ".devflow/planning" / "code-index"
|
|
178
178
|
script = Path(__file__).resolve().parents[3].parent / "devflow-intel" / "skills" / "workflow-code-index" / "scripts" / "code_index.py"
|
|
179
179
|
if not index.exists() or not script.exists():
|
|
180
180
|
return {"status": "unavailable", "reason": "No local code-index snapshot; source evidence is independent"}
|
|
@@ -218,7 +218,7 @@ def verify_core_result(root: Path, feature: str, evidence: Any, expected_status:
|
|
|
218
218
|
"""Accept only a Core-owned TC result bound to the feature and frozen suite."""
|
|
219
219
|
if not isinstance(evidence, dict):
|
|
220
220
|
return False, "missing Core acceptance-test result reference"
|
|
221
|
-
relative = f".planning/test-runs/{feature}/acceptance-results.json"
|
|
221
|
+
relative = f".devflow/planning/test-runs/{feature}/acceptance-results.json"
|
|
222
222
|
if evidence.get("path") != relative or not isinstance(evidence.get("tc_id"), str):
|
|
223
223
|
return False, "result must reference a Core acceptance TC for this feature"
|
|
224
224
|
try:
|
|
@@ -226,7 +226,7 @@ def verify_core_result(root: Path, feature: str, evidence: Any, expected_status:
|
|
|
226
226
|
if digest(result_file.read_bytes()) != evidence.get("sha256"):
|
|
227
227
|
return False, "acceptance result hash mismatch"
|
|
228
228
|
payload = read_json(result_file)
|
|
229
|
-
suite = read_json(safe_file(root, f".planning/requirements/{feature}/tests.json"))
|
|
229
|
+
suite = read_json(safe_file(root, f".devflow/planning/requirements/{feature}/tests.json"))
|
|
230
230
|
if payload.get("origin") != "core_acceptance_test_runner" or payload.get("feature") != feature:
|
|
231
231
|
return False, "not a Core acceptance-test run"
|
|
232
232
|
if payload.get("test_suite") != {"graph_revision": suite.get("graph_revision"), "fingerprint": suite.get("view_meta", {}).get("fingerprint")}:
|
|
@@ -252,7 +252,7 @@ def verify_core_result(root: Path, feature: str, evidence: Any, expected_status:
|
|
|
252
252
|
def verify_core_impact(root: Path, feature: str, evidence: dict, impact: str, trigger: str) -> tuple[bool, str]:
|
|
253
253
|
"""A failed TC alone does not establish the reviewer's causal/impact label."""
|
|
254
254
|
try:
|
|
255
|
-
suite = read_json(safe_file(root, f".planning/requirements/{feature}/tests.json"))
|
|
255
|
+
suite = read_json(safe_file(root, f".devflow/planning/requirements/{feature}/tests.json"))
|
|
256
256
|
node = next((n for n in suite.get("nodes", []) if isinstance(n, dict) and n.get("id") == evidence.get("tc_id")), None)
|
|
257
257
|
data = node.get("data", {}) if node else {}
|
|
258
258
|
if data.get("review_impact") == impact and data.get("review_trigger") == trigger:
|
|
@@ -263,7 +263,7 @@ def verify_core_impact(root: Path, feature: str, evidence: dict, impact: str, tr
|
|
|
263
263
|
|
|
264
264
|
|
|
265
265
|
def declared_change_paths(root: Path, feature: str) -> tuple[set[str], str, str]:
|
|
266
|
-
relative = f".planning/features/{feature}/变更清单.md"
|
|
266
|
+
relative = f".devflow/planning/features/{feature}/变更清单.md"
|
|
267
267
|
source = safe_file(root, relative)
|
|
268
268
|
declarations = re.findall(r"^\s*-\s*\*\*文件\*\*\s*[::]\s*(.+)$", source.read_text(encoding="utf-8"), re.MULTILINE)
|
|
269
269
|
paths = set()
|
|
@@ -295,7 +295,7 @@ def verify_coverage(root: Path, feature: str, required: list[str], coverage_evid
|
|
|
295
295
|
if not valid:
|
|
296
296
|
issues.append(f"{tag}: {reason}")
|
|
297
297
|
continue
|
|
298
|
-
suite = read_json(safe_file(root, f".planning/requirements/{feature}/tests.json"))
|
|
298
|
+
suite = read_json(safe_file(root, f".devflow/planning/requirements/{feature}/tests.json"))
|
|
299
299
|
node = next((n for n in suite.get("nodes", []) if isinstance(n, dict) and n.get("id") == ref["tc_id"]), None)
|
|
300
300
|
types = {"scenario:normal": {"api", "page"}, "scenario:unauthorized": {"permission"}, "scenario:failure_rollback": {"resilience", "boundary"}, "scenario:compatibility": {"migration"}}
|
|
301
301
|
data = node.get("data", {}) if node else {}
|
|
@@ -310,7 +310,7 @@ def verify_coverage(root: Path, feature: str, required: list[str], coverage_evid
|
|
|
310
310
|
|
|
311
311
|
def suite_has_failures(root: Path, feature: str) -> bool:
|
|
312
312
|
try:
|
|
313
|
-
payload = read_json(safe_file(root, f".planning/test-runs/{feature}/acceptance-results.json"))
|
|
313
|
+
payload = read_json(safe_file(root, f".devflow/planning/test-runs/{feature}/acceptance-results.json"))
|
|
314
314
|
return any(isinstance(item, dict) and item.get("status") != "passed" for item in payload.get("results", []))
|
|
315
315
|
except (OSError, ValueError, TypeError, json.JSONDecodeError):
|
|
316
316
|
return True
|
|
@@ -322,13 +322,13 @@ def gate_status(root: Path, feature: str, contract_id: str | None = None) -> dic
|
|
|
322
322
|
if not contract_id:
|
|
323
323
|
return {"status": "human_confirmation", "reason": "Current Core review contract identity is required"}
|
|
324
324
|
try:
|
|
325
|
-
contract = read_json(safe_file(root, f".planning/contracts/{feature}/{contract_id}.json"))
|
|
325
|
+
contract = read_json(safe_file(root, f".devflow/planning/contracts/{feature}/{contract_id}.json"))
|
|
326
326
|
if contract.get("origin") != "core_execution_contract" or contract.get("step") != "code-review" or contract.get("feature") != feature or contract.get("contract_id") != contract_id:
|
|
327
327
|
return {"status": "core_contract_conflict", "reason": "Review contract identity is not a frozen Core code-review contract"}
|
|
328
328
|
sys.path.insert(0, str(Path(__file__).resolve().parent))
|
|
329
329
|
from review_preflight import load_state
|
|
330
|
-
state = load_state(safe_file(root, ".planning/STATE.md"))
|
|
331
|
-
graph = read_json(safe_file(root, f".planning/requirements/{feature}/governance.json"))
|
|
330
|
+
state = load_state(safe_file(root, ".devflow/planning/STATE.md"))
|
|
331
|
+
graph = read_json(safe_file(root, f".devflow/planning/requirements/{feature}/governance.json"))
|
|
332
332
|
workflow = safe_file(root, contract["workflow_path"])
|
|
333
333
|
if (state.get("current_feature") != feature or state.get("current_step") != "code-review"
|
|
334
334
|
or state.get("revision") != contract.get("state_revision")
|
|
@@ -337,7 +337,7 @@ def gate_status(root: Path, feature: str, contract_id: str | None = None) -> dic
|
|
|
337
337
|
return {"status": "stale_evidence", "reason": "Review contract differs from current Core state, graph, or workflow"}
|
|
338
338
|
except (OSError, ValueError, KeyError, TypeError, ImportError, json.JSONDecodeError) as exc:
|
|
339
339
|
return {"status": "human_confirmation", "reason": f"Current Core review contract cannot be verified: {exc}"}
|
|
340
|
-
database = root / ".planning" / "review-runs" / "review-runs.sqlite"
|
|
340
|
+
database = root / ".devflow/planning" / "review-runs" / "review-runs.sqlite"
|
|
341
341
|
if not database.is_file() or database.is_symlink():
|
|
342
342
|
return {"status": "human_confirmation", "reason": "No Core review round exists"}
|
|
343
343
|
db = sqlite3.connect(f"file:{database}?mode=ro", uri=True)
|
|
@@ -366,7 +366,7 @@ def gate_status(root: Path, feature: str, contract_id: str | None = None) -> dic
|
|
|
366
366
|
index_generation = fixed.get("code_index_generation")
|
|
367
367
|
if index_generation is not None:
|
|
368
368
|
try:
|
|
369
|
-
snapshot = read_json(safe_file(root, ".planning/code-index/SNAPSHOT.json"))
|
|
369
|
+
snapshot = read_json(safe_file(root, ".devflow/planning/code-index/SNAPSHOT.json"))
|
|
370
370
|
if snapshot.get("generation") != index_generation:
|
|
371
371
|
return {"status": "stale_evidence", "reason": "Code-index generation changed after review", "chain_id": result.get("chain_id")}
|
|
372
372
|
except (OSError, ValueError, json.JSONDecodeError):
|
|
@@ -415,11 +415,11 @@ def review_markdown(result: dict) -> str:
|
|
|
415
415
|
|
|
416
416
|
def render_review(root: Path, feature: str, contract_id: str) -> dict:
|
|
417
417
|
root = root.resolve(strict=True)
|
|
418
|
-
contract = read_json(safe_file(root, f".planning/contracts/{feature}/{contract_id}.json"))
|
|
418
|
+
contract = read_json(safe_file(root, f".devflow/planning/contracts/{feature}/{contract_id}.json"))
|
|
419
419
|
path = next((item for item in contract.get("allowed_paths", []) if isinstance(item, str) and item.endswith("/REVIEW.md")), None)
|
|
420
420
|
if not path:
|
|
421
421
|
return {"status": "core_contract_conflict", "reason": "Core contract has no REVIEW.md output"}
|
|
422
|
-
database = root / ".planning/review-runs/review-runs.sqlite"
|
|
422
|
+
database = root / ".devflow/planning/review-runs/review-runs.sqlite"
|
|
423
423
|
if not database.is_file():
|
|
424
424
|
return {"status": "human_confirmation", "reason": "No Core review round exists"}
|
|
425
425
|
db = sqlite3.connect(f"file:{database}?mode=ro", uri=True)
|
|
@@ -616,7 +616,7 @@ def run(root: Path, request: dict) -> dict:
|
|
|
616
616
|
db.commit()
|
|
617
617
|
return result
|
|
618
618
|
if index_discovery.get("generation"):
|
|
619
|
-
current_snapshot = root / ".planning" / "code-index" / "SNAPSHOT.json"
|
|
619
|
+
current_snapshot = root / ".devflow/planning" / "code-index" / "SNAPSHOT.json"
|
|
620
620
|
if not current_snapshot.exists() or read_json(current_snapshot).get("generation") != index_discovery["generation"]:
|
|
621
621
|
result = response("stale_evidence", chain_id, round_no, questions=["Code-index generation changed during review"])
|
|
622
622
|
db.execute("INSERT INTO events(chain_id,status,detail_json) VALUES(?,?,?)", (chain_id, result["status"], canonical(result)))
|
|
@@ -645,7 +645,7 @@ def run(root: Path, request: dict) -> dict:
|
|
|
645
645
|
db.commit()
|
|
646
646
|
return result
|
|
647
647
|
status = "terminated_p0" if round_no == 3 and summary["P0"] else ("findings" if open_findings else "clean")
|
|
648
|
-
core_results = {rel: digest(safe_file(root, rel).read_bytes()) for rel in (f".planning/requirements/{target['feature']}/tests.json", f".planning/test-runs/{target['feature']}/acceptance-results.json")}
|
|
648
|
+
core_results = {rel: digest(safe_file(root, rel).read_bytes()) for rel in (f".devflow/planning/requirements/{target['feature']}/tests.json", f".devflow/planning/test-runs/{target['feature']}/acceptance-results.json")}
|
|
649
649
|
result = response(status, chain_id, round_no, fixed_versions={"source": versions, "authority": accepted, "core_results": core_results, "change_plan": {"path": change_plan_path, "sha256": change_plan_hash, "declared_paths": sorted(declared_paths)}, "code_index_generation": index_discovery.get("generation")}, index_discovery=index_discovery, coverage={"covered": sorted(covered), "gaps": gaps, "index_gap": index_discovery.get("reason") if index_discovery["status"] != "located" else None}, findings=findings, risk_summary=summary, improvement_plan=[{"finding_id": f["finding_id"], "severity": f["severity"], "action": f["improvement"]} for f in sorted(open_findings, key=lambda x: x["severity"])], all_p0_resolved=summary["P0"] == 0, severity_source="independent_reviewer_core_evidence_bound", semantic_causality_verified=True, automatic_release_allowed=status == "clean", termination_scope="current_task_only" if status == "terminated_p0" else None, reviewer_task={key: binding[key] for key in ("agent", "feature", "contract_id", "task_call_id", "report_sha256")}, history=[{"round": r, "status": json.loads(raw)["status"]} for r, raw in db.execute("SELECT round,result_json FROM rounds WHERE chain_id=? ORDER BY round", (chain_id,))])
|
|
650
650
|
db.execute("INSERT INTO reviewer_tasks(task_call_id,chain_id,round,report_sha256) VALUES(?,?,?,?)", (binding["task_call_id"], chain_id, round_no, binding["report_sha256"]))
|
|
651
651
|
db.execute("INSERT INTO rounds(chain_id,round,result_json) VALUES(?,?,?)", (chain_id, round_no, canonical(result)))
|
package/plugins/devflow-core/skills/workflow-orchestrator/scripts/runtime_context_collector.rb
CHANGED
|
@@ -14,8 +14,8 @@ require_relative "control_io"
|
|
|
14
14
|
|
|
15
15
|
module RuntimeContextCollector
|
|
16
16
|
SCHEMA_VERSION = 1
|
|
17
|
-
HISTORY_DIR = File.join(".context", "runtime-context", "revisions")
|
|
18
|
-
POINTER = File.join(".context", "runtime-context.json")
|
|
17
|
+
HISTORY_DIR = File.join(".devflow/context", "runtime-context", "revisions")
|
|
18
|
+
POINTER = File.join(".devflow/context", "runtime-context.json")
|
|
19
19
|
EXTRACTORS = {
|
|
20
20
|
"package.json" => :extract_package_json,
|
|
21
21
|
"requirements.txt" => :extract_requirements_txt,
|
|
@@ -170,7 +170,7 @@ module RuntimeContextCollector
|
|
|
170
170
|
history = File.join(root, HISTORY_DIR, "#{revision}.json")
|
|
171
171
|
DevflowControlIO.atomic_create(history, JSON.pretty_generate(snapshot) + "\n")
|
|
172
172
|
DevflowControlIO.atomic_write(File.join(root, POINTER), JSON.pretty_generate({ "current_revision" => revision, "path" => history.sub("#{root}/", "") }) + "\n")
|
|
173
|
-
DevflowControlIO.append_audit(File.join(root, ".context", "runtime-context", "audit.jsonl"), {
|
|
173
|
+
DevflowControlIO.append_audit(File.join(root, ".devflow/context", "runtime-context", "audit.jsonl"), {
|
|
174
174
|
"event" => "snapshot_collected", "snapshot_revision" => revision,
|
|
175
175
|
"repository_revision" => repository_revision, "coverage_status" => coverage_status
|
|
176
176
|
})
|
|
@@ -69,7 +69,7 @@ def lease_expiry(seconds)
|
|
|
69
69
|
end
|
|
70
70
|
|
|
71
71
|
root = Dir.pwd
|
|
72
|
-
state_path, = DevflowControlIO.resolve_control_path(root, ".planning/STATE.md", :state)
|
|
72
|
+
state_path, = DevflowControlIO.resolve_control_path(root, ".devflow/planning/STATE.md", :state)
|
|
73
73
|
result = catch(:transition_done) do
|
|
74
74
|
lock = DevflowControlIO.acquire_project_lock(root)
|
|
75
75
|
begin
|
|
@@ -129,7 +129,7 @@ result = catch(:transition_done) do
|
|
|
129
129
|
throw :transition_done, result
|
|
130
130
|
end
|
|
131
131
|
rollover_id = "ROL-#{SecureRandom.uuid}"
|
|
132
|
-
relative_path = ".planning/handoffs/#{state.fetch("current_feature")}/#{rollover_id}.json"
|
|
132
|
+
relative_path = ".devflow/planning/handoffs/#{state.fetch("current_feature")}/#{rollover_id}.json"
|
|
133
133
|
absolute_path, = DevflowControlIO.resolve_control_path(root, relative_path, :handoff)
|
|
134
134
|
payload = {
|
|
135
135
|
"schema_version" => 1,
|
|
@@ -144,9 +144,9 @@ result = catch(:transition_done) do
|
|
|
144
144
|
"status" => state["status"], "completed_steps" => state["completed_steps"], "pending_steps" => state["pending_steps"]
|
|
145
145
|
},
|
|
146
146
|
"references" => {
|
|
147
|
-
"state_path" => ".planning/STATE.md",
|
|
147
|
+
"state_path" => ".devflow/planning/STATE.md",
|
|
148
148
|
"workflow_path" => state["workflow_config"],
|
|
149
|
-
"artifact_registry" => ".planning/artifacts/index.yaml"
|
|
149
|
+
"artifact_registry" => ".devflow/planning/artifacts/index.yaml"
|
|
150
150
|
}
|
|
151
151
|
}
|
|
152
152
|
serialized = JSON.generate(payload) + "\n"
|
|
@@ -17,9 +17,9 @@ require_relative "control_io"
|
|
|
17
17
|
module StaticRuntimeContextCollector
|
|
18
18
|
SCHEMA_VERSION = 2
|
|
19
19
|
COLLECTOR_VERSION = "static-runtime-context-v2.1"
|
|
20
|
-
ROOT_DIR = File.join(".context", "static-runtime-context")
|
|
20
|
+
ROOT_DIR = File.join(".devflow/context", "static-runtime-context")
|
|
21
21
|
HISTORY_DIR = File.join(ROOT_DIR, "revisions")
|
|
22
|
-
POINTER = ".context/static-runtime-context.json"
|
|
22
|
+
POINTER = ".devflow/context/static-runtime-context.json"
|
|
23
23
|
AUDIT_PATH = File.join(ROOT_DIR, "audit.jsonl")
|
|
24
24
|
MAX_COMPOSE_BYTES = 1_048_576
|
|
25
25
|
EXCLUDED_ROOTS = %w[node_modules vendor dist build .git].freeze
|
|
@@ -11,7 +11,7 @@ require_relative "control_io"
|
|
|
11
11
|
require_relative "phase_ownership"
|
|
12
12
|
|
|
13
13
|
options = {
|
|
14
|
-
state: ".planning/STATE.md",
|
|
14
|
+
state: ".devflow/planning/STATE.md",
|
|
15
15
|
workflow: nil,
|
|
16
16
|
output: nil,
|
|
17
17
|
write: false,
|
|
@@ -72,10 +72,10 @@ unless ownership["ok"]
|
|
|
72
72
|
puts JSON.pretty_generate(ownership.merge("written" => false))
|
|
73
73
|
exit 0
|
|
74
74
|
end
|
|
75
|
-
workflow_source = options[:workflow] || state["workflow_config"] || ".planning/workflows/#{state.fetch("current_flow")}.yaml"
|
|
75
|
+
workflow_source = options[:workflow] || state["workflow_config"] || ".devflow/planning/workflows/#{state.fetch("current_flow")}.yaml"
|
|
76
76
|
workflow_path, = DevflowControlIO.resolve_control_path(root, workflow_source, :workflow)
|
|
77
77
|
workflow = load_yaml_file(workflow_path)
|
|
78
|
-
registry_source = options[:output] || workflow.dig("artifact_registry", "source") || ".planning/artifacts/index.yaml"
|
|
78
|
+
registry_source = options[:output] || workflow.dig("artifact_registry", "source") || ".devflow/planning/artifacts/index.yaml"
|
|
79
79
|
existing_registry_path, registry_path = DevflowControlIO.resolve_control_path(root, registry_source, :registry)
|
|
80
80
|
existing_by_path = {}
|
|
81
81
|
if options[:preserve] && File.exist?(existing_registry_path)
|
|
@@ -112,7 +112,7 @@ end
|
|
|
112
112
|
|
|
113
113
|
def questions_registry_entry(root, state, existing_by_path)
|
|
114
114
|
feature = state.fetch("current_feature", "").to_s
|
|
115
|
-
path = ".planning/features/#{feature}/questions.yaml"
|
|
115
|
+
path = ".devflow/planning/features/#{feature}/questions.yaml"
|
|
116
116
|
absolute, = DevflowControlIO.resolve_control_path(root, path, :artifact)
|
|
117
117
|
exists = File.exist?(absolute)
|
|
118
118
|
entry = {
|
|
@@ -180,7 +180,7 @@ artifacts = collect_outputs(workflow).map do |step, output|
|
|
|
180
180
|
}.reject { |_, value| value.nil? || value == [] }
|
|
181
181
|
end
|
|
182
182
|
|
|
183
|
-
questions_path = ".planning/features/#{state.fetch("current_feature", "")}/questions.yaml"
|
|
183
|
+
questions_path = ".devflow/planning/features/#{state.fetch("current_feature", "")}/questions.yaml"
|
|
184
184
|
questions_entry = questions_registry_entry(root, state, existing_by_path)
|
|
185
185
|
question_index = artifacts.index { |artifact| artifact["path"] == questions_path }
|
|
186
186
|
if question_index
|