openmoneta-dev-kit 2.0.1 → 2.1.0

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/VERSION CHANGED
@@ -1 +1 @@
1
- 2.0.1
1
+ 2.1.0
@@ -16,6 +16,10 @@ INPUT_JSON=$(cat 2>/dev/null || echo '{}')
16
16
  register_project_cursor() {
17
17
  local ws="$1"
18
18
  [[ -n "$ws" && -f "$ws/docs/INDEX.md" ]] || return 0
19
+ # Bỏ qua repo nguồn của chính kit (tránh update --all-projects đè docs bespoke).
20
+ if [[ -f "$ws/package.json" ]] && grep -q '"name": *"openmoneta-dev-kit"' "$ws/package.json" 2>/dev/null; then
21
+ return 0
22
+ fi
19
23
  [[ -f "$HOME/.cursor/.openmoneta-version" ]] || return 0
20
24
  local reg="$HOME/.cursor/.openmoneta-projects"
21
25
  local abs
@@ -454,6 +454,13 @@ function clearVerifyLoop(root: string) {
454
454
  function registerProjectOpenCode(root: string) {
455
455
  try {
456
456
  if (!fs.existsSync(path.join(root, "docs", "INDEX.md"))) return
457
+ // Bỏ qua repo nguồn của chính kit (tránh update --all-projects đè docs bespoke).
458
+ try {
459
+ const pkg = JSON.parse(fs.readFileSync(path.join(root, "package.json"), "utf8"))
460
+ if (pkg && pkg.name === "openmoneta-dev-kit") return
461
+ } catch {
462
+ // không có package.json hợp lệ → không phải repo nguồn, tiếp tục
463
+ }
457
464
  const home = process.env.HOME || process.env.USERPROFILE || ""
458
465
  const xdg = process.env.XDG_CONFIG_HOME || path.join(home, ".config")
459
466
  const ocHome = path.join(xdg, "opencode")
@@ -511,7 +518,7 @@ export const OpenMonetaGuard = async (ctx: GuardContext) => {
511
518
  {
512
519
  loaded_at: new Date().toISOString(),
513
520
  root,
514
- version: "2.0.0",
521
+ version: "2.0.2",
515
522
  load_count: globalState[globalKey],
516
523
  },
517
524
  null,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openmoneta-dev-kit",
3
- "version": "2.0.1",
3
+ "version": "2.1.0",
4
4
  "description": "OpenMoneta Dev Kit — Biến Cursor IDE / OpenCode thành team developer hoàn chỉnh với quy trình 6 bước, adaptive planning, hooks enforcement, và token-aware doc routing",
5
5
  "keywords": [
6
6
  "cursor",
@@ -9,8 +9,11 @@
9
9
  # bash docs-audit.sh --report # như trên
10
10
  # bash docs-audit.sh --worklist # TSV: <slug>\t<docsPath>\t<sourcePath>\t<missing|stale|ok>
11
11
  # bash docs-audit.sh --validate # liệt kê GHOST (doc trỏ source/module không tồn tại)
12
+ # bash docs-audit.sh --decisions # audit ADR (docs/decisions/): legacy / index-sync / supersede / module-link
13
+ # bash docs-audit.sh --decisions-worklist # TSV: <issue>\t<path> cho skill xử lý
12
14
  #
13
15
  # Stale detection: so commit mới nhất của source vs README (git); fallback mtime filesystem.
16
+ # ADR audit chỉ MECHANICAL (không bịa nội dung): phát hiện nợ ADR, không tự sửa.
14
17
 
15
18
  set -uo pipefail
16
19
 
@@ -18,8 +21,10 @@ MODE="report"
18
21
  case "${1:-}" in
19
22
  --worklist) MODE="worklist" ;;
20
23
  --validate) MODE="validate" ;;
24
+ --decisions) MODE="decisions" ;;
25
+ --decisions-worklist) MODE="decisions-worklist" ;;
21
26
  --report|"") MODE="report" ;;
22
- *) echo "[!] Mode không hợp lệ: $1 (dùng --report|--worklist|--validate)" >&2; exit 2 ;;
27
+ *) echo "[!] Mode không hợp lệ: $1 (dùng --report|--worklist|--validate|--decisions|--decisions-worklist)" >&2; exit 2 ;;
23
28
  esac
