openmoneta-dev-kit 2.2.1 → 2.3.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/README.md +7 -4
- package/VERSION +1 -1
- package/claude/agents/qa-autonomous.md +39 -0
- package/claude/agents/requirement-analyst.md +51 -0
- package/claude/agents/security-auditor.md +44 -0
- package/claude/agents/ui-tester.md +40 -0
- package/claude/hooks/bash-guard.sh +112 -0
- package/claude/hooks/posttooluse-adapter.sh +38 -0
- package/claude/hooks/pretooluse-adapter.sh +69 -0
- package/claude/hooks/sessionstart-adapter.sh +44 -0
- package/claude/hooks/stop-adapter.sh +60 -0
- package/claude/settings-hooks.json +55 -0
- package/hooks/inject-process-context.sh +24 -12
- package/hooks/verify-completion.sh +2 -1
- package/install-claude-code.sh +262 -0
- package/package.json +5 -2
- package/scripts/init-project.sh +25 -0
- package/skills/automated-testing/SKILL.md +2 -0
- package/skills/automated-testing/scripts/install-playwright.sh +3 -0
- package/skills/decision-recorder/SKILL.md +1 -1
- package/skills/docs-maintenance/SKILL.md +3 -1
- package/skills/module-architect/SKILL.md +2 -2
- package/src/commands/init.js +7 -1
- package/src/commands/install.js +21 -2
- package/src/commands/uninstall.js +54 -3
- package/src/commands/update.js +22 -6
- package/src/lib/paths.js +4 -0
- package/templates/AGENTS.md.tpl +5 -5
- package/uninstall.sh +62 -1
- package/update.sh +16 -1
package/src/commands/update.js
CHANGED
|
@@ -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
|
|
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
|
|
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 =
|
|
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 (!
|
|
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 =
|
|
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,
|
package/templates/AGENTS.md.tpl
CHANGED
|
@@ -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ừ
|
|
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 ""
|