prizmkit 1.1.110 → 1.1.112
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/bundled/VERSION.json +3 -3
- package/bundled/agents/prizm-dev-team-reviewer.md +15 -0
- package/bundled/dev-pipeline/prizmkit_runtime/interoperability.py +1 -0
- package/bundled/dev-pipeline/scripts/generate-bootstrap-prompt.py +55 -76
- package/bundled/dev-pipeline/scripts/generate-bugfix-prompt.py +283 -421
- package/bundled/dev-pipeline/scripts/generate-recovery-prompt.py +1 -1
- package/bundled/dev-pipeline/scripts/generate-refactor-prompt.py +259 -481
- package/bundled/dev-pipeline/scripts/init-bugfix-pipeline.py +34 -0
- package/bundled/dev-pipeline/scripts/init-pipeline.py +12 -0
- package/bundled/dev-pipeline/scripts/init-refactor-pipeline.py +24 -1
- package/bundled/dev-pipeline/scripts/prompt_framework.py +312 -0
- package/bundled/dev-pipeline/scripts/update-bug-status.py +87 -20
- package/bundled/dev-pipeline/scripts/update-feature-status.py +82 -16
- package/bundled/dev-pipeline/scripts/update-refactor-status.py +68 -28
- package/bundled/dev-pipeline/scripts/utils.py +171 -0
- package/bundled/dev-pipeline/templates/bootstrap-prompt.md +1 -1
- package/bundled/dev-pipeline/templates/bootstrap-tier2.md +10 -18
- package/bundled/dev-pipeline/templates/bootstrap-tier3.md +14 -25
- package/bundled/dev-pipeline/templates/bug-fix-list-schema.json +9 -1
- package/bundled/dev-pipeline/templates/bugfix-bootstrap-prompt.md +11 -8
- package/bundled/dev-pipeline/templates/refactor-bootstrap-prompt.md +122 -182
- package/bundled/dev-pipeline/templates/sections/bugfix-artifacts.md +16 -0
- package/bundled/dev-pipeline/templates/sections/bugfix-critical-paths.md +12 -0
- package/bundled/dev-pipeline/templates/sections/bugfix-mission.md +9 -0
- package/bundled/dev-pipeline/templates/sections/bugfix-phase-commit-report.md +31 -0
- package/bundled/dev-pipeline/templates/sections/bugfix-phase-critic.md +22 -0
- package/bundled/dev-pipeline/templates/sections/bugfix-phase-diagnose-plan.md +23 -0
- package/bundled/dev-pipeline/templates/sections/bugfix-phase-implement.md +20 -0
- package/bundled/dev-pipeline/templates/sections/bugfix-phase-init.md +9 -0
- package/bundled/dev-pipeline/templates/sections/bugfix-phase-manual-verification.md +15 -0
- package/bundled/dev-pipeline/templates/sections/bugfix-phase-review.md +29 -0
- package/bundled/dev-pipeline/templates/sections/bugfix-reminders.md +11 -0
- package/bundled/dev-pipeline/templates/sections/bugfix-session-context.md +7 -0
- package/bundled/dev-pipeline/templates/sections/bugfix-session-status.md +31 -0
- package/bundled/dev-pipeline/templates/sections/bugfix-task-contract.md +40 -0
- package/bundled/dev-pipeline/templates/sections/checkpoint-system.md +1 -1
- package/bundled/dev-pipeline/templates/sections/failure-capture.md +2 -2
- package/bundled/dev-pipeline/templates/sections/phase-browser-verification-auto.md +1 -1
- package/bundled/dev-pipeline/templates/sections/refactor-artifacts.md +17 -0
- package/bundled/dev-pipeline/templates/sections/refactor-critical-paths.md +13 -0
- package/bundled/dev-pipeline/templates/sections/refactor-mission.md +9 -0
- package/bundled/dev-pipeline/templates/sections/refactor-phase-commit-report.md +37 -0
- package/bundled/dev-pipeline/templates/sections/refactor-phase-critic.md +22 -0
- package/bundled/dev-pipeline/templates/sections/refactor-phase-implement.md +16 -0
- package/bundled/dev-pipeline/templates/sections/refactor-phase-init.md +9 -0
- package/bundled/dev-pipeline/templates/sections/refactor-phase-plan.md +22 -0
- package/bundled/dev-pipeline/templates/sections/refactor-phase-review.md +19 -0
- package/bundled/dev-pipeline/templates/sections/refactor-reminders.md +11 -0
- package/bundled/dev-pipeline/templates/sections/refactor-session-context.md +7 -0
- package/bundled/dev-pipeline/templates/sections/refactor-session-status.md +28 -0
- package/bundled/dev-pipeline/templates/sections/refactor-task-contract.md +52 -0
- package/bundled/dev-pipeline/tests/test_generate_bootstrap_prompt.py +122 -5
- package/bundled/dev-pipeline/tests/test_generate_bugfix_prompt.py +122 -0
- package/bundled/dev-pipeline/tests/test_generate_refactor_prompt.py +124 -0
- package/bundled/dev-pipeline/tests/test_python_runner_parity.py +197 -0
- package/bundled/dev-pipeline/tests/test_unified_cli.py +7 -3
- package/bundled/dev-pipeline/tests/test_utils.py +66 -1
- package/bundled/skills/_metadata.json +1 -1
- package/bundled/skills/app-planner/SKILL.md +8 -7
- package/bundled/skills/app-planner/references/project-brief-guide.md +2 -2
- package/bundled/skills/app-planner/references/rules/backend/derivation-rules.md +1 -1
- package/bundled/skills/app-planner/references/rules/frontend/derivation-rules.md +1 -1
- package/bundled/skills/app-planner/references/rules-configuration.md +53 -26
- package/bundled/skills/bug-fix-workflow/SKILL.md +191 -336
- package/bundled/skills/bug-planner/SKILL.md +6 -5
- package/bundled/skills/bug-planner/references/critic-and-verification.md +3 -3
- package/bundled/skills/bug-planner/references/schema-validation.md +2 -1
- package/bundled/skills/bug-planner/scripts/validate-bug-list.py +30 -1
- package/bundled/skills/bugfix-pipeline-launcher/SKILL.md +16 -16
- package/bundled/skills/bugfix-pipeline-launcher/references/configuration.md +2 -2
- package/bundled/skills/feature-pipeline-launcher/SKILL.md +19 -11
- package/bundled/skills/feature-planner/SKILL.md +9 -11
- package/bundled/skills/feature-planner/assets/planning-guide.md +1 -1
- package/bundled/skills/feature-planner/references/decomposition-patterns.md +1 -1
- package/bundled/skills/feature-planner/references/error-recovery.md +2 -1
- package/bundled/skills/feature-planner/references/incremental-feature-planning.md +2 -2
- package/bundled/skills/feature-planner/references/new-project-planning.md +35 -39
- package/bundled/skills/feature-planner/scripts/validate-and-generate.py +1 -1
- package/bundled/skills/feature-workflow/SKILL.md +169 -298
- package/bundled/skills/prizmkit/SKILL.md +103 -57
- package/bundled/skills/prizmkit-code-review/SKILL.md +97 -94
- package/bundled/skills/prizmkit-code-review/references/review-report-template.md +1 -0
- package/bundled/skills/prizmkit-code-review/references/reviewer-agent-prompt.md +13 -1
- package/bundled/skills/prizmkit-committer/SKILL.md +59 -47
- package/bundled/skills/prizmkit-deploy/SKILL.md +162 -381
- package/bundled/skills/prizmkit-deploy/references/ssh-adapter-flow.md +220 -0
- package/bundled/skills/prizmkit-implement/SKILL.md +51 -40
- package/bundled/skills/prizmkit-init/SKILL.md +4 -3
- package/bundled/skills/prizmkit-plan/SKILL.md +85 -70
- package/bundled/skills/prizmkit-prizm-docs/SKILL.md +94 -73
- package/bundled/skills/prizmkit-prizm-docs/assets/prizm-docs-format.md +20 -18
- package/bundled/skills/prizmkit-prizm-docs/references/op-update.md +18 -14
- package/bundled/skills/prizmkit-retrospective/SKILL.md +56 -48
- package/bundled/skills/prizmkit-retrospective/references/structural-sync-steps.md +79 -27
- package/bundled/skills/prizmkit-test/SKILL.md +138 -141
- package/bundled/skills/prizmkit-test/references/examples.md +10 -8
- package/bundled/skills/prizmkit-test/references/test-generation-steps.md +1 -1
- package/bundled/skills/prizmkit-test/references/test-report-template.md +2 -2
- package/bundled/skills/recovery-workflow/SKILL.md +195 -256
- package/bundled/skills/recovery-workflow/evals/evals.json +21 -13
- package/bundled/skills/recovery-workflow/references/detection.md +48 -39
- package/bundled/skills/recovery-workflow/scripts/detect-recovery-state.py +258 -322
- package/bundled/skills/refactor-pipeline-launcher/SKILL.md +29 -11
- package/bundled/skills/refactor-planner/SKILL.md +2 -2
- package/bundled/skills/refactor-planner/references/behavior-preservation.md +24 -19
- package/bundled/skills/refactor-planner/references/fast-path.md +2 -4
- package/bundled/skills/refactor-planner/references/planning-phases.md +2 -2
- package/bundled/skills/refactor-workflow/SKILL.md +173 -307
- package/package.json +1 -1
- package/src/scaffold.js +5 -0
- package/bundled/dev-pipeline/templates/agent-prompts/reviewer-review.md +0 -6
- package/bundled/skills/feature-workflow/references/brainstorm-guide.md +0 -137
- package/bundled/skills/refactor-workflow/references/brainstorm-guide.md +0 -116
|
@@ -2,11 +2,12 @@
|
|
|
2
2
|
"""
|
|
3
3
|
detect-recovery-state.py — Universal workflow recovery detector.
|
|
4
4
|
|
|
5
|
-
Auto-detects which interactive workflow
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
Auto-detects which interactive workflow or pipeline session was interrupted
|
|
6
|
+
by inspecting git branch names, durable planning artifacts, pipeline state,
|
|
7
|
+
current-workspace plans, review artifacts, and code changes.
|
|
8
8
|
|
|
9
|
-
Does NOT run tests —
|
|
9
|
+
Does NOT run tests — the skill controls test execution so the user can see
|
|
10
|
+
real-time output.
|
|
10
11
|
|
|
11
12
|
Usage:
|
|
12
13
|
python3 detect-recovery-state.py [--project-root .]
|
|
@@ -18,12 +19,9 @@ import os
|
|
|
18
19
|
import re
|
|
19
20
|
import subprocess
|
|
20
21
|
import sys
|
|
22
|
+
from pathlib import Path
|
|
21
23
|
|
|
22
24
|
|
|
23
|
-
# ---------------------------------------------------------------------------
|
|
24
|
-
# Git helper
|
|
25
|
-
# ---------------------------------------------------------------------------
|
|
26
|
-
|
|
27
25
|
def run_git(args, cwd=None):
|
|
28
26
|
"""Run a git command and return stdout, or empty string on failure."""
|
|
29
27
|
try:
|
|
@@ -48,16 +46,37 @@ def detect_main_branch(project_root):
|
|
|
48
46
|
return "main"
|
|
49
47
|
|
|
50
48
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
49
|
+
def relpath(path, project_root):
|
|
50
|
+
return os.path.relpath(path, project_root)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def file_exists(project_root, *parts):
|
|
54
|
+
path = os.path.join(project_root, *parts)
|
|
55
|
+
return path if os.path.isfile(path) else None
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def dir_has_content(project_root, *parts):
|
|
59
|
+
path = os.path.join(project_root, *parts)
|
|
60
|
+
return os.path.isdir(path) and bool(os.listdir(path))
|
|
61
|
+
|
|
54
62
|
|
|
55
63
|
def extract_bug_id_from_branch(branch):
|
|
56
|
-
"""Extract bug ID from branch name like fix/B-001-login-crash
|
|
57
|
-
match = re.match(r"fix/(B-\d+)", branch)
|
|
64
|
+
"""Extract bug ID from branch name like fix/B-001-login-crash -> B-001."""
|
|
65
|
+
match = re.match(r"fix/(B-\d+)", branch or "")
|
|
58
66
|
return match.group(1) if match else None
|
|
59
67
|
|
|
60
68
|
|
|
69
|
+
def latest_bugfix_artifact_id(project_root):
|
|
70
|
+
bugfix_dir = os.path.join(project_root, ".prizmkit", "bugfix")
|
|
71
|
+
if not os.path.isdir(bugfix_dir):
|
|
72
|
+
return None
|
|
73
|
+
bug_ids = sorted(
|
|
74
|
+
d for d in os.listdir(bugfix_dir)
|
|
75
|
+
if os.path.isdir(os.path.join(bugfix_dir, d))
|
|
76
|
+
)
|
|
77
|
+
return bug_ids[-1] if bug_ids else None
|
|
78
|
+
|
|
79
|
+
|
|
61
80
|
def detect_workflow_type(project_root):
|
|
62
81
|
"""Priority-ordered signature matching.
|
|
63
82
|
|
|
@@ -65,294 +84,273 @@ def detect_workflow_type(project_root):
|
|
|
65
84
|
"""
|
|
66
85
|
branch = run_git(["branch", "--show-current"], cwd=project_root)
|
|
67
86
|
|
|
68
|
-
# Priority 1: fix/* branch → bug-fix-workflow
|
|
69
87
|
if branch.startswith("fix/"):
|
|
70
|
-
|
|
71
|
-
|
|
88
|
+
return ("bug-fix-workflow", {
|
|
89
|
+
"bug_id": extract_bug_id_from_branch(branch),
|
|
90
|
+
"branch": branch,
|
|
91
|
+
"signal": "fix branch",
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
if dir_has_content(project_root, ".prizmkit", "state", "bugfix"):
|
|
95
|
+
return ("bug-fix-workflow", {
|
|
96
|
+
"bug_id": extract_bug_id_from_branch(branch) or latest_bugfix_artifact_id(project_root),
|
|
97
|
+
"branch": branch,
|
|
98
|
+
"signal": "bugfix pipeline state",
|
|
99
|
+
})
|
|
100
|
+
|
|
101
|
+
if file_exists(project_root, ".prizmkit", "plans", "bug-fix-list.json"):
|
|
102
|
+
return ("bug-fix-workflow", {
|
|
103
|
+
"bug_id": extract_bug_id_from_branch(branch) or latest_bugfix_artifact_id(project_root),
|
|
104
|
+
"branch": branch,
|
|
105
|
+
"signal": "bug-fix-list.json",
|
|
106
|
+
})
|
|
107
|
+
|
|
108
|
+
bug_id = latest_bugfix_artifact_id(project_root)
|
|
109
|
+
if bug_id:
|
|
110
|
+
return ("bug-fix-workflow", {
|
|
111
|
+
"bug_id": bug_id,
|
|
112
|
+
"branch": branch,
|
|
113
|
+
"signal": "optional bugfix artifacts",
|
|
114
|
+
})
|
|
72
115
|
|
|
73
|
-
# Priority 2: .prizmkit/bugfix/ has content → bug-fix-workflow
|
|
74
|
-
bugfix_dir = os.path.join(project_root, ".prizmkit", "bugfix")
|
|
75
|
-
if os.path.isdir(bugfix_dir):
|
|
76
|
-
bug_ids = sorted(
|
|
77
|
-
d for d in os.listdir(bugfix_dir)
|
|
78
|
-
if os.path.isdir(os.path.join(bugfix_dir, d))
|
|
79
|
-
)
|
|
80
|
-
if bug_ids:
|
|
81
|
-
return ("bug-fix-workflow", {"bug_id": bug_ids[-1], "branch": branch})
|
|
82
|
-
|
|
83
|
-
# Priority 3: refactor/* branch → refactor-workflow
|
|
84
116
|
if branch.startswith("refactor/"):
|
|
85
|
-
return ("refactor-workflow", {"branch": branch})
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
elif os.path.isfile(old_refactor):
|
|
94
|
-
print(f"⚠️ Migration notice: refactor-list.json found in root. "
|
|
95
|
-
f"Please move to .prizmkit/plans/refactor-list.json", file=sys.stderr)
|
|
96
|
-
return ("refactor-workflow", {"branch": branch})
|
|
97
|
-
|
|
98
|
-
# Priority 5: feat/* branch → feature-workflow
|
|
117
|
+
return ("refactor-workflow", {"branch": branch, "signal": "refactor branch"})
|
|
118
|
+
|
|
119
|
+
if file_exists(project_root, ".prizmkit", "plans", "refactor-list.json"):
|
|
120
|
+
return ("refactor-workflow", {"branch": branch, "signal": "refactor-list.json"})
|
|
121
|
+
|
|
122
|
+
if dir_has_content(project_root, ".prizmkit", "state", "refactor"):
|
|
123
|
+
return ("refactor-workflow", {"branch": branch, "signal": "refactor pipeline state"})
|
|
124
|
+
|
|
99
125
|
if branch.startswith("feat/"):
|
|
100
|
-
return ("feature-workflow", {"branch": branch})
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
return ("feature-workflow", {"branch": branch})
|
|
112
|
-
|
|
113
|
-
# No match
|
|
126
|
+
return ("feature-workflow", {"branch": branch, "signal": "feature branch"})
|
|
127
|
+
|
|
128
|
+
if file_exists(project_root, ".prizmkit", "plans", "feature-list.json"):
|
|
129
|
+
return ("feature-workflow", {"branch": branch, "signal": "feature-list.json"})
|
|
130
|
+
|
|
131
|
+
if dir_has_content(project_root, ".prizmkit", "state", "features"):
|
|
132
|
+
return ("feature-workflow", {"branch": branch, "signal": "feature pipeline state"})
|
|
133
|
+
|
|
134
|
+
if file_exists(project_root, "spec.md") or file_exists(project_root, "plan.md"):
|
|
135
|
+
return ("unknown-fast-path", {"branch": branch, "signal": "spec.md or plan.md"})
|
|
136
|
+
|
|
114
137
|
return (None, None)
|
|
115
138
|
|
|
116
139
|
|
|
117
140
|
def detect_other_workflows(project_root, primary_type):
|
|
118
|
-
"""Scan for
|
|
119
|
-
|
|
120
|
-
Returns a list of workflow type strings that also have signals present,
|
|
121
|
-
excluding the primary_type already detected.
|
|
122
|
-
"""
|
|
141
|
+
"""Scan for secondary workflow signals beyond the primary match."""
|
|
123
142
|
others = []
|
|
124
143
|
branch = run_git(["branch", "--show-current"], cwd=project_root)
|
|
125
144
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
]:
|
|
149
|
-
if os.path.isfile(path):
|
|
150
|
-
others.append("refactor-workflow")
|
|
151
|
-
break
|
|
152
|
-
|
|
153
|
-
# Feature signals
|
|
154
|
-
if primary_type != "feature-workflow":
|
|
155
|
-
if branch.startswith("feat/"):
|
|
156
|
-
others.append("feature-workflow")
|
|
157
|
-
else:
|
|
158
|
-
for path in [
|
|
159
|
-
os.path.join(project_root, ".prizmkit", "plans", "feature-list.json"),
|
|
160
|
-
os.path.join(project_root, "feature-list.json"),
|
|
161
|
-
]:
|
|
162
|
-
if os.path.isfile(path):
|
|
163
|
-
others.append("feature-workflow")
|
|
164
|
-
break
|
|
165
|
-
|
|
145
|
+
signals = [
|
|
146
|
+
("bug-fix-workflow", [
|
|
147
|
+
branch.startswith("fix/"),
|
|
148
|
+
file_exists(project_root, ".prizmkit", "plans", "bug-fix-list.json"),
|
|
149
|
+
dir_has_content(project_root, ".prizmkit", "state", "bugfix"),
|
|
150
|
+
latest_bugfix_artifact_id(project_root),
|
|
151
|
+
]),
|
|
152
|
+
("refactor-workflow", [
|
|
153
|
+
branch.startswith("refactor/"),
|
|
154
|
+
file_exists(project_root, ".prizmkit", "plans", "refactor-list.json"),
|
|
155
|
+
dir_has_content(project_root, ".prizmkit", "state", "refactor"),
|
|
156
|
+
]),
|
|
157
|
+
("feature-workflow", [
|
|
158
|
+
branch.startswith("feat/"),
|
|
159
|
+
file_exists(project_root, ".prizmkit", "plans", "feature-list.json"),
|
|
160
|
+
dir_has_content(project_root, ".prizmkit", "state", "features"),
|
|
161
|
+
]),
|
|
162
|
+
]
|
|
163
|
+
|
|
164
|
+
for workflow, checks in signals:
|
|
165
|
+
if workflow != primary_type and any(checks):
|
|
166
|
+
others.append(workflow)
|
|
166
167
|
return others
|
|
167
168
|
|
|
168
169
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
170
|
+
def find_first_existing(project_root, candidates):
|
|
171
|
+
for parts in candidates:
|
|
172
|
+
path = os.path.join(project_root, *parts)
|
|
173
|
+
if os.path.isfile(path) or os.path.isdir(path):
|
|
174
|
+
return relpath(path, project_root)
|
|
175
|
+
return None
|
|
172
176
|
|
|
173
|
-
def infer_bugfix_phase(project_root, bug_id, code_changes, commits_ahead):
|
|
174
|
-
"""Infer bug-fix-workflow phase from artifacts and git state.
|
|
175
177
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
178
|
+
def find_review_artifact(project_root):
|
|
179
|
+
candidates = [
|
|
180
|
+
("review-report.md",),
|
|
181
|
+
("code-review-report.md",),
|
|
182
|
+
(".prizmkit", "review-report.md"),
|
|
183
|
+
(".prizmkit", "code-review", "review-report.md"),
|
|
184
|
+
(".prizmkit", "reviews"),
|
|
185
|
+
]
|
|
186
|
+
return find_first_existing(project_root, candidates)
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
def find_session_artifact(project_root):
|
|
190
|
+
candidates = [
|
|
191
|
+
("context-snapshot.md",),
|
|
192
|
+
("session-summary.md",),
|
|
193
|
+
(".prizmkit", "context-snapshot.md"),
|
|
194
|
+
(".prizmkit", "session-summary.md"),
|
|
195
|
+
]
|
|
196
|
+
return find_first_existing(project_root, candidates)
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
def detect_fast_path_artifacts(project_root):
|
|
200
|
+
artifacts = {}
|
|
201
|
+
for name in ["spec.md", "plan.md"]:
|
|
202
|
+
path = file_exists(project_root, name)
|
|
203
|
+
artifacts[f"{name.replace('.', '_')}_exists"] = bool(path)
|
|
204
|
+
if path:
|
|
205
|
+
artifacts[f"{name.replace('.', '_')}_path"] = relpath(path, project_root)
|
|
206
|
+
|
|
207
|
+
review = find_review_artifact(project_root)
|
|
208
|
+
artifacts["review_artifact_exists"] = bool(review)
|
|
209
|
+
if review:
|
|
210
|
+
artifacts["review_artifact_path"] = review
|
|
211
|
+
|
|
212
|
+
session = find_session_artifact(project_root)
|
|
213
|
+
artifacts["session_artifact_exists"] = bool(session)
|
|
214
|
+
if session:
|
|
215
|
+
artifacts["session_artifact_path"] = session
|
|
216
|
+
|
|
217
|
+
return artifacts
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
def infer_bugfix_phase(project_root, context, code_changes, commits_ahead):
|
|
221
|
+
"""Infer bug-fix recovery phase from optional signals and git state."""
|
|
222
|
+
bug_id = context.get("bug_id") if context else None
|
|
183
223
|
bugfix_dir = os.path.join(project_root, ".prizmkit", "bugfix", bug_id) if bug_id else ""
|
|
184
|
-
has_fix_plan = bugfix_dir and os.path.isfile(os.path.join(bugfix_dir, "fix-plan.md"))
|
|
185
|
-
has_fix_report = bugfix_dir and os.path.isfile(os.path.join(bugfix_dir, "fix-report.md"))
|
|
224
|
+
has_fix_plan = bool(bugfix_dir and os.path.isfile(os.path.join(bugfix_dir, "fix-plan.md")))
|
|
225
|
+
has_fix_report = bool(bugfix_dir and os.path.isfile(os.path.join(bugfix_dir, "fix-report.md")))
|
|
186
226
|
|
|
187
|
-
artifacts =
|
|
227
|
+
artifacts = detect_fast_path_artifacts(project_root)
|
|
228
|
+
artifacts.update({
|
|
188
229
|
"fix_plan_exists": has_fix_plan,
|
|
189
230
|
"fix_report_exists": has_fix_report,
|
|
190
|
-
}
|
|
231
|
+
})
|
|
191
232
|
if has_fix_plan:
|
|
192
|
-
artifacts["fix_plan_path"] = os.path.
|
|
193
|
-
os.path.join(bugfix_dir, "fix-plan.md"), project_root
|
|
194
|
-
)
|
|
233
|
+
artifacts["fix_plan_path"] = relpath(os.path.join(bugfix_dir, "fix-plan.md"), project_root)
|
|
195
234
|
if has_fix_report:
|
|
196
|
-
artifacts["fix_report_path"] = os.path.
|
|
197
|
-
|
|
198
|
-
|
|
235
|
+
artifacts["fix_report_path"] = relpath(os.path.join(bugfix_dir, "fix-report.md"), project_root)
|
|
236
|
+
|
|
237
|
+
has_plan_artifact = artifacts.get("spec_md_exists") or artifacts.get("plan_md_exists") or has_fix_plan
|
|
238
|
+
has_review_artifact = artifacts.get("review_artifact_exists") or has_fix_report
|
|
199
239
|
|
|
200
240
|
if commits_ahead > 0:
|
|
201
241
|
return 7, "Merge Decision", artifacts, \
|
|
202
|
-
f"{commits_ahead} commit(s) ahead — fix
|
|
203
|
-
"merge decision
|
|
242
|
+
f"{commits_ahead} commit(s) ahead — fix may already be committed", \
|
|
243
|
+
"merge decision or branch handoff"
|
|
204
244
|
|
|
205
|
-
if
|
|
245
|
+
if has_review_artifact and code_changes["has_changes"]:
|
|
206
246
|
return 6, "User Verification", artifacts, \
|
|
207
|
-
"
|
|
208
|
-
"user verification
|
|
247
|
+
"review artifact found with code changes", \
|
|
248
|
+
"user verification -> commit -> merge decision"
|
|
209
249
|
|
|
210
|
-
if
|
|
250
|
+
if code_changes["has_changes"]:
|
|
211
251
|
return 5, "Review", artifacts, \
|
|
212
|
-
"
|
|
213
|
-
"code review
|
|
252
|
+
"code/test changes present without review artifact", \
|
|
253
|
+
"run tests if safe -> code review -> verification -> commit"
|
|
214
254
|
|
|
215
|
-
if
|
|
255
|
+
if has_plan_artifact:
|
|
216
256
|
return 4, "Fix", artifacts, \
|
|
217
|
-
"
|
|
218
|
-
"implement fix
|
|
257
|
+
"plan artifact found but no implementation changes", \
|
|
258
|
+
"implement fix -> review -> verification -> commit"
|
|
219
259
|
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
"
|
|
223
|
-
"diagnosis → triage → reproduce → fix → review → commit & merge"
|
|
260
|
+
return 1, "Diagnosis / Triage", artifacts, \
|
|
261
|
+
"bug-fix signal found but no durable implementation artifacts", \
|
|
262
|
+
"restore bug context -> diagnose -> choose recovery action"
|
|
224
263
|
|
|
225
264
|
|
|
226
|
-
def
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
No list file → Phase 1: Brainstorm
|
|
231
|
-
List file, no pipeline state → Phase 3: Launch
|
|
232
|
-
List file + pipeline state → Phase 4: Monitor
|
|
233
|
-
|
|
234
|
-
Checks new path (.prizmkit/plans/<list_filename>) first, then falls back
|
|
235
|
-
to old root-level path with a migration warning.
|
|
236
|
-
"""
|
|
237
|
-
# Check new path first, then old path with fallback warning
|
|
238
|
-
new_list_path = os.path.join(project_root, ".prizmkit", "plans", list_filename)
|
|
239
|
-
old_list_path = os.path.join(project_root, list_filename)
|
|
240
|
-
has_list = os.path.isfile(new_list_path)
|
|
241
|
-
if not has_list and os.path.isfile(old_list_path):
|
|
242
|
-
has_list = True
|
|
243
|
-
print(f"⚠️ Migration notice: {list_filename} found in root. "
|
|
244
|
-
f"Please move to .prizmkit/plans/{list_filename}", file=sys.stderr)
|
|
245
|
-
|
|
246
|
-
# Check new state path first, then old path with fallback warning
|
|
247
|
-
new_state_dir = os.path.join(project_root, ".prizmkit", "state", state_subdir)
|
|
248
|
-
old_state_dir = os.path.join(project_root, "dev-pipeline", "state", state_subdir)
|
|
249
|
-
has_pipeline_state = os.path.isdir(new_state_dir) and bool(os.listdir(new_state_dir))
|
|
250
|
-
if not has_pipeline_state and os.path.isdir(old_state_dir) and bool(os.listdir(old_state_dir)):
|
|
251
|
-
has_pipeline_state = True
|
|
252
|
-
print(f"⚠️ Migration notice: pipeline state found at dev-pipeline/state/{state_subdir}. "
|
|
253
|
-
f"Please move to .prizmkit/state/{state_subdir}", file=sys.stderr)
|
|
265
|
+
def infer_pipeline_workflow_phase(project_root, list_filename, state_subdir, workflow_label):
|
|
266
|
+
list_path = file_exists(project_root, ".prizmkit", "plans", list_filename)
|
|
267
|
+
has_state = dir_has_content(project_root, ".prizmkit", "state", state_subdir)
|
|
268
|
+
fast_path = detect_fast_path_artifacts(project_root)
|
|
254
269
|
|
|
255
270
|
artifacts = {
|
|
256
|
-
f"{workflow_label}_list_exists":
|
|
257
|
-
"pipeline_state_exists":
|
|
271
|
+
f"{workflow_label}_list_exists": bool(list_path),
|
|
272
|
+
"pipeline_state_exists": bool(has_state),
|
|
273
|
+
**fast_path,
|
|
258
274
|
}
|
|
275
|
+
if list_path:
|
|
276
|
+
artifacts[f"{workflow_label}_list_path"] = relpath(list_path, project_root)
|
|
259
277
|
|
|
260
|
-
if
|
|
261
|
-
return 4, "Monitor", artifacts, \
|
|
262
|
-
f"
|
|
263
|
-
"check
|
|
278
|
+
if list_path and has_state:
|
|
279
|
+
return 4, "Monitor / Recover Pipeline", artifacts, \
|
|
280
|
+
f"{list_filename} and pipeline state both exist", \
|
|
281
|
+
"check launcher status or run recovery script"
|
|
264
282
|
|
|
265
|
-
if
|
|
283
|
+
if list_path:
|
|
266
284
|
return 3, "Launch", artifacts, \
|
|
267
|
-
f"
|
|
268
|
-
"launch pipeline
|
|
285
|
+
f"{list_filename} exists without pipeline state", \
|
|
286
|
+
"launch pipeline or inspect/update list"
|
|
287
|
+
|
|
288
|
+
if fast_path.get("spec_md_exists") or fast_path.get("plan_md_exists"):
|
|
289
|
+
return 2, "Fast Path Continuation", artifacts, \
|
|
290
|
+
"current-workspace spec/plan artifact found", \
|
|
291
|
+
"continue implementation/review/commit based on diff"
|
|
269
292
|
|
|
270
|
-
return 1, "
|
|
271
|
-
f"no
|
|
272
|
-
f"{workflow_label}
|
|
293
|
+
return 1, "Route Selection", artifacts, \
|
|
294
|
+
f"no {list_filename} or pipeline state found", \
|
|
295
|
+
f"clarify {workflow_label} intent and choose path"
|
|
273
296
|
|
|
274
297
|
|
|
275
298
|
def infer_feature_phase(project_root):
|
|
276
|
-
"
|
|
277
|
-
return _infer_pipeline_workflow_phase(
|
|
278
|
-
project_root, "feature-list.json", "features", "feature"
|
|
279
|
-
)
|
|
299
|
+
return infer_pipeline_workflow_phase(project_root, "feature-list.json", "features", "feature")
|
|
280
300
|
|
|
281
301
|
|
|
282
302
|
def infer_refactor_phase(project_root):
|
|
283
|
-
"""
|
|
284
|
-
|
|
285
|
-
project_root, "refactor-list.json", "refactor", "refactor"
|
|
286
|
-
)
|
|
303
|
+
return infer_pipeline_workflow_phase(project_root, "refactor-list.json", "refactor", "refactor")
|
|
304
|
+
|
|
287
305
|
|
|
306
|
+
def infer_unknown_fast_path_phase(project_root, code_changes):
|
|
307
|
+
artifacts = detect_fast_path_artifacts(project_root)
|
|
308
|
+
if code_changes["has_changes"]:
|
|
309
|
+
return 5, "Review", artifacts, \
|
|
310
|
+
"spec/plan plus code changes found, but workflow family is unknown", \
|
|
311
|
+
"ask workflow family -> run tests/review -> continue"
|
|
312
|
+
return 2, "Fast Path Continuation", artifacts, \
|
|
313
|
+
"spec/plan found, but workflow family is unknown", \
|
|
314
|
+
"ask whether this is feature, bug fix, or refactor work"
|
|
288
315
|
|
|
289
|
-
# ---------------------------------------------------------------------------
|
|
290
|
-
# Git state helpers
|
|
291
|
-
# ---------------------------------------------------------------------------
|
|
292
316
|
|
|
293
317
|
def detect_commits_ahead(project_root, main_branch="main"):
|
|
294
|
-
"""
|
|
295
|
-
log_output = run_git(
|
|
296
|
-
["log", f"{main_branch}..HEAD", "--oneline"], cwd=project_root
|
|
297
|
-
)
|
|
318
|
+
log_output = run_git(["log", f"{main_branch}..HEAD", "--oneline"], cwd=project_root)
|
|
298
319
|
if log_output:
|
|
299
320
|
return len(log_output.strip().split("\n"))
|
|
300
321
|
return 0
|
|
301
322
|
|
|
302
323
|
|
|
303
324
|
def detect_git_state(project_root, main_branch="main", cached_branch=None):
|
|
304
|
-
"""Detect git branch and change state."""
|
|
305
325
|
current = cached_branch or run_git(["branch", "--show-current"], cwd=project_root)
|
|
306
326
|
|
|
307
|
-
|
|
308
|
-
uncommitted = 0
|
|
309
|
-
diff_stat = run_git(["diff", "--stat"], cwd=project_root)
|
|
310
|
-
if diff_stat:
|
|
311
|
-
lines = diff_stat.strip().split("\n")
|
|
312
|
-
uncommitted = max(0, len(lines) - 1)
|
|
313
|
-
|
|
314
|
-
# Staged changes
|
|
315
|
-
staged = 0
|
|
316
|
-
staged_stat = run_git(["diff", "--cached", "--stat"], cwd=project_root)
|
|
317
|
-
if staged_stat:
|
|
318
|
-
lines = staged_stat.strip().split("\n")
|
|
319
|
-
staged = max(0, len(lines) - 1)
|
|
320
|
-
|
|
327
|
+
uncommitted = run_git(["status", "--porcelain"], cwd=project_root)
|
|
321
328
|
commits_ahead = detect_commits_ahead(project_root, main_branch)
|
|
322
329
|
|
|
323
330
|
return {
|
|
324
331
|
"current_branch": current,
|
|
325
|
-
"
|
|
326
|
-
"staged_files": staged,
|
|
332
|
+
"changed_paths": len([line for line in uncommitted.splitlines() if line.strip()]),
|
|
327
333
|
"commits_ahead_of_main": commits_ahead,
|
|
328
334
|
}
|
|
329
335
|
|
|
330
336
|
|
|
331
|
-
# ---------------------------------------------------------------------------
|
|
332
|
-
# Code change detection (reused from original, workflow-agnostic)
|
|
333
|
-
# ---------------------------------------------------------------------------
|
|
334
|
-
|
|
335
337
|
def detect_code_changes(project_root, main_branch="main"):
|
|
336
|
-
"""Analyze
|
|
337
|
-
|
|
338
|
-
Filters out pipeline/config files that aren't source code — only counts
|
|
339
|
-
files that represent actual implementation work.
|
|
340
|
-
|
|
341
|
-
Uses a file_statuses dict keyed by filepath to avoid double-counting
|
|
342
|
-
files that appear in both committed diff and uncommitted changes.
|
|
343
|
-
"""
|
|
344
|
-
IGNORED_FILES = {
|
|
345
|
-
# Basename-matched list files (root-level legacy paths)
|
|
338
|
+
"""Analyze implementation changes relative to main and working tree."""
|
|
339
|
+
ignored_files = {
|
|
346
340
|
"feature-list.json",
|
|
347
341
|
"bug-fix-list.json",
|
|
348
342
|
"refactor-list.json",
|
|
349
|
-
|
|
343
|
+
"spec.md",
|
|
344
|
+
"plan.md",
|
|
345
|
+
"review-report.md",
|
|
346
|
+
"code-review-report.md",
|
|
347
|
+
"session-summary.md",
|
|
348
|
+
"context-snapshot.md",
|
|
350
349
|
"package-lock.json",
|
|
351
350
|
"yarn.lock",
|
|
352
351
|
"pnpm-lock.yaml",
|
|
353
352
|
}
|
|
354
|
-
|
|
355
|
-
IGNORED_PREFIXES = (
|
|
353
|
+
ignored_prefixes = (
|
|
356
354
|
".prizmkit/",
|
|
357
355
|
".agents/",
|
|
358
356
|
".codex/",
|
|
@@ -360,80 +358,46 @@ def detect_code_changes(project_root, main_branch="main"):
|
|
|
360
358
|
".codebuddy/",
|
|
361
359
|
)
|
|
362
360
|
|
|
363
|
-
def
|
|
364
|
-
"""Return True if this file represents implementation code."""
|
|
361
|
+
def is_implementation_file(filepath):
|
|
365
362
|
basename = os.path.basename(filepath)
|
|
366
|
-
if basename in
|
|
363
|
+
if basename in ignored_files:
|
|
364
|
+
return False
|
|
365
|
+
if any(filepath.startswith(prefix) for prefix in ignored_prefixes):
|
|
367
366
|
return False
|
|
368
|
-
for prefix in IGNORED_PREFIXES:
|
|
369
|
-
if filepath.startswith(prefix):
|
|
370
|
-
return False
|
|
371
367
|
return True
|
|
372
368
|
|
|
373
|
-
|
|
374
|
-
# Later sources (uncommitted, untracked) update the status if the file
|
|
375
|
-
# was already seen in a committed diff.
|
|
376
|
-
file_statuses = {} # filepath → "M" | "A" | "D"
|
|
377
|
-
|
|
378
|
-
# Diff relative to main (committed changes on branch)
|
|
379
|
-
diff_output = run_git(
|
|
380
|
-
["diff", main_branch, "--name-status"], cwd=project_root
|
|
381
|
-
)
|
|
369
|
+
file_statuses = {}
|
|
382
370
|
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
if len(parts) < 2:
|
|
389
|
-
continue
|
|
390
|
-
status, filepath = parts[0][0], parts[1] # first char of status
|
|
391
|
-
if not is_source_file(filepath):
|
|
392
|
-
continue
|
|
393
|
-
file_statuses[filepath] = status
|
|
394
|
-
|
|
395
|
-
# Uncommitted working tree changes — update status for already-seen files
|
|
396
|
-
uncommitted = run_git(["diff", "--name-status"], cwd=project_root)
|
|
397
|
-
if uncommitted:
|
|
398
|
-
for line in uncommitted.strip().split("\n"):
|
|
399
|
-
if not line.strip():
|
|
400
|
-
continue
|
|
371
|
+
for command in (["diff", main_branch, "--name-status"], ["diff", "--name-status"]):
|
|
372
|
+
output = run_git(command, cwd=project_root)
|
|
373
|
+
if not output:
|
|
374
|
+
continue
|
|
375
|
+
for line in output.splitlines():
|
|
401
376
|
parts = line.split("\t", 1)
|
|
402
377
|
if len(parts) < 2:
|
|
403
378
|
continue
|
|
404
379
|
status, filepath = parts[0][0], parts[1]
|
|
405
|
-
if
|
|
406
|
-
|
|
407
|
-
if filepath not in file_statuses:
|
|
408
|
-
file_statuses[filepath] = "M" # uncommitted change = modified
|
|
409
|
-
# If already tracked from branch diff, keep the branch-level status
|
|
380
|
+
if is_implementation_file(filepath):
|
|
381
|
+
file_statuses.setdefault(filepath, status)
|
|
410
382
|
|
|
411
|
-
|
|
412
|
-
untracked = run_git(
|
|
413
|
-
["ls-files", "--others", "--exclude-standard"], cwd=project_root
|
|
414
|
-
)
|
|
383
|
+
untracked = run_git(["ls-files", "--others", "--exclude-standard"], cwd=project_root)
|
|
415
384
|
if untracked:
|
|
416
|
-
for filepath in untracked.
|
|
385
|
+
for filepath in untracked.splitlines():
|
|
417
386
|
filepath = filepath.strip()
|
|
418
|
-
if filepath and
|
|
419
|
-
|
|
420
|
-
file_statuses[filepath] = "A" # untracked = added
|
|
387
|
+
if filepath and is_implementation_file(filepath):
|
|
388
|
+
file_statuses.setdefault(filepath, "A")
|
|
421
389
|
|
|
422
|
-
|
|
390
|
+
test_pattern = re.compile(r"(test|spec|__tests__|\.test\.|\.spec\.)", re.IGNORECASE)
|
|
391
|
+
dirs = set()
|
|
423
392
|
result = {
|
|
424
393
|
"files_modified": 0,
|
|
425
394
|
"files_added": 0,
|
|
426
395
|
"files_deleted": 0,
|
|
427
396
|
"test_files_touched": 0,
|
|
428
397
|
"directories_touched": [],
|
|
429
|
-
"has_changes":
|
|
398
|
+
"has_changes": bool(file_statuses),
|
|
430
399
|
}
|
|
431
400
|
|
|
432
|
-
test_patterns = re.compile(
|
|
433
|
-
r"(test|spec|__tests__|\.test\.|\.spec\.)", re.IGNORECASE
|
|
434
|
-
)
|
|
435
|
-
dirs = set()
|
|
436
|
-
|
|
437
401
|
for filepath, status in file_statuses.items():
|
|
438
402
|
if status == "M":
|
|
439
403
|
result["files_modified"] += 1
|
|
@@ -441,8 +405,7 @@ def detect_code_changes(project_root, main_branch="main"):
|
|
|
441
405
|
result["files_added"] += 1
|
|
442
406
|
elif status == "D":
|
|
443
407
|
result["files_deleted"] += 1
|
|
444
|
-
|
|
445
|
-
if test_patterns.search(filepath):
|
|
408
|
+
if test_pattern.search(filepath):
|
|
446
409
|
result["test_files_touched"] += 1
|
|
447
410
|
parent = os.path.dirname(filepath)
|
|
448
411
|
if parent:
|
|
@@ -450,28 +413,14 @@ def detect_code_changes(project_root, main_branch="main"):
|
|
|
450
413
|
dirs.add(os.sep.join(parts[:2]) + "/")
|
|
451
414
|
|
|
452
415
|
result["directories_touched"] = sorted(dirs)
|
|
453
|
-
result["has_changes"] = len(file_statuses) > 0
|
|
454
|
-
|
|
455
416
|
return result
|
|
456
417
|
|
|
457
418
|
|
|
458
|
-
# ---------------------------------------------------------------------------
|
|
459
|
-
# Main
|
|
460
|
-
# ---------------------------------------------------------------------------
|
|
461
|
-
|
|
462
419
|
def main():
|
|
463
|
-
parser = argparse.ArgumentParser(
|
|
464
|
-
|
|
465
|
-
)
|
|
466
|
-
parser.add_argument(
|
|
467
|
-
"--project-root",
|
|
468
|
-
default=None,
|
|
469
|
-
help="Project root directory (default: auto-detect from git)",
|
|
470
|
-
)
|
|
471
|
-
|
|
420
|
+
parser = argparse.ArgumentParser(description="Auto-detect interrupted workflow state for recovery")
|
|
421
|
+
parser.add_argument("--project-root", default=None, help="Project root directory (default: auto-detect from git)")
|
|
472
422
|
args = parser.parse_args()
|
|
473
423
|
|
|
474
|
-
# Resolve project root
|
|
475
424
|
if args.project_root:
|
|
476
425
|
project_root = os.path.abspath(args.project_root)
|
|
477
426
|
else:
|
|
@@ -479,46 +428,34 @@ def main():
|
|
|
479
428
|
project_root = git_root if git_root else os.getcwd()
|
|
480
429
|
|
|
481
430
|
main_branch = detect_main_branch(project_root)
|
|
482
|
-
|
|
483
|
-
# Step 1: Detect workflow type (also caches branch name)
|
|
484
431
|
workflow_type, context = detect_workflow_type(project_root)
|
|
485
432
|
|
|
486
433
|
if workflow_type is None:
|
|
487
|
-
|
|
434
|
+
print(json.dumps({
|
|
488
435
|
"detected": False,
|
|
489
|
-
"message":
|
|
490
|
-
|
|
491
|
-
"Use /feature-workflow, /bug-fix-workflow, or /refactor-workflow to start."
|
|
492
|
-
),
|
|
493
|
-
}
|
|
494
|
-
print(json.dumps(report, indent=2))
|
|
436
|
+
"message": "No interrupted workflow detected. Use /feature-workflow, /bug-fix-workflow, or /refactor-workflow to start.",
|
|
437
|
+
}, indent=2))
|
|
495
438
|
sys.exit(0)
|
|
496
439
|
|
|
497
|
-
|
|
498
|
-
other_workflows = detect_other_workflows(project_root, workflow_type)
|
|
499
|
-
|
|
500
|
-
# Step 2: Collect git state and code changes once (shared across phase inference + report)
|
|
501
|
-
cached_branch = context.get("branch")
|
|
440
|
+
cached_branch = context.get("branch") if context else None
|
|
502
441
|
git_state = detect_git_state(project_root, main_branch, cached_branch=cached_branch)
|
|
503
442
|
code_changes = detect_code_changes(project_root, main_branch)
|
|
443
|
+
other_workflows = detect_other_workflows(project_root, workflow_type)
|
|
504
444
|
|
|
505
|
-
# Step 3: Infer phase within the detected workflow
|
|
506
445
|
if workflow_type == "bug-fix-workflow":
|
|
507
|
-
phase, phase_name, artifacts, reason, remaining =
|
|
508
|
-
|
|
509
|
-
|
|
446
|
+
phase, phase_name, artifacts, reason, remaining = infer_bugfix_phase(
|
|
447
|
+
project_root, context, code_changes, git_state["commits_ahead_of_main"]
|
|
448
|
+
)
|
|
510
449
|
elif workflow_type == "feature-workflow":
|
|
511
|
-
phase, phase_name, artifacts, reason, remaining =
|
|
512
|
-
infer_feature_phase(project_root)
|
|
450
|
+
phase, phase_name, artifacts, reason, remaining = infer_feature_phase(project_root)
|
|
513
451
|
elif workflow_type == "refactor-workflow":
|
|
514
|
-
phase, phase_name, artifacts, reason, remaining =
|
|
515
|
-
|
|
452
|
+
phase, phase_name, artifacts, reason, remaining = infer_refactor_phase(project_root)
|
|
453
|
+
elif workflow_type == "unknown-fast-path":
|
|
454
|
+
phase, phase_name, artifacts, reason, remaining = infer_unknown_fast_path_phase(project_root, code_changes)
|
|
516
455
|
else:
|
|
517
|
-
# Should never reach here
|
|
518
456
|
print(json.dumps({"detected": False, "message": "Unknown workflow type"}), file=sys.stderr)
|
|
519
457
|
sys.exit(1)
|
|
520
458
|
|
|
521
|
-
# Step 4: Build report
|
|
522
459
|
report = {
|
|
523
460
|
"detected": True,
|
|
524
461
|
"workflow_type": workflow_type,
|
|
@@ -533,7 +470,6 @@ def main():
|
|
|
533
470
|
"remaining_work": remaining,
|
|
534
471
|
},
|
|
535
472
|
}
|
|
536
|
-
|
|
537
473
|
if other_workflows:
|
|
538
474
|
report["other_interrupted_workflows"] = other_workflows
|
|
539
475
|
|