@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,428 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
usage() {
|
|
5
|
+
cat <<'USAGE'
|
|
6
|
+
Usage:
|
|
7
|
+
superflow-guard.sh <change-dir> docs|design|implement|verify|archive [--apply]
|
|
8
|
+
|
|
9
|
+
Validate SDD phase readiness. With --apply, update .sdd/state.yaml through
|
|
10
|
+
superflow-state transition events.
|
|
11
|
+
USAGE
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
die() {
|
|
15
|
+
printf 'superflow-guard: %s\n' "$*" >&2
|
|
16
|
+
exit 1
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
20
|
+
STATE="$SCRIPT_DIR/superflow-state.sh"
|
|
21
|
+
HANDOFF="$SCRIPT_DIR/superflow-handoff.sh"
|
|
22
|
+
VALIDATE="$SCRIPT_DIR/superflow-yaml-validate.sh"
|
|
23
|
+
|
|
24
|
+
CHANGE_DIR="${1:-}"
|
|
25
|
+
PHASE="${2:-}"
|
|
26
|
+
MODE="${3:-}"
|
|
27
|
+
|
|
28
|
+
[[ -n "$CHANGE_DIR" && -n "$PHASE" ]] || {
|
|
29
|
+
usage
|
|
30
|
+
exit 1
|
|
31
|
+
}
|
|
32
|
+
[[ -d "$CHANGE_DIR" ]] || die "change dir not found: $CHANGE_DIR"
|
|
33
|
+
[[ -z "$MODE" || "$MODE" == "--apply" ]] || die "unknown option: $MODE"
|
|
34
|
+
|
|
35
|
+
CHANGE_DIR="$(cd "$CHANGE_DIR" && pwd)"
|
|
36
|
+
issues=()
|
|
37
|
+
|
|
38
|
+
require_file() {
|
|
39
|
+
local path="$1"
|
|
40
|
+
[[ -f "$CHANGE_DIR/$path" ]] || issues+=("missing file: $path")
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
require_grep() {
|
|
44
|
+
local pattern="$1"
|
|
45
|
+
local path="$2"
|
|
46
|
+
local label="$3"
|
|
47
|
+
local target="$CHANGE_DIR/$path"
|
|
48
|
+
[[ -f "$path" ]] && target="$path"
|
|
49
|
+
if [[ ! -f "$target" ]]; then
|
|
50
|
+
issues+=("missing file for check: $path")
|
|
51
|
+
elif ! grep -Eiq "$pattern" "$target"; then
|
|
52
|
+
issues+=("$label not found in $path")
|
|
53
|
+
fi
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
project_root_for_change() {
|
|
57
|
+
if git -C "$CHANGE_DIR" rev-parse --show-toplevel >/dev/null 2>&1; then
|
|
58
|
+
git -C "$CHANGE_DIR" rev-parse --show-toplevel
|
|
59
|
+
return
|
|
60
|
+
fi
|
|
61
|
+
if [[ "$CHANGE_DIR" == */openspec/changes/* ]]; then
|
|
62
|
+
dirname "$(dirname "$(dirname "$CHANGE_DIR")")"
|
|
63
|
+
return
|
|
64
|
+
fi
|
|
65
|
+
dirname "$(dirname "$CHANGE_DIR")"
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
require_test_report_lint() {
|
|
69
|
+
local report="$CHANGE_DIR/test-report.md"
|
|
70
|
+
local root lint output
|
|
71
|
+
root="$(project_root_for_change)"
|
|
72
|
+
|
|
73
|
+
for lint in \
|
|
74
|
+
"$root/.codex/hooks/superflow-test-report-lint.py" \
|
|
75
|
+
"$HOME/.codex/hooks/superflow-test-report-lint.py"; do
|
|
76
|
+
if [[ -x "$lint" ]]; then
|
|
77
|
+
output="$(mktemp)"
|
|
78
|
+
if ! "$lint" --tests "$CHANGE_DIR/tests.md" "$report" >"$output" 2>&1; then
|
|
79
|
+
issues+=("superflow-test-report-lint failed: $(tr '\n' ' ' < "$output" | sed -E 's/[[:space:]]+/ /g')")
|
|
80
|
+
fi
|
|
81
|
+
rm -f "$output"
|
|
82
|
+
return
|
|
83
|
+
fi
|
|
84
|
+
done
|
|
85
|
+
|
|
86
|
+
issues+=("superflow-test-report-lint.py not found for verify guard")
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
require_markdown_links_valid() {
|
|
90
|
+
local output
|
|
91
|
+
output="$(mktemp)"
|
|
92
|
+
if ! python3 - "$CHANGE_DIR" >"$output" 2>&1 <<'PY'
|
|
93
|
+
import os
|
|
94
|
+
import re
|
|
95
|
+
import sys
|
|
96
|
+
from pathlib import Path
|
|
97
|
+
|
|
98
|
+
change_dir = Path(sys.argv[1]).resolve()
|
|
99
|
+
files = [
|
|
100
|
+
p for p in change_dir.rglob("*.md")
|
|
101
|
+
if ".sdd" not in p.relative_to(change_dir).parts
|
|
102
|
+
]
|
|
103
|
+
state = change_dir / ".sdd" / "state.yaml"
|
|
104
|
+
if state.exists():
|
|
105
|
+
for line in state.read_text(errors="ignore").splitlines():
|
|
106
|
+
if line.startswith("technical_design:") or line.startswith("design_doc:"):
|
|
107
|
+
value = line.split(":", 1)[1].strip()
|
|
108
|
+
if value and value != "null":
|
|
109
|
+
candidate = (change_dir / value).resolve()
|
|
110
|
+
if candidate.exists() and candidate.suffix == ".md":
|
|
111
|
+
files.append(candidate)
|
|
112
|
+
|
|
113
|
+
link_re = re.compile(r"\[[^\]]+\]\(([^)]+\.md(?:#[^)]+)?)\)")
|
|
114
|
+
bad = []
|
|
115
|
+
seen = set()
|
|
116
|
+
for file in files:
|
|
117
|
+
if file in seen or not file.exists():
|
|
118
|
+
continue
|
|
119
|
+
seen.add(file)
|
|
120
|
+
try:
|
|
121
|
+
display_file = str(file.relative_to(change_dir))
|
|
122
|
+
except ValueError:
|
|
123
|
+
display_file = os.path.relpath(file, change_dir)
|
|
124
|
+
text = file.read_text(errors="ignore")
|
|
125
|
+
for match in link_re.finditer(text):
|
|
126
|
+
target = match.group(1).strip()
|
|
127
|
+
if (
|
|
128
|
+
target.startswith("#")
|
|
129
|
+
or re.match(r"^[a-zA-Z][a-zA-Z0-9+.-]*:", target)
|
|
130
|
+
or target.startswith("/")
|
|
131
|
+
):
|
|
132
|
+
continue
|
|
133
|
+
target_path = target.split("#", 1)[0]
|
|
134
|
+
resolved = (file.parent / target_path).resolve()
|
|
135
|
+
if not resolved.exists():
|
|
136
|
+
bad.append(
|
|
137
|
+
f"{display_file} -> {target} "
|
|
138
|
+
f"(resolved: {os.path.relpath(resolved, change_dir)})"
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
if bad:
|
|
142
|
+
print("; ".join(bad))
|
|
143
|
+
sys.exit(1)
|
|
144
|
+
PY
|
|
145
|
+
then
|
|
146
|
+
issues+=("broken markdown links: $(tr '\n' ' ' < "$output" | sed -E 's/[[:space:]]+/ /g')")
|
|
147
|
+
fi
|
|
148
|
+
rm -f "$output"
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
state_get() {
|
|
152
|
+
"$STATE" get "$CHANGE_DIR" "$1" 2>/dev/null || true
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
require_state_value() {
|
|
156
|
+
local key="$1"
|
|
157
|
+
local label="$2"
|
|
158
|
+
local value
|
|
159
|
+
value="$(state_get "$key")"
|
|
160
|
+
[[ -n "$value" && "$value" != "null" ]] || issues+=("$label is not set in .sdd/state.yaml")
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
require_optional_state_path() {
|
|
164
|
+
local key="$1"
|
|
165
|
+
local label="$2"
|
|
166
|
+
local value
|
|
167
|
+
value="$(state_get "$key")"
|
|
168
|
+
[[ -n "$value" && "$value" != "null" ]] || {
|
|
169
|
+
issues+=("$label is not set in .sdd/state.yaml")
|
|
170
|
+
return 0
|
|
171
|
+
}
|
|
172
|
+
[[ -f "$CHANGE_DIR/$value" || -f "$value" ]] || {
|
|
173
|
+
issues+=("$label path does not exist: $value")
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
require_state_file() {
|
|
178
|
+
require_file .sdd/state.yaml
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
require_spec_doc() {
|
|
182
|
+
if [[ -f "$CHANGE_DIR/spec.md" ]]; then
|
|
183
|
+
return
|
|
184
|
+
fi
|
|
185
|
+
if find "$CHANGE_DIR/specs" -path '*/spec.md' -type f 2>/dev/null | grep -q .; then
|
|
186
|
+
return
|
|
187
|
+
fi
|
|
188
|
+
issues+=("missing spec document: spec.md or specs/<capability>/spec.md")
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
require_handoff() {
|
|
192
|
+
require_file .sdd/handoff/sdd-context.md
|
|
193
|
+
require_file .sdd/handoff/sdd-context.json
|
|
194
|
+
require_file .sdd/handoff/sdd-context.sha256
|
|
195
|
+
require_state_value handoff_context "handoff_context"
|
|
196
|
+
require_state_value handoff_hash "handoff_hash"
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
require_handoff_current() {
|
|
200
|
+
local hash_file="$CHANGE_DIR/.sdd/handoff/sdd-context.sha256"
|
|
201
|
+
local recorded actual
|
|
202
|
+
[[ -f "$hash_file" ]] || return 0
|
|
203
|
+
recorded="$(tr -d '[:space:]' < "$hash_file")"
|
|
204
|
+
actual="$("$HANDOFF" "$CHANGE_DIR" --hash-only 2>/dev/null || true)"
|
|
205
|
+
[[ -n "$actual" ]] || {
|
|
206
|
+
issues+=("could not compute current handoff hash")
|
|
207
|
+
return 0
|
|
208
|
+
}
|
|
209
|
+
[[ "$recorded" == "$actual" ]] || {
|
|
210
|
+
issues+=("handoff hash is stale: recorded=$recorded actual=$actual")
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
require_beta_handoff_structure() {
|
|
215
|
+
local mode json
|
|
216
|
+
mode="$(state_get context_compression)"
|
|
217
|
+
[[ "$mode" == "beta" ]] || return 0
|
|
218
|
+
json="$CHANGE_DIR/.sdd/handoff/sdd-context.json"
|
|
219
|
+
[[ -s "$json" ]] || {
|
|
220
|
+
issues+=("beta handoff json missing or empty")
|
|
221
|
+
return 0
|
|
222
|
+
}
|
|
223
|
+
grep -q '"contextCompression": "beta"' "$json" || issues+=("beta handoff json missing contextCompression=beta")
|
|
224
|
+
grep -q '"role": "api"' "$json" || issues+=("beta handoff json missing api role")
|
|
225
|
+
grep -Eq '"role": "(spec|test)"' "$json" || issues+=("beta handoff json missing spec/test role")
|
|
226
|
+
grep -q '"projected": true' "$json" || issues+=("beta handoff json missing projected=true sources")
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
require_hash_recorded() {
|
|
230
|
+
local hash_file="$CHANGE_DIR/.sdd/handoff/sdd-context.sha256"
|
|
231
|
+
[[ -f "$hash_file" ]] || return 0
|
|
232
|
+
local hash
|
|
233
|
+
hash="$(tr -d '[:space:]' < "$hash_file")"
|
|
234
|
+
[[ -n "$hash" ]] || {
|
|
235
|
+
issues+=("handoff hash file is empty")
|
|
236
|
+
return 0
|
|
237
|
+
}
|
|
238
|
+
if ! grep -Riq "$hash" \
|
|
239
|
+
"$CHANGE_DIR/design.md" "$CHANGE_DIR/sdd-quality-gate.md" \
|
|
240
|
+
"$CHANGE_DIR/test-report.md" "$CHANGE_DIR/prompt" 2>/dev/null; then
|
|
241
|
+
issues+=("handoff hash is not recorded in design, quality gate, prompt, or test-report")
|
|
242
|
+
fi
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
change_has_field_status_risk() {
|
|
246
|
+
grep -RIEiq \
|
|
247
|
+
'字段值|状态|枚举|online|offline|上线|下线|删除|恢复|同步标记|sync marker|payment|refund|支付|退款|第三方状态|running_status|offline_time' \
|
|
248
|
+
"$CHANGE_DIR"/*.md "$CHANGE_DIR"/**/*.md 2>/dev/null
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
change_has_architecture_boundary_risk() {
|
|
252
|
+
grep -RIEiq \
|
|
253
|
+
'跨仓|跨服务|sibling|SDK|MQ|topic|consumer|scheduler|定时|device|设备|callback|回调|third[- ]party|第三方|mini[- ]program|小程序|gateway|网关|adapter|适配|protocol|协议|interconnect|互联互通|调用链|入口|出口' \
|
|
254
|
+
"$CHANGE_DIR"/*.md "$CHANGE_DIR"/**/*.md 2>/dev/null
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
first_prompt_rel() {
|
|
258
|
+
find "$CHANGE_DIR" -path '*/prompt/*.md' -type f | head -n 1 | sed "s#^$CHANGE_DIR/##"
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
require_any_prompt() {
|
|
262
|
+
if ! find "$CHANGE_DIR" -path '*/prompt/*.md' -type f | grep -q .; then
|
|
263
|
+
issues+=("missing implementation prompt under prompt/*.md")
|
|
264
|
+
fi
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
require_prompt_set() {
|
|
268
|
+
local task_count prompt_count non_index_prompt_count
|
|
269
|
+
require_file prompt/implementation.md
|
|
270
|
+
task_count="$(grep -E '^[[:space:]]*-[[:space:]]+\[[ xX]\]' "$CHANGE_DIR/tasks.md" 2>/dev/null | wc -l | tr -d ' ')"
|
|
271
|
+
prompt_count="$(find "$CHANGE_DIR/prompt" -maxdepth 1 -type f -name '*.md' 2>/dev/null | wc -l | tr -d ' ')"
|
|
272
|
+
non_index_prompt_count="$(find "$CHANGE_DIR/prompt" -maxdepth 1 -type f -name '*.md' ! -name 'implementation.md' 2>/dev/null | wc -l | tr -d ' ')"
|
|
273
|
+
if [[ "$task_count" -gt 0 && "$non_index_prompt_count" -eq 0 ]]; then
|
|
274
|
+
issues+=("missing task prompt under prompt/<task-name>.md; prompt/implementation.md alone is not enough")
|
|
275
|
+
fi
|
|
276
|
+
if [[ "$prompt_count" -eq 0 ]]; then
|
|
277
|
+
issues+=("missing prompt/*.md files")
|
|
278
|
+
fi
|
|
279
|
+
if [[ -f "$CHANGE_DIR/tasks.md" ]] && ! grep -Riq 'prompt/.*\.md' "$CHANGE_DIR/tasks.md" "$CHANGE_DIR/traceability-matrix.md" "$CHANGE_DIR/sdd-quality-gate.md" "$CHANGE_DIR/test-report.md" 2>/dev/null; then
|
|
280
|
+
issues+=("prompt files are not cross-linked from tasks/traceability/quality gate/test-report")
|
|
281
|
+
fi
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
transition_event=""
|
|
285
|
+
|
|
286
|
+
if [[ -x "$VALIDATE" && -f "$CHANGE_DIR/.sdd/state.yaml" ]]; then
|
|
287
|
+
"$VALIDATE" "$CHANGE_DIR" >/dev/null
|
|
288
|
+
fi
|
|
289
|
+
|
|
290
|
+
case "$PHASE" in
|
|
291
|
+
docs)
|
|
292
|
+
require_state_file
|
|
293
|
+
require_file proposal.md
|
|
294
|
+
require_file api.md
|
|
295
|
+
require_spec_doc
|
|
296
|
+
require_file design.md
|
|
297
|
+
require_file tasks.md
|
|
298
|
+
require_file tests.md
|
|
299
|
+
require_file traceability-matrix.md
|
|
300
|
+
require_file review-checklist.md
|
|
301
|
+
require_file sdd-quality-gate.md
|
|
302
|
+
require_file test-report.md
|
|
303
|
+
require_handoff
|
|
304
|
+
require_handoff_current
|
|
305
|
+
require_beta_handoff_structure
|
|
306
|
+
require_hash_recorded
|
|
307
|
+
require_grep 'Superpowers Technical Design Handoff|Superpower 技术详设|technical_design|源码级 HOW' design.md "Superpowers technical design handoff"
|
|
308
|
+
require_grep 'OpenSpec/SDD|WHAT|合同|API|DB|tests|验收' design.md "OpenSpec/SDD contract boundary"
|
|
309
|
+
require_grep '文档完整性|完整文档|proposal.md|api.md|design.md|tasks.md|tests.md' sdd-quality-gate.md "document completeness gate"
|
|
310
|
+
require_grep 'RED|红绿|GREEN' tests.md "RED/GREEN test contract"
|
|
311
|
+
require_grep 'curl|Postman|Newman|pytest|RestAssured|自动化命令' tests.md "interface automation command"
|
|
312
|
+
require_grep 'handoff_hash|sdd-context|上下文包|防漂移' sdd-quality-gate.md "handoff/context-drift gate"
|
|
313
|
+
require_markdown_links_valid
|
|
314
|
+
transition_event="docs-complete"
|
|
315
|
+
;;
|
|
316
|
+
design)
|
|
317
|
+
require_state_file
|
|
318
|
+
require_file proposal.md
|
|
319
|
+
require_file api.md
|
|
320
|
+
require_spec_doc
|
|
321
|
+
require_file design.md
|
|
322
|
+
require_file tasks.md
|
|
323
|
+
require_file tests.md
|
|
324
|
+
require_file traceability-matrix.md
|
|
325
|
+
require_file review-checklist.md
|
|
326
|
+
require_file sdd-quality-gate.md
|
|
327
|
+
require_file test-report.md
|
|
328
|
+
require_handoff
|
|
329
|
+
require_handoff_current
|
|
330
|
+
require_beta_handoff_structure
|
|
331
|
+
require_hash_recorded
|
|
332
|
+
workflow="$(state_get workflow)"
|
|
333
|
+
if [[ "$workflow" == "full" ]]; then
|
|
334
|
+
require_optional_state_path technical_design "technical_design"
|
|
335
|
+
technical_design_rel="$(state_get technical_design)"
|
|
336
|
+
if [[ -n "${technical_design_rel:-}" && "$technical_design_rel" != "null" ]]; then
|
|
337
|
+
require_grep 'Superpowers Technical Design|Superpower 技术详设|Technical Design|源码级 HOW' "$technical_design_rel" "Superpowers technical design"
|
|
338
|
+
require_grep 'OpenSpec/SDD|canonical|事实源|不得覆盖|不能覆盖' "$technical_design_rel" "technical design canonical boundary"
|
|
339
|
+
if change_has_architecture_boundary_risk; then
|
|
340
|
+
require_grep 'Architecture Boundary And Call Direction|架构边界与调用方向|模块职责.*调用方向|owner.*入口.*出口|禁止绕路' "$technical_design_rel" "architecture boundary and call direction matrix"
|
|
341
|
+
fi
|
|
342
|
+
if change_has_field_status_risk; then
|
|
343
|
+
require_grep 'Field And Status Reverse Impact|字段/状态反向影响面|写入点.*读取|读取/过滤点|派生/同步点' "$technical_design_rel" "field/status reverse impact matrix"
|
|
344
|
+
fi
|
|
345
|
+
fi
|
|
346
|
+
fi
|
|
347
|
+
require_grep 'Superpowers Technical Design Handoff|Superpower 技术详设|technical_design|源码级 HOW' design.md "Superpowers technical design handoff"
|
|
348
|
+
require_grep 'technical_design|Superpowers 技术详设|源码级 HOW' sdd-quality-gate.md "technical design quality gate"
|
|
349
|
+
require_markdown_links_valid
|
|
350
|
+
transition_event="design-complete"
|
|
351
|
+
;;
|
|
352
|
+
implement)
|
|
353
|
+
require_state_file
|
|
354
|
+
require_handoff
|
|
355
|
+
require_handoff_current
|
|
356
|
+
require_beta_handoff_structure
|
|
357
|
+
require_hash_recorded
|
|
358
|
+
require_any_prompt
|
|
359
|
+
require_prompt_set
|
|
360
|
+
require_grep 'OpenSpec/SDD|设计事实源|canonical|事实源' design.md "canonical source boundary"
|
|
361
|
+
prompt_rel="$(first_prompt_rel)"
|
|
362
|
+
if [[ -n "${prompt_rel:-}" ]]; then
|
|
363
|
+
require_grep 'Superpower 技术详设继承|Superpower 执行策略继承|technical_design|源码级 HOW' "$prompt_rel" "prompt Superpower strategy inheritance"
|
|
364
|
+
technical_design_rel="$(state_get technical_design)"
|
|
365
|
+
if [[ -n "${technical_design_rel:-}" && "$technical_design_rel" != "null" ]]; then
|
|
366
|
+
require_grep 'Superpower 技术详设继承|technical_design|源码级 HOW|Technical Design' "$prompt_rel" "prompt Superpowers technical design inheritance"
|
|
367
|
+
if change_has_field_status_risk; then
|
|
368
|
+
require_grep '字段/状态反向影响面|Field And Status Reverse Impact|读取/过滤点|派生/同步点' "$prompt_rel" "prompt field/status reverse impact inheritance"
|
|
369
|
+
fi
|
|
370
|
+
fi
|
|
371
|
+
require_grep '上下文防漂移|handoff_hash|sdd-context' "$prompt_rel" "prompt context drift inheritance"
|
|
372
|
+
fi
|
|
373
|
+
require_state_value build_mode "build_mode"
|
|
374
|
+
require_state_value isolation "isolation"
|
|
375
|
+
require_state_value tdd_mode "tdd_mode"
|
|
376
|
+
workflow="$(state_get workflow)"
|
|
377
|
+
review_mode="$(state_get review_mode)"
|
|
378
|
+
if [[ "$workflow" == "full" ]]; then
|
|
379
|
+
case "$review_mode" in
|
|
380
|
+
off|standard|thorough) ;;
|
|
381
|
+
*) issues+=("review_mode must be off, standard, or thorough before leaving implement") ;;
|
|
382
|
+
esac
|
|
383
|
+
fi
|
|
384
|
+
require_markdown_links_valid
|
|
385
|
+
transition_event="implement-complete"
|
|
386
|
+
;;
|
|
387
|
+
verify)
|
|
388
|
+
require_state_file
|
|
389
|
+
require_file test-report.md
|
|
390
|
+
require_grep 'RED|失败证据' test-report.md "RED evidence"
|
|
391
|
+
require_grep 'GREEN|通过证据' test-report.md "GREEN evidence"
|
|
392
|
+
require_grep '接口自动化|curl|Postman|Newman|pytest|RestAssured' test-report.md "interface automation evidence"
|
|
393
|
+
require_grep 'DB|数据库|SELECT|SHOW CREATE' test-report.md "DB evidence"
|
|
394
|
+
require_grep 'superflow-verify-integration|superflow-delivery-check|superflow-test-report-lint' test-report.md "SuperBridge Flow hook/script evidence"
|
|
395
|
+
require_test_report_lint
|
|
396
|
+
require_markdown_links_valid
|
|
397
|
+
if [[ "$(state_get verification_report)" == "" || "$(state_get verification_report)" == "null" ]]; then
|
|
398
|
+
"$STATE" set "$CHANGE_DIR" verification_report test-report.md
|
|
399
|
+
fi
|
|
400
|
+
transition_event="verify-pass"
|
|
401
|
+
;;
|
|
402
|
+
archive)
|
|
403
|
+
require_state_file
|
|
404
|
+
verify_result="$(state_get verify_result)"
|
|
405
|
+
[[ "$verify_result" == "pass" ]] || issues+=("verify_result must be pass before archive")
|
|
406
|
+
archived="$(state_get archived)"
|
|
407
|
+
[[ "$archived" != "true" ]] || issues+=("archived is already true")
|
|
408
|
+
require_state_value verification_report "verification_report"
|
|
409
|
+
transition_event="archived"
|
|
410
|
+
;;
|
|
411
|
+
*)
|
|
412
|
+
usage
|
|
413
|
+
exit 1
|
|
414
|
+
;;
|
|
415
|
+
esac
|
|
416
|
+
|
|
417
|
+
if [[ "${#issues[@]}" -gt 0 ]]; then
|
|
418
|
+
printf 'SDD guard failed for phase %s:\n' "$PHASE" >&2
|
|
419
|
+
printf -- '- %s\n' "${issues[@]}" >&2
|
|
420
|
+
exit 1
|
|
421
|
+
fi
|
|
422
|
+
|
|
423
|
+
printf 'SDD guard passed for phase %s\n' "$PHASE"
|
|
424
|
+
|
|
425
|
+
if [[ "$MODE" == "--apply" ]]; then
|
|
426
|
+
"$STATE" transition "$CHANGE_DIR" "$transition_event"
|
|
427
|
+
"$STATE" next "$CHANGE_DIR"
|
|
428
|
+
fi
|