@rpamis/comet 0.1.2 → 0.1.4
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/LICENSE +21 -21
- package/README.md +236 -184
- package/assets/manifest.json +2 -0
- package/assets/skills/comet/SKILL.md +18 -18
- package/assets/skills/comet/scripts/comet-guard.sh +79 -23
- package/assets/skills/comet/scripts/comet-yaml-validate.sh +130 -0
- package/assets/skills/comet-archive/SKILL.md +50 -7
- package/assets/skills/comet-build/SKILL.md +52 -14
- package/assets/skills/comet-design/SKILL.md +36 -4
- package/assets/skills/comet-hotfix/SKILL.md +47 -13
- package/assets/skills/comet-open/SKILL.md +51 -15
- package/assets/skills/comet-tweak/SKILL.md +47 -13
- package/assets/skills/comet-verify/SKILL.md +48 -16
- package/bin/comet.js +3 -3
- package/dist/core/init.d.ts.map +1 -1
- package/dist/core/init.js +90 -14
- package/dist/core/init.js.map +1 -1
- package/package.json +1 -1
- package/scripts/postinstall.js +44 -44
|
@@ -6,14 +6,37 @@
|
|
|
6
6
|
|
|
7
7
|
set -euo pipefail
|
|
8
8
|
|
|
9
|
-
CHANGE="$1"
|
|
10
|
-
PHASE="$2"
|
|
11
|
-
CHANGE_DIR="openspec/changes/$CHANGE"
|
|
12
|
-
|
|
13
9
|
red() { echo -e "\033[31m$1\033[0m" >&2; }
|
|
14
10
|
green() { echo -e "\033[32m$1\033[0m" >&2; }
|
|
15
11
|
warn() { echo -e "\033[33m$1\033[0m" >&2; }
|
|
16
12
|
|
|
13
|
+
# Input validation - prevent path traversal
|
|
14
|
+
validate_change_name() {
|
|
15
|
+
local name="$1"
|
|
16
|
+
# Reject empty names
|
|
17
|
+
if [ -z "$name" ]; then
|
|
18
|
+
red "ERROR: Change name cannot be empty" >&2
|
|
19
|
+
exit 1
|
|
20
|
+
fi
|
|
21
|
+
# Only allow alphanumeric, hyphens, and underscores
|
|
22
|
+
if [[ ! "$name" =~ ^[a-zA-Z0-9_-]+$ ]]; then
|
|
23
|
+
red "ERROR: Invalid change name: '$name'" >&2
|
|
24
|
+
red "Valid characters: a-z, A-Z, 0-9, -, _" >&2
|
|
25
|
+
exit 1
|
|
26
|
+
fi
|
|
27
|
+
# Reject path traversal attempts
|
|
28
|
+
if [[ "$name" =~ \.\. ]]; then
|
|
29
|
+
red "ERROR: Change name cannot contain '..' (path traversal not allowed)" >&2
|
|
30
|
+
exit 1
|
|
31
|
+
fi
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
validate_change_name "$1"
|
|
35
|
+
|
|
36
|
+
CHANGE="$1"
|
|
37
|
+
PHASE="$2"
|
|
38
|
+
CHANGE_DIR="openspec/changes/$CHANGE"
|
|
39
|
+
|
|
17
40
|
BLOCK=0
|
|
18
41
|
check() {
|
|
19
42
|
local desc="$1"
|
|
@@ -40,20 +63,11 @@ tasks_has_any() {
|
|
|
40
63
|
[ -f "$tasks" ] && grep -q '\- \[' "$tasks"
|
|
41
64
|
}
|
|
42
65
|
|
|
43
|
-
yaml_has_field() {
|
|
44
|
-
local field="$1"
|
|
45
|
-
local yaml="$CHANGE_DIR/.openspec.yaml"
|
|
46
|
-
[ -f "$yaml" ] && grep -q "^${field}:" "$yaml"
|
|
47
|
-
}
|
|
48
|
-
|
|
49
66
|
yaml_field_value() {
|
|
50
67
|
local field="$1"
|
|
51
|
-
local yaml="$CHANGE_DIR/.
|
|
68
|
+
local yaml="$CHANGE_DIR/.comet.yaml"
|
|
52
69
|
if [ -f "$yaml" ]; then
|
|
53
|
-
|
|
54
|
-
local escaped
|
|
55
|
-
escaped=$(echo "$field" | sed 's/\./\\./g')
|
|
56
|
-
grep "^${escaped}:" "$yaml" | sed "s/^${escaped}: *//" | tr -d '"' | tr -d "'"
|
|
70
|
+
grep "^${field}:" "$yaml" | sed "s/^${field}: *//" | tr -d '"' | tr -d "'"
|
|
57
71
|
fi
|
|
58
72
|
}
|
|
59
73
|
|
|
@@ -61,16 +75,57 @@ file_nonempty() {
|
|
|
61
75
|
[ -f "$1" ] && [ -s "$1" ]
|
|
62
76
|
}
|
|
63
77
|
|
|
78
|
+
preflight() {
|
|
79
|
+
local expected_phase="$1"
|
|
80
|
+
|
|
81
|
+
if [ ! -d "$CHANGE_DIR" ]; then
|
|
82
|
+
red "FATAL: change directory not found: $CHANGE_DIR"
|
|
83
|
+
exit 1
|
|
84
|
+
fi
|
|
85
|
+
if [ ! -f "$CHANGE_DIR/.comet.yaml" ]; then
|
|
86
|
+
red "FATAL: .comet.yaml not found in $CHANGE_DIR"
|
|
87
|
+
exit 1
|
|
88
|
+
fi
|
|
89
|
+
|
|
90
|
+
local actual_phase
|
|
91
|
+
actual_phase=$(yaml_field_value "phase" 2>/dev/null || true)
|
|
92
|
+
if [ "$actual_phase" != "$expected_phase" ]; then
|
|
93
|
+
red "FATAL: .comet.yaml phase is '$actual_phase', expected '$expected_phase'"
|
|
94
|
+
exit 1
|
|
95
|
+
fi
|
|
96
|
+
|
|
97
|
+
# Schema validation
|
|
98
|
+
local script_dir validate_script
|
|
99
|
+
script_dir="$(dirname "$(readlink -f "$0" 2>/dev/null || echo "$0")" 2>/dev/null || dirname "$0")"
|
|
100
|
+
validate_script="$script_dir/comet-yaml-validate.sh"
|
|
101
|
+
if [ -f "$validate_script" ]; then
|
|
102
|
+
if ! bash "$validate_script" "$CHANGE" 2>/dev/null; then
|
|
103
|
+
bash "$validate_script" "$CHANGE"
|
|
104
|
+
red "FATAL: .comet.yaml schema validation failed"
|
|
105
|
+
exit 1
|
|
106
|
+
fi
|
|
107
|
+
fi
|
|
108
|
+
}
|
|
109
|
+
|
|
64
110
|
maven_compiles() {
|
|
111
|
+
if [ "${COMET_SKIP_BUILD:-0}" = "1" ]; then
|
|
112
|
+
return 0
|
|
113
|
+
fi
|
|
65
114
|
mvn compile -q 2>/dev/null
|
|
66
115
|
}
|
|
67
116
|
|
|
68
117
|
verify_result_is_pass() {
|
|
69
118
|
local result
|
|
70
|
-
result=$(yaml_field_value "
|
|
119
|
+
result=$(yaml_field_value "verify_result" 2>/dev/null || true)
|
|
71
120
|
[ "$result" = "pass" ]
|
|
72
121
|
}
|
|
73
122
|
|
|
123
|
+
archived_is_true() {
|
|
124
|
+
local val
|
|
125
|
+
val=$(yaml_field_value "archived" 2>/dev/null || true)
|
|
126
|
+
[ "$val" = "true" ]
|
|
127
|
+
}
|
|
128
|
+
|
|
74
129
|
# --- Phase-specific checks ---
|
|
75
130
|
|
|
76
131
|
guard_open() {
|
|
@@ -86,7 +141,7 @@ guard_design() {
|
|
|
86
141
|
echo "=== Guard: design → build ===" >&2
|
|
87
142
|
|
|
88
143
|
local design_doc
|
|
89
|
-
design_doc=$(yaml_field_value "
|
|
144
|
+
design_doc=$(yaml_field_value "design_doc" 2>/dev/null || true)
|
|
90
145
|
|
|
91
146
|
check "proposal.md exists" file_nonempty "$CHANGE_DIR/proposal.md"
|
|
92
147
|
check "tasks.md exists" file_nonempty "$CHANGE_DIR/tasks.md"
|
|
@@ -94,7 +149,7 @@ guard_design() {
|
|
|
94
149
|
if [ -n "$design_doc" ] && [ "$design_doc" != "null" ]; then
|
|
95
150
|
check "Design Doc ($design_doc) exists" file_nonempty "$design_doc"
|
|
96
151
|
else
|
|
97
|
-
warn " [WARN] No design_doc recorded in .
|
|
152
|
+
warn " [WARN] No design_doc recorded in .comet.yaml"
|
|
98
153
|
fi
|
|
99
154
|
}
|
|
100
155
|
|
|
@@ -117,6 +172,7 @@ guard_verify() {
|
|
|
117
172
|
guard_archive() {
|
|
118
173
|
echo "=== Guard: archive completeness ===" >&2
|
|
119
174
|
|
|
175
|
+
check "archived is true" archived_is_true
|
|
120
176
|
check "proposal.md exists" file_nonempty "$CHANGE_DIR/proposal.md"
|
|
121
177
|
check "tasks.md all tasks checked" tasks_all_done
|
|
122
178
|
}
|
|
@@ -124,11 +180,11 @@ guard_archive() {
|
|
|
124
180
|
# --- Main ---
|
|
125
181
|
|
|
126
182
|
case "$PHASE" in
|
|
127
|
-
open) guard_open ;;
|
|
128
|
-
design) guard_design ;;
|
|
129
|
-
build) guard_build ;;
|
|
130
|
-
verify) guard_verify ;;
|
|
131
|
-
archive) guard_archive ;;
|
|
183
|
+
open) preflight "design" ; guard_open ;;
|
|
184
|
+
design) preflight "build" ; guard_design ;;
|
|
185
|
+
build) preflight "verify" ; guard_build ;;
|
|
186
|
+
verify) preflight "archive" ; guard_verify ;;
|
|
187
|
+
archive) preflight "archive" ; guard_archive ;;
|
|
132
188
|
*)
|
|
133
189
|
red "Unknown phase: $PHASE"
|
|
134
190
|
echo "Valid phases: open, design, build, verify, archive" >&2
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Comet YAML Schema Validator — validates .comet.yaml structure
|
|
3
|
+
# Usage: comet-yaml-validate.sh <change-name>
|
|
4
|
+
# Exit 0 = valid, exit 1 = errors found (printed to stderr)
|
|
5
|
+
|
|
6
|
+
set -euo pipefail
|
|
7
|
+
|
|
8
|
+
red() { echo -e "\033[31m$1\033[0m" >&2; }
|
|
9
|
+
green() { echo -e "\033[32m$1\033[0m" >&2; }
|
|
10
|
+
warn() { echo -e "\033[33m$1\033[0m" >&2; }
|
|
11
|
+
|
|
12
|
+
# Input validation - prevent path traversal
|
|
13
|
+
validate_change_name() {
|
|
14
|
+
local name="$1"
|
|
15
|
+
# Reject empty names
|
|
16
|
+
if [ -z "$name" ]; then
|
|
17
|
+
red "ERROR: Change name cannot be empty" >&2
|
|
18
|
+
exit 1
|
|
19
|
+
fi
|
|
20
|
+
# Only allow alphanumeric, hyphens, and underscores
|
|
21
|
+
if [[ ! "$name" =~ ^[a-zA-Z0-9_-]+$ ]]; then
|
|
22
|
+
red "ERROR: Invalid change name: '$name'" >&2
|
|
23
|
+
red "Valid characters: a-z, A-Z, 0-9, -, _" >&2
|
|
24
|
+
exit 1
|
|
25
|
+
fi
|
|
26
|
+
# Reject path traversal attempts
|
|
27
|
+
if [[ "$name" =~ \.\. ]]; then
|
|
28
|
+
red "ERROR: Change name cannot contain '..' (path traversal not allowed)" >&2
|
|
29
|
+
exit 1
|
|
30
|
+
fi
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
validate_change_name "$1"
|
|
34
|
+
|
|
35
|
+
CHANGE="$1"
|
|
36
|
+
YAML="openspec/changes/$CHANGE/.comet.yaml"
|
|
37
|
+
|
|
38
|
+
ERRORS=0
|
|
39
|
+
WARNINGS=0
|
|
40
|
+
|
|
41
|
+
# Helper: get value of a top-level field (handles null, empty, quoted)
|
|
42
|
+
field_value() {
|
|
43
|
+
grep "^${1}:" "$YAML" 2>/dev/null | sed "s/^${1}: *//" | tr -d '"' | tr -d "'" || true
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
fail() { red " FAIL: $1"; ERRORS=$((ERRORS + 1)); }
|
|
47
|
+
warn_msg() { warn " WARN: $1"; WARNINGS=$((WARNINGS + 1)); }
|
|
48
|
+
|
|
49
|
+
echo "[VALIDATE] $YAML" >&2
|
|
50
|
+
|
|
51
|
+
# --- Required fields ---
|
|
52
|
+
REQUIRED_FIELDS="workflow phase design_doc plan build_mode verify_mode verify_result verified_at archived"
|
|
53
|
+
for field in $REQUIRED_FIELDS; do
|
|
54
|
+
if ! grep -q "^${field}:" "$YAML" 2>/dev/null; then
|
|
55
|
+
fail "missing required field '$field'"
|
|
56
|
+
fi
|
|
57
|
+
done
|
|
58
|
+
|
|
59
|
+
# --- Enum validation ---
|
|
60
|
+
validate_enum() {
|
|
61
|
+
local field="$1" value="$2"
|
|
62
|
+
shift 2
|
|
63
|
+
local valid_values="$*"
|
|
64
|
+
|
|
65
|
+
# null or empty is always acceptable
|
|
66
|
+
if [ -z "$value" ] || [ "$value" = "null" ]; then
|
|
67
|
+
return 0
|
|
68
|
+
fi
|
|
69
|
+
|
|
70
|
+
for v in $valid_values; do
|
|
71
|
+
if [ "$value" = "$v" ]; then
|
|
72
|
+
return 0
|
|
73
|
+
fi
|
|
74
|
+
done
|
|
75
|
+
fail "$field='$value' is not valid. Expected: $valid_values"
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
workflow=$(field_value "workflow")
|
|
79
|
+
phase=$(field_value "phase")
|
|
80
|
+
build_mode=$(field_value "build_mode")
|
|
81
|
+
verify_mode=$(field_value "verify_mode")
|
|
82
|
+
verify_result=$(field_value "verify_result")
|
|
83
|
+
archived=$(field_value "archived")
|
|
84
|
+
design_doc=$(field_value "design_doc")
|
|
85
|
+
plan=$(field_value "plan")
|
|
86
|
+
|
|
87
|
+
validate_enum "workflow" "$workflow" "full hotfix tweak"
|
|
88
|
+
validate_enum "phase" "$phase" "design build verify archive"
|
|
89
|
+
validate_enum "build_mode" "$build_mode" "subagent-driven-development executing-plans direct"
|
|
90
|
+
validate_enum "verify_mode" "$verify_mode" "light full"
|
|
91
|
+
validate_enum "verify_result" "$verify_result" "pending pass fail"
|
|
92
|
+
validate_enum "archived" "$archived" "true false"
|
|
93
|
+
|
|
94
|
+
# --- Path validation ---
|
|
95
|
+
|
|
96
|
+
if [ -n "$design_doc" ] && [ "$design_doc" != "null" ]; then
|
|
97
|
+
if [ ! -f "$design_doc" ]; then
|
|
98
|
+
fail "design_doc='$design_doc' does not exist on disk"
|
|
99
|
+
fi
|
|
100
|
+
fi
|
|
101
|
+
|
|
102
|
+
if [ -n "$plan" ] && [ "$plan" != "null" ]; then
|
|
103
|
+
if [ ! -f "$plan" ]; then
|
|
104
|
+
fail "plan='$plan' does not exist on disk"
|
|
105
|
+
fi
|
|
106
|
+
fi
|
|
107
|
+
|
|
108
|
+
# --- Unknown keys check ---
|
|
109
|
+
KNOWN_KEYS="workflow phase design_doc plan build_mode verify_mode verify_result verified_at archived"
|
|
110
|
+
while IFS=: read -r key _; do
|
|
111
|
+
key="${key// /}"
|
|
112
|
+
[ -z "$key" ] && continue
|
|
113
|
+
found=0
|
|
114
|
+
for known in $KNOWN_KEYS; do
|
|
115
|
+
[ "$key" = "$known" ] && found=1 && break
|
|
116
|
+
done
|
|
117
|
+
if [ "$found" -eq 0 ]; then
|
|
118
|
+
warn_msg "unknown field '$key' found"
|
|
119
|
+
fi
|
|
120
|
+
done < "$YAML"
|
|
121
|
+
|
|
122
|
+
# --- Summary ---
|
|
123
|
+
echo "" >&2
|
|
124
|
+
if [ "$ERRORS" -gt 0 ]; then
|
|
125
|
+
red "$ERRORS error(s), $WARNINGS warning(s) — validation FAILED"
|
|
126
|
+
exit 1
|
|
127
|
+
else
|
|
128
|
+
green "0 errors, $WARNINGS warning(s) — validation PASSED"
|
|
129
|
+
exit 0
|
|
130
|
+
fi
|
|
@@ -9,13 +9,37 @@ description: "Comet 阶段 5:归档。用 /comet-archive 调用。同步 delta
|
|
|
9
9
|
|
|
10
10
|
- 验证已通过(阶段 4 完成)
|
|
11
11
|
- 分支已处理
|
|
12
|
-
- `openspec/changes/<name>/.
|
|
12
|
+
- `openspec/changes/<name>/.comet.yaml` 中 `verify_result: pass`
|
|
13
13
|
|
|
14
14
|
## 步骤
|
|
15
15
|
|
|
16
|
+
### 0. 入口状态验证(Entry Check)
|
|
17
|
+
|
|
18
|
+
在执行任何操作之前,读取并验证当前状态:
|
|
19
|
+
|
|
20
|
+
**检查清单:**
|
|
21
|
+
1. `openspec/changes/<name>/.comet.yaml` 存在
|
|
22
|
+
2. `phase` 字段的值为 `"archive"`
|
|
23
|
+
3. `verify_result` 字段的值为 `"pass"`
|
|
24
|
+
4. `archived` 字段为 `"false"` 或 null(尚未归档)
|
|
25
|
+
|
|
26
|
+
**验证方式:**
|
|
27
|
+
- `cat openspec/changes/<name>/.comet.yaml` 读取全部字段
|
|
28
|
+
- 如 `verify_result` 不是 `"pass"`,必须先完成验证
|
|
29
|
+
|
|
30
|
+
**失败输出:**
|
|
31
|
+
```
|
|
32
|
+
[HARD STOP] Entry check failed for comet-archive
|
|
33
|
+
Expected: phase=archive, verify_result=pass, archived=false|null
|
|
34
|
+
Actual: phase=<实际值>, verify_result=<实际值>, archived=<实际值>
|
|
35
|
+
Suggestion: Run comet-verify first, or this change was already archived.
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
验证通过后才进入步骤 1。
|
|
39
|
+
|
|
16
40
|
### 1. 执行归档
|
|
17
41
|
|
|
18
|
-
归档前如 `
|
|
42
|
+
归档前如 `verify_result` 不是 `pass`,停止归档并返回 `/comet-verify`。
|
|
19
43
|
|
|
20
44
|
**立即执行:** 使用 Skill 工具加载 `openspec-archive-change` 技能。禁止跳过此步骤。
|
|
21
45
|
|
|
@@ -24,6 +48,19 @@ description: "Comet 阶段 5:归档。用 /comet-archive 调用。同步 delta
|
|
|
24
48
|
2. 所有任务已标记 `[x]`
|
|
25
49
|
3. delta specs 同步状态
|
|
26
50
|
|
|
51
|
+
### 1b. 移动 Comet 状态文件
|
|
52
|
+
|
|
53
|
+
`openspec-archive-change` 不感知 `.comet.yaml`,因此 Comet 需要在 OpenSpec 归档完成后自行移动该文件:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
mv openspec/changes/<name>/.comet.yaml openspec/changes/archive/YYYY-MM-DD-<name>/.comet.yaml
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
【写入验证】移动完成后必须验证:
|
|
60
|
+
test -f openspec/changes/archive/YYYY-MM-DD-<name>/.comet.yaml
|
|
61
|
+
确认归档目录中 .comet.yaml 存在
|
|
62
|
+
如文件不在预期位置,检查 mv 命令是否成功执行。
|
|
63
|
+
|
|
27
64
|
### 2. Delta Spec 同步
|
|
28
65
|
|
|
29
66
|
归档时将 delta specs 同步到主 specs:
|
|
@@ -73,6 +110,7 @@ change 移入归档目录:
|
|
|
73
110
|
```
|
|
74
111
|
openspec/changes/archive/YYYY-MM-DD-<name>/
|
|
75
112
|
├── .openspec.yaml
|
|
113
|
+
├── .comet.yaml
|
|
76
114
|
├── proposal.md
|
|
77
115
|
├── design.md
|
|
78
116
|
├── specs/<capability>/spec.md
|
|
@@ -92,17 +130,22 @@ brainstorming → delta spec → 实施(增量修改)→ 验证 → 主 spec
|
|
|
92
130
|
- 主 specs 已更新(delta → main 同步完成)
|
|
93
131
|
- 关联 design doc 已标注归档状态
|
|
94
132
|
- 关联 plan 已标注归档状态
|
|
95
|
-
- `.
|
|
133
|
+
- `.comet.yaml` 中 `archived` 已记录为 `true`
|
|
96
134
|
- **阶段守卫**:运行 `bash $COMET_GUARD <change-name> archive`,全部 PASS 后确认归档完整
|
|
97
135
|
|
|
98
|
-
归档完成后,在归档目录的 `.
|
|
136
|
+
归档完成后,在归档目录的 `.comet.yaml` 中更新:
|
|
99
137
|
|
|
100
138
|
```yaml
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
archived: true
|
|
139
|
+
phase: archive
|
|
140
|
+
archived: true
|
|
104
141
|
```
|
|
105
142
|
|
|
143
|
+
【写入验证】更新完成后必须验证:
|
|
144
|
+
cat openspec/changes/archive/YYYY-MM-DD-<name>/.comet.yaml
|
|
145
|
+
确认 phase 行的值为 "archive"
|
|
146
|
+
确认 archived 行的值为 "true"
|
|
147
|
+
如任一字段不匹配,重试写入后再次验证。最多重试 2 次,仍失败则报告错误并终止。
|
|
148
|
+
|
|
106
149
|
## 完成
|
|
107
150
|
|
|
108
151
|
Comet 流程全部完成。如需开始新工作,调用 `/comet` 或 `/comet-open`。
|
|
@@ -12,6 +12,32 @@ description: "Comet 阶段 3:计划与构建。用 /comet-build 调用。制
|
|
|
12
12
|
|
|
13
13
|
## 步骤
|
|
14
14
|
|
|
15
|
+
### 0. 入口状态验证(Entry Check)
|
|
16
|
+
|
|
17
|
+
在执行任何操作之前,读取并验证当前状态:
|
|
18
|
+
|
|
19
|
+
**检查清单:**
|
|
20
|
+
1. `openspec/changes/<name>/.comet.yaml` 存在
|
|
21
|
+
2. `phase` 字段的值为 `"build"`
|
|
22
|
+
3. `design_doc` 字段非 null 且非空
|
|
23
|
+
4. `design_doc` 引用的文件存在(例如 `docs/superpowers/specs/YYYY-MM-DD-topic-design.md`)
|
|
24
|
+
5. `openspec/changes/<name>/proposal.md` 存在且非空
|
|
25
|
+
6. `openspec/changes/<name>/tasks.md` 存在且非空
|
|
26
|
+
|
|
27
|
+
**验证方式:**
|
|
28
|
+
- `cat openspec/changes/<name>/.comet.yaml` 读取全部字段
|
|
29
|
+
- 用 `ls` 或 `test -f` 确认 design_doc 文件存在
|
|
30
|
+
|
|
31
|
+
**失败输出:**
|
|
32
|
+
```
|
|
33
|
+
[HARD STOP] Entry check failed for comet-build
|
|
34
|
+
Expected: phase=build, design_doc=<path> exists
|
|
35
|
+
Actual: phase=<实际值>, design_doc=<实际值或文件不存在>
|
|
36
|
+
Suggestion: Run comet-design first, or verify design_doc file exists.
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
验证通过后才进入步骤 1。
|
|
40
|
+
|
|
15
41
|
### 1. 制定计划
|
|
16
42
|
|
|
17
43
|
**立即执行:** 使用 Skill 工具加载 `superpowers:writing-plans` 技能。禁止跳过此步骤。
|
|
@@ -30,14 +56,18 @@ design-doc: docs/superpowers/specs/YYYY-MM-DD-<topic>-design.md
|
|
|
30
56
|
|
|
31
57
|
### 2. 更新计划状态
|
|
32
58
|
|
|
33
|
-
在 `openspec/changes/<name>/.
|
|
59
|
+
在 `openspec/changes/<name>/.comet.yaml` 中合并更新以下字段(保留其他字段不变):
|
|
34
60
|
|
|
35
61
|
```yaml
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
plan: docs/superpowers/plans/YYYY-MM-DD-feature.md
|
|
62
|
+
phase: build
|
|
63
|
+
plan: docs/superpowers/plans/YYYY-MM-DD-feature.md
|
|
39
64
|
```
|
|
40
65
|
|
|
66
|
+
【写入验证】更新完成后必须验证:
|
|
67
|
+
cat openspec/changes/<name>/.comet.yaml
|
|
68
|
+
确认 plan 行的值为 "docs/superpowers/plans/YYYY-MM-DD-feature.md"
|
|
69
|
+
如不匹配,重试写入后再次验证。最多重试 2 次,仍失败则报告错误并终止。
|
|
70
|
+
|
|
41
71
|
### 3. 选择执行方式
|
|
42
72
|
|
|
43
73
|
向用户展示计划摘要(任务数、涉及模块),然后询问执行方式:
|
|
@@ -52,7 +82,7 @@ comet:
|
|
|
52
82
|
- 任务数 ≤ 2 且无跨模块依赖 → 推荐 B
|
|
53
83
|
- 来自 hotfix 路径 → 推荐 B
|
|
54
84
|
|
|
55
|
-
用户选择后,在 `openspec/changes/<name>/.
|
|
85
|
+
用户选择后,在 `openspec/changes/<name>/.comet.yaml` 中合并更新 `build_mode`(保留其他字段不变)。`build_mode` 只允许以下值之一:
|
|
56
86
|
|
|
57
87
|
- `subagent-driven-development`
|
|
58
88
|
- `executing-plans`
|
|
@@ -62,16 +92,19 @@ Few-shot 示例:
|
|
|
62
92
|
|
|
63
93
|
```yaml
|
|
64
94
|
# 用户选择稳健模式 / A
|
|
65
|
-
|
|
66
|
-
build_mode: subagent-driven-development
|
|
95
|
+
build_mode: subagent-driven-development
|
|
67
96
|
```
|
|
68
97
|
|
|
69
98
|
```yaml
|
|
70
99
|
# 用户选择快速模式 / B
|
|
71
|
-
|
|
72
|
-
build_mode: executing-plans
|
|
100
|
+
build_mode: executing-plans
|
|
73
101
|
```
|
|
74
102
|
|
|
103
|
+
【写入验证】更新完成后必须验证:
|
|
104
|
+
cat openspec/changes/<name>/.comet.yaml
|
|
105
|
+
确认 build_mode 行的值为 "<subagent-driven-development 或 executing-plans 或 direct>"
|
|
106
|
+
如不匹配,重试写入后再次验证。最多重试 2 次,仍失败则报告错误并终止。
|
|
107
|
+
|
|
75
108
|
然后,**立即执行:** 使用 Skill 工具加载对应技能。禁止跳过此步骤。
|
|
76
109
|
|
|
77
110
|
如所选 Superpowers 技能不可用,停止流程并提示安装或启用对应技能,不要用普通对话替代该步骤。
|
|
@@ -105,17 +138,22 @@ comet:
|
|
|
105
138
|
- tasks.md 全部勾选
|
|
106
139
|
- 代码已提交
|
|
107
140
|
- 测试通过
|
|
108
|
-
- `.
|
|
141
|
+
- `.comet.yaml` 中 `phase` 已更新为 `verify`
|
|
109
142
|
- **阶段守卫**:运行 `bash $COMET_GUARD <change-name> build`,全部 PASS 后才允许流转
|
|
110
143
|
|
|
111
|
-
|
|
144
|
+
退出前在 `.comet.yaml` 中合并更新以下字段(保留其他字段不变):
|
|
112
145
|
|
|
113
146
|
```yaml
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
verify_result: pending
|
|
147
|
+
phase: verify
|
|
148
|
+
verify_result: pending
|
|
117
149
|
```
|
|
118
150
|
|
|
151
|
+
【写入验证】更新完成后必须验证:
|
|
152
|
+
cat openspec/changes/<name>/.comet.yaml
|
|
153
|
+
确认 phase 行的值为 "verify"
|
|
154
|
+
确认 verify_result 行的值为 "pending"
|
|
155
|
+
如任一字段不匹配,重试写入后再次验证。最多重试 2 次,仍失败则报告错误并终止。
|
|
156
|
+
|
|
119
157
|
## 自动流转
|
|
120
158
|
|
|
121
159
|
退出条件满足后,**无需等待用户再次输入**,直接执行下一阶段:
|
|
@@ -12,6 +12,33 @@ description: "Comet 阶段 2:深度设计。用 /comet-design 调用。通过
|
|
|
12
12
|
|
|
13
13
|
## 步骤
|
|
14
14
|
|
|
15
|
+
### 0. 入口状态验证(Entry Check)
|
|
16
|
+
|
|
17
|
+
在执行任何操作之前,读取并验证当前状态:
|
|
18
|
+
|
|
19
|
+
**检查清单:**
|
|
20
|
+
1. `openspec/changes/<name>/.comet.yaml` 存在
|
|
21
|
+
2. `phase` 字段的值为 `"design"`
|
|
22
|
+
3. `workflow` 字段的值为 `"full"`
|
|
23
|
+
4. `design_doc` 字段为 `null` 或空
|
|
24
|
+
5. `openspec/changes/<name>/proposal.md` 存在且非空
|
|
25
|
+
6. `openspec/changes/<name>/design.md` 存在且非空
|
|
26
|
+
7. `openspec/changes/<name>/tasks.md` 存在且非空
|
|
27
|
+
|
|
28
|
+
**验证方式:**
|
|
29
|
+
- `cat openspec/changes/<name>/.comet.yaml` 读取全部字段
|
|
30
|
+
- 逐条比对检查清单
|
|
31
|
+
|
|
32
|
+
**失败输出:**
|
|
33
|
+
```
|
|
34
|
+
[HARD STOP] Entry check failed for comet-design
|
|
35
|
+
Expected: phase=design, design_doc=<empty/null>, workflow=full
|
|
36
|
+
Actual: phase=<实际值>, design_doc=<实际值>, workflow=<实际值>
|
|
37
|
+
Suggestion: Run comet-open first, or check if .comet.yaml was modified out of sequence.
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
验证通过后才进入步骤 1。
|
|
41
|
+
|
|
15
42
|
### 1a. 读取已有上下文
|
|
16
43
|
|
|
17
44
|
读取活跃 change 下的 `proposal.md` 和 `design.md`,将核心内容整理为摘要:
|
|
@@ -39,14 +66,19 @@ Design 摘要: <design.md 架构决策>
|
|
|
39
66
|
|
|
40
67
|
### 2. 更新 Comet 状态
|
|
41
68
|
|
|
42
|
-
在 `openspec/changes/<name>/.
|
|
69
|
+
在 `openspec/changes/<name>/.comet.yaml` 中合并更新以下字段(保留其他字段不变):
|
|
43
70
|
|
|
44
71
|
```yaml
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
design_doc: docs/superpowers/specs/YYYY-MM-DD-topic-design.md
|
|
72
|
+
phase: build
|
|
73
|
+
design_doc: docs/superpowers/specs/YYYY-MM-DD-topic-design.md
|
|
48
74
|
```
|
|
49
75
|
|
|
76
|
+
【写入验证】更新完成后必须验证:
|
|
77
|
+
cat openspec/changes/<name>/.comet.yaml
|
|
78
|
+
确认 phase 行的值为 "build"
|
|
79
|
+
确认 design_doc 行的值为 "docs/superpowers/specs/YYYY-MM-DD-topic-design.md"
|
|
80
|
+
如任一字段不匹配,重试写入后再次验证。最多重试 2 次,仍失败则报告错误并终止。
|
|
81
|
+
|
|
50
82
|
### 3. 双 Spec 分工
|
|
51
83
|
|
|
52
84
|
| Spec 类型 | 归属 | 存放位置 | 定义 |
|
|
@@ -20,6 +20,28 @@ Hotfix 是 Comet 五阶段能力的预设工作流,不是独立的平行流程
|
|
|
20
20
|
|
|
21
21
|
## 流程(preset workflow,4 阶段)
|
|
22
22
|
|
|
23
|
+
### 0. 入口状态验证(Entry Check)
|
|
24
|
+
|
|
25
|
+
在执行任何操作之前,验证当前状态:
|
|
26
|
+
|
|
27
|
+
**检查清单:**
|
|
28
|
+
1. `openspec/changes/<name>/` 目录不存在,或目录存在但 `.comet.yaml` 不存在(无冲突)
|
|
29
|
+
|
|
30
|
+
**验证方式:**
|
|
31
|
+
- `test -d openspec/changes/<name>` 检查目录
|
|
32
|
+
- 如目录存在,`test -f openspec/changes/<name>/.comet.yaml` 检查配置文件
|
|
33
|
+
- 如 `.comet.yaml` 已存在,读取 `phase` 检查是否为未完成的 hotfix
|
|
34
|
+
|
|
35
|
+
**失败输出(有冲突):**
|
|
36
|
+
```
|
|
37
|
+
[HARD STOP] Entry check failed for comet-hotfix
|
|
38
|
+
Expected: openspec/changes/<name>/.comet.yaml does not exist (new change)
|
|
39
|
+
Actual: .comet.yaml exists with phase=<实际值>
|
|
40
|
+
Suggestion: Pick a different change name, or check if an existing hotfix is in progress.
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
验证通过后才进入流程步骤。
|
|
44
|
+
|
|
23
45
|
执行链路:open → build → verify → archive。Hotfix 为每个阶段提供默认决策:精简开启、直接构建、按规模验证、验证通过后归档。
|
|
24
46
|
|
|
25
47
|
### 1. 快速开启(preset open)
|
|
@@ -34,21 +56,33 @@ Hotfix 是 Comet 五阶段能力的预设工作流,不是独立的平行流程
|
|
|
34
56
|
- `tasks.md` — 修复任务清单
|
|
35
57
|
- **无需 delta spec**(除非修复改变了已有 spec 的验收场景)
|
|
36
58
|
|
|
37
|
-
在 `openspec/changes/<name
|
|
59
|
+
在 `openspec/changes/<name>/` 下创建独立的 `.comet.yaml` 文件:
|
|
38
60
|
|
|
39
61
|
```yaml
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
archived: false
|
|
62
|
+
workflow: hotfix
|
|
63
|
+
phase: build
|
|
64
|
+
design_doc: null
|
|
65
|
+
plan: null
|
|
66
|
+
build_mode: direct
|
|
67
|
+
verify_mode: light
|
|
68
|
+
verify_result: pending
|
|
69
|
+
verified_at: null
|
|
70
|
+
archived: false
|
|
50
71
|
```
|
|
51
72
|
|
|
73
|
+
【写入验证】创建完成后必须验证:
|
|
74
|
+
cat openspec/changes/<name>/.comet.yaml
|
|
75
|
+
确认 workflow 行的值为 "hotfix"
|
|
76
|
+
确认 phase 行的值为 "build"
|
|
77
|
+
确认 design_doc 行的值为 "null"
|
|
78
|
+
确认 plan 行的值为 "null"
|
|
79
|
+
确认 build_mode 行的值为 "direct"
|
|
80
|
+
确认 verify_mode 行的值为 "light"
|
|
81
|
+
确认 verify_result 行的值为 "pending"
|
|
82
|
+
确认 verified_at 行的值为 "null"
|
|
83
|
+
确认 archived 行的值为 "false"
|
|
84
|
+
如任一字段不匹配,重试写入后再次验证。最多重试 2 次,仍失败则报告错误并终止。
|
|
85
|
+
|
|
52
86
|
### 2. 直接构建(preset build)
|
|
53
87
|
|
|
54
88
|
使用 hotfix 默认值:`build_mode: direct`。跳过 `superpowers:brainstorming` 和 `superpowers:writing-plans`(除非任务 > 3 个;若超过 3 个任务,转入 `/comet-build` 的计划与执行方式选择)。
|
|
@@ -87,11 +121,11 @@ comet:
|
|
|
87
121
|
- 回归测试揭示深层架构问题 → 停止 hotfix,升级为 `/comet`
|
|
88
122
|
- 修复需要额外接口变更 → 停止 hotfix,升级为 `/comet`
|
|
89
123
|
|
|
90
|
-
验证通过后,按 `/comet-verify` 的规则将
|
|
124
|
+
验证通过后,按 `/comet-verify` 的规则将 `.comet.yaml` 的 `verify_result` 记录为 `pass`,归档前不得跳过该状态。
|
|
91
125
|
|
|
92
126
|
### 4. 归档(preset archive)
|
|
93
127
|
|
|
94
|
-
复用 `/comet-archive`。归档前必须满足
|
|
128
|
+
复用 `/comet-archive`。归档前必须满足 `.comet.yaml` 中 `verify_result: pass`。
|
|
95
129
|
|
|
96
130
|
**立即执行:** 使用 Skill 工具加载 `comet-archive` 技能进行归档。禁止跳过此步骤。
|
|
97
131
|
如有 delta spec,按 comet-archive 规则同步到 main spec,并处理关联 Design Doc 与 Plan 的归档标注。
|