@guanlin4924/devflow-pi 0.1.12 → 0.1.14
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 +1 -4
- package/package.json +1 -1
- package/plugins/devflow-core/extensions/devflow-core.ts +235 -148
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/advance_state.rb +47 -15
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/control_io.rb +42 -0
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/init_state.rb +21 -2
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/phase_ownership.rb +154 -0
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/repair_control_plane.rb +35 -26
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/sync_artifacts.rb +18 -7
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/validate_state.rb +33 -8
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
require "json"
|
|
5
5
|
require "optparse"
|
|
6
6
|
require "yaml"
|
|
7
|
+
require_relative "control_io"
|
|
8
|
+
require_relative "phase_ownership"
|
|
7
9
|
|
|
8
10
|
module WorkflowStateValidator
|
|
9
11
|
REQUIRED_STATE_FIELDS = %w[
|
|
@@ -18,12 +20,18 @@ module WorkflowStateValidator
|
|
|
18
20
|
|
|
19
21
|
TERMINAL_ARTIFACT_STATUSES = %w[approved completed passed].freeze
|
|
20
22
|
NON_TERMINAL_ARTIFACT_STATUSES = %w[planned generated pending_rerun stale failed].freeze
|
|
23
|
+
TERMINAL_WORKFLOW_STATUSES = %w[completed failed cancelled].freeze
|
|
21
24
|
|
|
22
25
|
module_function
|
|
23
26
|
|
|
24
|
-
def validate(root:, state_path:, state_override: nil, workflow_override: nil, artifact_registry_override: nil, strict_artifact_status: true, strict_registry_revision: true)
|
|
27
|
+
def validate(root:, state_path:, state_override: nil, workflow_override: nil, artifact_registry_override: nil, strict_artifact_status: true, strict_registry_revision: true, phase_owner_override: nil)
|
|
25
28
|
root = File.expand_path(root)
|
|
26
|
-
|
|
29
|
+
canonical_state_path, = DevflowControlIO.resolve_control_path(root, ".planning/STATE.md", :state)
|
|
30
|
+
unless File.expand_path(state_path, root) == canonical_state_path
|
|
31
|
+
issues = [issue("error", "invalid_control_path", "STATE.md path must be .planning/STATE.md")]
|
|
32
|
+
return result(false, state_path, nil, nil, issues)
|
|
33
|
+
end
|
|
34
|
+
state_path = canonical_state_path
|
|
27
35
|
issues = []
|
|
28
36
|
|
|
29
37
|
state = state_override || load_state(state_path, issues)
|
|
@@ -34,8 +42,14 @@ module WorkflowStateValidator
|
|
|
34
42
|
end
|
|
35
43
|
return result(false, state_path, nil, nil, issues) if issues.any? { |entry| entry["severity"] == "error" }
|
|
36
44
|
|
|
45
|
+
ownership = PhaseOwnership.validate_state(root: root, state: state, owner_override: phase_owner_override)
|
|
46
|
+
unless ownership["ok"]
|
|
47
|
+
issues << issue("error", ownership["reason"], ownership["message"], ownership.reject { |key, _| %w[ok reason message].include?(key) })
|
|
48
|
+
return result(false, state_path, nil, nil, issues)
|
|
49
|
+
end
|
|
50
|
+
|
|
37
51
|
workflow_path = state["workflow_config"] || File.join(".planning", "workflows", "#{state.fetch("current_flow")}.yaml")
|
|
38
|
-
abs_workflow_path =
|
|
52
|
+
abs_workflow_path, workflow_path = DevflowControlIO.resolve_control_path(root, workflow_path, :workflow)
|
|
39
53
|
workflow = workflow_override || load_yaml(abs_workflow_path, issues, "workflow_config")
|
|
40
54
|
return result(false, state_path, workflow_path, nil, issues) unless workflow
|
|
41
55
|
|
|
@@ -103,7 +117,7 @@ module WorkflowStateValidator
|
|
|
103
117
|
|
|
104
118
|
registry = registry_override
|
|
105
119
|
unless registry
|
|
106
|
-
abs_registry_path =
|
|
120
|
+
abs_registry_path, = DevflowControlIO.resolve_control_path(root, registry_path, :registry)
|
|
107
121
|
unless File.exist?(abs_registry_path)
|
|
108
122
|
issues << issue("error", "missing_artifact_registry", "Artifact registry does not exist", path: registry_path)
|
|
109
123
|
return {}
|
|
@@ -121,7 +135,7 @@ module WorkflowStateValidator
|
|
|
121
135
|
)
|
|
122
136
|
end
|
|
123
137
|
Array(registry["artifacts"]).to_h { |artifact| [artifact.fetch("path"), artifact] }
|
|
124
|
-
rescue ArgumentError, TypeError, Psych::SyntaxError => e
|
|
138
|
+
rescue ArgumentError, TypeError, Psych::SyntaxError, DevflowControlIO::InvalidControlPath => e
|
|
125
139
|
issues << issue("error", "invalid_artifact_registry", e.message, path: registry_path)
|
|
126
140
|
{}
|
|
127
141
|
end
|
|
@@ -145,8 +159,10 @@ module WorkflowStateValidator
|
|
|
145
159
|
unknown.each do |step_id|
|
|
146
160
|
issues << issue("error", "unknown_tracked_step", "Tracked step is not defined in the active workflow", step: step_id)
|
|
147
161
|
end
|
|
148
|
-
|
|
149
|
-
|
|
162
|
+
unless %w[failed cancelled].include?(state["status"])
|
|
163
|
+
missing.each do |step_id|
|
|
164
|
+
issues << issue("error", "missing_tracked_step", "Workflow step is missing from both completed_steps and pending_steps", step: step_id)
|
|
165
|
+
end
|
|
150
166
|
end
|
|
151
167
|
|
|
152
168
|
current_step = state["current_step"]
|
|
@@ -162,6 +178,10 @@ module WorkflowStateValidator
|
|
|
162
178
|
missing_completed.each do |step_id|
|
|
163
179
|
issues << issue("error", "completed_status_missing_step", "Workflow status is completed but a workflow step is not completed", step: step_id)
|
|
164
180
|
end
|
|
181
|
+
elsif %w[failed cancelled].include?(state["status"])
|
|
182
|
+
if pending_ids.any?
|
|
183
|
+
issues << issue("error", "terminal_with_pending_steps", "Terminal workflow status must not retain pending steps", status: state["status"])
|
|
184
|
+
end
|
|
165
185
|
elsif pending_ids.empty?
|
|
166
186
|
issues << issue("error", "non_completed_without_pending_steps", "Workflow has no pending steps but status is not completed")
|
|
167
187
|
end
|
|
@@ -589,7 +609,12 @@ if __FILE__ == $PROGRAM_NAME
|
|
|
589
609
|
end.parse!
|
|
590
610
|
|
|
591
611
|
root = Dir.pwd
|
|
592
|
-
|
|
612
|
+
begin
|
|
613
|
+
state_path, = DevflowControlIO.resolve_control_path(root, options[:state], :state)
|
|
614
|
+
rescue DevflowControlIO::InvalidControlPath => error
|
|
615
|
+
puts JSON.pretty_generate({ "ok" => false, "errors" => [{ "code" => "invalid_control_path", "message" => error.message }] })
|
|
616
|
+
exit 1
|
|
617
|
+
end
|
|
593
618
|
validation = WorkflowStateValidator.validate(
|
|
594
619
|
root: root,
|
|
595
620
|
state_path: state_path,
|