24
29
 
25
30
  GIT_OK=0
@@ -100,6 +105,125 @@ slug_to_source() {
100
105
  fi
101
106
  }
102
107
 
108
+ # ---------- MODE: decisions / decisions-worklist (ADR audit) ----------
109
+ if [[ "$MODE" == "decisions" || "$MODE" == "decisions-worklist" ]]; then
110
+ WL=0; [[ "$MODE" == "decisions-worklist" ]] && WL=1
111
+ DDIR="docs/decisions"
112
+
113
+ emit() { # <issue> <path-or-msg>
114
+ if [[ "$WL" -eq 1 ]]; then printf '%s\t%s\n' "$1" "$2"; else printf ' %-16s %s\n' "$1" "$2"; fi
115
+ }
116
+
117
+ # ADR đúng format = NNNN-slug.md (NNNN sequential). Loại trừ file date YYYY-MM-DD-slug.md (legacy).
118
+ is_adr_file() {
119
+ local b="$1"
120
+ [[ "$b" =~ ^[0-9][0-9][0-9][0-9]-.*\.md$ ]] || return 1
121
+ [[ "$b" =~ ^[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]- ]] && return 1
122
+ return 0
123
+ }
124
+ adr_files() { # in ra path các ADR đúng format
125
+ local f b
126
+ for f in "$DDIR"/[0-9][0-9][0-9][0-9]-*.md; do
127
+ [[ -f "$f" ]] || continue
128
+ b=$(basename "$f")
129
+ is_adr_file "$b" && echo "$f"
130
+ done
131
+ }
132
+
133
+ if [[ ! -d "$DDIR" ]]; then
134
+ [[ "$WL" -eq 0 ]] && echo " Project chưa có layer Decision Memory (docs/decisions/). Bỏ qua ADR audit."
135
+ exit 0
136
+ fi
137
+
138
+ n_legacy=0; n_orphan=0; n_ghost=0; n_supersede=0; n_modlink=0
139
+
140
+ # (1) Legacy: file trong docs/decisions/ không theo NNNN-slug.md (ngoài INDEX.md)
141
+ for f in "$DDIR"/*; do
142
+ [[ -f "$f" ]] || continue
143
+ b=$(basename "$f")
144
+ [[ "$b" == "INDEX.md" ]] && continue
145
+ if ! is_adr_file "$b"; then
146
+ emit "LEGACY" "$f"
147
+ n_legacy=$((n_legacy+1))
148
+ fi
149
+ done
150
+
151
+ # (2a) ADR file đúng format nhưng KHÔNG có trong bảng INDEX
152
+ while IFS= read -r f; do
153
+ [[ -z "$f" ]] && continue
154
+ b=$(basename "$f")
155
+ if [[ -f "$DDIR/INDEX.md" ]] && grep -qF "$b" "$DDIR/INDEX.md" 2>/dev/null; then :; else
156
+ emit "NOT-IN-INDEX" "$f"
157
+ n_orphan=$((n_orphan+1))
158
+ fi
159
+ done < <(adr_files)
160
+
161
+ # (2b) INDEX trỏ ADR file đã mất
162
+ if [[ -f "$DDIR/INDEX.md" ]]; then
163
+ while IFS= read -r ref; do
164
+ [[ -z "$ref" ]] && continue
165
+ [[ -f "$DDIR/$ref" ]] || { emit "INDEX-GHOST" "$DDIR/INDEX.md → $ref"; n_ghost=$((n_ghost+1)); }
166
+ done < <(grep -oE '[0-9]{4}-[A-Za-z0-9._-]+\.md' "$DDIR/INDEX.md" 2>/dev/null | sort -u)
167
+ fi
168
+
169
+ # (3) Supersede integrity
170
+ while IFS= read -r f; do
171
+ [[ -z "$f" ]] && continue
172
+ sup=$(grep -oE '^\*\*Supersedes\*\*:[[:space:]]*ADR-[0-9]{4}' "$f" 2>/dev/null | grep -oE '[0-9]{4}' | head -1)
173
+ [[ -z "$sup" ]] && continue
174
+ target=$(ls "$DDIR/${sup}-"*.md 2>/dev/null | head -1)
175
+ if [[ -z "$target" ]]; then
176
+ emit "SUPERSEDE-MISS" "$(basename "$f") → ADR-$sup không tồn tại"
177
+ n_supersede=$((n_supersede+1))
178
+ elif ! grep -qE '^\*\*Status\*\*:.*Superseded by' "$target" 2>/dev/null; then
179
+ emit "SUPERSEDE-OPEN" "$(basename "$target") chưa đổi Status sang 'Superseded by' (bị $(basename "$f") thay)"
180
+ n_supersede=$((n_supersede+1))
181
+ fi
182
+ done < <(adr_files)
183
+
184
+ # (4) Module link (advisory): ADR khai Module(s) có docs/modules/<slug>/README.md nhưng chưa link ADR
185
+ while IFS= read -r f; do
186
+ [[ -z "$f" ]] && continue
187
+ b=$(basename "$f")
188
+ mods=$(grep -oE '^\*\*Module\(s\)\*\*:.*' "$f" 2>/dev/null | sed -E 's/^\*\*Module\(s\)\*\*:[[:space:]]*//')
189
+ [[ -z "$mods" ]] && continue
190
+ IFS=',' read -ra arr <<< "$mods"
191
+ for m in "${arr[@]}"; do
192
+ slug=$(echo "$m" | sed -E 's/^[[:space:]]+//; s/[[:space:]]+$//')
193
+ [[ -z "$slug" || "$slug" == "—" ]] && continue
194
+ readme="docs/modules/$slug/README.md"
195
+ [[ -f "$readme" ]] || continue
196
+ if ! grep -qF "$b" "$readme" 2>/dev/null; then
197
+ emit "MODLINK" "$readme chưa link $b (Module(s) của ADR)"
198
+ n_modlink=$((n_modlink+1))
199
+ fi
200
+ done
201
+ done < <(adr_files)
202
+
203
+ if [[ "$WL" -eq 1 ]]; then exit 0; fi
204
+
205
+ total=$((n_legacy+n_orphan+n_ghost+n_supersede))
206
+ echo ""
207
+ echo " ADR audit — $(pwd)/$DDIR"
208
+ echo " ──────────────────────────────────────────────────────────────"
209
+ if [[ "$total" -eq 0 && "$n_modlink" -eq 0 ]]; then
210
+ echo " ✓ Sạch: ADR đăng ký đầy đủ trong INDEX, không legacy/ghost, supersede toàn vẹn."
211
+ else
212
+ echo " Tổng: $total vấn đề cần xử lý"
213
+ echo " · $n_legacy legacy (file không theo NNNN-slug.md, chưa đăng ký)"
214
+ echo " · $n_orphan ADR chưa có trong INDEX"
215
+ echo " · $n_ghost INDEX trỏ ADR đã mất"
216
+ echo " · $n_supersede supersede không toàn vẹn"
217
+ [[ "$n_modlink" -gt 0 ]] && echo " · $n_modlink module README chưa link ADR (advisory)"
218
+ echo ""
219
+ echo " → Để MIGRATE legacy (reformat file có sẵn nội dung) + đăng ký INDEX:"
220
+ echo " mở Cursor/OpenCode và yêu cầu chạy skill 'docs-maintenance' (phạm vi ADR)."
221
+ echo " → ADR còn THIẾU cho quyết định CHƯA ghi: dùng skill 'decision-recorder' (cần ngữ cảnh thật, KHÔNG bịa từ code)."
222
+ fi
223
+ echo ""
224
+ exit 0
225
+ fi
226
+
103
227
  MODULES=$(collect_modules | sort -u)
