openmoneta-dev-kit 2.2.1 → 2.3.1

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.
@@ -25,9 +25,11 @@ function isKitRepo(dir) {
25
25
  }
26
26
  }
27
27
 
28
+ const ALL_TARGETS = ["cursor", "opencode", "claude"]
29
+
28
30
  function readRegistry() {
29
31
  const seen = new Set()
30
- for (const target of ["cursor", "opencode"]) {
32
+ for (const target of ALL_TARGETS) {
31
33
  let content
32
34
  try {
33
35
  content = fs.readFileSync(getProjectRegistry(target), "utf8")
@@ -49,7 +51,7 @@ function readRegistry() {
49
51
 
50
52
  function pruneRegistry() {
51
53
  let pruned = 0
52
- for (const target of ["cursor", "opencode"]) {
54
+ for (const target of ALL_TARGETS) {
53
55
  const reg = getProjectRegistry(target)
54
56
  let content
55
57
  try {
@@ -119,7 +121,7 @@ function scanSeed(root, pkgRoot) {
119
121
  console.log(` [!] Scan root không tồn tại: ${root}`)
120
122
  return
121
123
  }
122
- const targets = ["cursor", "opencode"].filter((t) => isInstalled(t))
124
+ const targets = ALL_TARGETS.filter((t) => isInstalled(t))
123
125
  if (targets.length === 0) {
124
126
  console.log(` [!] Chưa có install home nào để seed registry.`)
125
127
  return
@@ -196,6 +198,10 @@ async function run(args) {
196
198
  console.log(`\n OpenMoneta Dev Kit`)
197
199
  console.log(` Local : v${local || "unknown"}`)
198
200
  console.log(` Latest: v${latest || "không xác định"}`)
201
+ for (const t of ALL_TARGETS) {
202
+ const v = installedVersion(t)
203
+ console.log(` ${t.padEnd(8)}: ${v ? `v${v}` : "chưa cài"}`)
204
+ }
199
205
  if (latest && local && local !== latest) {
200
206
  console.log(`\n 🔔 Cập nhật có sẵn: v${local} → v${latest}`)
201
207
  console.log(` Chạy: openmoneta update`)
@@ -205,7 +211,7 @@ async function run(args) {
205
211
  return
206
212
  }
207
213
 
208
- if (!isInstalled("cursor") && !isInstalled("opencode")) {
214
+ if (!ALL_TARGETS.some((t) => isInstalled(t))) {
209
215
  console.log(`\n ❌ Chưa cài OpenMoneta. Chạy: openmoneta install`)
210
216
  process.exit(1)
211
217
  }
@@ -214,7 +220,7 @@ async function run(args) {
214
220
  // Phải so version ĐÃ CÀI (installedVersion) với version sẽ cài (local) — KHÔNG chỉ
215
221
  // so source-vs-npm — nếu không, khi source==npm mà global cũ hơn sẽ skip nhầm.
216
222
  if (autoYes && !force && !allProjects && !scan) {
217
- const targets = ["cursor", "opencode"].filter((t) => isInstalled(t))
223
+ const targets = ALL_TARGETS.filter((t) => isInstalled(t))
218
224
  const globalsCurrent = targets.length > 0 && targets.every((t) => installedVersion(t) === local)
219
225
  if (local && latest && local === latest && globalsCurrent) {
220
226
  console.log(`\n ✅ Already at latest version (v${local}) + global đã đồng bộ, skipping. Dùng --force để cài lại.`)
@@ -258,6 +264,16 @@ async function run(args) {
258
264
  }
259
265
  }
260
266
 
267
+ if (isInstalled("claude")) {
268
+ console.log(`\n ▶ Claude Code global...`)
269
+ try {
270
+ // Windows defer cho Claude Code (chưa có .ps1) — chạy bash trực tiếp.
271
+ execSync(`bash "${path.join(pkgRoot, "install-claude-code.sh")}" --yes`, { stdio: "inherit", cwd: pkgRoot })
272
+ } catch {
273
+ console.error(` ⚠ Claude Code update failed`)
274
+ }
275
+ }
276
+
261
277
  console.log(`\n ✅ Global update done.`)
262
278
 
263
279
  if (!skipProjects) {
@@ -326,7 +342,7 @@ async function run(args) {
326
342
  }
327
343
  }
328
344
 
329
- console.log(`\n 🎉 Hoàn tất. Restart Cursor/OpenCode để áp dụng.`)
345
+ console.log(`\n 🎉 Hoàn tất. Restart Cursor/OpenCode/Claude Code để áp dụng.`)
330
346
  }
331
347
 
332
348
  module.exports = {
package/src/lib/paths.js CHANGED
@@ -12,15 +12,18 @@ const XDG_CONFIG = process.env.XDG_CONFIG_HOME || path.join(HOME, ".config")
12
12
 
13
13
  const CURSOR_DIR = path.join(HOME, ".cursor")
14
14
  const OPENCODE_DIR = path.join(XDG_CONFIG, "opencode")
15
+ const CLAUDE_DIR = path.join(HOME, ".claude")
15
16
  const REPO_DIR = path.join(HOME, "OpenMoneta-Dev-Kit") // legacy
16
17
 
17
18
  function versionFilePath(target) {
18
19
  if (target === "opencode") return path.join(OPENCODE_DIR, ".openmoneta-version")
20
+ if (target === "claude") return path.join(CLAUDE_DIR, ".openmoneta-version")
19
21
  return path.join(CURSOR_DIR, ".openmoneta-version")
20
22
  }
21
23
 
22
24
  function getProjectRegistry(target) {
23
25
  if (target === "opencode") return path.join(OPENCODE_DIR, ".openmoneta-projects")
26
+ if (target === "claude") return path.join(CLAUDE_DIR, ".openmoneta-projects")
24
27
  return path.join(CURSOR_DIR, ".openmoneta-projects")
25
28
  }
26
29
 
@@ -55,6 +58,7 @@ module.exports = {
55
58
  HOME,
56
59
  CURSOR_DIR,
57
60
  OPENCODE_DIR,
61
+ CLAUDE_DIR,
58
62
  REPO_DIR,
59
63
  versionFilePath,
60
64
  getProjectRegistry,
@@ -1,6 +1,6 @@
1
1
  # AGENTS.md — Quy trình chuẩn (OpenMoneta Dev Kit v{{VERSION}})
2
2
 
3
- > File này được tạo từ `~/.cursor/templates/AGENTS.md.tpl`. Chạy `bash ~/.cursor/scripts/init-project.sh .` để re-sync (idempotent, giữ phần `<!-- BEGIN PROJECT OVERRIDE -->`).
3
+ > File này được tạo từ `templates/AGENTS.md.tpl` của install home (`~/.cursor` | `~/.config/opencode` | `~/.claude`). Chạy `bash <home>/scripts/init-project.sh .` để re-sync (idempotent, giữ phần `<!-- BEGIN PROJECT OVERRIDE -->`). Claude Code đọc file này qua shim `CLAUDE.md` (`@AGENTS.md`).
4
4
 
5
5
  ## Nguyên tắc vàng
6
6
 
@@ -94,13 +94,13 @@
94
94
 
95
95
  ## Hooks enforce
96
96
 
97
- > Cursor dùng bash hooks (`~/.cursor/hooks/`). OpenCode dùng plugin guard `openmoneta-guard.ts` — `tool.execute.before/after` tương đương 2 hook đầu, `event:session.idle` tương đương `verify-completion` (re-prompt thay vì block cứng).
97
+ > Cursor dùng bash hooks (`~/.cursor/hooks/`). OpenCode dùng plugin guard `openmoneta-guard.ts` — `tool.execute.before/after` tương đương 2 hook đầu, `event:session.idle` tương đương `verify-completion` (re-prompt thay vì block cứng). Claude Code dùng adapter (`~/.claude/hooks/openmoneta/`) dịch protocol → gọi lại bash hooks gốc; `Stop` hook block cứng như Cursor + matcher `Bash` chặn cả shell search trước docs-first.
98
98
 
99
99
  | Hook | Khi nào | Hậu quả |
100
100
  |---|---|---|
101
- | `enforce-docs-first` | preToolUse Read/Glob/Grep | BLOCK source code đọc nếu chưa Read `docs/INDEX.md`; nếu có `docs/decisions/INDEX.md` thì còn BLOCK đến khi đã đọc `docs/decisions/` (chống flip-flop kiến trúc) |
102
- | `check-plan-exists` | preToolUse Write/StrReplace/EditNotebook/Delete | ALLOW task thường không plan; BLOCK file nhạy cảm không plan, plan Draft, hoặc file ngoài scope plan |
103
- | `verify-completion` | stop (Cursor) / `session.idle` (OpenCode) | Cursor BLOCK kết thúc nếu Check 5/6/9/10/11 fail (gồm ADR supersede integrity + plan đổi kiến trúc thiếu ADR); OpenCode re-prompt nhắc hoàn tất, loop guard ≤4 lần |
101
+ | `enforce-docs-first` | preToolUse Read/Glob/Grep (Claude Code: thêm Bash search) | BLOCK source code đọc nếu chưa Read `docs/INDEX.md`; nếu có `docs/decisions/INDEX.md` thì còn BLOCK đến khi đã đọc `docs/decisions/` (chống flip-flop kiến trúc) |
102
+ | `check-plan-exists` | preToolUse Write/StrReplace/EditNotebook/Delete (Claude Code: Write/Edit/NotebookEdit) | ALLOW task thường không plan; BLOCK file nhạy cảm không plan, plan Draft, hoặc file ngoài scope plan |
103
+ | `verify-completion` | stop (Cursor/Claude Code) / `session.idle` (OpenCode) | Cursor + Claude Code BLOCK kết thúc nếu Check 5/6/9/10/11 fail (gồm ADR supersede integrity + plan đổi kiến trúc thiếu ADR); OpenCode re-prompt nhắc hoàn tất, loop guard ≤4 lần |
104
104
 
105
105
  ## Override cho dự án này
106
106
 
package/uninstall.sh CHANGED
@@ -89,5 +89,66 @@ else
89
89
  echo "✅ Đã uninstall."
90
90
  fi
91
91
 
92
+ # === Claude Code (~/.claude) — surgical theo manifest ===
93
+ # ~/.claude chứa data + skills/agents riêng của user → TUYỆT ĐỐI không rm -rf
94
+ # thư mục chuẩn. Chỉ xóa item kit đã cài (ghi trong .openmoneta-manifest) + gỡ
95
+ # hooks entries openmoneta khỏi settings.json.
96
+ CLAUDE_DIR="$HOME/.claude"
97
+ if [[ -f "$CLAUDE_DIR/.openmoneta-version" ]]; then
98
+ echo ""
99
+ echo "==> Gỡ Claude Code config ($CLAUDE_DIR)..."
100
+
101
+ MANIFEST="$CLAUDE_DIR/.openmoneta-manifest"
102
+ if [[ -f "$MANIFEST" ]]; then
103
+ while IFS= read -r item; do
104
+ [[ -z "$item" ]] && continue
105
+ case "$item" in
106
+ /*|*..*) continue ;; # manifest chỉ chứa path tương đối an toàn
107
+ esac
108
+ if [[ -e "$CLAUDE_DIR/$item" ]]; then
109
+ rm -rf "${CLAUDE_DIR:?}/$item"
110
+ echo " - $item"
111
+ fi
112
+ done < "$MANIFEST"
113
+ rm -f "$MANIFEST"
114
+ fi
115
+
116
+ SETTINGS="$CLAUDE_DIR/settings.json"
117
+ if [[ -f "$SETTINGS" ]] && command -v python3 >/dev/null 2>&1; then
118
+ python3 - "$SETTINGS" <<'PYEOF' || echo " [!] Không parse được settings.json — gỡ hooks openmoneta thủ công nếu cần."
119
+ import json, sys
120
+
121
+ path = sys.argv[1]
122
+ with open(path) as f:
123
+ settings = json.load(f)
124
+
125
+ hooks = settings.get("hooks")
126
+ if isinstance(hooks, dict):
127
+ def is_om(entry):
128
+ return any(
129
+ "hooks/openmoneta/" in (h.get("command") or "")
130
+ for h in entry.get("hooks", [])
131
+ if isinstance(h, dict)
132
+ )
133
+ for event in list(hooks.keys()):
134
+ if isinstance(hooks[event], list):
135
+ hooks[event] = [e for e in hooks[event] if not is_om(e)]
136
+ if not hooks[event]:
137
+ del hooks[event]
138
+ if not hooks:
139
+ del settings["hooks"]
140
+
141
+ with open(path, "w") as f:
142
+ json.dump(settings, f, indent=2, ensure_ascii=False)
143
+ f.write("\n")
144
+ print(" - hooks entries openmoneta trong settings.json")
145
+ PYEOF
146
+ fi
147
+
148
+ rm -f "$CLAUDE_DIR/.openmoneta-version" "$CLAUDE_DIR/.openmoneta-repo" \
149
+ "$CLAUDE_DIR/.openmoneta-installed-at" "$CLAUDE_DIR/.openmoneta-update-check"
150
+ echo "✅ Đã gỡ Claude Code config (skills/agents riêng của bạn giữ nguyên)."
151
+ fi
152
+
92
153
  echo ""
93
- echo "Restart Cursor để áp dụng."
154
+ echo "Restart Cursor/Claude Code để áp dụng."
package/update.sh CHANGED
@@ -127,7 +127,8 @@ sync_project() {
127
127
  registry_files() {
128
128
  printf '%s\n' \
129
129
  "$HOME/.cursor/.openmoneta-projects" \
130
- "${XDG_CONFIG_HOME:-$HOME/.config}/opencode/.openmoneta-projects"
130
+ "${XDG_CONFIG_HOME:-$HOME/.config}/opencode/.openmoneta-projects" \
131
+ "$HOME/.claude/.openmoneta-projects"
131
132
  }
132
133
 
133
134
  # === Helper: đọc registry (merge 2 home, bỏ dòng trống, dedup) ===
@@ -168,6 +169,7 @@ scan_seed() {
168
169
  [[ -f "$HOME/.cursor/.openmoneta-version" ]] && homes+=("$HOME/.cursor/.openmoneta-projects")
169
170
  [[ -f "${XDG_CONFIG_HOME:-$HOME/.config}/opencode/.openmoneta-version" ]] && \
170
171
  homes+=("${XDG_CONFIG_HOME:-$HOME/.config}/opencode/.openmoneta-projects")
172
+ [[ -f "$HOME/.claude/.openmoneta-version" ]] && homes+=("$HOME/.claude/.openmoneta-projects")
171
173
  if [[ ${#homes[@]} -eq 0 ]]; then
172
174
  echo " [!] Chưa có install home nào để seed registry."
173
175
  return 0
@@ -306,6 +308,19 @@ else
306
308
  echo " Cài tay nếu cần: bash $REPO_DIR/install-opencode.sh"
307
309
  fi
308
310
 
311
+ # === Step 2C: Global install (Claude Code) ===
312
+ # CHỈ chạy nếu đã từng cài OpenMoneta cho Claude Code (opt-in qua install-claude-code.sh).
313
+ # Không tự cài khi chỉ thấy binary `claude` — tránh đụng ~/.claude của user ngoài ý muốn.
314
+ CLAUDE_DIR="$HOME/.claude"
315
+ if [[ -f "$CLAUDE_DIR/.openmoneta-version" ]]; then
316
+ echo ""
317
+ echo "==> Phát hiện OpenMoneta for Claude Code → chạy install-claude-code.sh..."
318
+ bash "$REPO_DIR/install-claude-code.sh" --yes
319
+ else
320
+ echo ""
321
+ echo "ℹ️ Chưa cài OpenMoneta cho Claude Code, bỏ qua. Opt-in: bash $REPO_DIR/install-claude-code.sh"
322
+ fi
323
+
309
324
  echo ""
310
325
  echo "✅ Global update hoàn tất: v$CURRENT_VERSION → v$NEW_VERSION"
311
326
  echo ""