@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 +20 -8
- package/assets/skills/comet/scripts/comet-archive.sh +8 -2
- package/assets/skills/comet/scripts/comet-guard.sh +32 -22
- package/assets/skills/comet/scripts/comet-state.sh +495 -0
- package/assets/skills/comet-archive/SKILL.md +5 -18
- package/assets/skills/comet-build/SKILL.md +16 -23
- package/assets/skills/comet-design/SKILL.md +7 -23
- package/assets/skills/comet-hotfix/SKILL.md +9 -43
- package/assets/skills/comet-open/SKILL.md +9 -31
- package/assets/skills/comet-tweak/SKILL.md +9 -43
- package/assets/skills/comet-verify/SKILL.md +10 -30
- package/assets/skills-zh/comet/SKILL.md +7 -1
- package/assets/skills-zh/comet-archive/SKILL.md +5 -18
- package/assets/skills-zh/comet-build/SKILL.md +16 -23
- package/assets/skills-zh/comet-design/SKILL.md +7 -23
- package/assets/skills-zh/comet-hotfix/SKILL.md +9 -43
- package/assets/skills-zh/comet-open/SKILL.md +9 -31
- package/assets/skills-zh/comet-tweak/SKILL.md +9 -43
- package/assets/skills-zh/comet-verify/SKILL.md +10 -30
- package/package.json +1 -1
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
|
|
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
|
|
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. **
|
|
170
|
-
-
|
|
171
|
-
-
|
|
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
|
-
│ │
|
|
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 "$
|
|
65
|
-
|
|
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
|
|
185
|
+
local state_sh="$SCRIPT_DIR/comet-state.sh"
|
|
186
186
|
local p="$1"
|
|
187
187
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
;;
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
;;
|
|
208
|
-
|
|
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
|
-
|
|
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
|
|