@rpamis/comet 0.1.7 → 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 CHANGED
@@ -90,12 +90,14 @@ After `comet init`, three groups of skills are installed to the selected platfor
90
90
  | `/comet-hotfix` | Preset: Quick bug fix (skips brainstorming) |
91
91
  | `/comet-tweak` | Preset: Small change (skips brainstorming and full plan) |
92
92
 
93
- ### Guard Scripts
93
+ ### Guard & Automation Scripts
94
94
 
95
95
  | Script | Purpose |
96
96
  |--------|---------|
97
- | `comet-guard.sh` | Phase transition guard — validates exit conditions before phase transitions |
97
+ | `comet-guard.sh` | Phase transition guard — validates exit conditions, `--apply` auto-updates `.comet.yaml` |
98
+ | `comet-archive.sh` | One-command archive — validates state, syncs specs, moves to archive, updates status |
98
99
  | `comet-yaml-validate.sh` | Schema validator — validates `.comet.yaml` structure and field values |
100
+ | `comet-state.sh` | Unified state management — init/set/get/check/scale, agents' exclusive YAML interface |
99
101
 
100
102
  ### OpenSpec Skills
101
103
 
@@ -160,15 +162,17 @@ Comet uses a decoupled state architecture with separate YAML files:
160
162
 
161
163
  ### Reliability Features
162
164
 
163
- Comet includes three-layer defense to ensure agent execution reliability:
165
+ Comet ensures agent execution reliability through automated state transitions:
164
166
 
165
167
  1. **Entry Verification** — Each phase validates preconditions before execution
166
168
  - Checks file existence, state consistency, and phase transitions
167
169
  - Outputs `[HARD STOP]` with actionable suggestions if validation fails
168
170
 
169
- 2. **Write-Then-Verify** — Every state write is immediately verified
170
- - After updating `.comet.yaml`, agents must verify field values
171
- - Automatic retry mechanism (up to 2 attempts) on mismatch
171
+ 2. **Automated State Transitions** — `comet-guard.sh --apply` updates `.comet.yaml` automatically
172
+ - All phase transitions (design build → verify archive) use `guard --apply`
173
+ - No manual state editing required eliminates write-verification errors
174
+ - `comet-state.sh` is the agents' exclusive interface for state operations
175
+ - Guard and archive scripts use `comet-state.sh` internally for state management
172
176
 
173
177
  3. **Schema Validation** — `comet-yaml-validate.sh` ensures data integrity
174
178
  - Validates required fields (10 fields)
@@ -176,6 +180,12 @@ Comet includes three-layer defense to ensure agent execution reliability:
176
180
  - Validates referenced file paths exist
177
181
  - Detects unknown/typos fields
178
182
 
183
+ 4. **Archive Automation** — `comet-archive.sh` handles the full archive flow in one command
184
+ - Validates entry state, syncs delta specs to main specs
185
+ - Annotates design doc and plan frontmatter
186
+ - Moves change to archive directory and updates `archived: true`
187
+ - Supports `--dry-run` for preview
188
+
179
189
  **Security**: Path traversal protection on all change name inputs
180
190
 
181
191
  ## Project Structure
@@ -185,8 +195,10 @@ your-project/
185
195
  ├── .claude/skills/ # Platform skills dir (Comet + OpenSpec + Superpowers)
186
196
  │ ├── comet/SKILL.md
187
197
  │ │ └── scripts/
188
- │ │ ├── comet-guard.sh # Phase transition guard
189
- │ │ └── comet-yaml-validate.sh # Schema validator
198
+ │ │ ├── comet-guard.sh # Phase transition guard (--apply auto-updates state)
199
+ │ │ ├── comet-archive.sh # One-command archive automation
200
+ │ │ ├── comet-yaml-validate.sh # Schema validator
201
+ │ │ └── comet-state.sh # Unified state management (init/set/get/check/scale)
190
202
  │ ├── comet-*/SKILL.md
191
203
  │ ├── openspec-*/SKILL.md
192
204
  │ └── brainstorming/SKILL.md
@@ -37,6 +37,8 @@ validate_change_name "$CHANGE"
37
37
 
38
38
  CHANGE_DIR="openspec/changes/$CHANGE"
39
39
  YAML="$CHANGE_DIR/.comet.yaml"
40
+ SCRIPT_DIR="$(cd "$(dirname "$(readlink -f "$0" 2>/dev/null || echo "$0")" 2>/dev/null || dirname "$0")" && pwd)"
41
+ STATE_SH="$SCRIPT_DIR/comet-state.sh"
40
42
  TODAY=$(date +%Y-%m-%d)
