@rpamis/comet 0.2.0 → 0.2.2

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.
@@ -1,258 +1,258 @@
1
- #!/bin/bash
2
- # Comet Archive — automates the archive phase in one command
3
- # Usage: comet-archive.sh <change-name> [--dry-run]
4
- # Exit 0 = archive complete, exit 1 = fatal error
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
- yellow() { echo -e "\033[33m$1\033[0m" >&2; }
11
-
12
- DRY_RUN=0
13
- if [[ "${2:-}" == "--dry-run" ]]; then
14
- DRY_RUN=1
15
- fi
16
-
17
- # Input validation
18
- validate_change_name() {
19
- local name="$1"
20
- if [ -z "$name" ]; then
21
- red "FATAL: Change name cannot be empty"
22
- exit 1
23
- fi
24
- if [[ ! "$name" =~ ^[a-zA-Z0-9_-]+$ ]]; then
25
- red "FATAL: Invalid change name: '$name'"
26
- red "Valid characters: a-z, A-Z, 0-9, -, _"
27
- exit 1
28
- fi
29
- if [[ "$name" =~ \.\. ]]; then
30
- red "FATAL: Change name cannot contain '..'"
31
- exit 1
32
- fi
33
- }
34
-
35
- CHANGE="$1"
36
- validate_change_name "$CHANGE"
37
-
38
- CHANGE_DIR="openspec/changes/$CHANGE"
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"
42
- TODAY=$(date +%Y-%m-%d)
43
- ARCHIVE_NAME="${TODAY}-${CHANGE}"
44
- ARCHIVE_DIR="openspec/changes/archive/${ARCHIVE_NAME}"
45
-
46
- STEPS_OK=0
47
- STEPS_TOTAL=0
48
-
49
- step_ok() {
50
- green " [OK] $1"
51
- STEPS_OK=$((STEPS_OK + 1))
52
- STEPS_TOTAL=$((STEPS_TOTAL + 1))
53
- }
54
-
55
- step_fail() {
56
- red " [FAIL] $1"
57
- STEPS_TOTAL=$((STEPS_TOTAL + 1))
58
- }
59
-
60
- echo "=== Comet Archive: $CHANGE ===" >&2
61
-
62
- # --- Step 1: Read .comet.yaml, extract paths ---
63
-
64
- yaml_field() {
65
- local field="$1"
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
72
- fi
73
- }
74
-
75
- if [ ! -f "$YAML" ]; then
76
- red "FATAL: .comet.yaml not found in $CHANGE_DIR/"
77
- exit 1
78
- fi
79
-
80
- DESIGN_DOC=$(yaml_field "design_doc")
81
- PLAN_PATH=$(yaml_field "plan")
82
-
83
- # --- Step 2: Validate entry state ---
84
-
85
- PHASE_VAL=$(yaml_field "phase")
86
- VERIFY_VAL=$(yaml_field "verify_result")
87
- ARCHIVED_VAL=$(yaml_field "archived")
88
-
89
- if [ "$PHASE_VAL" != "archive" ]; then
90
- red "FATAL: phase is '$PHASE_VAL', expected 'archive'"
91
- exit 1
92
- fi
93
-
94
- if [ "$VERIFY_VAL" != "pass" ]; then
95
- red "FATAL: verify_result is '$VERIFY_VAL', expected 'pass'. Run comet-verify first."
96
- exit 1
97
- fi
98
-
99
- if [ "$ARCHIVED_VAL" = "true" ]; then
100
- red "FATAL: change already archived"
101
- exit 1
102
- fi
103
-
104
- step_ok "Entry state verified"
105
-
106
- # --- Step 3: Check archive target ---
107
-
108
- if [ -d "$ARCHIVE_DIR" ]; then
109
- red "FATAL: archive target already exists: $ARCHIVE_DIR"
110
- exit 1
111
- fi
112
-
113
- step_ok "Archive target available"
114
-
115
- # --- Step 4: Sync delta specs → main specs ---
116
-
117
- sync_delta_specs() {
118
- local delta_root="$CHANGE_DIR/specs"
119
- if [ ! -d "$delta_root" ]; then
120
- return 0
121
- fi
122
-
123
- for delta_spec_dir in "$delta_root"/*/; do
124
- [ -d "$delta_spec_dir" ] || continue
125
- local capability
126
- capability=$(basename "$delta_spec_dir")
127
- local delta_spec="$delta_spec_dir/spec.md"
128
- local main_spec="openspec/specs/$capability/spec.md"
129
-
130
- if [ ! -f "$delta_spec" ]; then
131
- continue
132
- fi
133
-
134
- STEPS_TOTAL=$((STEPS_TOTAL + 1))
135
-
136
- if [ "$DRY_RUN" -eq 1 ]; then
137
- yellow " [DRY-RUN] Would sync: $capability → $main_spec"
138
- STEPS_OK=$((STEPS_OK + 1))
139
- continue
140
- fi
141
-
142
- if [ ! -f "$main_spec" ]; then
143
- mkdir -p "openspec/specs/$capability"
144
- fi
145
- cp "$delta_spec" "$main_spec"
146
-
147
- step_ok "Delta spec synced: $capability → openspec/specs/$capability/spec.md"
148
- done
149
- }
150
-
151
- sync_delta_specs
152
-
153
- # --- Step 5: Annotate design doc frontmatter ---
154
-
155
- annotate_frontmatter() {
156
- local file="$1"
157
- local extra_fields="$2"
158
-
159
- if [ ! -f "$file" ]; then
160
- return 0
161
- fi
162
-
163
- STEPS_TOTAL=$((STEPS_TOTAL + 1))
164
-
165
- if [ "$DRY_RUN" -eq 1 ]; then
166
- yellow " [DRY-RUN] Would annotate: $file"
167
- STEPS_OK=$((STEPS_OK + 1))
168
- return 0
169
- fi
170
-
171
- if head -1 "$file" | grep -q '^---'; then
172
- local tmp_file
173
- tmp_file=$(mktemp)
174
- awk -v archive="$ARCHIVE_NAME" -v extra="$extra_fields" '
175
- /^archived-with:/ { next }
176
- NR==1 && /^---/ { print; next }
177
- /^---/ && NR>1 {
178
- print "archived-with: " archive
179
- if (extra != "") print extra
180
- print; next
181
- }
182
- { print }
183
- ' "$file" > "$tmp_file"
184
- mv "$tmp_file" "$file"
185
- else
186
- local tmp_file
187
- tmp_file=$(mktemp)
188
- {
189
- echo "---"
190
- echo "archived-with: $ARCHIVE_NAME"
191
- if [ -n "$extra_fields" ]; then
192
- echo "$extra_fields"
193
- fi
194
- echo "status: final"
195
- echo "---"
196
- cat "$file"
197
- } > "$tmp_file"
198
- mv "$tmp_file" "$file"
199
- fi
200
-
201
- step_ok "Annotated: $file"
202
- }
203
-
204
- if [ -n "$DESIGN_DOC" ] && [ "$DESIGN_DOC" != "null" ]; then
205
- annotate_frontmatter "$DESIGN_DOC" "status: final"
206
- fi
207
-
208
- # --- Step 6: Annotate plan frontmatter ---
209
-
210
- if [ -n "$PLAN_PATH" ] && [ "$PLAN_PATH" != "null" ]; then
211
- annotate_frontmatter "$PLAN_PATH" ""
212
- fi
213
-
214
- # --- Step 7: Move change to archive ---
215
-
216
- STEPS_TOTAL=$((STEPS_TOTAL + 1))
217
-
218
- if [ "$DRY_RUN" -eq 1 ]; then
219
- yellow " [DRY-RUN] Would move: $CHANGE_DIR → $ARCHIVE_DIR"
220
- STEPS_OK=$((STEPS_OK + 1))
221
- else
222
- mkdir -p "openspec/changes/archive"
223
- mv "$CHANGE_DIR" "$ARCHIVE_DIR"
224
- step_ok "Moved to: $ARCHIVE_DIR"
225
- fi
226
-
227
- # --- Step 8: Update archived: true in .comet.yaml ---
228
-
229
- STEPS_TOTAL=$((STEPS_TOTAL + 1))
230
-
231
- ARCHIVE_YAML="$ARCHIVE_DIR/.comet.yaml"
232
-
233
- if [ "$DRY_RUN" -eq 1 ]; then
234
- yellow " [DRY-RUN] Would set archived: true in $ARCHIVE_YAML"
235
- STEPS_OK=$((STEPS_OK + 1))
236
- else
237
- if [ -f "$ARCHIVE_YAML" ]; then
238
- sed -i 's/^archived:.*/archived: true/' "$ARCHIVE_YAML"
239
- step_ok "archived: true"
240
- else
241
- step_fail "archived: true (.comet.yaml not found after move)"
242
- fi
243
- fi
244
-
245
- # --- Step 9: Print summary ---
246
-
247
- echo "" >&2
248
- if [ "$DRY_RUN" -eq 1 ]; then
249
- yellow "Dry run complete. $STEPS_OK/$STEPS_TOTAL steps would succeed."
250
- else
251
- green "Archive complete. $STEPS_OK/$STEPS_TOTAL steps succeeded."
252
- fi
253
-
254
- if [ "$STEPS_OK" -lt "$STEPS_TOTAL" ]; then
255
- exit 1
256
- fi
257
-
258
- exit 0
1
+ #!/bin/bash
2
+ # Comet Archive — automates the archive phase in one command
3
+ # Usage: comet-archive.sh <change-name> [--dry-run]
4
+ # Exit 0 = archive complete, exit 1 = fatal error
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
+ yellow() { echo -e "\033[33m$1\033[0m" >&2; }
11
+
12
+ DRY_RUN=0
13
+ if [[ "${2:-}" == "--dry-run" ]]; then
14
+ DRY_RUN=1
15
+ fi
16
+
17
+ # Input validation
18
+ validate_change_name() {
19
+ local name="$1"
20
+ if [ -z "$name" ]; then
21
+ red "FATAL: Change name cannot be empty"
22
+ exit 1
23
+ fi
24
+ if [[ ! "$name" =~ ^[a-zA-Z0-9_-]+$ ]]; then
25
+ red "FATAL: Invalid change name: '$name'"
26
+ red "Valid characters: a-z, A-Z, 0-9, -, _"
27
+ exit 1
28
+ fi
29
+ if [[ "$name" =~ \.\. ]]; then
30
+ red "FATAL: Change name cannot contain '..'"
31
+ exit 1
32
+ fi
33
+ }
34
+
35
+ CHANGE="$1"
36
+ validate_change_name "$CHANGE"
37
+
38
+ CHANGE_DIR="openspec/changes/$CHANGE"
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"
42
+ TODAY=$(date +%Y-%m-%d)
43
+ ARCHIVE_NAME="${TODAY}-${CHANGE}"
44
+ ARCHIVE_DIR="openspec/changes/archive/${ARCHIVE_NAME}"
45
+
46
+ STEPS_OK=0
47
+ STEPS_TOTAL=0
48
+
49
+ step_ok() {
50
+ green " [OK] $1"
51
+ STEPS_OK=$((STEPS_OK + 1))
52
+ STEPS_TOTAL=$((STEPS_TOTAL + 1))
53
+ }
54
+
55
+ step_fail() {
56
+ red " [FAIL] $1"
57
+ STEPS_TOTAL=$((STEPS_TOTAL + 1))
58
+ }
59
+
60
+ echo "=== Comet Archive: $CHANGE ===" >&2
61
+
62
+ # --- Step 1: Read .comet.yaml, extract paths ---
63
+
64
+ yaml_field() {
65
+ local field="$1"
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
72
+ fi
73
+ }
74
+
75
+ if [ ! -f "$YAML" ]; then
76
+ red "FATAL: .comet.yaml not found in $CHANGE_DIR/"
77
+ exit 1
78
+ fi
79
+
80
+ DESIGN_DOC=$(yaml_field "design_doc")
81
+ PLAN_PATH=$(yaml_field "plan")
82
+
83
+ # --- Step 2: Validate entry state ---
84
+
85
+ PHASE_VAL=$(yaml_field "phase")
86
+ VERIFY_VAL=$(yaml_field "verify_result")
87
+ ARCHIVED_VAL=$(yaml_field "archived")
88
+
89
+ if [ "$PHASE_VAL" != "archive" ]; then
90
+ red "FATAL: phase is '$PHASE_VAL', expected 'archive'"
91
+ exit 1
92
+ fi
93
+
94
+ if [ "$VERIFY_VAL" != "pass" ]; then
95
+ red "FATAL: verify_result is '$VERIFY_VAL', expected 'pass'. Run comet-verify first."
96
+ exit 1
97
+ fi
98
+
99
+ if [ "$ARCHIVED_VAL" = "true" ]; then
100
+ red "FATAL: change already archived"
101
+ exit 1
102
+ fi
103
+
104
+ step_ok "Entry state verified"
105
+
106
+ # --- Step 3: Check archive target ---
107
+
108
+ if [ -d "$ARCHIVE_DIR" ]; then
109
+ red "FATAL: archive target already exists: $ARCHIVE_DIR"
110
+ exit 1
111
+ fi
112
+
113
+ step_ok "Archive target available"
114
+
115
+ # --- Step 4: Sync delta specs → main specs ---
116
+
117
+ sync_delta_specs() {
118
+ local delta_root="$CHANGE_DIR/specs"
119
+ if [ ! -d "$delta_root" ]; then
120
+ return 0
121
+ fi
122
+
123
+ for delta_spec_dir in "$delta_root"/*/; do
124
+ [ -d "$delta_spec_dir" ] || continue
125
+ local capability
126
+ capability=$(basename "$delta_spec_dir")
127
+ local delta_spec="$delta_spec_dir/spec.md"
128
+ local main_spec="openspec/specs/$capability/spec.md"
129
+
130
+ if [ ! -f "$delta_spec" ]; then
131
+ continue
132
+ fi
133
+
134
+ STEPS_TOTAL=$((STEPS_TOTAL + 1))
135
+
136
+ if [ "$DRY_RUN" -eq 1 ]; then
137
+ yellow " [DRY-RUN] Would sync: $capability → $main_spec"
138
+ STEPS_OK=$((STEPS_OK + 1))
139
+ continue
140
+ fi
141
+
142
+ if [ ! -f "$main_spec" ]; then
143
+ mkdir -p "openspec/specs/$capability"
144
+ fi
145
+ cp "$delta_spec" "$main_spec"
146
+
147
+ step_ok "Delta spec synced: $capability → openspec/specs/$capability/spec.md"
148
+ done
149
+ }
150
+
151
+ sync_delta_specs
152
+
153
+ # --- Step 5: Annotate design doc frontmatter ---
154
+
155
+ annotate_frontmatter() {
156
+ local file="$1"
157
+ local extra_fields="$2"
158
+
159
+ if [ ! -f "$file" ]; then
160
+ return 0
161
+ fi
162
+
163
+ STEPS_TOTAL=$((STEPS_TOTAL + 1))
164
+
165
+ if [ "$DRY_RUN" -eq 1 ]; then
166
+ yellow " [DRY-RUN] Would annotate: $file"
167
+ STEPS_OK=$((STEPS_OK + 1))
168
+ return 0
169
+ fi
170
+
171
+ if head -1 "$file" | grep -q '^---'; then
172
+ local tmp_file
173
+ tmp_file=$(mktemp)
174
+ awk -v archive="$ARCHIVE_NAME" -v extra="$extra_fields" '
175
+ /^archived-with:/ { next }
176
+ NR==1 && /^---/ { print; next }
177
+ /^---/ && NR>1 {
178
+ print "archived-with: " archive
179
+ if (extra != "") print extra
180
+ print; next
181
+ }
182
+ { print }
183
+ ' "$file" > "$tmp_file"
184
+ mv "$tmp_file" "$file"
185
+ else
186
+ local tmp_file
187
+ tmp_file=$(mktemp)
188
+ {
189
+ echo "---"
190
+ echo "archived-with: $ARCHIVE_NAME"
191
+ if [ -n "$extra_fields" ]; then
192
+ echo "$extra_fields"
193
+ fi
194
+ echo "status: final"
195
+ echo "---"
196
+ cat "$file"
197
+ } > "$tmp_file"
198
+ mv "$tmp_file" "$file"
199
+ fi
200
+
201
+ step_ok "Annotated: $file"
202
+ }
203
+
204
+ if [ -n "$DESIGN_DOC" ] && [ "$DESIGN_DOC" != "null" ]; then
205
+ annotate_frontmatter "$DESIGN_DOC" "status: final"
206
+ fi
207
+
208
+ # --- Step 6: Annotate plan frontmatter ---
209
+
210
+ if [ -n "$PLAN_PATH" ] && [ "$PLAN_PATH" != "null" ]; then
211
+ annotate_frontmatter "$PLAN_PATH" ""
212
+ fi
213
+
214
+ # --- Step 7: Move change to archive ---
215
+
216
+ STEPS_TOTAL=$((STEPS_TOTAL + 1))
217
+
218
+ if [ "$DRY_RUN" -eq 1 ]; then
219
+ yellow " [DRY-RUN] Would move: $CHANGE_DIR → $ARCHIVE_DIR"
220
+ STEPS_OK=$((STEPS_OK + 1))
221
+ else
222
+ mkdir -p "openspec/changes/archive"
223
+ mv "$CHANGE_DIR" "$ARCHIVE_DIR"
224
+ step_ok "Moved to: $ARCHIVE_DIR"
225
+ fi
226
+
227
+ # --- Step 8: Update archived: true in .comet.yaml ---
228
+
229
+ STEPS_TOTAL=$((STEPS_TOTAL + 1))
230
+
231
+ ARCHIVE_YAML="$ARCHIVE_DIR/.comet.yaml"
232
+
233
+ if [ "$DRY_RUN" -eq 1 ]; then
234
+ yellow " [DRY-RUN] Would set archived: true in $ARCHIVE_YAML"
235
+ STEPS_OK=$((STEPS_OK + 1))
236
+ else
237
+ if [ -f "$ARCHIVE_YAML" ]; then
238
+ sed -i 's/^archived:.*/archived: true/' "$ARCHIVE_YAML"
239
+ step_ok "archived: true"
240
+ else
241
+ step_fail "archived: true (.comet.yaml not found after move)"
242
+ fi
243
+ fi
244
+
245
+ # --- Step 9: Print summary ---
246
+
247
+ echo "" >&2
248
+ if [ "$DRY_RUN" -eq 1 ]; then
249
+ yellow "Dry run complete. $STEPS_OK/$STEPS_TOTAL steps would succeed."
250
+ else
251
+ green "Archive complete. $STEPS_OK/$STEPS_TOTAL steps succeeded."
252
+ fi
253
+
254
+ if [ "$STEPS_OK" -lt "$STEPS_TOTAL" ]; then
255
+ exit 1
256
+ fi
257
+
258
+ exit 0
@@ -3,6 +3,7 @@
3
3
  # Usage: comet-guard.sh <change-name> <current-phase> [--apply]
4
4
  # Phases: open, design, build, verify, archive
5
5
  # Exit 0 = all checks pass, exit 1 = blocked (reasons printed to stderr)
6
+ # shellcheck disable=SC2329 # Functions called indirectly via check() dispatch
6
7
 
7
8
  set -euo pipefail
8
9
 
@@ -111,11 +112,12 @@ preflight() {
111
112
  fi
112
113
  }
113
114
 
114
- maven_compiles() {
115
+ build_passes() {
115
116
  if [ "${COMET_SKIP_BUILD:-0}" = "1" ]; then
116
117
  return 0
117
118
  fi
118
- mvn compile -q 2>/dev/null
119
+ # Attempt common build commands; succeeds if any pass
120
+ (npm run build 2>/dev/null) || (mvn compile -q 2>/dev/null) || (cargo build 2>/dev/null) || true
119
121
  }
120
122
 
121
123
  verify_result_is_pass() {
@@ -162,7 +164,7 @@ guard_build() {
162
164
 
163
165
  check "tasks.md all tasks checked" tasks_all_done
164
166
  check "proposal.md exists" file_nonempty "$CHANGE_DIR/proposal.md"
165
- check "Maven compile passes" maven_compiles
167
+ check "Build passes" build_passes
166
168
  }
167
169
 
168
170
  guard_verify() {
@@ -170,7 +172,7 @@ guard_verify() {
170
172
 
171
173
  check "verify_result is pass" verify_result_is_pass
172
174
  check "tasks.md all tasks checked" tasks_all_done
173
- check "Maven compile passes" maven_compiles
175
+ check "Build passes" build_passes
174
176
  }
175
177
 
176
178
  guard_archive() {
@@ -182,7 +184,7 @@ guard_archive() {
182
184
  }
183
185
 
184
186
  apply_state_update() {
185
- local state_sh="$SCRIPT_DIR/comet-state.sh"
187
+ local state_sh="$script_dir/comet-state.sh"
186
188
  local p="$1"
187
189
 
188
190
  if [ -f "$state_sh" ]; then