@rpamis/comet 0.2.5 → 0.2.6
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 +11 -4
- package/assets/manifest.json +1 -1
- package/assets/skills/comet/SKILL.md +19 -1
- package/assets/skills/comet/scripts/comet-archive.sh +255 -258
- package/assets/skills/comet/scripts/comet-guard.sh +407 -257
- package/assets/skills/comet/scripts/comet-state.sh +680 -616
- package/assets/skills/comet/scripts/comet-yaml-validate.sh +157 -138
- package/assets/skills/comet-archive/SKILL.md +3 -0
- package/assets/skills/comet-build/SKILL.md +27 -1
- package/assets/skills-zh/comet/SKILL.md +15 -1
- package/assets/skills-zh/comet-archive/SKILL.md +3 -0
- package/assets/skills-zh/comet-build/SKILL.md +27 -1
- package/bin/comet.js +3 -3
- package/package.json +1 -1
- package/scripts/postinstall.js +44 -44
package/LICENSE
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2026 rpamis
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 rpamis
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -235,6 +235,8 @@ verified_at: null
|
|
|
235
235
|
archived: false
|
|
236
236
|
```
|
|
237
237
|
|
|
238
|
+
In full workflow, `build_mode` and `isolation` may temporarily be `null` at init time, but they must be resolved before `build → verify`. `direct` is allowed by default only for hotfix/tweak; full workflow requires `direct_override: true`. Projects can configure `build_command` / `verify_command` in the change or repo root, and guard will run those commands first and print failure output.
|
|
239
|
+
|
|
238
240
|
All states and execution phases are updated via scripts, and **each phase verifies that tasks are truly completed before exiting — conditions are met before the phase exits and state is updated**. Compared to recording complex state management mechanisms in Skills, the script approach strongly guarantees the reliability of core state transitions, correctness of YAML files, and convenience of breakpoint recovery — Agents only need to use Comet's built-in commands to read state and know the current Spec's situation.
|
|
239
241
|
|
|
240
242
|
### Reliability Features
|
|
@@ -252,18 +254,23 @@ Comet ensures agent execution reliability through automated state transitions:
|
|
|
252
254
|
- Guard and archive scripts use `comet-state.sh` internally for state management
|
|
253
255
|
|
|
254
256
|
3. **Schema Validation** — `comet-yaml-validate.sh` ensures data integrity
|
|
255
|
-
- Validates required
|
|
256
|
-
- Validates enum values
|
|
257
|
+
- Validates required and optional fields
|
|
258
|
+
- Validates enum values, including `direct_override`
|
|
257
259
|
- Validates referenced file paths exist
|
|
258
260
|
- Detects unknown/typos fields
|
|
259
261
|
|
|
260
|
-
4. **
|
|
262
|
+
4. **Build Decision Enforcement** — Guard and state transitions both block skipped build choices
|
|
263
|
+
- `isolation` must be `branch` or `worktree`
|
|
264
|
+
- `build_mode` must be selected before leaving build
|
|
265
|
+
- Full workflow `build_mode: direct` requires `direct_override: true`
|
|
266
|
+
|
|
267
|
+
5. **Verification Evidence** — Guard enforces proof before phase advance
|
|
261
268
|
- `verify-pass` transition requires `verification_report` pointing to an existing report file
|
|
262
269
|
- `branch_status` must be `handled` before verify can pass
|
|
263
270
|
- Guard checks `verification_report exists` and `branch_status=handled` as hard prerequisites
|
|
264
271
|
- Prevents false phase advances when verification or branch handling was skipped
|
|
265
272
|
|
|
266
|
-
|
|
273
|
+
6. **Archive Automation** — `comet-archive.sh` handles the full archive flow in one command
|
|
267
274
|
- Validates entry state, syncs delta specs to main specs
|
|
268
275
|
- Annotates design doc and plan frontmatter
|
|
269
276
|
- Moves change to archive directory and updates `archived: true`
|
package/assets/manifest.json
CHANGED
|
@@ -156,6 +156,8 @@ build_mode: subagent-driven-development
|
|
|
156
156
|
isolation: branch
|
|
157
157
|
verify_mode: light
|
|
158
158
|
verify_result: pending
|
|
159
|
+
verification_report: null
|
|
160
|
+
branch_status: pending
|
|
159
161
|
verified_at: null
|
|
160
162
|
archived: false
|
|
161
163
|
```
|
|
@@ -167,12 +169,28 @@ archived: false
|
|
|
167
169
|
| `design_doc` | Associated Superpowers Design Doc path, can be empty |
|
|
168
170
|
| `plan` | Associated Superpowers Plan path, can be empty |
|
|
169
171
|
| `build_mode` | Selected execution mode, can be empty |
|
|
170
|
-
| `isolation` | `branch` or `worktree`, workspace isolation method
|
|
172
|
+
| `isolation` | `branch` or `worktree`, workspace isolation method. Full workflow init may leave this as `null`, but only until `/comet-build` Step 3; hotfix/tweak default to `branch` |
|
|
171
173
|
| `verify_mode` | `light` or `full`, can be empty |
|
|
172
174
|
| `verify_result` | `pending`, `pass`, or `fail` |
|
|
175
|
+
| `verification_report` | Verification report file path; must point to an existing file before verify can pass |
|
|
176
|
+
| `branch_status` | `pending` or `handled`; set to `handled` after branch handling completes |
|
|
173
177
|
| `verified_at` | Verification pass time, can be empty |
|
|
174
178
|
| `archived` | Whether change is archived |
|
|
175
179
|
|
|
180
|
+
Optional fields:
|
|
181
|
+
|
|
182
|
+
| Field | Meaning |
|
|
183
|
+
|-------|---------|
|
|
184
|
+
| `direct_override` | `true`/`false`. Full workflow may use `build_mode: direct` only when this is explicitly `true` |
|
|
185
|
+
| `build_command` | Project build command. Guard runs this first and prints failure output |
|
|
186
|
+
| `verify_command` | Project verification command. Verify guard runs this first; if absent, it falls back to the build command |
|
|
187
|
+
|
|
188
|
+
State-machine hard constraints:
|
|
189
|
+
- Before `build → verify`, `isolation` must be `branch` or `worktree`
|
|
190
|
+
- Before `build → verify`, `build_mode` must be selected
|
|
191
|
+
- `build_mode: direct` is allowed by default only for `hotfix` / `tweak`; full workflow requires `direct_override: true`
|
|
192
|
+
- These constraints are enforced by both `comet-guard.sh build --apply` and `comet-state.sh transition <name> build-complete`
|
|
193
|
+
|
|
176
194
|
### Script Location
|
|
177
195
|
|
|
178
196
|
Comet scripts are distributed in `comet/scripts/`. **Do not hardcode paths** — locate once, cache in env vars:
|
|
@@ -1,258 +1,255 @@
|
|
|
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
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
if [
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
fi
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
if [ "$
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
if [ "$
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
tmp_file
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
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: Mark archived via comet-state transition ---
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
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
|
+
step_dry_run() {
|
|
61
|
+
yellow " [DRY-RUN] $1"
|
|
62
|
+
STEPS_OK=$((STEPS_OK + 1))
|
|
63
|
+
STEPS_TOTAL=$((STEPS_TOTAL + 1))
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
echo "=== Comet Archive: $CHANGE ===" >&2
|
|
67
|
+
|
|
68
|
+
# --- Step 1: Read .comet.yaml, extract paths ---
|
|
69
|
+
|
|
70
|
+
yaml_field() {
|
|
71
|
+
local field="$1"
|
|
72
|
+
if [ -f "$STATE_SH" ]; then
|
|
73
|
+
bash "$STATE_SH" get "$CHANGE" "$field" 2>/dev/null
|
|
74
|
+
else
|
|
75
|
+
if [ -f "$YAML" ]; then
|
|
76
|
+
grep "^${field}:" "$YAML" | sed "s/^${field}: *//" | tr -d '"' | tr -d "'"
|
|
77
|
+
fi
|
|
78
|
+
fi
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if [ ! -f "$YAML" ]; then
|
|
82
|
+
red "FATAL: .comet.yaml not found in $CHANGE_DIR/"
|
|
83
|
+
exit 1
|
|
84
|
+
fi
|
|
85
|
+
|
|
86
|
+
DESIGN_DOC=$(yaml_field "design_doc")
|
|
87
|
+
PLAN_PATH=$(yaml_field "plan")
|
|
88
|
+
|
|
89
|
+
# --- Step 2: Validate entry state ---
|
|
90
|
+
|
|
91
|
+
PHASE_VAL=$(yaml_field "phase")
|
|
92
|
+
VERIFY_VAL=$(yaml_field "verify_result")
|
|
93
|
+
ARCHIVED_VAL=$(yaml_field "archived")
|
|
94
|
+
|
|
95
|
+
if [ "$PHASE_VAL" != "archive" ]; then
|
|
96
|
+
red "FATAL: phase is '$PHASE_VAL', expected 'archive'"
|
|
97
|
+
exit 1
|
|
98
|
+
fi
|
|
99
|
+
|
|
100
|
+
if [ "$VERIFY_VAL" != "pass" ]; then
|
|
101
|
+
red "FATAL: verify_result is '$VERIFY_VAL', expected 'pass'. Run comet-verify first."
|
|
102
|
+
exit 1
|
|
103
|
+
fi
|
|
104
|
+
|
|
105
|
+
if [ "$ARCHIVED_VAL" = "true" ]; then
|
|
106
|
+
red "FATAL: change already archived"
|
|
107
|
+
exit 1
|
|
108
|
+
fi
|
|
109
|
+
|
|
110
|
+
step_ok "Entry state verified"
|
|
111
|
+
|
|
112
|
+
# --- Step 3: Check archive target ---
|
|
113
|
+
|
|
114
|
+
if [ -d "$ARCHIVE_DIR" ]; then
|
|
115
|
+
red "FATAL: archive target already exists: $ARCHIVE_DIR"
|
|
116
|
+
exit 1
|
|
117
|
+
fi
|
|
118
|
+
|
|
119
|
+
step_ok "Archive target available"
|
|
120
|
+
|
|
121
|
+
# --- Step 4: Sync delta specs → main specs ---
|
|
122
|
+
|
|
123
|
+
sync_delta_specs() {
|
|
124
|
+
local delta_root="$CHANGE_DIR/specs"
|
|
125
|
+
if [ ! -d "$delta_root" ]; then
|
|
126
|
+
return 0
|
|
127
|
+
fi
|
|
128
|
+
|
|
129
|
+
for delta_spec_dir in "$delta_root"/*/; do
|
|
130
|
+
[ -d "$delta_spec_dir" ] || continue
|
|
131
|
+
local capability
|
|
132
|
+
capability=$(basename "$delta_spec_dir")
|
|
133
|
+
local delta_spec="$delta_spec_dir/spec.md"
|
|
134
|
+
local main_spec="openspec/specs/$capability/spec.md"
|
|
135
|
+
|
|
136
|
+
if [ ! -f "$delta_spec" ]; then
|
|
137
|
+
continue
|
|
138
|
+
fi
|
|
139
|
+
|
|
140
|
+
if [ "$DRY_RUN" -eq 1 ]; then
|
|
141
|
+
step_dry_run "Would sync: $capability → $main_spec"
|
|
142
|
+
continue
|
|
143
|
+
fi
|
|
144
|
+
|
|
145
|
+
if [ ! -f "$main_spec" ]; then
|
|
146
|
+
mkdir -p "openspec/specs/$capability"
|
|
147
|
+
elif ! cmp -s "$main_spec" "$delta_spec"; then
|
|
148
|
+
yellow " [DIFF] Delta spec differs from main spec before sync: $capability"
|
|
149
|
+
diff -u "$main_spec" "$delta_spec" >&2 || true
|
|
150
|
+
fi
|
|
151
|
+
cp "$delta_spec" "$main_spec"
|
|
152
|
+
|
|
153
|
+
step_ok "Delta spec synced: $capability → openspec/specs/$capability/spec.md"
|
|
154
|
+
done
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
sync_delta_specs
|
|
158
|
+
|
|
159
|
+
# --- Step 5: Annotate design doc frontmatter ---
|
|
160
|
+
|
|
161
|
+
annotate_frontmatter() {
|
|
162
|
+
local file="$1"
|
|
163
|
+
local extra_fields="$2"
|
|
164
|
+
|
|
165
|
+
if [ ! -f "$file" ]; then
|
|
166
|
+
return 0
|
|
167
|
+
fi
|
|
168
|
+
|
|
169
|
+
if [ "$DRY_RUN" -eq 1 ]; then
|
|
170
|
+
step_dry_run "Would annotate: $file"
|
|
171
|
+
return 0
|
|
172
|
+
fi
|
|
173
|
+
|
|
174
|
+
if head -1 "$file" | grep -q '^---'; then
|
|
175
|
+
local tmp_file
|
|
176
|
+
tmp_file=$(mktemp)
|
|
177
|
+
awk -v archive="$ARCHIVE_NAME" -v extra="$extra_fields" '
|
|
178
|
+
/^archived-with:/ { next }
|
|
179
|
+
NR==1 && /^---/ { print; next }
|
|
180
|
+
/^---/ && NR>1 {
|
|
181
|
+
print "archived-with: " archive
|
|
182
|
+
if (extra != "") print extra
|
|
183
|
+
print; next
|
|
184
|
+
}
|
|
185
|
+
{ print }
|
|
186
|
+
' "$file" > "$tmp_file"
|
|
187
|
+
mv "$tmp_file" "$file"
|
|
188
|
+
else
|
|
189
|
+
local tmp_file
|
|
190
|
+
tmp_file=$(mktemp)
|
|
191
|
+
{
|
|
192
|
+
echo "---"
|
|
193
|
+
echo "archived-with: $ARCHIVE_NAME"
|
|
194
|
+
if [ -n "$extra_fields" ]; then
|
|
195
|
+
echo "$extra_fields"
|
|
196
|
+
fi
|
|
197
|
+
echo "status: final"
|
|
198
|
+
echo "---"
|
|
199
|
+
cat "$file"
|
|
200
|
+
} > "$tmp_file"
|
|
201
|
+
mv "$tmp_file" "$file"
|
|
202
|
+
fi
|
|
203
|
+
|
|
204
|
+
step_ok "Annotated: $file"
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
if [ -n "$DESIGN_DOC" ] && [ "$DESIGN_DOC" != "null" ]; then
|
|
208
|
+
annotate_frontmatter "$DESIGN_DOC" "status: final"
|
|
209
|
+
fi
|
|
210
|
+
|
|
211
|
+
# --- Step 6: Annotate plan frontmatter ---
|
|
212
|
+
|
|
213
|
+
if [ -n "$PLAN_PATH" ] && [ "$PLAN_PATH" != "null" ]; then
|
|
214
|
+
annotate_frontmatter "$PLAN_PATH" ""
|
|
215
|
+
fi
|
|
216
|
+
|
|
217
|
+
# --- Step 7: Move change to archive ---
|
|
218
|
+
|
|
219
|
+
if [ "$DRY_RUN" -eq 1 ]; then
|
|
220
|
+
step_dry_run "Would move: $CHANGE_DIR → $ARCHIVE_DIR"
|
|
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: Mark archived via comet-state transition ---
|
|
228
|
+
|
|
229
|
+
ARCHIVE_YAML="$ARCHIVE_DIR/.comet.yaml"
|
|
230
|
+
|
|
231
|
+
if [ "$DRY_RUN" -eq 1 ]; then
|
|
232
|
+
step_dry_run "Would set archived: true in $ARCHIVE_YAML"
|
|
233
|
+
else
|
|
234
|
+
if [ -f "$ARCHIVE_YAML" ]; then
|
|
235
|
+
bash "$STATE_SH" transition "$ARCHIVE_NAME" archived >/dev/null
|
|
236
|
+
step_ok "archived: true"
|
|
237
|
+
else
|
|
238
|
+
step_fail "archived: true (.comet.yaml not found after move)"
|
|
239
|
+
fi
|
|
240
|
+
fi
|
|
241
|
+
|
|
242
|
+
# --- Step 9: Print summary ---
|
|
243
|
+
|
|
244
|
+
echo "" >&2
|
|
245
|
+
if [ "$DRY_RUN" -eq 1 ]; then
|
|
246
|
+
yellow "Dry run complete. $STEPS_OK/$STEPS_TOTAL steps would succeed."
|
|
247
|
+
else
|
|
248
|
+
green "Archive complete. $STEPS_OK/$STEPS_TOTAL steps succeeded."
|
|
249
|
+
fi
|
|
250
|
+
|
|
251
|
+
if [ "$STEPS_OK" -lt "$STEPS_TOTAL" ]; then
|
|
252
|
+
exit 1
|
|
253
|
+
fi
|
|
254
|
+
|
|
255
|
+
exit 0
|