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" ] && [ -d "openspec/changes/archive/$CHANGE" ]; then
53
- CHANGE_DIR="openspec/changes/archive/$CHANGE"
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
- check "PRD file ($design_doc) exists" file_nonempty "$design_doc"
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
  ## 退出条件
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "xwang",
3
- "version": "0.0.7",
3
+ "version": "0.0.8",
4
4
  "description": "xwang CLI",
5
5
  "keywords": [
6
6
  "xwang",