xwang 0.0.7 → 0.0.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.
|
@@ -13,6 +13,35 @@ red() { echo -e "\033[31m$1\033[0m" >&2; }
|
|
|
13
13
|
green() { echo -e "\033[32m$1\033[0m" >&2; }
|
|
14
14
|
warn() { echo -e "\033[33m$1\033[0m" >&2; }
|
|
15
15
|
|
|
16
|
+
# --- Project root resolution ---
|
|
17
|
+
|
|
18
|
+
find_project_root() {
|
|
19
|
+
if [ -n "${XWANG_PROJECT_ROOT:-}" ]; then
|
|
20
|
+
printf '%s' "$XWANG_PROJECT_ROOT"
|
|
21
|
+
return 0
|
|
22
|
+
fi
|
|
23
|
+
|
|
24
|
+
local git_root
|
|
25
|
+
git_root=$(git rev-parse --show-toplevel 2>/dev/null || true)
|
|
26
|
+
if [ -n "$git_root" ]; then
|
|
27
|
+
printf '%s' "$git_root"
|
|
28
|
+
return 0
|
|
29
|
+
fi
|
|
30
|
+
|
|
31
|
+
local dir="$PWD"
|
|
32
|
+
while [ "$dir" != "/" ]; do
|
|
33
|
+
if [ -d "$dir/openspec/changes" ]; then
|
|
34
|
+
printf '%s' "$dir"
|
|
35
|
+
return 0
|
|
36
|
+
fi
|
|
37
|
+
dir=$(dirname "$dir")
|
|
38
|
+
done
|
|
39
|
+
|
|
40
|
+
printf '%s' "$PWD"
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
PROJECT_ROOT=$(find_project_root)
|
|
44
|
+
|
|
16
45
|
# --- Input validation ---
|
|
17
46
|
|
|
18
47
|
validate_change_name() {
|
|
@@ -48,9 +77,16 @@ else
|
|
|
48
77
|
if [[ "${3:-}" == "--apply" ]]; then
|
|
49
78
|
APPLY=1
|
|
50
79
|
fi
|
|
51
|
-
CHANGE_DIR="openspec/changes/$CHANGE"
|
|
52
|
-
if [ "$PHASE" = "archive" ] && [ ! -d "$CHANGE_DIR" ]
|
|
53
|
-
|
|
80
|
+
CHANGE_DIR="$PROJECT_ROOT/openspec/changes/$CHANGE"
|
|
81
|
+
if [ "$PHASE" = "archive" ] && [ ! -d "$CHANGE_DIR" ]; then
|
|
82
|
+
if [ -d "$PROJECT_ROOT/openspec/changes/archive/$CHANGE" ]; then
|
|
83
|
+
CHANGE_DIR="$PROJECT_ROOT/openspec/changes/archive/$CHANGE"
|
|
84
|
+
elif [ -d "$PROJECT_ROOT/openspec/changes/archive" ]; then
|
|
85
|
+
archived=$(find "$PROJECT_ROOT/openspec/changes/archive" -maxdepth 1 -type d -name "*-$CHANGE" -print -quit 2>/dev/null || true)
|
|
86
|
+
if [ -n "$archived" ]; then
|
|
87
|
+
CHANGE_DIR="$archived"
|
|
88
|
+
fi
|
|
89
|
+
fi
|
|
54
90
|
fi
|
|
55
91
|
fi
|
|
56
92
|
|
|
@@ -306,7 +342,7 @@ branch_status_handled() {
|
|
|
306
342
|
design_doc_recorded() {
|
|
307
343
|
local design_doc
|
|
308
344
|
design_doc=$(yaml_field_value "design_doc" 2>/dev/null || true)
|
|
309
|
-
if [ -n "$design_doc" ] && [ "$design_doc" != "null" ] && [ -f "$design_doc" ]; then
|
|
345
|
+
if [ -n "$design_doc" ] && [ "$design_doc" != "null" ] && { [ -f "$PROJECT_ROOT/$design_doc" ] || [ -f "$design_doc" ]; }; then
|
|
310
346
|
return 0
|
|
311
347
|
fi
|
|
312
348
|
echo "design_doc must point to an existing PRD for full workflow before leaving design." >&2
|
|
@@ -410,6 +446,7 @@ guard_design() {
|
|
|
410
446
|
check "design.md exists and non-empty" file_nonempty "$CHANGE_DIR/design.md"
|
|
411
447
|
check "tasks.md exists and non-empty" file_nonempty "$CHANGE_DIR/tasks.md"
|
|
412
448
|
check "tasks.md has at least one task" tasks_has_any
|
|
449
|
+
check "OpenSpec artifacts language consistency" openspec_artifacts_language_consistent
|
|
413
450
|
|
|
414
451
|
if [ "$workflow" = "full" ]; then
|
|
415
452
|
check "design_doc is recorded for full workflow" design_doc_recorded
|
|
@@ -418,7 +455,10 @@ guard_design() {
|
|
|
418
455
|
local design_doc
|
|
419
456
|
design_doc=$(yaml_field_value "design_doc" 2>/dev/null || true)
|
|
420
457
|
if [ -n "$design_doc" ] && [ "$design_doc" != "null" ]; then
|
|
421
|
-
|
|
458
|
+
local doc_path="$design_doc"
|
|
459
|
+
[ -f "$PROJECT_ROOT/$design_doc" ] && doc_path="$PROJECT_ROOT/$design_doc"
|
|
460
|
+
check "PRD file ($design_doc) exists" file_nonempty "$doc_path"
|
|
461
|
+
check "PRD language consistency" design_doc_language_consistent
|
|
422
462
|
elif [ "$workflow" != "full" ]; then
|
|
423
463
|
warn " [WARN] No design_doc recorded in .xwang.yaml (optional for quick/tweak)"
|
|
424
464
|
fi
|
|
@@ -454,6 +494,13 @@ guard_archive() {
|
|
|
454
494
|
check "proposal.md exists" file_nonempty "$CHANGE_DIR/proposal.md"
|
|
455
495
|
check "design.md exists" file_nonempty "$CHANGE_DIR/design.md"
|
|
456
496
|
check "tasks.md all tasks checked" tasks_all_done
|
|
497
|
+
check "OpenSpec artifacts language consistency" openspec_artifacts_language_consistent
|
|
498
|
+
|
|
499
|
+
local design_doc
|
|
500
|
+
design_doc=$(yaml_field_value "design_doc" 2>/dev/null || true)
|
|
501
|
+
if [ -n "$design_doc" ] && [ "$design_doc" != "null" ]; then
|
|
502
|
+
check "PRD language consistency" design_doc_language_consistent
|
|
503
|
+
fi
|
|
457
504
|
}
|
|
458
505
|
|
|
459
506
|
locate_state_script() {
|
|
@@ -470,6 +517,66 @@ locate_state_script() {
|
|
|
470
517
|
return 1
|
|
471
518
|
}
|
|
472
519
|
|
|
520
|
+
locate_doc_lang_check() {
|
|
521
|
+
local check_sh="$SCRIPT_DIR/xwang-doc-lang-check.sh"
|
|
522
|
+
if [ -f "$check_sh" ]; then
|
|
523
|
+
echo "$check_sh"
|
|
524
|
+
return 0
|
|
525
|
+
fi
|
|
526
|
+
check_sh="$(find "$SCRIPT_DIR" "$SCRIPT_DIR/.." "$HOME" -path '*/xwang/scripts/xwang-doc-lang-check.sh' -type f -print -quit 2>/dev/null || true)"
|
|
527
|
+
if [ -n "$check_sh" ] && [ -f "$check_sh" ]; then
|
|
528
|
+
echo "$check_sh"
|
|
529
|
+
return 0
|
|
530
|
+
fi
|
|
531
|
+
return 1
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
design_doc_language_consistent() {
|
|
535
|
+
local design_doc
|
|
536
|
+
design_doc=$(yaml_field_value "design_doc" 2>/dev/null || true)
|
|
537
|
+
if [ -z "$design_doc" ] || [ "$design_doc" = "null" ]; then
|
|
538
|
+
return 0
|
|
539
|
+
fi
|
|
540
|
+
|
|
541
|
+
local target=""
|
|
542
|
+
if [ -f "$PROJECT_ROOT/$design_doc" ]; then
|
|
543
|
+
target="$PROJECT_ROOT/$design_doc"
|
|
544
|
+
elif [ -f "$design_doc" ]; then
|
|
545
|
+
target="$design_doc"
|
|
546
|
+
elif [ -f "$CHANGE_DIR/design.md" ]; then
|
|
547
|
+
# design_doc may be stale after archiving; fall back to design.md in the change dir
|
|
548
|
+
target="$CHANGE_DIR/design.md"
|
|
549
|
+
fi
|
|
550
|
+
|
|
551
|
+
if [ -z "$target" ]; then
|
|
552
|
+
echo "design_doc file not found: $design_doc" >&2
|
|
553
|
+
return 1
|
|
554
|
+
fi
|
|
555
|
+
|
|
556
|
+
local check_sh
|
|
557
|
+
if ! check_sh=$(locate_doc_lang_check); then
|
|
558
|
+
echo "xwang-doc-lang-check.sh not found; skipping language check" >&2
|
|
559
|
+
return 0
|
|
560
|
+
fi
|
|
561
|
+
"$XWANG_BASH" "$check_sh" "$target" >/dev/null 2>&1
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
openspec_artifacts_language_consistent() {
|
|
565
|
+
local check_sh
|
|
566
|
+
if ! check_sh=$(locate_doc_lang_check); then
|
|
567
|
+
echo "xwang-doc-lang-check.sh not found; skipping language check" >&2
|
|
568
|
+
return 0
|
|
569
|
+
fi
|
|
570
|
+
local files=()
|
|
571
|
+
for f in "$CHANGE_DIR/proposal.md" "$CHANGE_DIR/design.md" "$CHANGE_DIR/tasks.md"; do
|
|
572
|
+
[ -f "$f" ] && files+=("$f")
|
|
573
|
+
done
|
|
574
|
+
if [ ${#files[@]} -eq 0 ]; then
|
|
575
|
+
return 0
|
|
576
|
+
fi
|
|
577
|
+
"$XWANG_BASH" "$check_sh" "${files[@]}" >/dev/null 2>&1
|
|
578
|
+
}
|
|
579
|
+
|
|
473
580
|
apply_state_update() {
|
|
474
581
|
local state_sh
|
|
475
582
|
if ! state_sh=$(locate_state_script); then
|
|
@@ -77,6 +77,7 @@ fi
|
|
|
77
77
|
- [ ] 调用 `/openspec-archive-change <name>`(或等价的 OpenSpec archive 命令)按 delta 语义合并主 spec 并移动 change 到归档目录。
|
|
78
78
|
- [ ] 如归档命令返回非零退出码,报告错误并停止。
|
|
79
79
|
- [ ] 归档成功后,确认 change 目录已移动到 `openspec/changes/archive/YYYY-MM-DD-<name>/`(或 OpenSpec 默认归档路径)。
|
|
80
|
+
- [ ] **同步 `.xwang.yaml` 中的文件路径**:如果 `design_doc`、`plan`、`verification_report` 等字段指向的是 `openspec/changes/<name>/` 下的旧路径,更新为归档目录 `openspec/changes/archive/YYYY-MM-DD-<name>/` 下的相对路径,避免后续 guard 或读取时路径失效。
|
|
80
81
|
- [ ] 向用户汇报归档完成、新目录路径与生命周期闭环状态。
|
|
81
82
|
|
|
82
83
|
## 退出条件
|