104
228
 
105
229
  # ---------- MODE: validate (ghost) ----------
@@ -1,22 +1,33 @@
1
1
  ---
2
2
  name: docs-maintenance
3
- description: "ON-DEMAND ONLY: dùng khi user yêu cầu tạo docs còn thiếu / backfill module README / refresh docs lỗi thời / audit docs / bảo trì docs dự án cũ. KHÔNG tự trigger trong quy trình bình thường."
3
+ description: "ON-DEMAND ONLY: dùng khi user yêu cầu tạo docs còn thiếu / backfill module README / refresh docs lỗi thời / audit docs / bảo trì docs dự án / audit & migrate ADR legacy. KHÔNG tự trigger trong quy trình bình thường."
4
4
  ---
5
5
 
6
6
  # Docs Maintenance
7
7
 
8
- Quét cả repo một lượt để **backfill module README còn thiếu** và **refresh README đã lỗi thời** so với code, rồi **đồng bộ `docs/INDEX.md`** (Modules hiện có + Token Routing).
8
+ Quét cả repo một lượt để **backfill module README còn thiếu** và **refresh README đã lỗi thời** so với code, rồi **đồng bộ `docs/INDEX.md`** (Modules hiện có + Token Routing). Ngoài ra **audit + migrate ADR legacy** trong `docs/decisions/` (phần mechanical, KHÔNG bịa rationale).
9
9
 
