@rpamis/comet 0.1.6 → 0.1.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +24 -11
- package/assets/skills/comet/SKILL.md +16 -3
- package/assets/skills/comet/scripts/comet-archive.sh +258 -0
- package/assets/skills/comet/scripts/comet-guard.sh +51 -1
- package/assets/skills/comet/scripts/comet-state.sh +495 -0
- package/assets/skills/comet-archive/SKILL.md +21 -109
- package/assets/skills/comet-build/SKILL.md +23 -73
- package/assets/skills/comet-design/SKILL.md +14 -31
- package/assets/skills/comet-hotfix/SKILL.md +9 -43
- package/assets/skills/comet-open/SKILL.md +8 -61
- package/assets/skills/comet-tweak/SKILL.md +9 -43
- package/assets/skills/comet-verify/SKILL.md +13 -61
- package/assets/skills-zh/comet/SKILL.md +23 -4
- package/assets/skills-zh/comet-archive/SKILL.md +21 -109
- package/assets/skills-zh/comet-build/SKILL.md +23 -73
- package/assets/skills-zh/comet-design/SKILL.md +14 -31
- package/assets/skills-zh/comet-hotfix/SKILL.md +9 -43
- package/assets/skills-zh/comet-open/SKILL.md +8 -61
- package/assets/skills-zh/comet-tweak/SKILL.md +9 -43
- package/assets/skills-zh/comet-verify/SKILL.md +13 -61
- package/package.json +1 -1
|
@@ -0,0 +1,495 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Comet State — unified interface for .comet.yaml state management
|
|
3
|
+
# Usage: comet-state.sh <subcommand> <change-name> [args...]
|
|
4
|
+
#
|
|
5
|
+
# Subcommands:
|
|
6
|
+
# init <change-name> <workflow> — Initialize .comet.yaml with workflow defaults
|
|
7
|
+
# get <change-name> <field> — Read a field value from .comet.yaml
|
|
8
|
+
# set <change-name> <field> <val> — Update a field value
|
|
9
|
+
# check <phase> <change-name> — Verify entry requirements for a phase
|
|
10
|
+
# scale <change-name> — Assess and set verification mode based on metrics
|
|
11
|
+
#
|
|
12
|
+
# Workflows: full, hotfix, tweak
|
|
13
|
+
# Phases for check: open, design, build, verify, archive
|
|
14
|
+
|
|
15
|
+
set -euo pipefail
|
|
16
|
+
|
|
17
|
+
# --- Color output helpers ---
|
|
18
|
+
|
|
19
|
+
red() { echo -e "\033[31m$1\033[0m" >&2; }
|
|
20
|
+
green() { echo -e "\033[32m$1\033[0m" >&2; }
|
|
21
|
+
yellow() { echo -e "\033[33m$1\033[0m" >&2; }
|
|
22
|
+
|
|
23
|
+
# --- Script location ---
|
|
24
|
+
|
|
25
|
+
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
26
|
+
|
|
27
|
+
# --- Input validation ---
|
|
28
|
+
|
|
29
|
+
validate_change_name() {
|
|
30
|
+
local name="$1"
|
|
31
|
+
# Reject empty names
|
|
32
|
+
if [ -z "$name" ]; then
|
|
33
|
+
red "ERROR: Change name cannot be empty" >&2
|
|
34
|
+
exit 1
|
|
35
|
+
fi
|
|
36
|
+
# Only allow alphanumeric, hyphens, and underscores
|
|
37
|
+
if [[ ! "$name" =~ ^[a-zA-Z0-9_-]+$ ]]; then
|
|
38
|
+
red "ERROR: Invalid change name: '$name'" >&2
|
|
39
|
+
red "Valid characters: a-z, A-Z, 0-9, -, _" >&2
|
|
40
|
+
exit 1
|
|
41
|
+
fi
|
|
42
|
+
# Reject path traversal attempts
|
|
43
|
+
if [[ "$name" =~ \.\. ]]; then
|
|
44
|
+
red "ERROR: Change name cannot contain '..' (path traversal not allowed)" >&2
|
|
45
|
+
exit 1
|
|
46
|
+
fi
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
validate_enum() {
|
|
50
|
+
local value="$1"
|
|
51
|
+
shift
|
|
52
|
+
local valid_values=("$@")
|
|
53
|
+
|
|
54
|
+
for valid in "${valid_values[@]}"; do
|
|
55
|
+
if [ "$value" = "$valid" ]; then
|
|
56
|
+
return 0
|
|
57
|
+
fi
|
|
58
|
+
done
|
|
59
|
+
|
|
60
|
+
red "ERROR: Invalid value: '$value'" >&2
|
|
61
|
+
red "Valid values: ${valid_values[*]}" >&2
|
|
62
|
+
exit 1
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
# --- Helper functions ---
|
|
66
|
+
|
|
67
|
+
yaml_field() {
|
|
68
|
+
local field="$1"
|
|
69
|
+
local yaml_file="$2"
|
|
70
|
+
if [ -f "$yaml_file" ]; then
|
|
71
|
+
grep "^${field}:" "$yaml_file" | sed "s/^${field}: *//" | tr -d '"' | tr -d "'"
|
|
72
|
+
fi
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
file_nonempty() {
|
|
76
|
+
[ -f "$1" ] && [ -s "$1" ]
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
# --- Subcommands ---
|
|
80
|
+
|
|
81
|
+
cmd_init() {
|
|
82
|
+
local change_name="$1"
|
|
83
|
+
local workflow="$2"
|
|
84
|
+
|
|
85
|
+
validate_change_name "$change_name"
|
|
86
|
+
validate_enum "$workflow" "full" "hotfix" "tweak"
|
|
87
|
+
|
|
88
|
+
local change_dir="openspec/changes/$change_name"
|
|
89
|
+
local yaml_file="$change_dir/.comet.yaml"
|
|
90
|
+
|
|
91
|
+
# Check if .comet.yaml already exists
|
|
92
|
+
if [ -f "$yaml_file" ]; then
|
|
93
|
+
red "ERROR: .comet.yaml already exists at $yaml_file"
|
|
94
|
+
exit 1
|
|
95
|
+
fi
|
|
96
|
+
|
|
97
|
+
# Create change directory if it doesn't exist
|
|
98
|
+
mkdir -p "$change_dir"
|
|
99
|
+
|
|
100
|
+
# Set workflow-appropriate defaults
|
|
101
|
+
local phase build_mode isolation verify_mode
|
|
102
|
+
|
|
103
|
+
case "$workflow" in
|
|
104
|
+
full)
|
|
105
|
+
phase="design"
|
|
106
|
+
build_mode="null"
|
|
107
|
+
isolation="null"
|
|
108
|
+
verify_mode="null"
|
|
109
|
+
;;
|
|
110
|
+
hotfix|tweak)
|
|
111
|
+
phase="build"
|
|
112
|
+
build_mode="direct"
|
|
113
|
+
isolation="branch"
|
|
114
|
+
verify_mode="light"
|
|
115
|
+
;;
|
|
116
|
+
esac
|
|
117
|
+
|
|
118
|
+
# Write .comet.yaml
|
|
119
|
+
cat > "$yaml_file" <<EOF
|
|
120
|
+
phase: $phase
|
|
121
|
+
build_mode: $build_mode
|
|
122
|
+
isolation: $isolation
|
|
123
|
+
verify_mode: $verify_mode
|
|
124
|
+
design_doc: null
|
|
125
|
+
plan: null
|
|
126
|
+
verify_result: pending
|
|
127
|
+
verified_at: null
|
|
128
|
+
archived: false
|
|
129
|
+
EOF
|
|
130
|
+
|
|
131
|
+
green "Initialized: $yaml_file (workflow=$workflow)"
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
cmd_get() {
|
|
135
|
+
local change_name="$1"
|
|
136
|
+
local field="$2"
|
|
137
|
+
|
|
138
|
+
validate_change_name "$change_name"
|
|
139
|
+
|
|
140
|
+
local change_dir="openspec/changes/$change_name"
|
|
141
|
+
local yaml_file="$change_dir/.comet.yaml"
|
|
142
|
+
|
|
143
|
+
# Check if .comet.yaml exists
|
|
144
|
+
if [ ! -f "$yaml_file" ]; then
|
|
145
|
+
red "ERROR: .comet.yaml not found at $yaml_file"
|
|
146
|
+
exit 1
|
|
147
|
+
fi
|
|
148
|
+
|
|
149
|
+
# Read and output the field value
|
|
150
|
+
local value
|
|
151
|
+
value=$(yaml_field "$field" "$yaml_file")
|
|
152
|
+
echo "${value:-}"
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
cmd_set() {
|
|
156
|
+
local change_name="$1"
|
|
157
|
+
local field="$2"
|
|
158
|
+
local value="$3"
|
|
159
|
+
|
|
160
|
+
validate_change_name "$change_name"
|
|
161
|
+
|
|
162
|
+
local change_dir="openspec/changes/$change_name"
|
|
163
|
+
local yaml_file="$change_dir/.comet.yaml"
|
|
164
|
+
|
|
165
|
+
# Check if .comet.yaml exists
|
|
166
|
+
if [ ! -f "$yaml_file" ]; then
|
|
167
|
+
red "ERROR: .comet.yaml not found at $yaml_file"
|
|
168
|
+
exit 1
|
|
169
|
+
fi
|
|
170
|
+
|
|
171
|
+
# Validate field name
|
|
172
|
+
case "$field" in
|
|
173
|
+
workflow|phase|build_mode|isolation|verify_mode|verify_result|archived|design_doc|plan|verified_at)
|
|
174
|
+
# Valid field
|
|
175
|
+
;;
|
|
176
|
+
*)
|
|
177
|
+
red "ERROR: Unknown field: '$field'" >&2
|
|
178
|
+
red "Valid fields: workflow, phase, design_doc, plan, build_mode, isolation, verify_mode, verify_result, verified_at, archived" >&2
|
|
179
|
+
exit 1
|
|
180
|
+
;;
|
|
181
|
+
esac
|
|
182
|
+
|
|
183
|
+
# Validate enum values
|
|
184
|
+
case "$field" in
|
|
185
|
+
workflow)
|
|
186
|
+
validate_enum "$value" "full" "hotfix" "tweak"
|
|
187
|
+
;;
|
|
188
|
+
phase)
|
|
189
|
+
validate_enum "$value" "design" "build" "verify" "archive"
|
|
190
|
+
;;
|
|
191
|
+
build_mode)
|
|
192
|
+
validate_enum "$value" "subagent-driven-development" "executing-plans" "direct"
|
|
193
|
+
;;
|
|
194
|
+
isolation)
|
|
195
|
+
validate_enum "$value" "branch" "worktree"
|
|
196
|
+
;;
|
|
197
|
+
verify_mode)
|
|
198
|
+
validate_enum "$value" "light" "full"
|
|
199
|
+
;;
|
|
200
|
+
verify_result)
|
|
201
|
+
validate_enum "$value" "pending" "pass" "fail"
|
|
202
|
+
;;
|
|
203
|
+
archived)
|
|
204
|
+
validate_enum "$value" "true" "false"
|
|
205
|
+
;;
|
|
206
|
+
design_doc|plan|verified_at)
|
|
207
|
+
# No validation for path fields and date fields
|
|
208
|
+
;;
|
|
209
|
+
esac
|
|
210
|
+
|
|
211
|
+
# Write or update the field
|
|
212
|
+
if grep -q "^${field}:" "$yaml_file"; then
|
|
213
|
+
# Field exists, replace it
|
|
214
|
+
sed -i "s/^${field}:.*/${field}: ${value}/" "$yaml_file"
|
|
215
|
+
else
|
|
216
|
+
# Field doesn't exist, append it
|
|
217
|
+
echo "${field}: ${value}" >> "$yaml_file"
|
|
218
|
+
fi
|
|
219
|
+
|
|
220
|
+
green "[SET] ${field}=${value}"
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
# --- Check helpers for entry verification ---
|
|
224
|
+
|
|
225
|
+
CHECK_BLOCK=0
|
|
226
|
+
|
|
227
|
+
check_pass() {
|
|
228
|
+
local msg="$1"
|
|
229
|
+
echo " $(green "[PASS]") $msg"
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
check_fail() {
|
|
233
|
+
local msg="$1"
|
|
234
|
+
echo " $(red "[FAIL]") $msg"
|
|
235
|
+
CHECK_BLOCK=1
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
check_nonempty() {
|
|
239
|
+
local desc="$1"
|
|
240
|
+
local path="$1"
|
|
241
|
+
if file_nonempty "$path"; then
|
|
242
|
+
check_pass "$desc non-empty"
|
|
243
|
+
else
|
|
244
|
+
check_fail "$desc missing or empty"
|
|
245
|
+
fi
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
check_yaml_is() {
|
|
249
|
+
local field="$1"
|
|
250
|
+
local expected="$2"
|
|
251
|
+
local change_name="$3"
|
|
252
|
+
local actual
|
|
253
|
+
actual=$(cmd_get "$change_name" "$field")
|
|
254
|
+
if [ "$actual" = "$expected" ]; then
|
|
255
|
+
check_pass "${field}=${actual} (expected: ${expected})"
|
|
256
|
+
else
|
|
257
|
+
check_fail "${field}=${actual} (expected: ${expected})"
|
|
258
|
+
fi
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
check_yaml_empty() {
|
|
262
|
+
local field="$1"
|
|
263
|
+
local change_name="$2"
|
|
264
|
+
local value
|
|
265
|
+
value=$(cmd_get "$change_name" "$field")
|
|
266
|
+
if [ -z "$value" ] || [ "$value" = "null" ]; then
|
|
267
|
+
check_pass "${field} is empty/null"
|
|
268
|
+
else
|
|
269
|
+
check_fail "${field}=${value} (expected: empty/null)"
|
|
270
|
+
fi
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
check_file_not_exists() {
|
|
274
|
+
local desc="$1"
|
|
275
|
+
local path="$2"
|
|
276
|
+
if [ ! -f "$path" ]; then
|
|
277
|
+
check_pass "$desc does not exist"
|
|
278
|
+
else
|
|
279
|
+
check_fail "$desc exists (should not exist)"
|
|
280
|
+
fi
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
cmd_check() {
|
|
284
|
+
local phase="$1"
|
|
285
|
+
local change_name="$2"
|
|
286
|
+
|
|
287
|
+
validate_change_name "$change_name"
|
|
288
|
+
validate_enum "$phase" "open" "design" "build" "verify" "archive"
|
|
289
|
+
|
|
290
|
+
local change_dir="openspec/changes/$change_name"
|
|
291
|
+
local yaml_file="$change_dir/.comet.yaml"
|
|
292
|
+
local proposal_file="$change_dir/proposal.md"
|
|
293
|
+
local design_file="$change_dir/design.md"
|
|
294
|
+
local tasks_file="$change_dir/tasks.md"
|
|
295
|
+
|
|
296
|
+
echo "=== Entry Check: comet-${phase} ==="
|
|
297
|
+
|
|
298
|
+
# For non-open phases, .comet.yaml must exist
|
|
299
|
+
if [ "$phase" != "open" ]; then
|
|
300
|
+
if [ ! -f "$yaml_file" ]; then
|
|
301
|
+
red "ERROR: .comet.yaml not found at $yaml_file"
|
|
302
|
+
exit 1
|
|
303
|
+
fi
|
|
304
|
+
fi
|
|
305
|
+
|
|
306
|
+
# Phase-specific checks
|
|
307
|
+
case "$phase" in
|
|
308
|
+
open)
|
|
309
|
+
check_file_not_exists ".comet.yaml" "$yaml_file"
|
|
310
|
+
check_nonempty "proposal.md" "$proposal_file"
|
|
311
|
+
check_nonempty "design.md" "$design_file"
|
|
312
|
+
check_nonempty "tasks.md" "$tasks_file"
|
|
313
|
+
;;
|
|
314
|
+
design)
|
|
315
|
+
check_pass ".comet.yaml exists"
|
|
316
|
+
check_yaml_is "phase" "design" "$change_name"
|
|
317
|
+
check_yaml_is "workflow" "full" "$change_name"
|
|
318
|
+
check_yaml_empty "design_doc" "$change_name"
|
|
319
|
+
check_nonempty "proposal.md" "$proposal_file"
|
|
320
|
+
check_nonempty "design.md" "$design_file"
|
|
321
|
+
check_nonempty "tasks.md" "$tasks_file"
|
|
322
|
+
;;
|
|
323
|
+
build)
|
|
324
|
+
check_pass ".comet.yaml exists"
|
|
325
|
+
check_yaml_is "phase" "build" "$change_name"
|
|
326
|
+
# Check design_doc is non-null and file exists
|
|
327
|
+
local design_doc
|
|
328
|
+
design_doc=$(cmd_get "$change_name" "design_doc")
|
|
329
|
+
if [ -n "$design_doc" ] && [ "$design_doc" != "null" ] && [ -f "$change_dir/$design_doc" ]; then
|
|
330
|
+
check_pass "design_doc=${design_doc} (file exists)"
|
|
331
|
+
else
|
|
332
|
+
check_fail "design_doc=${design_doc} (expected: non-null and file exists)"
|
|
333
|
+
fi
|
|
334
|
+
check_nonempty "proposal.md" "$proposal_file"
|
|
335
|
+
check_nonempty "tasks.md" "$tasks_file"
|
|
336
|
+
;;
|
|
337
|
+
verify)
|
|
338
|
+
check_pass ".comet.yaml exists"
|
|
339
|
+
check_yaml_is "phase" "verify" "$change_name"
|
|
340
|
+
# Check verify_result is pending or null
|
|
341
|
+
local verify_result
|
|
342
|
+
verify_result=$(cmd_get "$change_name" "verify_result")
|
|
343
|
+
if [ "$verify_result" = "pending" ] || [ -z "$verify_result" ] || [ "$verify_result" = "null" ]; then
|
|
344
|
+
check_pass "verify_result=${verify_result} (expected: pending or null)"
|
|
345
|
+
else
|
|
346
|
+
check_fail "verify_result=${verify_result} (expected: pending or null)"
|
|
347
|
+
fi
|
|
348
|
+
;;
|
|
349
|
+
archive)
|
|
350
|
+
check_pass ".comet.yaml exists"
|
|
351
|
+
check_yaml_is "phase" "archive" "$change_name"
|
|
352
|
+
check_yaml_is "verify_result" "pass" "$change_name"
|
|
353
|
+
# Check archived is NOT true
|
|
354
|
+
local archived
|
|
355
|
+
archived=$(cmd_get "$change_name" "archived")
|
|
356
|
+
if [ "$archived" != "true" ]; then
|
|
357
|
+
check_pass "archived=${archived} (expected: not true)"
|
|
358
|
+
else
|
|
359
|
+
check_fail "archived=${archived} (expected: not true)"
|
|
360
|
+
fi
|
|
361
|
+
;;
|
|
362
|
+
*)
|
|
363
|
+
red "ERROR: Unknown phase for check: $phase"
|
|
364
|
+
exit 1
|
|
365
|
+
;;
|
|
366
|
+
esac
|
|
367
|
+
|
|
368
|
+
echo ""
|
|
369
|
+
if [ "$CHECK_BLOCK" -eq 1 ]; then
|
|
370
|
+
red "BLOCKED — fix failing checks before proceeding"
|
|
371
|
+
exit 1
|
|
372
|
+
else
|
|
373
|
+
green "ALL CHECKS PASSED — ready to proceed"
|
|
374
|
+
exit 0
|
|
375
|
+
fi
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
cmd_scale() {
|
|
379
|
+
local change_name="$1"
|
|
380
|
+
|
|
381
|
+
validate_change_name "$change_name"
|
|
382
|
+
|
|
383
|
+
local change_dir="openspec/changes/$change_name"
|
|
384
|
+
local yaml_file="$change_dir/.comet.yaml"
|
|
385
|
+
|
|
386
|
+
# Verify .comet.yaml exists
|
|
387
|
+
if [ ! -f "$yaml_file" ]; then
|
|
388
|
+
red "ERROR: .comet.yaml not found at $yaml_file"
|
|
389
|
+
exit 1
|
|
390
|
+
fi
|
|
391
|
+
|
|
392
|
+
# Read metrics
|
|
393
|
+
# 1. Task count: count lines matching `- [` in tasks.md
|
|
394
|
+
local tasks_file="$change_dir/tasks.md"
|
|
395
|
+
local task_count=0
|
|
396
|
+
if [ -f "$tasks_file" ]; then
|
|
397
|
+
task_count=$(grep -c '^\- \[' "$tasks_file" 2>/dev/null || echo "0")
|
|
398
|
+
fi
|
|
399
|
+
|
|
400
|
+
# 2. Delta spec count: count files named spec.md under specs/*/spec.md
|
|
401
|
+
local delta_spec_count=0
|
|
402
|
+
if [ -d "$change_dir/specs" ]; then
|
|
403
|
+
delta_spec_count=$(find "$change_dir/specs" -name "spec.md" -type f 2>/dev/null | wc -l | tr -d ' ')
|
|
404
|
+
fi
|
|
405
|
+
|
|
406
|
+
# 3. Changed files: from git diff --stat HEAD
|
|
407
|
+
local changed_files=0
|
|
408
|
+
if git rev-parse --git-dir > /dev/null 2>&1; then
|
|
409
|
+
# Extract the number before "file" in the last line
|
|
410
|
+
local stat_output
|
|
411
|
+
stat_output=$(git diff --stat HEAD 2>/dev/null | tail -1)
|
|
412
|
+
if [[ "$stat_output" =~ ([0-9]+)\ file ]]; then
|
|
413
|
+
changed_files="${BASH_REMATCH[1]}"
|
|
414
|
+
fi
|
|
415
|
+
fi
|
|
416
|
+
|
|
417
|
+
# Decision rules
|
|
418
|
+
local result="light"
|
|
419
|
+
if [ "$task_count" -gt 3 ] || [ "$delta_spec_count" -gt 1 ] || [ "$changed_files" -gt 5 ]; then
|
|
420
|
+
result="full"
|
|
421
|
+
fi
|
|
422
|
+
|
|
423
|
+
# Output assessment to stderr
|
|
424
|
+
echo "=== Scale Assessment: $change_name ===" >&2
|
|
425
|
+
echo " Tasks: $task_count (threshold: 3)" >&2
|
|
426
|
+
echo " Delta specs: $delta_spec_count capabilities (threshold: 1)" >&2
|
|
427
|
+
echo " Changed files: $changed_files (threshold: 5)" >&2
|
|
428
|
+
echo " → Result: $result" >&2
|
|
429
|
+
|
|
430
|
+
# Update verify_mode in .comet.yaml
|
|
431
|
+
sed -i "s/^verify_mode:.*/verify_mode: $result/" "$yaml_file"
|
|
432
|
+
|
|
433
|
+
green "[SCALE] verify_mode=$result"
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
# --- Main ---
|
|
437
|
+
|
|
438
|
+
SUBCOMMAND="${1:-}"
|
|
439
|
+
shift || true
|
|
440
|
+
|
|
441
|
+
case "$SUBCOMMAND" in
|
|
442
|
+
init)
|
|
443
|
+
if [ $# -lt 2 ]; then
|
|
444
|
+
red "Usage: comet-state.sh init <change-name> <workflow>" >&2
|
|
445
|
+
red "Workflows: full, hotfix, tweak" >&2
|
|
446
|
+
exit 1
|
|
447
|
+
fi
|
|
448
|
+
cmd_init "$@"
|
|
449
|
+
;;
|
|
450
|
+
get)
|
|
451
|
+
if [ $# -lt 2 ]; then
|
|
452
|
+
red "Usage: comet-state.sh get <change-name> <field>" >&2
|
|
453
|
+
exit 1
|
|
454
|
+
fi
|
|
455
|
+
cmd_get "$@"
|
|
456
|
+
;;
|
|
457
|
+
set)
|
|
458
|
+
if [ $# -lt 3 ]; then
|
|
459
|
+
red "Usage: comet-state.sh set <change-name> <field> <value>" >&2
|
|
460
|
+
exit 1
|
|
461
|
+
fi
|
|
462
|
+
cmd_set "$@"
|
|
463
|
+
;;
|
|
464
|
+
check)
|
|
465
|
+
if [ $# -lt 2 ]; then
|
|
466
|
+
red "Usage: comet-state.sh check <phase> <change-name>" >&2
|
|
467
|
+
red "Phases: open, design, build, verify, archive" >&2
|
|
468
|
+
exit 1
|
|
469
|
+
fi
|
|
470
|
+
cmd_check "$@"
|
|
471
|
+
;;
|
|
472
|
+
scale)
|
|
473
|
+
if [ $# -lt 1 ]; then
|
|
474
|
+
red "Usage: comet-state.sh scale <change-name>" >&2
|
|
475
|
+
exit 1
|
|
476
|
+
fi
|
|
477
|
+
cmd_scale "$@"
|
|
478
|
+
;;
|
|
479
|
+
*)
|
|
480
|
+
red "Unknown subcommand: $SUBCOMMAND" >&2
|
|
481
|
+
echo "" >&2
|
|
482
|
+
echo "Usage: comet-state.sh <subcommand> <change-name> [args...]" >&2
|
|
483
|
+
echo "" >&2
|
|
484
|
+
echo "Subcommands:" >&2
|
|
485
|
+
echo " init <change-name> <workflow> — Initialize .comet.yaml with workflow defaults" >&2
|
|
486
|
+
echo " get <change-name> <field> — Read a field value from .comet.yaml" >&2
|
|
487
|
+
echo " set <change-name> <field> <val> — Update a field value in .comet.yaml" >&2
|
|
488
|
+
echo " check <phase> <change-name> — Verify entry requirements for a phase" >&2
|
|
489
|
+
echo " scale <change-name> — Assess and set verification mode based on metrics" >&2
|
|
490
|
+
echo "" >&2
|
|
491
|
+
echo "Workflows: full, hotfix, tweak" >&2
|
|
492
|
+
echo "Phases for check: open, design, build, verify, archive" >&2
|
|
493
|
+
exit 1
|
|
494
|
+
;;
|
|
495
|
+
esac
|
|
@@ -15,137 +15,49 @@ description: "Comet Phase 5: Archive. Invoke with /comet-archive. Sync delta spe
|
|
|
15
15
|
|
|
16
16
|
### 0. Entry State Verification (Entry Check)
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
Execute entry verification:
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
3. `verify_result` field value is `"pass"`
|
|
24
|
-
4. `archived` field is `"false"` or null (not yet archived)
|
|
25
|
-
|
|
26
|
-
**Verification method:**
|
|
27
|
-
- `cat openspec/changes/<name>/.comet.yaml` to read all fields
|
|
28
|
-
- If `verify_result` is not `"pass"`, must complete verification first
|
|
29
|
-
|
|
30
|
-
**Failure output:**
|
|
31
|
-
```
|
|
32
|
-
[HARD STOP] Entry check failed for comet-archive
|
|
33
|
-
Expected: phase=archive, verify_result=pass, archived=false|null
|
|
34
|
-
Actual: phase=<actual-value>, verify_result=<actual-value>, archived=<actual-value>
|
|
35
|
-
Suggestion: Run comet-verify first, or this change was already archived.
|
|
20
|
+
```bash
|
|
21
|
+
COMET_STATE=$(find . -path '*/comet/scripts/comet-state.sh' -type f -print -quit)
|
|
22
|
+
bash "$COMET_STATE" check <name> archive
|
|
36
23
|
```
|
|
37
24
|
|
|
38
|
-
Proceed to Step 1
|
|
25
|
+
Proceed to Step 1 after verification passes. The script outputs specific failure reasons when verification fails.
|
|
39
26
|
|
|
40
27
|
### 1. Execute Archive
|
|
41
28
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
**Immediately execute:** Use the Skill tool to load the `openspec-archive-change` skill. Skipping this step is prohibited.
|
|
45
|
-
|
|
46
|
-
After the skill loads, follow its guidance to archive. Automatic checks:
|
|
47
|
-
1. Artifact completion status (proposal, design, specs, tasks)
|
|
48
|
-
2. All tasks marked `[x]`
|
|
49
|
-
3. Delta specs sync status
|
|
50
|
-
|
|
51
|
-
### 1b. Move Comet State File
|
|
52
|
-
|
|
53
|
-
`openspec-archive-change` is not aware of `.comet.yaml`, so Comet needs to move this file itself after OpenSpec archiving completes:
|
|
29
|
+
Run the archive script to automatically complete all steps:
|
|
54
30
|
|
|
55
31
|
```bash
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
【Write verification】After move completion, must verify:
|
|
60
|
-
test -f openspec/changes/archive/YYYY-MM-DD-<name>/.comet.yaml
|
|
61
|
-
Confirm .comet.yaml exists in archive directory
|
|
62
|
-
If file is not at expected location, check if mv command executed successfully.
|
|
63
|
-
|
|
64
|
-
### 2. Delta Spec Sync
|
|
65
|
-
|
|
66
|
-
Sync delta specs to main specs during archiving:
|
|
67
|
-
|
|
68
|
-
```
|
|
69
|
-
openspec/changes/<name>/specs/<capability>/spec.md
|
|
70
|
-
↓ sync
|
|
71
|
-
openspec/specs/<capability>/spec.md ← main spec (persistent)
|
|
32
|
+
COMET_ARCHIVE=$(find . -path '*/comet/scripts/comet-archive.sh' -type f -print -quit)
|
|
33
|
+
bash "$COMET_ARCHIVE" "<change-name>"
|
|
72
34
|
```
|
|
73
35
|
|
|
74
|
-
|
|
36
|
+
The script automatically executes:
|
|
37
|
+
1. Entry state validation (phase=archive, verify_result=pass, archived=false)
|
|
38
|
+
2. Delta spec sync to main spec (overwrite)
|
|
39
|
+
3. Design doc frontmatter annotation (archived-with, status)
|
|
40
|
+
4. Plan frontmatter annotation (archived-with)
|
|
41
|
+
5. Move change to archive directory
|
|
42
|
+
6. Update archived: true
|
|
75
43
|
|
|
76
|
-
|
|
44
|
+
If script returns non-zero exit code, report error and stop.
|
|
45
|
+
If script returns zero exit code, archive is complete.
|
|
77
46
|
|
|
78
|
-
|
|
47
|
+
Use `--dry-run` flag to preview without executing.
|
|
79
48
|
|
|
80
|
-
|
|
81
|
-
- Compare delta spec final version with design doc content
|
|
82
|
-
- If there are discrepancies (incremental spec modifications during implementation), set the following metadata in design doc's YAML frontmatter:
|
|
83
|
-
|
|
84
|
-
```yaml
|
|
85
|
-
---
|
|
86
|
-
archived-with: YYYY-MM-DD-<name>
|
|
87
|
-
status: superseded-by-main-spec
|
|
88
|
-
implementation-notes: |
|
|
89
|
-
<briefly describe key changes deviating from original design during implementation>
|
|
90
|
-
---
|
|
91
|
-
```
|
|
92
|
-
|
|
93
|
-
- If completely consistent, only set:
|
|
94
|
-
|
|
95
|
-
```yaml
|
|
96
|
-
---
|
|
97
|
-
archived-with: YYYY-MM-DD-<name>
|
|
98
|
-
status: final
|
|
99
|
-
---
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
**3b. Plan Association Annotation**
|
|
103
|
-
|
|
104
|
-
Find implementation plans associated with current change in `docs/superpowers/plans/`, set the same `archived-with` metadata in YAML frontmatter.
|
|
105
|
-
|
|
106
|
-
### 4. Archive Directory
|
|
107
|
-
|
|
108
|
-
Change moves to archive directory:
|
|
109
|
-
|
|
110
|
-
```
|
|
111
|
-
openspec/changes/archive/YYYY-MM-DD-<name>/
|
|
112
|
-
├── .openspec.yaml
|
|
113
|
-
├── .comet.yaml
|
|
114
|
-
├── proposal.md
|
|
115
|
-
├── design.md
|
|
116
|
-
├── specs/<capability>/spec.md
|
|
117
|
-
└── tasks.md
|
|
118
|
-
```
|
|
119
|
-
|
|
120
|
-
### 5. Lifecycle Closed Loop
|
|
49
|
+
### 2. Lifecycle Closed Loop
|
|
121
50
|
|
|
122
51
|
Spec lifecycle completes here:
|
|
123
52
|
```
|
|
124
|
-
brainstorming → delta spec → implementation
|
|
53
|
+
brainstorming → delta spec → implementation → verification → main spec overwrite → design doc annotation → archive
|
|
125
54
|
```
|
|
126
55
|
|
|
127
56
|
## Exit Conditions
|
|
128
57
|
|
|
129
|
-
-
|
|
130
|
-
- Main specs updated (delta → main sync complete)
|
|
131
|
-
- Associated design doc annotated with archive status
|
|
132
|
-
- Associated plan annotated with archive status
|
|
133
|
-
- `.comet.yaml` `archived` recorded as `true`
|
|
58
|
+
- Archive script executed successfully (exit code 0)
|
|
134
59
|
- **Phase guard**: Run `bash $COMET_GUARD <change-name> archive`, confirm archive complete after all PASS
|
|
135
60
|
|
|
136
|
-
After archiving completes, update `.comet.yaml` in archive directory:
|
|
137
|
-
|
|
138
|
-
```yaml
|
|
139
|
-
phase: archive
|
|
140
|
-
archived: true
|
|
141
|
-
```
|
|
142
|
-
|
|
143
|
-
【Write verification】After update completion, must verify:
|
|
144
|
-
cat openspec/changes/archive/YYYY-MM-DD-<name>/.comet.yaml
|
|
145
|
-
Confirm phase line value is "archive"
|
|
146
|
-
Confirm archived line value is "true"
|
|
147
|
-
If any field does not match, retry write then verify again. Maximum 2 retries, report error and terminate if still fails.
|
|
148
|
-
|
|
149
61
|
## Complete
|
|
150
62
|
|
|
151
63
|
Comet workflow complete. To start new work, invoke `/comet` or `/comet-open`.
|