41
43
  ARCHIVE_NAME="${TODAY}-${CHANGE}"
42
44
  ARCHIVE_DIR="openspec/changes/archive/${ARCHIVE_NAME}"
@@ -61,8 +63,12 @@ echo "=== Comet Archive: $CHANGE ===" >&2
61
63
 
62
64
  yaml_field() {
63
65
  local field="$1"
64
- if [ -f "$YAML" ]; then
65
- grep "^${field}:" "$YAML" | sed "s/^${field}: *//" | tr -d '"' | tr -d "'"
66
+ if [ -f "$STATE_SH" ]; then
67
+ bash "$STATE_SH" get "$CHANGE" "$field" 2>/dev/null
68
+ else
69
+ if [ -f "$YAML" ]; then
70
+ grep "^${field}:" "$YAML" | sed "s/^${field}: *//" | tr -d '"' | tr -d "'"
71
+ fi
66
72
  fi
67
73
  }
68
74
 
@@ -182,30 +182,40 @@ guard_archive() {
182
182
  }
183
183
 
184
184
  apply_state_update() {
185
- local yaml="$CHANGE_DIR/.comet.yaml"
185
+ local state_sh="$SCRIPT_DIR/comet-state.sh"
186
186
  local p="$1"
187
187
 
188
- case "$p" in
189
- open)
190
- sed -i 's/^phase:.*/phase: design/' "$yaml"
191
- ;;
192
- design)
193
- sed -i 's/^phase:.*/phase: build/' "$yaml"
194
- ;;
195
- build)
196
- sed -i 's/^phase:.*/phase: verify/' "$yaml"
197
- sed -i 's/^verify_result:.*/verify_result: pending/' "$yaml"
198
- ;;
199
- verify)
200
- sed -i 's/^phase:.*/phase: archive/' "$yaml"
201
- sed -i 's/^verify_result:.*/verify_result: pass/' "$yaml"
202
- if ! grep -q '^verified_at:' "$yaml" 2>/dev/null; then
203
- echo "verified_at: $(date +%Y-%m-%d)" >> "$yaml"
204
- else
205
- sed -i "s/^verified_at:.*/verified_at: $(date +%Y-%m-%d)/" "$yaml"
206
- fi
207
- ;;
208
- esac
188
+ if [ -f "$state_sh" ]; then
189
+ case "$p" in
190
+ open) bash "$state_sh" set "$CHANGE" phase design ;;
191
+ design) bash "$state_sh" set "$CHANGE" phase build ;;
192
+ build)
193
+ bash "$state_sh" set "$CHANGE" phase verify
194
+ bash "$state_sh" set "$CHANGE" verify_result pending
195
+ ;;
196
+ verify)
197
+ bash "$state_sh" set "$CHANGE" phase archive
198
+ bash "$state_sh" set "$CHANGE" verify_result pass
199
+ bash "$state_sh" set "$CHANGE" verified_at "$(date +%Y-%m-%d)"
200
+ ;;
201
+ esac
202
+ else
203
+ local yaml="$CHANGE_DIR/.comet.yaml"
204
+ case "$p" in
205
+ open) sed -i 's/^phase:.*/phase: design/' "$yaml" ;;
206
+ design) sed -i 's/^phase:.*/phase: build/' "$yaml" ;;
207
+ build) sed -i 's/^phase:.*/phase: verify/' "$yaml"; sed -i 's/^verify_result:.*/verify_result: pending/' "$yaml" ;;
208
+ verify)
209
+ sed -i 's/^phase:.*/phase: archive/' "$yaml"
210
+ sed -i 's/^verify_result:.*/verify_result: pass/' "$yaml"
211
+ if ! grep -q '^verified_at:' "$yaml" 2>/dev/null; then
212
+ echo "verified_at: $(date +%Y-%m-%d)" >> "$yaml"
213
+ else
214
+ sed -i "s/^verified_at:.*/verified_at: $(date +%Y-%m-%d)/" "$yaml"
215
+ fi
216
+ ;;
217
+ esac
218
+ fi
209
219
  }
210
220
 
211
221
  # --- Main ---
@@ -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,27 +15,14 @@ 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
- Before performing any operations, read and verify the current state:
18
+ Execute entry verification:
19
19
 
20
- **Checklist:**
21
- 1. `openspec/changes/<name>/.comet.yaml` exists
22
- 2. `phase` field value is `"archive"`
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 only after verification passes.
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