@chenmk/superflow 0.1.0
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/INSTALL.en.md +106 -0
- package/INSTALL.md +664 -0
- package/LICENSE +21 -0
- package/README.md +142 -0
- package/README.zh-CN.md +117 -0
- package/assets/context-templates/business-rules.md +98 -0
- package/assets/context-templates/decisions.md +153 -0
- package/assets/context-templates/external-systems.md +166 -0
- package/assets/context-templates/incidents.md +89 -0
- package/assets/manifest.json +53 -0
- package/assets/prompts/superflow-archive.md +9 -0
- package/assets/prompts/superflow-clarify.md +10 -0
- package/assets/prompts/superflow-design.md +10 -0
- package/assets/prompts/superflow-docs.md +10 -0
- package/assets/prompts/superflow-implement.md +10 -0
- package/assets/prompts/superflow-pipeline.md +13 -0
- package/assets/prompts/superflow-verify.md +10 -0
- package/assets/rules/superflow-phase-guard.md +50 -0
- package/assets/scripts/claude-auto-backup-hook.sh +313 -0
- package/assets/scripts/codex-auto-backup-hook.sh +361 -0
- package/assets/scripts/install-sql-pre-commit.sh +44 -0
- package/assets/scripts/superflow-contract-hooks.sh +744 -0
- package/assets/scripts/superflow-delivery-check.sh +315 -0
- package/assets/scripts/superflow-dependency-update-hook.sh +161 -0
- package/assets/scripts/superflow-enforce-hook.sh +70 -0
- package/assets/scripts/superflow-hook-guard.sh +132 -0
- package/assets/scripts/superflow-integration-evidence-hook.sh +80 -0
- package/assets/scripts/superflow-sql-sync-hook.py +950 -0
- package/assets/scripts/superflow-test-report-lint.py +433 -0
- package/assets/scripts/superflow-verify-integration.sh +90 -0
- package/assets/scripts/sync-settings-json.py +52 -0
- package/assets/skills/api-doc-changelog/SKILL.md +193 -0
- package/assets/skills/openspec-apply-change/SKILL.md +156 -0
- package/assets/skills/openspec-archive-change/SKILL.md +114 -0
- package/assets/skills/openspec-explore/SKILL.md +288 -0
- package/assets/skills/openspec-propose/SKILL.md +110 -0
- package/assets/skills/superflow-archive/SKILL.md +61 -0
- package/assets/skills/superflow-clarify/SKILL.md +146 -0
- package/assets/skills/superflow-clarify/agents/openai.yaml +4 -0
- package/assets/skills/superflow-design/SKILL.md +83 -0
- package/assets/skills/superflow-design/agents/openai.yaml +4 -0
- package/assets/skills/superflow-docs/SKILL.md +316 -0
- package/assets/skills/superflow-docs/agents/openai.yaml +4 -0
- package/assets/skills/superflow-hotfix/SKILL.md +48 -0
- package/assets/skills/superflow-implement/SKILL.md +461 -0
- package/assets/skills/superflow-implement/agents/openai.yaml +4 -0
- package/assets/skills/superflow-pipeline/SKILL.md +844 -0
- package/assets/skills/superflow-pipeline/agents/openai.yaml +4 -0
- package/assets/skills/superflow-pipeline/references/api-design-template.md +431 -0
- package/assets/skills/superflow-pipeline/references/architecture-design-template.md +119 -0
- package/assets/skills/superflow-pipeline/references/batch-prompt-template.md +536 -0
- package/assets/skills/superflow-pipeline/references/batch-split-guide.md +140 -0
- package/assets/skills/superflow-pipeline/references/decision-point.md +30 -0
- package/assets/skills/superflow-pipeline/references/dirty-worktree.md +35 -0
- package/assets/skills/superflow-pipeline/references/document-templates.md +123 -0
- package/assets/skills/superflow-pipeline/references/feature-gated-workflow.md +124 -0
- package/assets/skills/superflow-pipeline/references/implementation-prompt-template.md +1056 -0
- package/assets/skills/superflow-pipeline/references/mock-strategy-guide.md +86 -0
- package/assets/skills/superflow-pipeline/references/openspec-format.md +57 -0
- package/assets/skills/superflow-pipeline/references/orchestration.md +639 -0
- package/assets/skills/superflow-pipeline/references/p0-baseline-template.md +174 -0
- package/assets/skills/superflow-pipeline/references/project-config.md +40 -0
- package/assets/skills/superflow-pipeline/references/prompt-usage-template.md +152 -0
- package/assets/skills/superflow-pipeline/references/quality-gate.md +299 -0
- package/assets/skills/superflow-pipeline/references/quality-standards.md +190 -0
- package/assets/skills/superflow-pipeline/references/reviewer-checklist.md +154 -0
- package/assets/skills/superflow-pipeline/references/sql-risk-review-checklist.md +323 -0
- package/assets/skills/superflow-pipeline/references/subagent-progress.md +90 -0
- package/assets/skills/superflow-pipeline/references/superpower-technical-design-template.md +125 -0
- package/assets/skills/superflow-pipeline/references/test-execution-template.md +220 -0
- package/assets/skills/superflow-pipeline/references/test-guide.md +30 -0
- package/assets/skills/superflow-pipeline/references/traceability-matrix.md +106 -0
- package/assets/skills/superflow-pipeline/references/validation-integrity.md +134 -0
- package/assets/skills/superflow-pipeline/scripts/superflow-archive.sh +178 -0
- package/assets/skills/superflow-pipeline/scripts/superflow-env.sh +118 -0
- package/assets/skills/superflow-pipeline/scripts/superflow-guard.sh +428 -0
- package/assets/skills/superflow-pipeline/scripts/superflow-handoff.sh +296 -0
- package/assets/skills/superflow-pipeline/scripts/superflow-state.sh +574 -0
- package/assets/skills/superflow-pipeline/scripts/superflow-status.sh +172 -0
- package/assets/skills/superflow-pipeline/scripts/superflow-yaml-validate.sh +138 -0
- package/assets/skills/superflow-table-impact-analysis/SKILL.md +77 -0
- package/assets/skills/superflow-tweak/SKILL.md +46 -0
- package/assets/skills/superflow-verify/SKILL.md +112 -0
- package/assets/skills-en/api-doc-changelog/SKILL.md +193 -0
- package/assets/skills-en/openspec-apply-change/SKILL.md +156 -0
- package/assets/skills-en/openspec-archive-change/SKILL.md +114 -0
- package/assets/skills-en/openspec-explore/SKILL.md +288 -0
- package/assets/skills-en/openspec-propose/SKILL.md +110 -0
- package/assets/skills-en/superflow-archive/SKILL.md +61 -0
- package/assets/skills-en/superflow-clarify/SKILL.md +146 -0
- package/assets/skills-en/superflow-clarify/agents/openai.yaml +4 -0
- package/assets/skills-en/superflow-design/SKILL.md +83 -0
- package/assets/skills-en/superflow-design/agents/openai.yaml +4 -0
- package/assets/skills-en/superflow-docs/SKILL.md +316 -0
- package/assets/skills-en/superflow-docs/agents/openai.yaml +4 -0
- package/assets/skills-en/superflow-hotfix/SKILL.md +48 -0
- package/assets/skills-en/superflow-implement/SKILL.md +461 -0
- package/assets/skills-en/superflow-implement/agents/openai.yaml +4 -0
- package/assets/skills-en/superflow-pipeline/SKILL.md +844 -0
- package/assets/skills-en/superflow-pipeline/agents/openai.yaml +4 -0
- package/assets/skills-en/superflow-pipeline/references/api-design-template.md +431 -0
- package/assets/skills-en/superflow-pipeline/references/architecture-design-template.md +119 -0
- package/assets/skills-en/superflow-pipeline/references/batch-prompt-template.md +536 -0
- package/assets/skills-en/superflow-pipeline/references/batch-split-guide.md +140 -0
- package/assets/skills-en/superflow-pipeline/references/decision-point.md +30 -0
- package/assets/skills-en/superflow-pipeline/references/dirty-worktree.md +35 -0
- package/assets/skills-en/superflow-pipeline/references/document-templates.md +123 -0
- package/assets/skills-en/superflow-pipeline/references/feature-gated-workflow.md +124 -0
- package/assets/skills-en/superflow-pipeline/references/implementation-prompt-template.md +1056 -0
- package/assets/skills-en/superflow-pipeline/references/mock-strategy-guide.md +86 -0
- package/assets/skills-en/superflow-pipeline/references/openspec-format.md +57 -0
- package/assets/skills-en/superflow-pipeline/references/orchestration.md +639 -0
- package/assets/skills-en/superflow-pipeline/references/p0-baseline-template.md +174 -0
- package/assets/skills-en/superflow-pipeline/references/project-config.md +40 -0
- package/assets/skills-en/superflow-pipeline/references/prompt-usage-template.md +152 -0
- package/assets/skills-en/superflow-pipeline/references/quality-gate.md +299 -0
- package/assets/skills-en/superflow-pipeline/references/quality-standards.md +190 -0
- package/assets/skills-en/superflow-pipeline/references/reviewer-checklist.md +154 -0
- package/assets/skills-en/superflow-pipeline/references/sql-risk-review-checklist.md +323 -0
- package/assets/skills-en/superflow-pipeline/references/subagent-progress.md +90 -0
- package/assets/skills-en/superflow-pipeline/references/superpower-technical-design-template.md +125 -0
- package/assets/skills-en/superflow-pipeline/references/test-execution-template.md +220 -0
- package/assets/skills-en/superflow-pipeline/references/test-guide.md +30 -0
- package/assets/skills-en/superflow-pipeline/references/traceability-matrix.md +106 -0
- package/assets/skills-en/superflow-pipeline/references/validation-integrity.md +134 -0
- package/assets/skills-en/superflow-pipeline/scripts/superflow-archive.sh +178 -0
- package/assets/skills-en/superflow-pipeline/scripts/superflow-env.sh +118 -0
- package/assets/skills-en/superflow-pipeline/scripts/superflow-guard.sh +428 -0
- package/assets/skills-en/superflow-pipeline/scripts/superflow-handoff.sh +296 -0
- package/assets/skills-en/superflow-pipeline/scripts/superflow-state.sh +574 -0
- package/assets/skills-en/superflow-pipeline/scripts/superflow-status.sh +172 -0
- package/assets/skills-en/superflow-pipeline/scripts/superflow-yaml-validate.sh +138 -0
- package/assets/skills-en/superflow-table-impact-analysis/SKILL.md +77 -0
- package/assets/skills-en/superflow-tweak/SKILL.md +46 -0
- package/assets/skills-en/superflow-verify/SKILL.md +112 -0
- package/dist/cli/index.js +186 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/commands/archive.js +6 -0
- package/dist/commands/archive.js.map +1 -0
- package/dist/commands/clarify.js +6 -0
- package/dist/commands/clarify.js.map +1 -0
- package/dist/commands/design.js +6 -0
- package/dist/commands/design.js.map +1 -0
- package/dist/commands/docs.js +6 -0
- package/dist/commands/docs.js.map +1 -0
- package/dist/commands/doctor.js +473 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/implement.js +6 -0
- package/dist/commands/implement.js.map +1 -0
- package/dist/commands/init.js +471 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/pipeline.js +6 -0
- package/dist/commands/pipeline.js.map +1 -0
- package/dist/commands/scan.js +59 -0
- package/dist/commands/scan.js.map +1 -0
- package/dist/commands/status.js +173 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/uninstall.js +213 -0
- package/dist/commands/uninstall.js.map +1 -0
- package/dist/commands/update.js +187 -0
- package/dist/commands/update.js.map +1 -0
- package/dist/commands/verify.js +6 -0
- package/dist/commands/verify.js.map +1 -0
- package/dist/core/assets.js +27 -0
- package/dist/core/assets.js.map +1 -0
- package/dist/core/context.js +100 -0
- package/dist/core/context.js.map +1 -0
- package/dist/core/dependencies.js +146 -0
- package/dist/core/dependencies.js.map +1 -0
- package/dist/core/detect.js +71 -0
- package/dist/core/detect.js.map +1 -0
- package/dist/core/i18n.js +103 -0
- package/dist/core/i18n.js.map +1 -0
- package/dist/core/integrity.js +46 -0
- package/dist/core/integrity.js.map +1 -0
- package/dist/core/manifest.js +18 -0
- package/dist/core/manifest.js.map +1 -0
- package/dist/core/prompts.js +20 -0
- package/dist/core/prompts.js.map +1 -0
- package/dist/core/registry.js +134 -0
- package/dist/core/registry.js.map +1 -0
- package/dist/core/rules.js +17 -0
- package/dist/core/rules.js.map +1 -0
- package/dist/core/scripts.js +40 -0
- package/dist/core/scripts.js.map +1 -0
- package/dist/core/skill-check.js +31 -0
- package/dist/core/skill-check.js.map +1 -0
- package/dist/core/skills.js +56 -0
- package/dist/core/skills.js.map +1 -0
- package/dist/core/state.js +43 -0
- package/dist/core/state.js.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/path.js +11 -0
- package/dist/utils/path.js.map +1 -0
- package/dist/utils/shell.js +29 -0
- package/dist/utils/shell.js.map +1 -0
- package/package.json +60 -0
|
@@ -0,0 +1,574 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
usage() {
|
|
5
|
+
cat <<'USAGE'
|
|
6
|
+
Usage:
|
|
7
|
+
superflow-state.sh init <change-dir> [workflow|phase] [phase]
|
|
8
|
+
superflow-state.sh status <change-dir>
|
|
9
|
+
superflow-state.sh set <change-dir> <key> <value>
|
|
10
|
+
superflow-state.sh get <change-dir> <key>
|
|
11
|
+
superflow-state.sh phase <change-dir>
|
|
12
|
+
superflow-state.sh transition <change-dir> <docs-complete|design-complete|implement-complete|verify-pass|verify-fail|archive-reopen|archived>
|
|
13
|
+
superflow-state.sh next <change-dir>
|
|
14
|
+
superflow-state.sh recover <change-dir>
|
|
15
|
+
superflow-state.sh scale <change-dir>
|
|
16
|
+
superflow-state.sh task-checkoff <file> <task-text>
|
|
17
|
+
|
|
18
|
+
State is stored at <change-dir>/.sdd/state.yaml.
|
|
19
|
+
USAGE
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
die() {
|
|
23
|
+
printf 'superflow-state: %s\n' "$*" >&2
|
|
24
|
+
exit 1
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
today_utc() {
|
|
28
|
+
date -u '+%Y-%m-%d'
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
now_utc() {
|
|
32
|
+
date -u '+%Y-%m-%dT%H:%M:%SZ'
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
state_file() {
|
|
36
|
+
printf '%s/.sdd/state.yaml' "$1"
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
ensure_change_dir() {
|
|
40
|
+
[[ -d "$1" ]] || die "change dir not found: $1"
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
normalize_null() {
|
|
44
|
+
local value="${1:-}"
|
|
45
|
+
if [[ -z "$value" || "$value" == "null" ]]; then
|
|
46
|
+
printf 'null'
|
|
47
|
+
else
|
|
48
|
+
printf '%s' "$value"
|
|
49
|
+
fi
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
yaml_value_from_file() {
|
|
53
|
+
local file="$1"
|
|
54
|
+
local key="$2"
|
|
55
|
+
[[ -f "$file" ]] || return 1
|
|
56
|
+
awk -F':' -v k="$key" '
|
|
57
|
+
$1 == k {
|
|
58
|
+
value = $0
|
|
59
|
+
sub("^[^:]*:[[:space:]]*", "", value)
|
|
60
|
+
sub("[[:space:]]+#.*$", "", value)
|
|
61
|
+
gsub(/^[[:space:]]+|[[:space:]]+$/, "", value)
|
|
62
|
+
gsub(/^"|"$/, "", value)
|
|
63
|
+
gsub(/^'\''|'\''$/, "", value)
|
|
64
|
+
print value
|
|
65
|
+
found=1
|
|
66
|
+
}
|
|
67
|
+
END { exit found ? 0 : 1 }
|
|
68
|
+
' "$file"
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
project_root_for_change() {
|
|
72
|
+
if git -C "$CHANGE_DIR" rev-parse --show-toplevel >/dev/null 2>&1; then
|
|
73
|
+
git -C "$CHANGE_DIR" rev-parse --show-toplevel
|
|
74
|
+
else
|
|
75
|
+
dirname "$(dirname "$CHANGE_DIR")"
|
|
76
|
+
fi
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
sdd_config_value() {
|
|
80
|
+
local key="$1"
|
|
81
|
+
local default="$2"
|
|
82
|
+
local env_name="$3"
|
|
83
|
+
local root value
|
|
84
|
+
|
|
85
|
+
if [[ -n "${!env_name:-}" ]]; then
|
|
86
|
+
printf '%s\n' "${!env_name}"
|
|
87
|
+
return
|
|
88
|
+
fi
|
|
89
|
+
|
|
90
|
+
if value="$(yaml_value_from_file "$CHANGE_DIR/.sdd/config.yaml" "$key" 2>/dev/null)"; then
|
|
91
|
+
[[ -n "$value" ]] && { printf '%s\n' "$value"; return; }
|
|
92
|
+
fi
|
|
93
|
+
|
|
94
|
+
root="$(project_root_for_change)"
|
|
95
|
+
if value="$(yaml_value_from_file "$root/.sdd/config.yaml" "$key" 2>/dev/null)"; then
|
|
96
|
+
[[ -n "$value" ]] && { printf '%s\n' "$value"; return; }
|
|
97
|
+
fi
|
|
98
|
+
|
|
99
|
+
printf '%s\n' "$default"
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
review_mode_default() {
|
|
103
|
+
local value
|
|
104
|
+
value="$(sdd_config_value review_mode null SUPERFLOW_REVIEW_MODE)"
|
|
105
|
+
if [[ "$value" == "null" && -n "${SDD_REVIEW_MODE:-}" ]]; then
|
|
106
|
+
value="$SDD_REVIEW_MODE"
|
|
107
|
+
fi
|
|
108
|
+
validate_config_enum review_mode "$value" "null off standard thorough"
|
|
109
|
+
printf '%s\n' "$value"
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
validate_config_enum() {
|
|
113
|
+
local key="$1"
|
|
114
|
+
local value="$2"
|
|
115
|
+
local allowed="$3"
|
|
116
|
+
local item
|
|
117
|
+
for item in $allowed; do
|
|
118
|
+
[[ "$value" == "$item" ]] && return
|
|
119
|
+
done
|
|
120
|
+
die "invalid $key: $value (expected: $allowed)"
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
field_value() {
|
|
124
|
+
local key="$1"
|
|
125
|
+
[[ -f "$STATE_FILE" ]] || return 1
|
|
126
|
+
awk -F':' -v k="$key" '
|
|
127
|
+
$1 == k {
|
|
128
|
+
value = $0
|
|
129
|
+
sub("^[^:]*:[[:space:]]*", "", value)
|
|
130
|
+
gsub(/^[[:space:]]+|[[:space:]]+$/, "", value)
|
|
131
|
+
print value
|
|
132
|
+
found=1
|
|
133
|
+
}
|
|
134
|
+
END { exit found ? 0 : 1 }
|
|
135
|
+
' "$STATE_FILE"
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
replace_field() {
|
|
139
|
+
local key="$1"
|
|
140
|
+
local value="$2"
|
|
141
|
+
local tmp
|
|
142
|
+
tmp="$(mktemp)"
|
|
143
|
+
|
|
144
|
+
if grep -q "^${key}:" "$STATE_FILE" 2>/dev/null; then
|
|
145
|
+
awk -v k="$key" -v v="$value" '
|
|
146
|
+
index($0, k ":") == 1 { print k ": " v; next }
|
|
147
|
+
{ print }
|
|
148
|
+
' "$STATE_FILE" > "$tmp"
|
|
149
|
+
else
|
|
150
|
+
cat "$STATE_FILE" > "$tmp"
|
|
151
|
+
printf '%s: %s\n' "$key" "$value" >> "$tmp"
|
|
152
|
+
fi
|
|
153
|
+
|
|
154
|
+
awk -v now="$(now_utc)" '
|
|
155
|
+
/^updated_at:/ { print "updated_at: " now; seen=1; next }
|
|
156
|
+
{ print }
|
|
157
|
+
END { if (!seen) print "updated_at: " now }
|
|
158
|
+
' "$tmp" > "$STATE_FILE"
|
|
159
|
+
rm -f "$tmp"
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
cmd_init() {
|
|
163
|
+
local workflow_or_phase="${3:-full}"
|
|
164
|
+
local phase="${4:-}"
|
|
165
|
+
local workflow
|
|
166
|
+
local base_ref="null"
|
|
167
|
+
local context_compression auto_transition review_mode
|
|
168
|
+
|
|
169
|
+
case "$workflow_or_phase" in
|
|
170
|
+
docs|design|implement|verify|archive|done)
|
|
171
|
+
workflow="full"
|
|
172
|
+
phase="$workflow_or_phase"
|
|
173
|
+
;;
|
|
174
|
+
full|hotfix|tweak)
|
|
175
|
+
workflow="$workflow_or_phase"
|
|
176
|
+
phase="${phase:-docs}"
|
|
177
|
+
;;
|
|
178
|
+
sdd)
|
|
179
|
+
workflow="full"
|
|
180
|
+
phase="${phase:-docs}"
|
|
181
|
+
;;
|
|
182
|
+
*)
|
|
183
|
+
die "invalid workflow or phase: $workflow_or_phase"
|
|
184
|
+
;;
|
|
185
|
+
esac
|
|
186
|
+
|
|
187
|
+
mkdir -p "$(dirname "$STATE_FILE")"
|
|
188
|
+
context_compression="$(sdd_config_value context_compression off SDD_CONTEXT_COMPRESSION)"
|
|
189
|
+
auto_transition="$(sdd_config_value auto_transition true SDD_AUTO_TRANSITION)"
|
|
190
|
+
validate_config_enum context_compression "$context_compression" "off beta"
|
|
191
|
+
validate_config_enum auto_transition "$auto_transition" "true false"
|
|
192
|
+
if [[ "$workflow" == "hotfix" || "$workflow" == "tweak" ]]; then
|
|
193
|
+
review_mode="off"
|
|
194
|
+
else
|
|
195
|
+
review_mode="$(review_mode_default)"
|
|
196
|
+
fi
|
|
197
|
+
|
|
198
|
+
if git -C "$CHANGE_DIR" rev-parse --is-inside-work-tree >/dev/null 2>&1; then
|
|
199
|
+
if base_ref_candidate="$(git -C "$CHANGE_DIR" rev-parse --verify HEAD 2>/dev/null)"; then
|
|
200
|
+
base_ref="$base_ref_candidate"
|
|
201
|
+
fi
|
|
202
|
+
fi
|
|
203
|
+
|
|
204
|
+
if [[ ! -f "$STATE_FILE" ]]; then
|
|
205
|
+
cat > "$STATE_FILE" <<EOF
|
|
206
|
+
workflow: $workflow
|
|
207
|
+
phase: $phase
|
|
208
|
+
canonical_spec: openspec-sdd
|
|
209
|
+
context_compression: $context_compression
|
|
210
|
+
design_doc: null
|
|
211
|
+
technical_design: null
|
|
212
|
+
plan: null
|
|
213
|
+
base_ref: $base_ref
|
|
214
|
+
build_mode: null
|
|
215
|
+
build_pause: null
|
|
216
|
+
subagent_dispatch: null
|
|
217
|
+
tdd_mode: null
|
|
218
|
+
review_mode: $review_mode
|
|
219
|
+
isolation: null
|
|
220
|
+
verify_mode: null
|
|
221
|
+
auto_transition: $auto_transition
|
|
222
|
+
verify_result: pending
|
|
223
|
+
verification_report: null
|
|
224
|
+
branch_status: pending
|
|
225
|
+
archived: false
|
|
226
|
+
direct_override: false
|
|
227
|
+
build_command: null
|
|
228
|
+
verify_command: null
|
|
229
|
+
handoff_context: null
|
|
230
|
+
handoff_hash: null
|
|
231
|
+
superpower_strategy: null
|
|
232
|
+
implementation_prompt: null
|
|
233
|
+
worktree_ports: null
|
|
234
|
+
created_at: $(today_utc)
|
|
235
|
+
verified_at: null
|
|
236
|
+
updated_at: $(now_utc)
|
|
237
|
+
EOF
|
|
238
|
+
fi
|
|
239
|
+
|
|
240
|
+
printf '%s\n' "$STATE_FILE"
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
cmd_set() {
|
|
244
|
+
local key="${3:-}"
|
|
245
|
+
local value="${4:-}"
|
|
246
|
+
[[ -n "$key" ]] || die "missing key"
|
|
247
|
+
[[ -f "$STATE_FILE" ]] || cmd_init init "$CHANGE_DIR" docs >/dev/null
|
|
248
|
+
|
|
249
|
+
case "$key" in
|
|
250
|
+
phase)
|
|
251
|
+
if [[ "${SUPERFLOW_FORCE_PHASE:-0}" != "1" && "${SDD_FORCE_PHASE:-0}" != "1" ]]; then
|
|
252
|
+
die "setting phase directly is blocked; use superflow-state.sh transition <change-dir> <event> or set SUPERFLOW_FORCE_PHASE=1 for repair"
|
|
253
|
+
fi
|
|
254
|
+
;;
|
|
255
|
+
workflow|canonical_spec|context_compression|design_doc|technical_design|plan|base_ref|build_mode|build_pause|subagent_dispatch|tdd_mode|review_mode|isolation|verify_mode|auto_transition|verify_result|verification_report|branch_status|archived|direct_override|build_command|verify_command|handoff_context|handoff_hash|superpower_strategy|implementation_prompt|worktree_ports|created_at|verified_at|updated_at) ;;
|
|
256
|
+
*) die "unknown state key: $key" ;;
|
|
257
|
+
esac
|
|
258
|
+
|
|
259
|
+
replace_field "$key" "$(normalize_null "$value")"
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
cmd_get() {
|
|
263
|
+
local key="${3:-}"
|
|
264
|
+
[[ -n "$key" ]] || die "missing key"
|
|
265
|
+
[[ -f "$STATE_FILE" ]] || die "state not found: $STATE_FILE"
|
|
266
|
+
field_value "$key"
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
require_phase() {
|
|
270
|
+
local expected="$1"
|
|
271
|
+
local current
|
|
272
|
+
current="$(field_value phase 2>/dev/null || true)"
|
|
273
|
+
[[ "$current" == "$expected" ]] || die "expected phase '$expected', got '${current:-missing}'"
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
require_file_value_exists() {
|
|
277
|
+
local key="$1"
|
|
278
|
+
local value
|
|
279
|
+
value="$(field_value "$key" 2>/dev/null || true)"
|
|
280
|
+
value="$(normalize_null "$value")"
|
|
281
|
+
[[ "$value" != "null" ]] || die "$key is not set"
|
|
282
|
+
[[ -f "$CHANGE_DIR/$value" || -f "$value" ]] || die "$key path does not exist: $value"
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
require_implement_decisions() {
|
|
286
|
+
local workflow build_mode isolation tdd_mode review_mode subagent_dispatch direct_override
|
|
287
|
+
workflow="$(field_value workflow 2>/dev/null || printf 'full')"
|
|
288
|
+
build_mode="$(field_value build_mode 2>/dev/null || printf 'null')"
|
|
289
|
+
isolation="$(field_value isolation 2>/dev/null || printf 'null')"
|
|
290
|
+
tdd_mode="$(field_value tdd_mode 2>/dev/null || printf 'null')"
|
|
291
|
+
review_mode="$(field_value review_mode 2>/dev/null || printf 'null')"
|
|
292
|
+
subagent_dispatch="$(field_value subagent_dispatch 2>/dev/null || printf 'null')"
|
|
293
|
+
direct_override="$(field_value direct_override 2>/dev/null || printf 'false')"
|
|
294
|
+
|
|
295
|
+
case "$isolation" in branch|worktree|null) ;; *) die "invalid isolation: $isolation" ;; esac
|
|
296
|
+
[[ "$isolation" != "null" ]] || die "isolation must be branch or worktree before verify"
|
|
297
|
+
|
|
298
|
+
case "$build_mode" in subagent-driven-development|executing-plans|team-prompt|direct|null) ;; *) die "invalid build_mode: $build_mode" ;; esac
|
|
299
|
+
[[ "$build_mode" != "null" ]] || die "build_mode must be selected before verify"
|
|
300
|
+
|
|
301
|
+
if [[ "$build_mode" == "subagent-driven-development" && "$subagent_dispatch" != "confirmed" ]]; then
|
|
302
|
+
die "subagent_dispatch must be confirmed for subagent-driven-development"
|
|
303
|
+
fi
|
|
304
|
+
|
|
305
|
+
if [[ "$workflow" == "full" ]]; then
|
|
306
|
+
case "$tdd_mode" in tdd|direct) ;; *) die "tdd_mode must be tdd or direct for full workflow" ;; esac
|
|
307
|
+
case "$review_mode" in off|standard|thorough) ;; *) die "review_mode must be off, standard, or thorough for full workflow" ;; esac
|
|
308
|
+
if [[ "$build_mode" == "direct" && "$direct_override" != "true" ]]; then
|
|
309
|
+
die "full workflow direct build requires direct_override=true"
|
|
310
|
+
fi
|
|
311
|
+
fi
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
cmd_transition() {
|
|
315
|
+
local event="${3:-}"
|
|
316
|
+
[[ -f "$STATE_FILE" ]] || die "state not found: $STATE_FILE"
|
|
317
|
+
|
|
318
|
+
case "$event" in
|
|
319
|
+
docs-complete)
|
|
320
|
+
require_phase docs
|
|
321
|
+
require_file_value_exists handoff_context
|
|
322
|
+
workflow="$(field_value workflow 2>/dev/null || printf 'full')"
|
|
323
|
+
if [[ "$workflow" == "full" ]]; then
|
|
324
|
+
replace_field phase design
|
|
325
|
+
else
|
|
326
|
+
replace_field phase implement
|
|
327
|
+
fi
|
|
328
|
+
;;
|
|
329
|
+
design-complete)
|
|
330
|
+
require_phase design
|
|
331
|
+
require_file_value_exists technical_design
|
|
332
|
+
replace_field phase implement
|
|
333
|
+
;;
|
|
334
|
+
implement-complete)
|
|
335
|
+
require_phase implement
|
|
336
|
+
require_implement_decisions
|
|
337
|
+
replace_field phase verify
|
|
338
|
+
replace_field verify_result pending
|
|
339
|
+
replace_field branch_status pending
|
|
340
|
+
;;
|
|
341
|
+
verify-pass)
|
|
342
|
+
require_phase verify
|
|
343
|
+
require_file_value_exists verification_report
|
|
344
|
+
replace_field verify_result pass
|
|
345
|
+
replace_field verified_at "$(today_utc)"
|
|
346
|
+
replace_field phase archive
|
|
347
|
+
;;
|
|
348
|
+
verify-fail)
|
|
349
|
+
require_phase verify
|
|
350
|
+
replace_field verify_result fail
|
|
351
|
+
replace_field phase implement
|
|
352
|
+
;;
|
|
353
|
+
archive-reopen)
|
|
354
|
+
require_phase archive
|
|
355
|
+
replace_field phase verify
|
|
356
|
+
replace_field archived false
|
|
357
|
+
;;
|
|
358
|
+
archived)
|
|
359
|
+
require_phase archive
|
|
360
|
+
replace_field archived true
|
|
361
|
+
replace_field phase done
|
|
362
|
+
;;
|
|
363
|
+
*)
|
|
364
|
+
die "unknown transition event: $event"
|
|
365
|
+
;;
|
|
366
|
+
esac
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
cmd_status() {
|
|
370
|
+
[[ -f "$STATE_FILE" ]] || die "state not found: $STATE_FILE"
|
|
371
|
+
cat "$STATE_FILE"
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
cmd_next() {
|
|
375
|
+
[[ -f "$STATE_FILE" ]] || die "state not found: $STATE_FILE"
|
|
376
|
+
local phase workflow auto archived skill
|
|
377
|
+
phase="$(field_value phase 2>/dev/null || printf 'docs')"
|
|
378
|
+
workflow="$(field_value workflow 2>/dev/null || printf 'full')"
|
|
379
|
+
auto="$(field_value auto_transition 2>/dev/null || printf 'true')"
|
|
380
|
+
archived="$(field_value archived 2>/dev/null || printf 'false')"
|
|
381
|
+
|
|
382
|
+
if [[ "$archived" == "true" || "$phase" == "done" ]]; then
|
|
383
|
+
printf 'NEXT: done\n'
|
|
384
|
+
printf 'HINT: SDD lifecycle is complete.\n'
|
|
385
|
+
return
|
|
386
|
+
fi
|
|
387
|
+
|
|
388
|
+
case "$phase" in
|
|
389
|
+
docs) skill="superflow-docs" ;;
|
|
390
|
+
design) skill="superflow-design" ;;
|
|
391
|
+
implement) skill="superflow-implement" ;;
|
|
392
|
+
verify) skill="superflow-verify" ;;
|
|
393
|
+
archive) skill="superflow-archive" ;;
|
|
394
|
+
*) skill="superflow-pipeline" ;;
|
|
395
|
+
esac
|
|
396
|
+
|
|
397
|
+
if [[ "$workflow" == "hotfix" && "$phase" == "implement" ]]; then
|
|
398
|
+
skill="superflow-hotfix"
|
|
399
|
+
elif [[ "$workflow" == "tweak" && "$phase" == "implement" ]]; then
|
|
400
|
+
skill="superflow-tweak"
|
|
401
|
+
fi
|
|
402
|
+
|
|
403
|
+
if [[ "$auto" == "false" ]]; then
|
|
404
|
+
printf 'NEXT: manual\n'
|
|
405
|
+
else
|
|
406
|
+
printf 'NEXT: auto\n'
|
|
407
|
+
fi
|
|
408
|
+
printf 'SKILL: %s\n' "$skill"
|
|
409
|
+
printf 'PHASE: %s\n' "$phase"
|
|
410
|
+
printf 'HINT: continue with $%s for phase %s.\n' "$skill" "$phase"
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
cmd_recover() {
|
|
414
|
+
[[ -f "$STATE_FILE" ]] || die "state not found: $STATE_FILE"
|
|
415
|
+
local phase handoff hash prompt report verify_result archived technical_design
|
|
416
|
+
local build_pause build_mode isolation plan subagent_dispatch review_mode
|
|
417
|
+
phase="$(field_value phase 2>/dev/null || printf 'docs')"
|
|
418
|
+
handoff="$(field_value handoff_context 2>/dev/null || printf 'null')"
|
|
419
|
+
hash="$(field_value handoff_hash 2>/dev/null || printf 'null')"
|
|
420
|
+
prompt="$(field_value implementation_prompt 2>/dev/null || printf 'null')"
|
|
421
|
+
technical_design="$(field_value technical_design 2>/dev/null || printf 'null')"
|
|
422
|
+
report="$(field_value verification_report 2>/dev/null || printf 'null')"
|
|
423
|
+
verify_result="$(field_value verify_result 2>/dev/null || printf 'pending')"
|
|
424
|
+
archived="$(field_value archived 2>/dev/null || printf 'false')"
|
|
425
|
+
build_pause="$(field_value build_pause 2>/dev/null || printf 'null')"
|
|
426
|
+
build_mode="$(field_value build_mode 2>/dev/null || printf 'null')"
|
|
427
|
+
isolation="$(field_value isolation 2>/dev/null || printf 'null')"
|
|
428
|
+
plan="$(field_value plan 2>/dev/null || printf 'null')"
|
|
429
|
+
subagent_dispatch="$(field_value subagent_dispatch 2>/dev/null || printf 'null')"
|
|
430
|
+
review_mode="$(field_value review_mode 2>/dev/null || printf 'null')"
|
|
431
|
+
|
|
432
|
+
printf 'SDD Recovery\n'
|
|
433
|
+
printf 'phase: %s\n' "$phase"
|
|
434
|
+
printf 'handoff_context: %s\n' "$handoff"
|
|
435
|
+
printf 'handoff_hash: %s\n' "$hash"
|
|
436
|
+
printf 'implementation_prompt: %s\n' "$prompt"
|
|
437
|
+
printf 'technical_design: %s\n' "$technical_design"
|
|
438
|
+
printf 'plan: %s\n' "$plan"
|
|
439
|
+
printf 'build_pause: %s\n' "$build_pause"
|
|
440
|
+
printf 'build_mode: %s\n' "$build_mode"
|
|
441
|
+
printf 'isolation: %s\n' "$isolation"
|
|
442
|
+
printf 'subagent_dispatch: %s\n' "$subagent_dispatch"
|
|
443
|
+
printf 'review_mode: %s\n' "$review_mode"
|
|
444
|
+
printf 'verification_report: %s\n' "$report"
|
|
445
|
+
printf 'verify_result: %s\n' "$verify_result"
|
|
446
|
+
printf 'archived: %s\n' "$archived"
|
|
447
|
+
|
|
448
|
+
case "$phase" in
|
|
449
|
+
docs)
|
|
450
|
+
printf 'Recovery action: read current OpenSpec/SDD contract docs and handoff, regenerate handoff if docs changed, then run superflow-guard docs.\n'
|
|
451
|
+
;;
|
|
452
|
+
design)
|
|
453
|
+
printf 'Recovery action: read .sdd/handoff/sdd-context.md, api.md, design.md, tests.md, brainstorm-summary.md when present, then use superflow-design to create or refresh technical_design before superflow-guard design.\n'
|
|
454
|
+
;;
|
|
455
|
+
implement)
|
|
456
|
+
if [[ "$build_pause" == "plan-ready" && "$isolation" != "null" && "$build_mode" != "null" ]]; then
|
|
457
|
+
printf 'Recovery action: stale plan-ready pause detected; run superflow-state.sh set <change-dir> build_pause null, then resume from the first unchecked task using build_mode=%s.\n' "$build_mode"
|
|
458
|
+
elif [[ "$build_pause" == "plan-ready" && "$plan" != "null" ]]; then
|
|
459
|
+
if [[ -f "$CHANGE_DIR/$plan" || -f "$plan" ]]; then
|
|
460
|
+
printf 'Recovery action: plan-ready pause is active; do not regenerate the plan. Ask the user to choose isolation/build_mode/tdd_mode, record decisions, then continue implementation.\n'
|
|
461
|
+
else
|
|
462
|
+
printf 'Recovery action: plan-ready pause is corrupt because plan is missing. Return to superflow-implement to repair or regenerate the plan before coding.\n'
|
|
463
|
+
fi
|
|
464
|
+
elif [[ "$build_mode" == "subagent-driven-development" ]]; then
|
|
465
|
+
printf 'Recovery action: act as coordinator only; reload Superpowers subagent-driven-development, read .sdd/subagent-progress.md, and resume the exact checkpoint without coding in the main session.\n'
|
|
466
|
+
else
|
|
467
|
+
printf 'Recovery action: read .sdd/handoff/sdd-context.md plus api.md/design.md/tests.md and technical_design, verify prompt hash, then continue implementation prompt/worktree from the first incomplete batch.\n'
|
|
468
|
+
fi
|
|
469
|
+
;;
|
|
470
|
+
verify)
|
|
471
|
+
printf 'Recovery action: read test-report.md, rerun required hook scripts, set verification_report, then run superflow-guard verify.\n'
|
|
472
|
+
;;
|
|
473
|
+
archive)
|
|
474
|
+
if [[ "$archived" == "true" ]]; then
|
|
475
|
+
printf 'Recovery action: archive already marked complete; do not rerun archive.\n'
|
|
476
|
+
else
|
|
477
|
+
printf 'Recovery action: verification passed; ask user for archive confirmation before marking archived.\n'
|
|
478
|
+
fi
|
|
479
|
+
;;
|
|
480
|
+
done)
|
|
481
|
+
printf 'Recovery action: lifecycle complete; no further action.\n'
|
|
482
|
+
;;
|
|
483
|
+
esac
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
cmd_scale() {
|
|
487
|
+
[[ -f "$STATE_FILE" ]] || cmd_init init "$CHANGE_DIR" docs >/dev/null
|
|
488
|
+
local task_count capability_count changed_files risk_hits mode
|
|
489
|
+
|
|
490
|
+
task_count="$(grep -RE '^- \[[ xX]\]' "$CHANGE_DIR"/*.md "$CHANGE_DIR"/**/*.md 2>/dev/null | wc -l | tr -d ' ')"
|
|
491
|
+
capability_count="$(find "$CHANGE_DIR" -path '*/specs/*/spec.md' -type f 2>/dev/null | wc -l | tr -d ' ')"
|
|
492
|
+
changed_files=0
|
|
493
|
+
if git -C "$CHANGE_DIR" rev-parse --is-inside-work-tree >/dev/null 2>&1; then
|
|
494
|
+
changed_files="$(git -C "$CHANGE_DIR" diff --name-only HEAD 2>/dev/null | wc -l | tr -d ' ')"
|
|
495
|
+
fi
|
|
496
|
+
|
|
497
|
+
risk_hits="$(grep -REi 'api|接口|curl|SQL|数据库|Mapper|XML|跨仓|状态字段|枚举|真实入口|payment|refund|MQ|定时任务|第三方|SDK' "$CHANGE_DIR"/*.md "$CHANGE_DIR"/**/*.md 2>/dev/null | wc -l | tr -d ' ')"
|
|
498
|
+
|
|
499
|
+
mode="light"
|
|
500
|
+
if [[ "$task_count" -gt 3 || "$capability_count" -gt 1 || "$changed_files" -gt 4 || "$risk_hits" -gt 0 ]]; then
|
|
501
|
+
mode="full"
|
|
502
|
+
fi
|
|
503
|
+
|
|
504
|
+
replace_field verify_mode "$mode"
|
|
505
|
+
printf 'verify_mode: %s\n' "$mode"
|
|
506
|
+
printf 'task_count: %s\n' "$task_count"
|
|
507
|
+
printf 'capability_count: %s\n' "$capability_count"
|
|
508
|
+
printf 'changed_files: %s\n' "$changed_files"
|
|
509
|
+
printf 'sdd_risk_hits: %s\n' "$risk_hits"
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
cmd_task_checkoff() {
|
|
513
|
+
local file="${2:-}"
|
|
514
|
+
local task_text="${3:-}"
|
|
515
|
+
[[ -n "$file" && -n "$task_text" ]] || die "usage: superflow-state.sh task-checkoff <file> <task-text>"
|
|
516
|
+
[[ -f "$file" ]] || die "task file not found: $file"
|
|
517
|
+
|
|
518
|
+
awk -v task="$task_text" '
|
|
519
|
+
index($0, task) > 0 {
|
|
520
|
+
count++
|
|
521
|
+
if ($0 ~ /^[[:space:]]*-[[:space:]]+\[[xX]\]/) checked++
|
|
522
|
+
last=$0
|
|
523
|
+
}
|
|
524
|
+
END {
|
|
525
|
+
if (count == 0) {
|
|
526
|
+
printf "task-checkoff failed: task text not found: %s\n", task > "/dev/stderr"
|
|
527
|
+
exit 1
|
|
528
|
+
}
|
|
529
|
+
if (count > 1) {
|
|
530
|
+
printf "task-checkoff failed: task text is not unique (%d matches): %s\n", count, task > "/dev/stderr"
|
|
531
|
+
exit 1
|
|
532
|
+
}
|
|
533
|
+
if (checked != 1) {
|
|
534
|
+
printf "task-checkoff failed: task is not checked: %s\n", last > "/dev/stderr"
|
|
535
|
+
exit 1
|
|
536
|
+
}
|
|
537
|
+
printf "task-checkoff passed: %s\n", task
|
|
538
|
+
}
|
|
539
|
+
' "$file"
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
CMD="${1:-}"
|
|
543
|
+
CHANGE_DIR="${2:-}"
|
|
544
|
+
|
|
545
|
+
[[ -n "$CMD" && "$CMD" != "-h" && "$CMD" != "--help" ]] || {
|
|
546
|
+
usage
|
|
547
|
+
exit 0
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
if [[ "$CMD" == "task-checkoff" ]]; then
|
|
551
|
+
cmd_task_checkoff "$@"
|
|
552
|
+
exit 0
|
|
553
|
+
fi
|
|
554
|
+
|
|
555
|
+
[[ -n "$CHANGE_DIR" ]] || die "missing change dir"
|
|
556
|
+
ensure_change_dir "$CHANGE_DIR"
|
|
557
|
+
CHANGE_DIR="$(cd "$CHANGE_DIR" && pwd)"
|
|
558
|
+
STATE_FILE="$(state_file "$CHANGE_DIR")"
|
|
559
|
+
|
|
560
|
+
case "$CMD" in
|
|
561
|
+
init) cmd_init "$@" ;;
|
|
562
|
+
status) cmd_status ;;
|
|
563
|
+
set) cmd_set "$@" ;;
|
|
564
|
+
get) cmd_get "$@" ;;
|
|
565
|
+
phase) cmd_get get "$CHANGE_DIR" phase ;;
|
|
566
|
+
transition) cmd_transition "$@" ;;
|
|
567
|
+
next) cmd_next ;;
|
|
568
|
+
recover) cmd_recover ;;
|
|
569
|
+
scale) cmd_scale ;;
|
|
570
|
+
*)
|
|
571
|
+
usage
|
|
572
|
+
exit 1
|
|
573
|
+
;;
|
|
574
|
+
esac
|