10
10
  Dùng khi onboard/bảo trì **dự án cũ** đã tích lũy nợ doc (code đụng nhiều nhưng README không được cập nhật), hoặc khi user yêu cầu rõ. Đây là phiên bản "chạy hàng loạt cho cả repo" của skill `module-architect` (vốn chạy từng module/session).
11
11
 
12
+ ## Hai phạm vi tách bạch
13
+
14
+ | Phạm vi | Nguồn chân lý | Skill này làm | KHÔNG làm |
15
+ |---|---|---|---|
16
+ | **Module README** (WHAT) | Source code (verify bằng grep) | Backfill MISSING + refresh STALE + sync INDEX | — |
17
+ | **ADR** (WHY/WHY-NOT) | Phán đoán kiến trúc của con người | Audit mechanical (legacy/index-sync/supersede/module-link) + **migrate file legacy ĐÃ CÓ nội dung** | **KHÔNG bịa rationale ADR từ code**; tạo ADR cho quyết định CHƯA ghi → `decision-recorder` |
18
+
12
19
  ## Iron Law
13
20
 
14
21
  ```
15
- CHỈ VIẾT NHỮNG GÌ VERIFY ĐƯỢC TRONG CODE. KHÔNG BỊA API / PATH / DEPENDENCY.
22
+ CHỈ VIẾT NHỮNG GÌ VERIFY ĐƯỢC TRONG NGUỒN. KHÔNG BỊA.
23
+ - Module README: mỗi dòng truy về symbol/import có thật trong source.
24
+ - ADR: mỗi rationale truy về nội dung file legacy ĐÃ CÓ. KHÔNG suy diễn WHY/root-cause từ code hiện tại.
16
25
  ```
17
26
 
18
27
  Stale docs còn tệ hơn không có docs — session sau AI đọc sai, làm sai. Mỗi dòng trong README phải truy về một symbol/import có thật trong source. Không chắc → mô tả mức ý định cao, KHÔNG bịa signature.
19
28
 
29
+ **ADR bịa còn nguy hiểm hơn**: ADR giả tạo ra "trí nhớ quyết định" sai → session sau tin theo và đảo kiến trúc sai hướng — phá đúng cái Decision Memory muốn chống. KHÔNG bao giờ chế WHY/rejected-alternatives/root-cause từ code. File legacy không đủ rationale → BÁO user, KHÔNG tự điền.
30
+
20
31
  ## Ranh giới (Lean — KHÔNG làm gì)
21
32
 
22
33
  - **KHÔNG** sinh bộ doc tổng quan kiểu khác (`system-architecture.md`, `project-roadmap.md`, `codebase-summary.md`...). Mô hình OM là **per-module README 3 sections + `docs/INDEX.md`**, đủ để navigate token-aware.
@@ -81,6 +92,48 @@ Cho mỗi module status `stale`:
81
92
 
82
93
  In tóm tắt: `created / updated / skipped` + cảnh báo (module không verify được, ghost). Gợi ý chạy lại `openmoneta docs --validate` để xác nhận sạch.
83
94
 
