@house365/comate 0.9.4 → 0.9.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 +106 -106
- package/docs/COMATE_MANUAL.md +709 -707
- package/package.json +1 -1
- package/skills/comate/SKILL.md +342 -214
- package/skills/comate/reference/decision-points.md +103 -103
- package/skills/comate/reference/dirty-worktree.md +58 -58
- package/skills/comate/reference/prerequisites.md +89 -89
- package/skills/comate/scripts/comate-lib.sh +5 -1
- package/skills/comate/scripts/comate.sh +98 -16
- package/skills/comate/tests/comate.bats +96 -1
- package/skills/comate-archive/SKILL.md +63 -63
- package/skills/comate-build/SKILL.md +246 -169
- package/skills/comate-design/SKILL.md +173 -101
- package/skills/comate-fix/SKILL.md +9 -5
- package/skills/comate-gate/SKILL.md +257 -257
- package/skills/comate-gate/scaffold/docs/README.md +36 -36
- package/skills/comate-gate/scaffold/docs/architecture/README.md +31 -31
- package/skills/comate-gate/scaffold/docs/knowledge-base/README.md +48 -48
- package/skills/comate-gate/scaffold/docs/knowledge-base/integrations/_TEMPLATE/README.md +49 -49
- package/skills/comate-gate/scaffold/docs/knowledge-base/integrations/_TEMPLATE/api-snapshot.md +47 -47
- package/skills/comate-gate/scaffold/docs/knowledge-base/requirements/_templates/PRD.md +97 -97
- package/skills/comate-grill/SKILL.md +185 -185
- package/skills/comate-kb-integration/scripts/fetch_rendered_doc.py +84 -84
- package/skills/comate-open/SKILL.md +201 -148
- package/skills/comate-verify/SKILL.md +152 -143
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
# sources find <file> — reverse lookup: changes citing a file
|
|
20
20
|
# gate <prd> review — create/refresh gate.yaml next to the PRD, pin hash
|
|
21
21
|
# gate <prd> set <field> <value> — write score | blocking_open | gate_status | …
|
|
22
|
-
# gate <prd> pass [--tbd] —
|
|
22
|
+
# gate <prd> pass [--tbd] — pass clean gate or explicitly accepted TBD blockers
|
|
23
23
|
# gate <prd> spawned <change> — record a change fanned out from this PRD
|
|
24
24
|
# gate <prd> status [--json] — print gate status (computes stale on hash drift)
|
|
25
25
|
# gate <prd> check — precondition guard before spawning a change
|
|
@@ -60,7 +60,7 @@ Usage: comate.sh <command> ...
|
|
|
60
60
|
state <name> init <workflow> full | fix
|
|
61
61
|
state <name> get <field>
|
|
62
62
|
state <name> set <field> <value>
|
|
63
|
-
state <name> transition <event> open-complete|design-complete|build-complete|verify-pass|verify-fail|archived
|
|
63
|
+
state <name> transition <event> open-complete|design-complete|build-complete|verify-pass|verify-fail|fix-upgrade|archived
|
|
64
64
|
state <name> check <phase> [--json]
|
|
65
65
|
state <name> recover <phase>
|
|
66
66
|
state <name> scale
|
|
@@ -72,9 +72,10 @@ Usage: comate.sh <command> ...
|
|
|
72
72
|
sources <name> check
|
|
73
73
|
sources <name> list
|
|
74
74
|
sources find <file>
|
|
75
|
+
dependency <name> archived verify an exact archived change exists
|
|
75
76
|
gate <prd> review create/refresh gate.yaml next to PRD, pin hash
|
|
76
77
|
gate <prd> set <field> <value> score | blocking_open | gate_status | …
|
|
77
|
-
gate <prd> pass [--tbd]
|
|
78
|
+
gate <prd> pass [--tbd] pass: zero blockers; --tbd: accepted blockers
|
|
78
79
|
gate <prd> spawned <change> record a change fanned out from this PRD
|
|
79
80
|
gate <prd> status [--json]
|
|
80
81
|
gate <prd> check precondition guard before spawning a change
|
|
@@ -138,6 +139,8 @@ state_init() {
|
|
|
138
139
|
schema_version: $COMATE_SCHEMA_VERSION
|
|
139
140
|
workflow: $workflow
|
|
140
141
|
phase: open
|
|
142
|
+
phase_step: null
|
|
143
|
+
phase_step_data: null
|
|
141
144
|
build_mode: $build_mode
|
|
142
145
|
tdd_mode: $tdd_mode
|
|
143
146
|
isolation: $isolation
|
|
@@ -237,7 +240,7 @@ state_transition() {
|
|
|
237
240
|
validate_change_name "$name"
|
|
238
241
|
validate_enum_event() {
|
|
239
242
|
case "$1" in
|
|
240
|
-
open-complete|design-complete|build-complete|verify-pass|verify-fail|archived) return 0 ;;
|
|
243
|
+
open-complete|design-complete|build-complete|verify-pass|verify-fail|fix-upgrade|archived) return 0 ;;
|
|
241
244
|
*) die "$COMATE_USAGE" "ERROR: unknown event '$1'" ;;
|
|
242
245
|
esac
|
|
243
246
|
}
|
|
@@ -246,6 +249,13 @@ state_transition() {
|
|
|
246
249
|
local yaml; yaml=$(require_yaml "$name")
|
|
247
250
|
validate_flat_yaml "$yaml"
|
|
248
251
|
|
|
252
|
+
# phase_step is local to the current phase. Carrying it into the next phase
|
|
253
|
+
# makes identical step numbers ambiguous and can skip mandatory work.
|
|
254
|
+
_clear_phase_progress() {
|
|
255
|
+
yaml_set "$yaml" phase_step null
|
|
256
|
+
yaml_set "$yaml" phase_step_data null
|
|
257
|
+
}
|
|
258
|
+
|
|
249
259
|
case "$event" in
|
|
250
260
|
open-complete)
|
|
251
261
|
_require_phase "$yaml" open
|
|
@@ -255,10 +265,12 @@ state_transition() {
|
|
|
255
265
|
else
|
|
256
266
|
yaml_set "$yaml" phase build
|
|
257
267
|
fi
|
|
268
|
+
_clear_phase_progress
|
|
258
269
|
;;
|
|
259
270
|
design-complete)
|
|
260
271
|
_require_phase "$yaml" design
|
|
261
272
|
yaml_set "$yaml" phase build
|
|
273
|
+
_clear_phase_progress
|
|
262
274
|
;;
|
|
263
275
|
build-complete)
|
|
264
276
|
_require_phase "$yaml" build
|
|
@@ -267,6 +279,7 @@ state_transition() {
|
|
|
267
279
|
yaml_set "$yaml" verify_result pending
|
|
268
280
|
yaml_set "$yaml" verification_report null
|
|
269
281
|
yaml_set "$yaml" branch_status pending
|
|
282
|
+
_clear_phase_progress
|
|
270
283
|
;;
|
|
271
284
|
verify-pass)
|
|
272
285
|
_require_phase "$yaml" verify
|
|
@@ -274,12 +287,36 @@ state_transition() {
|
|
|
274
287
|
yaml_set "$yaml" verify_result pass
|
|
275
288
|
yaml_set "$yaml" phase archive
|
|
276
289
|
yaml_set "$yaml" verified_at "$(today)"
|
|
290
|
+
_clear_phase_progress
|
|
277
291
|
;;
|
|
278
292
|
verify-fail)
|
|
279
293
|
_require_phase "$yaml" verify
|
|
280
|
-
|
|
294
|
+
# The failure is captured in the report; once routed back to build the
|
|
295
|
+
# active verification state must be pending or the orchestrator loops.
|
|
296
|
+
yaml_set "$yaml" verify_result pending
|
|
281
297
|
yaml_set "$yaml" phase build
|
|
298
|
+
yaml_set "$yaml" verification_report null
|
|
299
|
+
yaml_set "$yaml" branch_status pending
|
|
300
|
+
_clear_phase_progress
|
|
301
|
+
;;
|
|
302
|
+
fix-upgrade)
|
|
303
|
+
[ "$(yaml_get "$yaml" workflow)" = "fix" ] || \
|
|
304
|
+
die "$COMATE_BLOCK" "ERROR: fix-upgrade requires workflow=fix"
|
|
305
|
+
case "$(yaml_get "$yaml" phase)" in
|
|
306
|
+
open|build) ;;
|
|
307
|
+
*) die "$COMATE_BLOCK" "ERROR: fix-upgrade is only valid from open or build" ;;
|
|
308
|
+
esac
|
|
309
|
+
yaml_set "$yaml" workflow full
|
|
310
|
+
yaml_set "$yaml" phase design
|
|
311
|
+
yaml_set "$yaml" build_mode null
|
|
312
|
+
yaml_set "$yaml" tdd_mode null
|
|
313
|
+
yaml_set "$yaml" isolation null
|
|
314
|
+
yaml_set "$yaml" verify_mode null
|
|
315
|
+
yaml_set "$yaml" direct_override false
|
|
316
|
+
yaml_set "$yaml" verify_result pending
|
|
317
|
+
yaml_set "$yaml" verification_report null
|
|
282
318
|
yaml_set "$yaml" branch_status pending
|
|
319
|
+
_clear_phase_progress
|
|
283
320
|
;;
|
|
284
321
|
archived)
|
|
285
322
|
_require_phase "$yaml" archive
|
|
@@ -498,15 +535,19 @@ state_recover() {
|
|
|
498
535
|
yaml="$dir/.comate.yaml"
|
|
499
536
|
[ -f "$yaml" ] || die "$COMATE_CORRUPT" "ERROR: .comate.yaml not found at $yaml"
|
|
500
537
|
|
|
501
|
-
local phase workflow
|
|
538
|
+
local phase workflow phase_step phase_step_data
|
|
502
539
|
phase=$(yaml_get "$yaml" phase)
|
|
503
540
|
workflow=$(yaml_get "$yaml" workflow)
|
|
541
|
+
phase_step=$(yaml_get "$yaml" phase_step)
|
|
542
|
+
phase_step_data=$(yaml_get "$yaml" phase_step_data)
|
|
504
543
|
# If a phase arg was passed, honor it for reporting; else use stored phase.
|
|
505
544
|
[ -n "$phase_arg" ] && phase="$phase_arg"
|
|
506
545
|
|
|
507
546
|
echo "=== Recovery Context: $name ==="
|
|
508
547
|
echo "Phase: $phase"
|
|
509
548
|
echo "Workflow: $workflow"
|
|
549
|
+
echo "Phase step: ${phase_step:-null}"
|
|
550
|
+
echo "Phase step data: ${phase_step_data:-null}"
|
|
510
551
|
echo ""
|
|
511
552
|
|
|
512
553
|
local design_doc plan verify_result verify_mode verification_report
|
|
@@ -578,7 +619,11 @@ state_recover() {
|
|
|
578
619
|
echo "Tasks: tasks.md MISSING"
|
|
579
620
|
fi
|
|
580
621
|
echo ""
|
|
581
|
-
if [ "$
|
|
622
|
+
if [[ "$phase_step" == build.blocked-by-* ]]; then
|
|
623
|
+
local dep="$phase_step_data"
|
|
624
|
+
if [ -z "$dep" ] || [ "$dep" = "null" ]; then dep="${phase_step#build.blocked-by-}"; fi
|
|
625
|
+
echo "Recovery action: Blocked by $dep. Run: comate.sh dependency $dep archived"
|
|
626
|
+
elif [ "$isolation" = "null" ] || [ -z "$isolation" ]; then
|
|
582
627
|
echo "Recovery action: Isolation not selected. AskUserQuestion for branch/worktree."
|
|
583
628
|
elif [ "$build_mode" = "null" ] || [ -z "$build_mode" ]; then
|
|
584
629
|
echo "Recovery action: Build mode not selected. AskUserQuestion for execution method."
|
|
@@ -600,7 +645,9 @@ state_recover() {
|
|
|
600
645
|
_field_status "branch_status" "$branch_status"
|
|
601
646
|
_field_status "impl_hash" "$impl_hash"
|
|
602
647
|
echo ""
|
|
603
|
-
if [ "$
|
|
648
|
+
if [ "$branch_status" = "discarded" ]; then
|
|
649
|
+
echo "Recovery action: Work was discarded. Run verify-fail to return to build before reimplementing, or explicitly abandon the change."
|
|
650
|
+
elif [ "$verify_result" = "pass" ] && [ "$branch_status" = "handled" ]; then
|
|
604
651
|
echo "Recovery action: Verification complete. Run guard to transition to archive."
|
|
605
652
|
elif [ "$verify_result" = "pass" ]; then
|
|
606
653
|
echo "Recovery action: Verified but branch not handled. Complete branch handling, set branch_status=handled."
|
|
@@ -1345,6 +1392,23 @@ sources_find() {
|
|
|
1345
1392
|
return 0
|
|
1346
1393
|
}
|
|
1347
1394
|
|
|
1395
|
+
# dependency <name> archived — prove completion from archived state, rather
|
|
1396
|
+
# than inferring it from absence in `openspec list`.
|
|
1397
|
+
dependency_archived() {
|
|
1398
|
+
local name="$1"
|
|
1399
|
+
validate_change_name "$name"
|
|
1400
|
+
[ ! -d "openspec/changes/$name" ] || \
|
|
1401
|
+
die "$COMATE_BLOCK" "BLOCK: dependency '$name' is still active"
|
|
1402
|
+
local found="" yaml
|
|
1403
|
+
while IFS= read -r yaml; do
|
|
1404
|
+
[ "$(yaml_get "$yaml" archived)" = "true" ] && found="$yaml"
|
|
1405
|
+
done < <(find openspec/changes/archive -mindepth 2 -maxdepth 2 \
|
|
1406
|
+
-path "*/????-??-??-${name}/.comate.yaml" -type f 2>/dev/null | sort)
|
|
1407
|
+
[ -n "$found" ] || \
|
|
1408
|
+
die "$COMATE_BLOCK" "BLOCK: no archived=true record found for dependency '$name'"
|
|
1409
|
+
log_pass "[DEPENDENCY] archived: $name ($found)"
|
|
1410
|
+
}
|
|
1411
|
+
|
|
1348
1412
|
# =====================================================================
|
|
1349
1413
|
# gate — phase 0: PRD quality gate + split precondition
|
|
1350
1414
|
# =====================================================================
|
|
@@ -1416,10 +1480,8 @@ gate_set() {
|
|
|
1416
1480
|
log_pass "[GATE] set $field=$value"
|
|
1417
1481
|
}
|
|
1418
1482
|
|
|
1419
|
-
# gate <prd> pass [--tbd] — flip to passed/passed-with-tbd.
|
|
1420
|
-
#
|
|
1421
|
-
# edit invalidates the pass. --tbd records that the user authorised proceeding
|
|
1422
|
-
# with unresolved TBDs (spawned changes must carry ⚠ markers).
|
|
1483
|
+
# gate <prd> pass [--tbd] — flip to passed/passed-with-tbd. Normal pass requires
|
|
1484
|
+
# zero blockers; --tbd requires at least one explicitly accepted blocker.
|
|
1423
1485
|
gate_pass() {
|
|
1424
1486
|
local prd; prd=$(require_prd "$1")
|
|
1425
1487
|
local tbd=0
|
|
@@ -1427,9 +1489,22 @@ gate_pass() {
|
|
|
1427
1489
|
local gate; gate=$(gate_path_for "$prd")
|
|
1428
1490
|
[ -f "$gate" ] || die "$COMATE_CORRUPT" "ERROR: gate not found (run 'gate review' first): $gate"
|
|
1429
1491
|
|
|
1430
|
-
local
|
|
1431
|
-
|
|
1432
|
-
|
|
1492
|
+
local score blocking changes_map
|
|
1493
|
+
score=$(yaml_get "$gate" score)
|
|
1494
|
+
blocking=$(yaml_get "$gate" blocking_open)
|
|
1495
|
+
changes_map=$(yaml_get "$gate" changes_map)
|
|
1496
|
+
[[ "$score" =~ ^[0-9]+$ ]] && [ "$score" -ge 0 ] && [ "$score" -le 100 ] || \
|
|
1497
|
+
die "$COMATE_BLOCK" "BLOCK: score must be an integer from 0 to 100 (got '$score')"
|
|
1498
|
+
[[ "$blocking" =~ ^[0-9]+$ ]] || \
|
|
1499
|
+
die "$COMATE_BLOCK" "BLOCK: blocking_open must be a non-negative integer (got '$blocking')"
|
|
1500
|
+
if [ "$tbd" -eq 1 ]; then
|
|
1501
|
+
[ "$blocking" -gt 0 ] || \
|
|
1502
|
+
die "$COMATE_BLOCK" "BLOCK: --tbd requires at least one recorded unresolved blocker"
|
|
1503
|
+
elif [ "$blocking" -ne 0 ]; then
|
|
1504
|
+
die "$COMATE_BLOCK" "BLOCK: blocking_open='$blocking' — resolve all blocking issues or use --tbd after explicit user authorization"
|
|
1505
|
+
fi
|
|
1506
|
+
if [ -z "$changes_map" ] || [ "$changes_map" = "null" ]; then
|
|
1507
|
+
die "$COMATE_BLOCK" "BLOCK: changes_map is required before passing the gate"
|
|
1433
1508
|
fi
|
|
1434
1509
|
local report; report=$(yaml_get "$gate" review_report)
|
|
1435
1510
|
if [ -z "$report" ] || [ "$report" = "null" ] || ! file_nonempty "$report"; then
|
|
@@ -1703,7 +1778,7 @@ status() {
|
|
|
1703
1778
|
echo "No active changes."
|
|
1704
1779
|
return 0
|
|
1705
1780
|
fi
|
|
1706
|
-
local any=0 d name yaml phase workflow build_mode vr dd plan total done tasks_file
|
|
1781
|
+
local any=0 d name yaml phase phase_step workflow build_mode vr dd plan total done tasks_file
|
|
1707
1782
|
for d in "$changes_dir"/*/; do
|
|
1708
1783
|
[ -d "$d" ] || continue
|
|
1709
1784
|
name=$(basename "$d")
|
|
@@ -1713,6 +1788,7 @@ status() {
|
|
|
1713
1788
|
[ "$(yaml_get "$yaml" archived)" = "true" ] && continue
|
|
1714
1789
|
any=1
|
|
1715
1790
|
phase=$(yaml_get "$yaml" phase)
|
|
1791
|
+
phase_step=$(yaml_get "$yaml" phase_step)
|
|
1716
1792
|
workflow=$(yaml_get "$yaml" workflow)
|
|
1717
1793
|
build_mode=$(yaml_get "$yaml" build_mode)
|
|
1718
1794
|
vr=$(yaml_get "$yaml" verify_result)
|
|
@@ -1726,6 +1802,7 @@ status() {
|
|
|
1726
1802
|
fi
|
|
1727
1803
|
echo "• $name [phase: $phase, $done/$total tasks]"
|
|
1728
1804
|
echo " workflow: $workflow | build_mode: $build_mode"
|
|
1805
|
+
[ -n "$phase_step" ] && [ "$phase_step" != "null" ] && echo " step: $phase_step"
|
|
1729
1806
|
[ -n "$dd" ] && [ "$dd" != "null" ] && echo " design: $dd"
|
|
1730
1807
|
[ -n "$plan" ] && [ "$plan" != "null" ] && echo " plan: $plan"
|
|
1731
1808
|
[ "$phase" = "verify" ] && echo " verify_result: $vr"
|
|
@@ -1870,6 +1947,11 @@ case "$CMD" in
|
|
|
1870
1947
|
esac
|
|
1871
1948
|
fi
|
|
1872
1949
|
;;
|
|
1950
|
+
dependency)
|
|
1951
|
+
NAME="${1:-}"; SUB="${2:-}"
|
|
1952
|
+
[ -n "$NAME" ] && [ "$SUB" = "archived" ] || { usage_top; exit "$COMATE_USAGE"; }
|
|
1953
|
+
dependency_archived "$NAME"
|
|
1954
|
+
;;
|
|
1873
1955
|
gate)
|
|
1874
1956
|
PRD="${1:-}"; SUB="${2:-}"
|
|
1875
1957
|
[ -n "$PRD" ] && [ -n "$SUB" ] || { usage_top; exit "$COMATE_USAGE"; }
|
|
@@ -144,8 +144,10 @@ seed_open() {
|
|
|
144
144
|
|
|
145
145
|
@test "open-complete routes full to design" {
|
|
146
146
|
seed_open
|
|
147
|
+
comate state demo set phase_step open.review-confirmed >/dev/null
|
|
147
148
|
comate state demo transition open-complete
|
|
148
149
|
[ "$(comate state demo get phase)" = "design" ]
|
|
150
|
+
[ "$(comate state demo get phase_step)" = "null" ]
|
|
149
151
|
}
|
|
150
152
|
|
|
151
153
|
@test "open-complete routes fix to build" {
|
|
@@ -201,6 +203,56 @@ seed_open() {
|
|
|
201
203
|
[ "$status" -eq 1 ]
|
|
202
204
|
}
|
|
203
205
|
|
|
206
|
+
@test "fix-upgrade resets preset decisions and enters design" {
|
|
207
|
+
comate state demo init fix
|
|
208
|
+
comate state demo transition open-complete
|
|
209
|
+
comate state demo set phase_step build.options-confirmed >/dev/null
|
|
210
|
+
comate state demo transition fix-upgrade
|
|
211
|
+
[ "$(comate state demo get workflow)" = "full" ]
|
|
212
|
+
[ "$(comate state demo get phase)" = "design" ]
|
|
213
|
+
[ "$(comate state demo get build_mode)" = "null" ]
|
|
214
|
+
[ "$(comate state demo get tdd_mode)" = "null" ]
|
|
215
|
+
[ "$(comate state demo get isolation)" = "null" ]
|
|
216
|
+
[ "$(comate state demo get phase_step)" = "null" ]
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
@test "discarded branch cannot pass verification" {
|
|
220
|
+
comate state demo init full
|
|
221
|
+
comate state demo set phase verify >/dev/null
|
|
222
|
+
printf '# pass\n' > report.md
|
|
223
|
+
comate state demo set verification_report report.md >/dev/null
|
|
224
|
+
comate state demo set branch_status discarded >/dev/null
|
|
225
|
+
run comate state demo transition verify-pass
|
|
226
|
+
[ "$status" -eq 1 ]
|
|
227
|
+
[ "$(comate state demo get phase)" = "verify" ]
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
@test "verify-fail returns to build without a failure routing loop" {
|
|
231
|
+
comate state demo init full
|
|
232
|
+
comate state demo set phase verify >/dev/null
|
|
233
|
+
comate state demo set verify_result fail >/dev/null
|
|
234
|
+
comate state demo transition verify-fail
|
|
235
|
+
[ "$(comate state demo get phase)" = "build" ]
|
|
236
|
+
[ "$(comate state demo get verify_result)" = "pending" ]
|
|
237
|
+
[ "$(comate state demo get verification_report)" = "null" ]
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
@test "recover reports phase-local progress" {
|
|
241
|
+
comate state demo init full
|
|
242
|
+
comate state demo set phase_step open.review-awaiting >/dev/null
|
|
243
|
+
run comate state demo recover open
|
|
244
|
+
[ "$status" -eq 0 ]
|
|
245
|
+
[[ "$output" == *"Phase step: open.review-awaiting"* ]]
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
@test "status exposes awaiting decisions" {
|
|
249
|
+
comate state demo init full
|
|
250
|
+
comate state demo set phase_step open.review-awaiting >/dev/null
|
|
251
|
+
run comate status
|
|
252
|
+
[ "$status" -eq 0 ]
|
|
253
|
+
[[ "$output" == *"step: open.review-awaiting"* ]]
|
|
254
|
+
}
|
|
255
|
+
|
|
204
256
|
# --- guard open ---
|
|
205
257
|
|
|
206
258
|
@test "guard open passes with full artifacts and applies" {
|
|
@@ -436,6 +488,18 @@ SH
|
|
|
436
488
|
[ "$status" -eq 0 ]
|
|
437
489
|
}
|
|
438
490
|
|
|
491
|
+
@test "dependency archived requires an archived=true record" {
|
|
492
|
+
comate state dep init full
|
|
493
|
+
run comate dependency dep archived
|
|
494
|
+
[ "$status" -eq 1 ]
|
|
495
|
+
comate state dep set phase archive >/dev/null
|
|
496
|
+
comate state dep transition archived >/dev/null
|
|
497
|
+
mkdir -p openspec/changes/archive
|
|
498
|
+
mv openspec/changes/dep openspec/changes/archive/2026-08-20-dep
|
|
499
|
+
run comate dependency dep archived
|
|
500
|
+
[ "$status" -eq 0 ]
|
|
501
|
+
}
|
|
502
|
+
|
|
439
503
|
@test "top-level usage error returns code 2" {
|
|
440
504
|
run comate frobnicate
|
|
441
505
|
[ "$status" -eq 2 ]
|
|
@@ -503,16 +567,41 @@ seed_prd() {
|
|
|
503
567
|
comate gate "$prd" review >/dev/null
|
|
504
568
|
comate gate "$prd" set score 90 >/dev/null
|
|
505
569
|
comate gate "$prd" set blocking_open 0 >/dev/null
|
|
570
|
+
comate gate "$prd" set changes_map "demo:功能项1" >/dev/null
|
|
506
571
|
run comate gate "$prd" pass
|
|
507
572
|
[ "$status" -eq 1 ]
|
|
508
573
|
[[ "$output" == *"report"* ]]
|
|
509
574
|
}
|
|
510
575
|
|
|
576
|
+
@test "gate pass blocks without a confirmed changes map" {
|
|
577
|
+
local prd; prd=$(seed_prd)
|
|
578
|
+
comate gate "$prd" review >/dev/null
|
|
579
|
+
comate gate "$prd" set score 90 >/dev/null
|
|
580
|
+
comate gate "$prd" set blocking_open 0 >/dev/null
|
|
581
|
+
printf '# report\n' > "docs/knowledge-base/requirements/test/PRD-001-REVIEW.md"
|
|
582
|
+
run comate gate "$prd" pass
|
|
583
|
+
[ "$status" -eq 1 ]
|
|
584
|
+
[[ "$output" == *"changes_map"* ]]
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
@test "gate pass --tbd requires unresolved blockers" {
|
|
588
|
+
local prd; prd=$(seed_prd)
|
|
589
|
+
comate gate "$prd" review >/dev/null
|
|
590
|
+
comate gate "$prd" set score 90 >/dev/null
|
|
591
|
+
comate gate "$prd" set blocking_open 0 >/dev/null
|
|
592
|
+
comate gate "$prd" set changes_map "demo:功能项1" >/dev/null
|
|
593
|
+
printf '# report\n' > "docs/knowledge-base/requirements/test/PRD-001-REVIEW.md"
|
|
594
|
+
run comate gate "$prd" pass --tbd
|
|
595
|
+
[ "$status" -eq 1 ]
|
|
596
|
+
[[ "$output" == *"requires at least one"* ]]
|
|
597
|
+
}
|
|
598
|
+
|
|
511
599
|
@test "gate pass succeeds and check passes after report written" {
|
|
512
600
|
local prd; prd=$(seed_prd)
|
|
513
601
|
comate gate "$prd" review >/dev/null
|
|
514
602
|
comate gate "$prd" set score 90 >/dev/null
|
|
515
603
|
comate gate "$prd" set blocking_open 0 >/dev/null
|
|
604
|
+
comate gate "$prd" set changes_map "demo:功能项1" >/dev/null
|
|
516
605
|
printf '# 评审报告\n' > \
|
|
517
606
|
"docs/knowledge-base/requirements/test/PRD-001-REVIEW.md"
|
|
518
607
|
run comate gate "$prd" pass
|
|
@@ -525,7 +614,8 @@ seed_prd() {
|
|
|
525
614
|
local prd; prd=$(seed_prd)
|
|
526
615
|
comate gate "$prd" review >/dev/null
|
|
527
616
|
comate gate "$prd" set score 65 >/dev/null
|
|
528
|
-
comate gate "$prd" set blocking_open
|
|
617
|
+
comate gate "$prd" set blocking_open 2 >/dev/null
|
|
618
|
+
comate gate "$prd" set changes_map "demo:功能项1" >/dev/null
|
|
529
619
|
printf '# 评审报告\n' > \
|
|
530
620
|
"docs/knowledge-base/requirements/test/PRD-001-REVIEW.md"
|
|
531
621
|
run comate gate "$prd" pass --tbd
|
|
@@ -539,6 +629,7 @@ seed_prd() {
|
|
|
539
629
|
comate gate "$prd" review >/dev/null
|
|
540
630
|
comate gate "$prd" set score 90 >/dev/null
|
|
541
631
|
comate gate "$prd" set blocking_open 0 >/dev/null
|
|
632
|
+
comate gate "$prd" set changes_map "demo:功能项1" >/dev/null
|
|
542
633
|
printf '# 评审报告\n' > \
|
|
543
634
|
"docs/knowledge-base/requirements/test/PRD-001-REVIEW.md"
|
|
544
635
|
comate gate "$prd" pass >/dev/null
|
|
@@ -554,6 +645,7 @@ seed_prd() {
|
|
|
554
645
|
comate gate "$prd" review >/dev/null
|
|
555
646
|
comate gate "$prd" set score 90 >/dev/null
|
|
556
647
|
comate gate "$prd" set blocking_open 0 >/dev/null
|
|
648
|
+
comate gate "$prd" set changes_map "demo:功能项1" >/dev/null
|
|
557
649
|
printf '# 评审报告\n' > \
|
|
558
650
|
"docs/knowledge-base/requirements/test/PRD-001-REVIEW.md"
|
|
559
651
|
comate gate "$prd" pass >/dev/null
|
|
@@ -572,6 +664,7 @@ seed_prd() {
|
|
|
572
664
|
comate gate "$prd" review >/dev/null
|
|
573
665
|
comate gate "$prd" set score 90 >/dev/null
|
|
574
666
|
comate gate "$prd" set blocking_open 0 >/dev/null
|
|
667
|
+
comate gate "$prd" set changes_map "login-flow:功能项1" >/dev/null
|
|
575
668
|
printf '# 报告\n' > \
|
|
576
669
|
"docs/knowledge-base/requirements/test/PRD-001-REVIEW.md"
|
|
577
670
|
comate gate "$prd" pass >/dev/null
|
|
@@ -587,6 +680,7 @@ seed_prd() {
|
|
|
587
680
|
comate gate "$prd" review >/dev/null
|
|
588
681
|
comate gate "$prd" set score 90 >/dev/null
|
|
589
682
|
comate gate "$prd" set blocking_open 0 >/dev/null
|
|
683
|
+
comate gate "$prd" set changes_map "login-flow:功能项1;logout-flow:功能项2" >/dev/null
|
|
590
684
|
printf '# 报告\n' > \
|
|
591
685
|
"docs/knowledge-base/requirements/test/PRD-001-REVIEW.md"
|
|
592
686
|
comate gate "$prd" pass >/dev/null
|
|
@@ -616,6 +710,7 @@ seed_prd() {
|
|
|
616
710
|
comate gate "$prd" review >/dev/null
|
|
617
711
|
comate gate "$prd" set score 90 >/dev/null
|
|
618
712
|
comate gate "$prd" set blocking_open 0 >/dev/null
|
|
713
|
+
comate gate "$prd" set changes_map "demo:功能项1" >/dev/null
|
|
619
714
|
printf '# 报告\n' > \
|
|
620
715
|
"docs/knowledge-base/requirements/test/PRD-001-REVIEW.md"
|
|
621
716
|
comate gate "$prd" pass >/dev/null
|
|
@@ -1,63 +1,63 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: comate-archive
|
|
3
|
-
description: "comate 阶段 5:归档。用 /comate-archive 调用。委托 OpenSpec 合并 delta spec 并归档 change。"
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# comate 阶段 5:归档(Archive)
|
|
7
|
-
|
|
8
|
-
## 前置条件
|
|
9
|
-
|
|
10
|
-
- 验证已通过(阶段 4 完成),分支已处理
|
|
11
|
-
- `openspec/changes/<name>/.comate.yaml` 中 `verify_result: pass`
|
|
12
|
-
|
|
13
|
-
## 步骤
|
|
14
|
-
|
|
15
|
-
### 0. 入口状态验证
|
|
16
|
-
|
|
17
|
-
```bash
|
|
18
|
-
COMATE="${COMATE:-$(for r in . ./.agents/skills ./.claude/skills ./.cursor/skills ./.codex/skills "$HOME"/.agents/skills "$HOME"/.claude/skills "$HOME"/.config/skills "$HOME"/.cursor/skills "$HOME"/.codex/skills "$HOME"/.gemini/skills; do
|
|
19
|
-
[ -d "$r" ] && find "$r" -maxdepth 6 -path '*/comate/scripts/comate.sh' -type f -print -quit 2>/dev/null
|
|
20
|
-
done | head -1)}"
|
|
21
|
-
if [ -z "$COMATE" ]; then
|
|
22
|
-
echo "ERROR: comate.sh 未找到,请确认 comate skill 已安装。" >&2
|
|
23
|
-
return 1 2>/dev/null || exit 1
|
|
24
|
-
fi
|
|
25
|
-
bash "$COMATE" state <name> check archive
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
### 1. 执行归档
|
|
29
|
-
|
|
30
|
-
```bash
|
|
31
|
-
bash "$COMATE" archive "<name>"
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
脚本自动完成:
|
|
35
|
-
1. 入口状态验证(phase=archive, verify_result=pass, archived=false)
|
|
36
|
-
2. 委托 `openspec archive <name> -y` 合并 delta spec 到主 spec;无 delta spec 时使用 `--skip-specs`
|
|
37
|
-
3. Design doc 前置元数据标注(archived-with, status: final),并把正文中指向 `openspec/changes/<name>/` 的引用重写为归档路径
|
|
38
|
-
4. Plan 前置元数据标注(archived-with),同样重写正文 OpenSpec 路径引用
|
|
39
|
-
5. 由 OpenSpec 移动 change 到 `openspec/changes/archive/YYYY-MM-DD-<name>/`
|
|
40
|
-
6. 通过 `state transition <archive-name> archived` 设 `archived: true`
|
|
41
|
-
7. 重写归档后 `.comate.yaml` 中随 change 移动的自指字段(`source_manifest` / `handoff_context` / `impl_context`)指向新归档路径,使 `sources <name> check/list` 等命令对归档 change 仍可用
|
|
42
|
-
|
|
43
|
-
非零退出码 → 报告错误并停止。零退出码 → 归档完成。摘要 `X/Y steps succeeded` 以真实执行步骤计数。
|
|
44
|
-
|
|
45
|
-
需预览不实际执行:加 `--dry-run`。
|
|
46
|
-
|
|
47
|
-
### 2. 生命周期闭环
|
|
48
|
-
|
|
49
|
-
```
|
|
50
|
-
brainstorming → delta spec → 实施 → 验证 → OpenSpec 合并主 spec → design doc 标注 → 归档
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
## 退出条件
|
|
54
|
-
|
|
55
|
-
- 归档脚本退出码 0
|
|
56
|
-
- 归档目录 `openspec/changes/archive/YYYY-MM-DD-<name>/` 存在
|
|
57
|
-
- 归档后 `.comate.yaml` 中 `archived: true`
|
|
58
|
-
|
|
59
|
-
归档成功后**不要再对原 change 名跑 guard**,原活跃目录已不存在。
|
|
60
|
-
|
|
61
|
-
## 完成
|
|
62
|
-
|
|
63
|
-
comate 流程全部完成。如需开始新工作,调用 `/comate` 或 `/comate-open`。
|
|
1
|
+
---
|
|
2
|
+
name: comate-archive
|
|
3
|
+
description: "comate 阶段 5:归档。用 /comate-archive 调用。委托 OpenSpec 合并 delta spec 并归档 change。"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# comate 阶段 5:归档(Archive)
|
|
7
|
+
|
|
8
|
+
## 前置条件
|
|
9
|
+
|
|
10
|
+
- 验证已通过(阶段 4 完成),分支已处理
|
|
11
|
+
- `openspec/changes/<name>/.comate.yaml` 中 `verify_result: pass`
|
|
12
|
+
|
|
13
|
+
## 步骤
|
|
14
|
+
|
|
15
|
+
### 0. 入口状态验证
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
COMATE="${COMATE:-$(for r in . ./.agents/skills ./.claude/skills ./.cursor/skills ./.codex/skills "$HOME"/.agents/skills "$HOME"/.claude/skills "$HOME"/.config/skills "$HOME"/.cursor/skills "$HOME"/.codex/skills "$HOME"/.gemini/skills; do
|
|
19
|
+
[ -d "$r" ] && find "$r" -maxdepth 6 -path '*/comate/scripts/comate.sh' -type f -print -quit 2>/dev/null
|
|
20
|
+
done | head -1)}"
|
|
21
|
+
if [ -z "$COMATE" ]; then
|
|
22
|
+
echo "ERROR: comate.sh 未找到,请确认 comate skill 已安装。" >&2
|
|
23
|
+
return 1 2>/dev/null || exit 1
|
|
24
|
+
fi
|
|
25
|
+
bash "$COMATE" state <name> check archive
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
### 1. 执行归档
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
bash "$COMATE" archive "<name>"
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
脚本自动完成:
|
|
35
|
+
1. 入口状态验证(phase=archive, verify_result=pass, archived=false)
|
|
36
|
+
2. 委托 `openspec archive <name> -y` 合并 delta spec 到主 spec;无 delta spec 时使用 `--skip-specs`
|
|
37
|
+
3. Design doc 前置元数据标注(archived-with, status: final),并把正文中指向 `openspec/changes/<name>/` 的引用重写为归档路径
|
|
38
|
+
4. Plan 前置元数据标注(archived-with),同样重写正文 OpenSpec 路径引用
|
|
39
|
+
5. 由 OpenSpec 移动 change 到 `openspec/changes/archive/YYYY-MM-DD-<name>/`
|
|
40
|
+
6. 通过 `state transition <archive-name> archived` 设 `archived: true`
|
|
41
|
+
7. 重写归档后 `.comate.yaml` 中随 change 移动的自指字段(`source_manifest` / `handoff_context` / `impl_context`)指向新归档路径,使 `sources <name> check/list` 等命令对归档 change 仍可用
|
|
42
|
+
|
|
43
|
+
非零退出码 → 报告错误并停止。零退出码 → 归档完成。摘要 `X/Y steps succeeded` 以真实执行步骤计数。
|
|
44
|
+
|
|
45
|
+
需预览不实际执行:加 `--dry-run`。
|
|
46
|
+
|
|
47
|
+
### 2. 生命周期闭环
|
|
48
|
+
|
|
49
|
+
```
|
|
50
|
+
brainstorming → delta spec → 实施 → 验证 → OpenSpec 合并主 spec → design doc 标注 → 归档
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## 退出条件
|
|
54
|
+
|
|
55
|
+
- 归档脚本退出码 0
|
|
56
|
+
- 归档目录 `openspec/changes/archive/YYYY-MM-DD-<name>/` 存在
|
|
57
|
+
- 归档后 `.comate.yaml` 中 `archived: true`
|
|
58
|
+
|
|
59
|
+
归档成功后**不要再对原 change 名跑 guard**,原活跃目录已不存在。
|
|
60
|
+
|
|
61
|
+
## 完成
|
|
62
|
+
|
|
63
|
+
comate 流程全部完成。如需开始新工作,调用 `/comate` 或 `/comate-open`。
|