95
+ ## ADR audit + migrate legacy (docs/decisions/)
96
+
97
+ Chạy khi user yêu cầu "audit ADR", "bảo trì decisions", "migrate quyết định cũ", hoặc khi onboard dự án có `docs/decisions/` lộn xộn. Bỏ qua nếu project chưa có `docs/decisions/`.
98
+
99
+ ### 1. Audit (deterministic)
100
+
101
+ ```bash
102
+ bash ~/.cursor/scripts/docs-audit.sh --decisions # report 4 loại vấn đề
103
+ bash ~/.cursor/scripts/docs-audit.sh --decisions-worklist # TSV: <issue>\t<path>
104
+ ```
105
+
106
+ (OpenCode: `~/.config/opencode/scripts/docs-audit.sh`.) 4 loại issue:
107
+
108
+ - **LEGACY**: file trong `docs/decisions/` không theo `NNNN-slug.md` (vd `YYYY-MM-DD-*.md`) → ứng viên migrate.
109
+ - **NOT-IN-INDEX**: ADR đúng format nhưng thiếu dòng trong `INDEX.md`.
110
+ - **INDEX-GHOST**: `INDEX.md` trỏ ADR file đã mất.
111
+ - **SUPERSEDE-MISS / SUPERSEDE-OPEN**: `Supersedes: ADR-XXXX` trỏ ADR không tồn tại, hoặc ADR cũ chưa đổi Status sang `Superseded by`.
112
+ - **MODLINK** (advisory): module README chưa link ADR khai trong `Module(s)`.
113
+
114
+ ### 2. Migrate LEGACY → ADR chuẩn (CHỈ reformat, KHÔNG bịa)
115
+
116
+ Cho mỗi file LEGACY:
117
+
118
+ 1. **Đọc file legacy** — nó ĐÃ CÓ rationale thật. KHÔNG suy diễn từ code.
119
+ 2. Xác định `NNNN` mới = max ADR hiện có trong INDEX + 1 (4 chữ số).
120
+ 3. Tạo `docs/decisions/NNNN-<slug>.md` theo `~/.cursor/templates/adr.md.tpl`, **map nội dung có sẵn** vào 5 section (Context/Decision/Rejected alternatives/Consequences/Failed approaches log). Phần nào file cũ KHÔNG có → để trống + ghi `(legacy: không ghi rõ)`, KHÔNG chế ra.
121
+ 4. Field: `Status` (giữ theo file cũ nếu có, mặc định `Accepted (LOCKED)`), `Date` (lấy từ tên file/nội dung cũ), `Module(s)` (nếu suy được từ nội dung), `Plan nguồn: —`.
122
+ 5. Xóa file legacy cũ (đã chuyển nội dung) — hoặc nếu format cũ là chuẩn nội bộ của dự án, hỏi user trước khi xóa.
123
+ 6. Thêm dòng vào bảng `INDEX.md`.
124
+
125
+ ### 3. Sửa NOT-IN-INDEX / INDEX-GHOST / SUPERSEDE / MODLINK
126
+
127
+ - **NOT-IN-INDEX**: đọc ADR → thêm dòng vào bảng INDEX (id, tiêu đề, status, module, date).
128
+ - **INDEX-GHOST**: dòng INDEX trỏ file mất → hỏi user (xóa dòng hay khôi phục file). KHÔNG tự xóa.
129
+ - **SUPERSEDE-OPEN**: đổi ADR cũ sang `Status: Superseded by ADR-NNNN` (mechanical, an toàn).
130
+ - **SUPERSEDE-MISS**: target không tồn tại → BÁO user (có thể typo hoặc file mất), KHÔNG đoán.
131
+ - **MODLINK**: thêm link ADR vào section "## Quyết định kiến trúc (ADR)" của module README.
132
+
133
+ ### 4. Báo nếu thiếu rationale
134
+
135
+ File legacy chỉ có tiêu đề/1 dòng, không đủ WHY → migrate phần có được, **liệt kê rõ cho user** ADR nào cần bổ sung rationale qua `decision-recorder`. KHÔNG tự bịa cho đủ section.
136
+
84
137
  ## Bảng Rationalization (cái cớ → sự thật)
85
138
 
86
139
  | Cái cớ | Sự thật |
@@ -90,6 +143,8 @@ In tóm tắt: `created / updated / skipped` + cảnh báo (module không verify
90
143
  | "Viết lại cả README cho gọn" | Phá nội dung đang đúng + tốn token. Chỉ sửa phần lệch. |
91
144
  | "Thêm doc tổng quan cho đầy đủ" | Trái Lean. OM chỉ module README + INDEX. |
92
145
  | "Module mới khỏi thêm Token Routing" | Không có keyword → AI không tìm thấy module → đọc loạn. Bắt buộc thêm. |
146
+ | "File legacy thiếu WHY, mình suy từ code cho đủ ADR" | Bịa rationale = trí nhớ quyết định giả = tệ hơn không có. Để trống + báo user. |
147
+ | "Tạo luôn ADR cho quyết định chưa ai ghi" | Sai skill. Đó là việc của `decision-recorder` (cần ngữ cảnh thật). |
93
148
 
94
149
  ## Red Flags — DỪNG
95
150
 
@@ -98,9 +153,14 @@ In tóm tắt: `created / updated / skipped` + cảnh báo (module không verify
98
153
  - Đang định sinh `system-architecture.md` / `codebase-summary.md`.
99
154
  - Đang định xóa GHOST mà chưa hỏi user.
100
155
  - Tạo module mới trong INDEX nhưng quên Token Routing keyword.
156
+ - Đang điền section Rejected-alternatives/root-cause của ADR mà chưa thấy nó trong file legacy.
157
+ - Đang tạo ADR mới cho quyết định chưa từng được ghi (→ việc của `decision-recorder`).
158
+ - Đang xóa file legacy/INDEX-GHOST mà chưa hỏi user.
101
159
 
102
160
  ## Examples
103
161
 
104
162
  - User: "Dự án này nhiều module thiếu docs, tạo giúp" → `init`: chạy worklist → tạo mọi MISSING + refresh STALE → sync INDEX → report.
105
163
  - User: "Doc còn khớp code không?" → `audit`: chỉ report.
106
164
  - User: "Cập nhật doc 3 module vừa refactor" → `sync` (giới hạn các slug đó).
165
+ - User: "Audit ADR / decisions lộn xộn" → `docs-audit.sh --decisions` → report 4 loại issue.
166
+ - User: "Migrate mấy file quyết định cũ vào ADR chuẩn" → đọc từng file legacy → reformat sang `NNNN-slug.md` + đăng ký INDEX (không bịa phần thiếu, báo user).
package/src/cli.js CHANGED
@@ -56,6 +56,7 @@ Biến Cursor IDE / OpenCode thành team developer hoàn chỉnh.
56
56
 
57
57
  openmoneta docs Audit module README (thiếu/lỗi thời) + sync INDEX
58
58
  openmoneta docs --validate Phát hiện doc trỏ module/source không tồn tại (ghost)
59
+ openmoneta docs --decisions Audit ADR (docs/decisions/): legacy/index-sync/supersede/module-link
59
60
 
60
61
  openmoneta uninstall Gỡ cài đặt
61
62
 
@@ -6,6 +6,8 @@ const { getPkgRoot, isWindows } = require("../lib/paths")
6
6
  async function run(args) {
7
7
  const validate = args.includes("--validate")
8
8
  const worklist = args.includes("--worklist")
9
+ const decisions = args.includes("--decisions")
10
+ const decisionsWorklist = args.includes("--decisions-worklist")
9
11
 
10
12
  const pkgRoot = getPkgRoot()
11
13
  const script = path.join(pkgRoot, "scripts", "docs-audit.sh")
@@ -17,7 +19,9 @@ async function run(args) {
17
19
  }
18
20
 
19
21
  let mode = "--report"
20
- if (validate) mode = "--validate"
22
+ if (decisionsWorklist) mode = "--decisions-worklist"
23
+ else if (decisions) mode = "--decisions"
24
+ else if (validate) mode = "--validate"
21
25
  else if (worklist) mode = "--worklist"
22
26
 
23
27
  try {
@@ -13,6 +13,18 @@ function isOpenmonetaProject(dir) {
13
13
  }
14
14
  }
15
15
 
16
+ // Repo nguồn của chính kit (package.json name == openmoneta-dev-kit). Consumer
17
+ // project không có chữ ký này. Dùng để KHÔNG re-render init lên repo nguồn,
18
+ // tránh đè docs bespoke của kit (docs/INDEX.md, plans/INDEX.md, decisions/).
19
+ function isKitRepo(dir) {
20
+ try {
21
+ const pkg = JSON.parse(fs.readFileSync(path.join(dir, "package.json"), "utf8"))
22
+ return pkg && pkg.name === "openmoneta-dev-kit"
23
+ } catch {
24
+ return false
25
+ }
26
+ }
27
+
16
28
  function readRegistry() {
17
29
  const seen = new Set()
18
30
  for (const target of ["cursor", "opencode"]) {
@@ -49,7 +61,7 @@ function pruneRegistry() {
49
61
  for (const line of content.split("\n")) {
50
62
  const p = line.trim()
51
63
  if (!p) continue
52
- if (isOpenmonetaProject(p)) kept.push(p)
64
+ if (isOpenmonetaProject(p) && !isKitRepo(p)) kept.push(p)
53
65
  else pruned++
54
66
  }
55
67
  fs.writeFileSync(reg, kept.length ? kept.join("\n") + "\n" : "")
@@ -254,8 +266,8 @@ async function run(args) {
254
266
  const pruned = pruneRegistry()
255
267
  if (pruned > 0) console.log(`\n ℹ Registry: prune ${pruned} entry chết.`)
256
268
 
257
- const projects = readRegistry()
258
- if (isOpenmonetaProject(cwd) && !projects.includes(fs.realpathSync(cwd))) {
269
+ const projects = readRegistry().filter((p) => !isKitRepo(p))
270
+ if (isOpenmonetaProject(cwd) && !isKitRepo(cwd) && !projects.includes(fs.realpathSync(cwd))) {
259
271
  projects.push(fs.realpathSync(cwd))
260
272
  }
261
273
 
@@ -280,9 +292,13 @@ async function run(args) {
280
292
  } else {
281
293
  try {
282
294
  fs.accessSync(path.join(cwd, "docs", "INDEX.md"))
283
- console.log(`\n ▶ Syncing project: ${path.basename(cwd)}`)
284
- syncProject(initScript, cwd)
285
- console.log(`\n ✅ Project synced.`)
295
+ if (isKitRepo(cwd)) {
296
+ console.log(`\n ℹ Bỏ qua sync: đây là repo nguồn OpenMoneta Dev Kit (không re-render lên chính nó).`)
297
+ } else {
298
+ console.log(`\n ▶ Syncing project: ${path.basename(cwd)}`)
299
+ syncProject(initScript, cwd)
300
+ console.log(`\n ✅ Project synced.`)
301
+ }
286
302
  } catch (err) {
287
303
  if (isWindows()) {
288
304
  console.log(`\n ⚠ Không thể sync project (cần Git Bash). Cài tại: https://git-scm.com/download/win`)
@@ -294,7 +310,7 @@ async function run(args) {
294
310
  }
295
311
 
296
312
  const others = readRegistry().filter(
297
- (p) => isOpenmonetaProject(p) && !(isOpenmonetaProject(cwd) && p === fs.realpathSync(cwd))
313
+ (p) => isOpenmonetaProject(p) && !isKitRepo(p) && !(isOpenmonetaProject(cwd) && p === fs.realpathSync(cwd))
298
314
  )
299
315
  if (others.length > 0) {
300
316
  console.log(`\n ℹ Có ${others.length} project khác trong registry chưa sync. Sync tất cả:`)
@@ -308,5 +324,5 @@ async function run(args) {
308
324
 
309
325
  module.exports = {
310
326
  run,
311
- _internal: { isOpenmonetaProject, readRegistry, pruneRegistry, findProjects, scanSeed },
327
+ _internal: { isOpenmonetaProject, isKitRepo, readRegistry, pruneRegistry, findProjects, scanSeed },
312
328
  }