openmoneta-dev-kit 1.9.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.
Files changed (46) hide show
  1. package/README.md +103 -0
  2. package/agents/qa-autonomous.md +131 -0
  3. package/agents/requirement-analyst.md +98 -0
  4. package/agents/security-auditor.md +120 -0
  5. package/agents/ui-tester.md +186 -0
  6. package/bin/openmoneta.js +11 -0
  7. package/hooks/check-plan-exists.sh +154 -0
  8. package/hooks/enforce-docs-first.sh +169 -0
  9. package/hooks/inject-process-context.sh +117 -0
  10. package/hooks/track-changes.sh +46 -0
  11. package/hooks/verify-completion.sh +165 -0
  12. package/hooks.json +30 -0
  13. package/opencode/AGENTS.md.tpl +38 -0
  14. package/opencode/agents/qa-autonomous.md +42 -0
  15. package/opencode/agents/requirement-analyst.md +51 -0
  16. package/opencode/agents/security-auditor.md +46 -0
  17. package/opencode/agents/ui-tester.md +43 -0
  18. package/opencode/plugins/openmoneta-guard.ts +389 -0
  19. package/package.json +41 -0
  20. package/scripts/debug-hooks.sh +54 -0
  21. package/scripts/init-project.sh +438 -0
  22. package/scripts/list-affected-modules.sh +74 -0
  23. package/skills/auth-bypass-testing/SKILL.md +236 -0
  24. package/skills/automated-testing/SKILL.md +162 -0
  25. package/skills/automated-testing/scripts/install-playwright.sh +134 -0
  26. package/skills/module-architect/SKILL.md +256 -0
  27. package/skills/plan-writer/SKILL.md +229 -0
  28. package/skills/requirement-analysis/SKILL.md +163 -0
  29. package/skills/safe-push/SKILL.md +182 -0
  30. package/skills/security-checklist/SKILL.md +116 -0
  31. package/skills/test-strategy/SKILL.md +135 -0
  32. package/skills/ui-test-loop/SKILL.md +161 -0
  33. package/src/cli.js +63 -0
  34. package/src/commands/check.js +30 -0
  35. package/src/commands/init.js +43 -0
  36. package/src/commands/install.js +50 -0
  37. package/src/commands/uninstall.js +74 -0
  38. package/src/commands/update.js +81 -0
  39. package/src/lib/paths.js +46 -0
  40. package/src/lib/version.js +45 -0
  41. package/templates/AGENTS.md.tpl +106 -0
  42. package/templates/docs-INDEX.md.tpl +62 -0
  43. package/templates/env.test.tpl +16 -0
  44. package/templates/karpathy-reference.md +49 -0
  45. package/templates/plans-INDEX.md.tpl +38 -0
  46. package/templates/playwright.config.ts.tpl +44 -0
@@ -0,0 +1,182 @@
1
+ ---
2
+ name: safe-push
3
+ description: "CORE CONDITIONAL: kích hoạt khi user yêu cầu commit + push / push code / đẩy code / merge lên remote / lên main. Đảm bảo pre-push sync + conflict resolution + safe fast-forward push, không đè code người khác. KHÔNG dùng --force trên shared branch."
4
+ ---
5
+
6
+ # Safe Push (CORE CONDITIONAL)
7
+
8
+ Skill này chạy ở **Bước 6 — Pre-push Sync + Safe Push**.
9
+
10
+ Chỉ kích hoạt khi user yêu cầu rõ:
11
+ - "commit + push"
12
+ - "push code"
13
+ - "đẩy code"
14
+ - "đẩy lên remote"
15
+ - "merge lên main"
16
+ - "push bản này"
17
+
18
+ Không kích hoạt cho task code bình thường chưa có yêu cầu push.
19
+
20
+ ## Mục tiêu
21
+
22
+ Đảm bảo trước khi `git push`, local branch đã đồng bộ với remote mới nhất để không đè code người khác trong repo có nhiều contributor.
23
+
24
+ Vấn đề cần chặn:
25
+
26
+ ```text
27
+ T0: AI bắt đầu sửa file a từ remote v1
28
+ T1: Người khác sửa file a và push remote v2
29
+ T2: AI push code dựa trên v1
30
+ ```
31
+
32
+ Bước 6 bắt buộc `fetch + rebase` ngay trước push. Nếu remote có commit mới, local phải rebase lên commit đó trước. Nếu có conflict logic, hỏi user, không tự đoán.
33
+
34
+ ## Nguyên tắc bắt buộc
35
+
36
+ 1. **Không force push shared branch**: tuyệt đối không chạy `git push --force` hoặc `git push -f` lên `main`, `master`, `develop`, `staging`, `production`.
37
+ 2. **Không auto-resolve conflict code logic**: file code business (`*.ts`, `*.tsx`, `*.py`, `*.go`, `*.java`, `*.rb`, `*.php`, `*.rs`) phải hỏi user nếu conflict cùng logic/dòng.
38
+ 3. **Re-test sau rebase/conflict**: code đã đổi ngữ cảnh sau rebase, phải chạy lại verify tối thiểu phù hợp repo trước khi push.
39
+ 4. **Push thường trước**: dùng `git push` fast-forward. Nếu rejected do remote mới, quay lại fetch/rebase. Loop tối đa 3 lần.
40
+ 5. **Không deploy trong skill này**: CI/CD/deploy là pipeline ngoài scope trừ khi user yêu cầu skill riêng.
41
+
42
+ ## Workflow 7 bước
43
+
44
+ ### 1. Pre-flight branch
45
+
46
+ Chạy:
47
+
48
+ ```bash
49
+ git status --short
50
+ git branch --show-current
51
+ git remote -v
52
+ ```
53
+
54
+ Nếu branch là `main`, `master`, `develop`, `staging`, `production`:
55
+ - Cảnh báo user đây là shared branch.
56
+ - Chỉ tiếp tục nếu user đã yêu cầu push rõ.
57
+ - Không dùng force push trong mọi trường hợp.
58
+
59
+ Nếu working tree chưa clean:
60
+ - Nếu user yêu cầu commit + push: commit trước theo Git Safety Protocol.
61
+ - Nếu còn file conflict/untracked không rõ scope: hỏi user.
62
+
63
+ ### 2. Fetch remote ngay trước push
64
+
65
+ ```bash
66
+ BRANCH=$(git branch --show-current)
67
+ git fetch origin "$BRANCH"
68
+ ```
69
+
70
+ Nếu branch chưa track remote:
71
+ - Dùng `git push -u origin HEAD` sau khi các bước sync/test đã pass.
72
+
73
+ ### 3. So sánh local với remote
74
+
75
+ ```bash
76
+ git status -sb
77
+ git rev-list --left-right --count HEAD...origin/$BRANCH
78
+ ```
79
+
80
+ Diễn giải:
81
+ - `0 0`: local == remote, có thể push nếu đã có commit mới local.
82
+ - `N 0`: local ahead remote, có thể push sau test.
83
+ - `0 N`: remote ahead, phải rebase.
84
+ - `N M`: diverged, phải rebase.
85
+
86
+ ### 4. Rebase với remote nếu cần
87
+
88
+ ```bash
89
+ git pull --rebase origin "$BRANCH"
90
+ ```
91
+
92
+ Nếu rebase sạch:
93
+ - Chuyển sang bước test.
94
+
95
+ Nếu conflict:
96
+ - Chuyển sang bước 5.
97
+
98
+ ### 5. Conflict resolution policy
99
+
100
+ Trước tiên liệt kê conflict:
101
+
102
+ ```bash
103
+ git status --short
104
+ git diff --name-only --diff-filter=U
105
+ ```
106
+
107
+ | Loại file conflict | Strategy |
108
+ |---|---|
109
+ | `package-lock.json`, `yarn.lock`, `pnpm-lock.yaml` | Không sửa tay nếu tránh được. Resolve package files rồi regenerate bằng package manager phù hợp (`npm install`, `yarn install`, `pnpm install`). |
110
+ | Generated files (`dist/`, `build/`, `.next/`, `coverage/`) | Cảnh báo user. Thường không nên commit generated output. |
111
+ | Code logic (`*.ts`, `*.tsx`, `*.py`, `*.go`, ...) | Hỏi user bằng `AskQuestion`. Không tự chọn ours/theirs nếu thay đổi có ý nghĩa business. |
112
+ | Migration/schema SQL | Escalate user. Có thể cần đổi thứ tự/tên migration để giữ lịch sử đúng. |
113
+ | Docs/plans (`*.md`) | Có thể merge thủ công nếu rõ ràng; nếu nội dung user/team conflict, hỏi user. |
114
+
115
+ Sau khi user quyết định:
116
+
117
+ ```bash
118
+ git add <resolved-files>
119
+ git rebase --continue
120
+ ```
121
+
122
+ Nếu không thể resolve an toàn:
123
+ - `git rebase --abort`
124
+ - Báo user rõ file conflict và lý do dừng.
125
+
126
+ ### 6. Re-run verify tối thiểu
127
+
128
+ Chọn verify theo repo:
129
+ - Nếu có `package.json`: chạy lint/typecheck/test script liên quan nếu tồn tại.
130
+ - Nếu không có script test: chạy check nhẹ nhất có sẵn (`npm run lint`, `npm run typecheck`, `go test ./...`, `pytest`, v.v.).
131
+ - Nếu user không yêu cầu test và repo lớn: chạy smoke verify đã ghi trong plan.
132
+
133
+ Nếu verify fail:
134
+ - Fix nếu lỗi đơn giản và nằm trong scope.
135
+ - Nếu lỗi do conflict logic hoặc ngoài scope: dừng và hỏi user.
136
+
137
+ ### 7. Safe push
138
+
139
+ ```bash
140
+ git push
141
+ ```
142
+
143
+ Nếu push rejected vì remote có commit mới:
144
+ 1. Quay lại bước 2.
145
+ 2. Loop tối đa 3 lần.
146
+ 3. Nếu vẫn rejected/conflict liên tục, dừng và báo user.
147
+
148
+ Không dùng:
149
+
150
+ ```bash
151
+ git push --force
152
+ git push -f
153
+ ```
154
+
155
+ Chỉ cân nhắc `--force-with-lease` trên feature branch cá nhân khi user yêu cầu rõ và branch không phải shared branch.
156
+
157
+ ## Output bắt buộc
158
+
159
+ Sau khi push thành công, báo ngắn:
160
+ - Branch đã push.
161
+ - Commit SHA mới nhất.
162
+ - Remote status.
163
+ - Có rebase/conflict không.
164
+ - Verify đã chạy gì.
165
+
166
+ Ví dụ:
167
+
168
+ ```text
169
+ Đã push branch feature/search-form.
170
+ - SHA: abc1234
171
+ - Pre-push sync: remote ahead 1 commit, rebase sạch
172
+ - Verify: npm run lint pass
173
+ - Push: git push pass
174
+ ```
175
+
176
+ Nếu dừng vì conflict:
177
+
178
+ ```text
179
+ Đã dừng trước push vì conflict code logic ở src/a.ts.
180
+ Remote có thay đổi mới của người khác trên cùng block logic.
181
+ Cần bạn chọn hướng merge trước khi tiếp tục.
182
+ ```
@@ -0,0 +1,116 @@
1
+ ---
2
+ name: security-checklist
3
+ description: "ON-DEMAND ONLY: chỉ kích hoạt khi user explicitly yêu cầu security audit/review (vd 'audit security login flow', 'check OWASP cho API /payment'), HOẶC task có chạm auth/payment/PII và bạn muốn tự kiểm tra trước commit. KHÔNG tự trigger trong quy trình bình thường (v1.5.0 đã bỏ Bước 5 Security khỏi core process)."
4
+ ---
5
+
6
+ # Security Checklist (ON-DEMAND)
7
+
8
+ Skill này **KHÔNG** nằm trong quy trình core (v1.5.0+). Chỉ dùng khi:
9
+
10
+ - User explicit yêu cầu: "audit security X", "review OWASP cho Y", "check secrets".
11
+ - Bạn (AI) chủ động muốn check trước commit nếu task chạm auth/payment/PII/admin/permission.
12
+ - Trước major release.
13
+
14
+ Có thể delegate sang sub-agent `security-auditor` để có audit độc lập.
15
+
16
+ ## Checklist 10 mục (OWASP Top 10 mapping)
17
+
18
+ Áp dụng các mục liên quan đến task hiện tại. Tick từng mục:
19
+
20
+ ### A01 — Broken Access Control
21
+ - [ ] Mọi endpoint có middleware authn check
22
+ - [ ] Authz check (role/permission) đúng resource owner
23
+ - [ ] Không trả về data của user khác trong response
24
+ - [ ] IDOR: sequential ID không cho enumerate
25
+
26
+ ### A02 — Cryptographic Failures
27
+ - [ ] HTTPS only (HSTS header)
28
+ - [ ] Password hash bằng bcrypt/argon2 (KHÔNG md5/sha1)
29
+ - [ ] JWT dùng RS256/ES256 (HS256 chỉ khi shared secret đảm bảo)
30
+ - [ ] Sensitive data không log
31
+
32
+ ### A03 — Injection
33
+ - [ ] SQL: dùng parameterized query / ORM (không string concat)
34
+ - [ ] NoSQL: validate operator (`$where`, `$ne` blacklist)
35
+ - [ ] OS command: dùng `execFile` thay `exec`, escape arg
36
+ - [ ] HTML output: escape qua framework (React, Vue auto-escape)
37
+
38
+ ### A04 — Insecure Design
39
+ - [ ] Rate limit ở endpoint sensitive (login, password reset)
40
+ - [ ] Account lockout sau N lần fail
41
+ - [ ] Workflow business logic không bypass được
42
+
43
+ ### A05 — Security Misconfiguration
44
+ - [ ] Default credentials đã đổi
45
+ - [ ] Stack trace KHÔNG lộ trong production
46
+ - [ ] CORS không `*` cho endpoint có credentials
47
+ - [ ] Security headers: CSP, X-Frame-Options, X-Content-Type-Options
48
+
49
+ ### A06 — Vulnerable Components
50
+ - [ ] `npm audit` / `pip-audit` / `cargo audit` không có HIGH/CRITICAL
51
+ - [ ] Dependencies cập nhật trong 6 tháng
52
+
53
+ ### A07 — Identification and Authentication Failures
54
+ - [ ] MFA cho admin
55
+ - [ ] Session timeout hợp lý
56
+ - [ ] Logout invalidate token thật sự (server-side)
57
+ - [ ] Password policy: min 8 char, không common password
58
+
59
+ ### A08 — Software and Data Integrity Failures
60
+ - [ ] CI/CD pipeline pin version dependency
61
+ - [ ] Subresource Integrity cho external scripts
62
+ - [ ] Verify webhook signature (Stripe, GitHub, etc.)
63
+
64
+ ### A09 — Security Logging and Monitoring Failures
65
+ - [ ] Log auth events (login success/fail)
66
+ - [ ] Log access control fail
67
+ - [ ] Log không chứa secrets/PII
68
+
69
+ ### A10 — Server-Side Request Forgery (SSRF)
70
+ - [ ] Không cho user input URL để fetch không validate
71
+ - [ ] Block private IP range (10.x, 192.168.x, 169.254.x)
72
+
73
+ ## Secrets scan command
74
+
75
+ Chạy ở root project trước commit:
76
+
77
+ ```bash
78
+ # Tìm các pattern khả nghi
79
+ rg -i "(api[_-]?key|secret|token|password|private[_-]?key)\s*[:=]\s*['\"][^'\"]{8,}" \
80
+ --glob '!node_modules' --glob '!*.lock' --glob '!.env*' --glob '!CHANGELOG.md'
81
+
82
+ # Check .env không vô tình commit
83
+ git ls-files | grep -E '\.env$|\.env\.local$|\.env\.production$' && echo "WARNING: .env committed!"
84
+
85
+ # Test bypass token check
86
+ rg "TEST_BYPASS_TOKEN\s*=" --glob '!.env.test' --glob '!*.tpl'
87
+ ```
88
+
89
+ ## Khi nào delegate sang `security-auditor`
90
+
91
+ - Task ảnh hưởng auth/authz
92
+ - Task xử lý payment/PII
93
+ - Task expose endpoint mới ra internet
94
+ - Trước mỗi major release
95
+
96
+ Sub-agent sẽ chạy checklist độc lập + scan secrets, output report ngắn để parent review.
97
+
98
+ ## Output bắt buộc
99
+
100
+ Vào section `## Security Check` của plan:
101
+
102
+ ```markdown
103
+ ## Security Check
104
+
105
+ **Date**: YYYY-MM-DD HH:mm
106
+ **Checked by**: parent | security-auditor
107
+
108
+ - [x] A01: ... (notes)
109
+ - [x] A03: ... (notes)
110
+ - [N/A] A10: không có user-input URL
111
+
112
+ **Issues found**:
113
+ - (none) | <description + plan to fix>
114
+
115
+ **Secrets scan**: PASS | FAIL <details>
116
+ ```
@@ -0,0 +1,135 @@
1
+ ---
2
+ name: test-strategy
3
+ description: "ON-DEMAND ONLY: chỉ kích hoạt khi user explicitly yêu cầu viết test (vd 'viết unit test cho X', 'add E2E cho login flow'), HOẶC khi bạn (AI) cần TDD-first cho bug fix khó. KHÔNG tự trigger trong quy trình bình thường (v1.5.0 đã bỏ Bước 6 Test khỏi core process). Phân tầng test: Unit ~70%, Integration ~20%, E2E ~10% với tools mặc định theo stack (Vitest/Jest/Pytest/Go test)."
4
+ ---
5
+
6
+ # Test Strategy
7
+
8
+ ## Test Pyramid
9
+
10
+ ```
11
+ /\
12
+ /E2\ ~10% — chậm, đắt, kiểm tra user flow thật
13
+ /----\
14
+ / Inte \ ~20% — kiểm tra modules giao tiếp với nhau
15
+ /--------\
16
+ / Unit \ ~70% — nhanh, kiểm tra function/class riêng lẻ
17
+ /------------\
18
+ ```
19
+
20
+ ## Chọn tool theo stack
21
+
22
+ | Stack | Unit | Integration | E2E | Coverage |
23
+ |---|---|---|---|---|
24
+ | Node/TS | Vitest (default) hoặc Jest | Vitest + supertest/msw | Playwright | c8 (vitest), jest --coverage |
25
+ | Python | Pytest | Pytest + httpx/responses | Playwright (python) | pytest-cov |
26
+ | Go | go test | go test (build tag integration) | Playwright (gọi từ Go binary) | go test -cover |
27
+ | Rust | cargo test | cargo test (integration_tests/) | Playwright | tarpaulin |
28
+
29
+ Phát hiện stack qua: `package.json`, `pyproject.toml`/`requirements.txt`, `go.mod`, `Cargo.toml`.
30
+
31
+ ## Khi nào dùng loại nào
32
+
33
+ ### Unit test (~70%)
34
+
35
+ - ✅ Logic thuần (validation, transform, computation)
36
+ - ✅ Edge cases của 1 function
37
+ - ✅ Pure functions, hooks không side-effect
38
+ - ❌ Test framework code (React component render → integration thì hơn)
39
+
40
+ ### Integration test (~20%)
41
+
42
+ - ✅ Module A gọi module B với data thật
43
+ - ✅ API endpoint với mock DB hoặc test DB
44
+ - ✅ React component với providers (router, store)
45
+ - ❌ Test browser behavior thật → E2E
46
+
47
+ ### E2E test (~10%)
48
+
49
+ - ✅ User flow critical (đăng ký, đăng nhập, checkout)
50
+ - ✅ Cross-browser/multi-viewport behavior
51
+ - ✅ Smoke test sau deploy
52
+ - ❌ Test mọi edge case → quá chậm, dùng unit
53
+
54
+ ## Quy tắc viết test
55
+
56
+ ### 1. AAA Pattern (Arrange / Act / Assert)
57
+
58
+ ```ts
59
+ test('parseDate trả null khi input rỗng', () => {
60
+ // Arrange
61
+ const input = '';
62
+ // Act
63
+ const result = parseDate(input);
64
+ // Assert
65
+ expect(result).toBeNull();
66
+ });
67
+ ```
68
+
69
+ ### 2. Test name = behavior
70
+
71
+ - ✅ "trả null khi input rỗng"
72
+ - ✅ "throw khi user không có quyền admin"
73
+ - ❌ "test parseDate" (vô nghĩa)
74
+ - ❌ "should work" (không nói được gì)
75
+
76
+ ### 3. Một test → một behavior
77
+
78
+ Nhiều `expect` OK nếu cùng một behavior. Nhưng nhiều behavior → tách test.
79
+
80
+ ### 4. Coverage không phải metric duy nhất
81
+
82
+ - Aim: branch coverage **≥80%** cho code business
83
+ - Aim: branch coverage **≥95%** cho code security/payment
84
+ - KHÔNG aim 100% mù quáng — test trivial getters tốn công vô ích.
85
+
86
+ ## Bug fix workflow — TDD bắt buộc (Karpathy #4)
87
+
88
+ > Tham khảo: [`templates/karpathy-reference.md`](../../templates/karpathy-reference.md) — nguyên tắc "Goal-Driven Execution".
89
+
90
+ Cho **bug fix** (KHÔNG áp dụng cho feature mới — feature mới linh hoạt theo workflow chuẩn bên dưới):
91
+
92
+ 1. **Viết test reproducing bug TRƯỚC** — test phải FAIL.
93
+ - Test name = mô tả bug. Vd: `test('parseDate trả null khi input là "0"', ...)`.
94
+ - Chạy → confirm RED (fail đúng symptom user báo).
95
+ 2. **Commit test** riêng với message `test: reproduce <bug-summary>`.
96
+ 3. **Fix code**.
97
+ 4. Chạy lại → confirm GREEN.
98
+ 5. **Commit fix** riêng với message `fix: <bug-summary>`.
99
+ 6. (Optional) Refactor → vẫn GREEN.
100
+
101
+ ### Lý do TDD-first cho bug
102
+
103
+ - Bug pass test sau fix nhưng KHÔNG có test reproducing → không chứng minh được bug exact đã fix → dễ regression.
104
+ - 2 commit riêng (test + fix) giúp `git log` tự document được bug + fix tương ứng.
105
+ - Reviewer thấy ngay test đã fail trước khi fix.
106
+
107
+ ### Output bắt buộc trong plan (cho bug fix)
108
+
109
+ - [ ] Test reproducing bug đã viết và confirm FAIL trước khi fix → **Verify**: `git log --oneline | grep '^test: reproduce'`
110
+ - [ ] Test PASS sau khi fix → **Verify**: command chạy test cụ thể trả 0 fail
111
+ - [ ] 2 commit riêng (test + fix), không squash trước review
112
+
113
+ ## Workflow Bước 6a (feature mới)
114
+
115
+ 1. Đọc plan → xác định AC cần verify.
116
+ 2. Mỗi AC ≥ 1 test (unit/integration/E2E tùy nature).
117
+ 3. Viết test trước hoặc sau code đều OK (cho **feature mới**), nhưng phải xanh trước khi sang Bước 7.
118
+ 4. Chạy:
119
+ - JS/TS: `npx vitest run --coverage` (hoặc `jest --coverage`)
120
+ - Python: `pytest --cov`
121
+ - Go: `go test ./... -cover`
122
+ 5. Ghi coverage % vào plan section "Test Plan".
123
+ 6. Lưu kết quả vào `.cursor/.last-test-result` (hook `verify-completion` đọc):
124
+ ```json
125
+ {"status": "pass", "timestamp": "2026-04-23T14:30:00Z", "coverage": 87.5}
126
+ ```
127
+
128
+ ## Khi delegate sang `qa-autonomous`
129
+
130
+ Nên delegate khi:
131
+ - Test loop có thể nhiều iteration (>3 lần fix)
132
+ - Test log dài, sẽ nhồi context parent
133
+ - Cần debug deeper với nhiều variations
134
+
135
+ Sub-agent tự loop test-fix-retest, chỉ báo cáo khi pass hoặc fail >3 lần.
@@ -0,0 +1,161 @@
1
+ ---
2
+ name: ui-test-loop
3
+ description: "ON-DEMAND ONLY: chỉ kích hoạt khi user explicitly yêu cầu UI test loop (vd 'test UI mobile + tablet + desktop, fix lỗi rồi retest', 'visual regression test cho component X'). KHÔNG tự trigger trong quy trình bình thường (v1.5.0 đã bỏ hook ui-checkpoint). Workflow loop test-fix-retest cho UI/UX bằng Playwright. Hard limit 5 vòng trước khi escalate user."
4
+ ---
5
+
6
+ # UI Test Loop với Checkpoint
7
+
8
+ Workflow chuẩn để **AI tự test UI, tự fix, tự retest** đến khi đạt yêu cầu — nhưng có **safety checkpoint** mỗi 2 vòng để user duyệt và tránh đi sai hướng quá lâu.
9
+
10
+ ## Workflow
11
+
12
+ ```mermaid
13
+ flowchart LR
14
+ Start[Đọc AC từ plan] --> Sess[Tạo .ui-session.json]
15
+ Sess --> Write[Viết Playwright test theo AC]
16
+ Write --> Run[Chạy multi-viewport]
17
+ Run --> Pass{Pass?}
18
+ Pass -->|Có| Done[Cleanup .ui-session.json + báo cáo]
19
+ Pass -->|Không| Fix[Đọc lỗi, sửa code]
20
+ Fix --> Inc[iter++]
21
+ Inc --> Limit{iter >= 10?}
22
+ Limit -->|Có| Escalate[Escalate user]
23
+ Limit -->|Không| Run
24
+ ```
25
+
26
+ Hook `subagentStop` (`ui-checkpoint.sh`) tự động kích hoạt **mỗi 2 vòng subagent stop** — buộc subagent show screenshot trước khi tiếp tục.
27
+
28
+ ## Bước thực hiện (cho `ui-tester` subagent)
29
+
30
+ ### 1. Khởi tạo session
31
+
32
+ Tạo file `.cursor/.ui-session.json` ở workspace để hook biết kích hoạt:
33
+
34
+ ```bash
35
+ mkdir -p .cursor
36
+ cat > .cursor/.ui-session.json <<EOF
37
+ {
38
+ "plan_slug": "$(basename "$PLAN_FILE" .md)",
39
+ "started_at": "$(date -Iseconds)",
40
+ "iter": 0
41
+ }
42
+ EOF
43
+ ```
44
+
45
+ Set env:
46
+ ```bash
47
+ export PLAN_SLUG="2026-04-23-add-google-login"
48
+ export UI_ITER=0
49
+ ```
50
+
51
+ ### 2. Đọc Acceptance Criteria
52
+
53
+ Mở plan file → tìm section `## Acceptance Criteria`. Mỗi AC = 1 hoặc nhiều test case.
54
+
55
+ ### 3. Viết test
56
+
57
+ ```ts
58
+ import { test, expect } from '@playwright/test';
59
+
60
+ // AC1: Button "Đăng nhập Google" hiển thị icon + text đúng
61
+ test('AC1: login button visible with correct content', async ({ page }, testInfo) => {
62
+ await page.goto('/login');
63
+
64
+ const btn = page.getByRole('button', { name: /Đăng nhập Google/i });
65
+ await expect(btn).toBeVisible();
66
+ await expect(btn.locator('img[alt*="Google"]')).toBeVisible();
67
+
68
+ await page.screenshot({
69
+ path: `tests/screenshots/${process.env.PLAN_SLUG}/iter-${process.env.UI_ITER}/${testInfo.project.name}-ac1.png`,
70
+ fullPage: true,
71
+ });
72
+ });
73
+
74
+ // AC2: Click button mở popup OAuth
75
+ test('AC2: click opens OAuth popup', async ({ page, context }) => {
76
+ await page.goto('/login');
77
+ const popupPromise = context.waitForEvent('page');
78
+ await page.getByRole('button', { name: /Đăng nhập Google/i }).click();
79
+ const popup = await popupPromise;
80
+ await expect(popup).toHaveURL(/accounts\.google\.com/);
81
+ });
82
+ ```
83
+
84
+ ### 4. Chạy test multi-viewport
85
+
86
+ ```bash
87
+ UI_ITER=$((UI_ITER + 1)) npx playwright test login.spec.ts
88
+ ```
89
+
90
+ Lưu kết quả:
91
+ ```bash
92
+ STATUS=$([[ $? == 0 ]] && echo "pass" || echo "fail")
93
+ echo "{\"status\": \"$STATUS\", \"timestamp\": \"$(date -Iseconds)\", \"tool\": \"playwright\", \"iter\": $UI_ITER}" > .cursor/.last-test-result
94
+ ```
95
+
96
+ ### 5. Loop quyết định
97
+
98
+ ```
99
+ if test pass:
100
+ → cleanup .ui-session.json
101
+ → báo cáo "✅ UI tests pass sau N vòng. Screenshots tại tests/screenshots/<slug>/iter-N/"
102
+ → end
103
+
104
+ if test fail:
105
+ → đọc lỗi từ tests/playwright-report/
106
+ → debug: ưu tiên fix CSS/component, KHÔNG sửa test cho match code sai
107
+ → UI_ITER++
108
+ → loop lại bước 4
109
+ ```
110
+
111
+ ### 6. Checkpoint (tự động qua hook)
112
+
113
+ Hook `ui-checkpoint.sh` chạy ở `subagentStop`. Khi `loop_count` chia hết cho 2 → trả `followup_message` buộc subagent:
114
+ - Show screenshot mới nhất ở `tests/screenshots/<slug>/iter-<n>/`
115
+ - Mô tả ngắn những gì đã thử và kết quả
116
+ - **Dừng và chờ user duyệt** trước khi loop tiếp
117
+
118
+ User trả lời:
119
+ - "OK tiếp tục" → loop tiếp
120
+ - "Sửa thêm X" → adjust và loop
121
+ - "Stop, tôi tự xử" → cleanup `.ui-session.json` và end
122
+
123
+ ### 7. Hard limit & Escalate
124
+
125
+ Sau **5 checkpoint** (≈ 10 iteration), hook không gửi followup nữa, subagent phải:
126
+ - Tóm tắt tất cả những gì đã thử (mỗi iter ngắn 1 dòng)
127
+ - List screenshots quan trọng để user xem
128
+ - Hypothesis: vì sao chưa pass
129
+ - Đề xuất: cần user can thiệp gì
130
+
131
+ ## Quy tắc fix
132
+
133
+ 1. **Ưu tiên fix code, không fix test** — trừ khi test sai assertion.
134
+ 2. **Fix cause, không fix symptom** — nếu CSS overflow, sửa root cause (flex layout) thay vì hack `overflow: hidden`.
135
+ 3. **Một thay đổi 1 lần** — không fix nhiều thứ cùng lúc, khó debug.
136
+ 4. **Verify với 1 viewport trước**, OK mới chạy full multi-viewport.
137
+
138
+ ## Cleanup khi xong
139
+
140
+ ```bash
141
+ rm -f .cursor/.ui-session.json
142
+ unset PLAN_SLUG UI_ITER
143
+ ```
144
+
145
+ ## Output bắt buộc
146
+
147
+ Trong báo cáo cuối:
148
+
149
+ ```markdown
150
+ ## UI Test Result
151
+
152
+ - Plan: `plans/<plan-slug>.md`
153
+ - Iterations: N
154
+ - Checkpoints: M (user duyệt qua các vòng 2, 4, ...)
155
+ - Final status: PASS | FAIL (escalated)
156
+ - Screenshots: `tests/screenshots/<slug>/iter-<final>/`
157
+ - Coverage AC:
158
+ - [x] AC1: ...
159
+ - [x] AC2: ...
160
+ - [ ] AC3: ... (escalate vì <reason>)
161
+ ```
package/src/cli.js ADDED
@@ -0,0 +1,63 @@
1
+ const { setPkgRoot, isInstalled } = require("./lib/paths")
2
+ const { getLocalVersion } = require("./lib/version")
3
+
4
+ async function cli(pkgRoot) {
5
+ setPkgRoot(pkgRoot)
6
+
7
+ const cmd = process.argv[2]
8
+ const args = process.argv.slice(3)
9
+
10
+ switch (cmd) {
11
+ case "install":
12
+ return require("./commands/install").run(args)
13
+ case "init":
14
+ return require("./commands/init").run(args)
15
+ case "update":
16
+ return require("./commands/update").run(args)
17
+ case "uninstall":
18
+ return require("./commands/uninstall").run(args)
19
+ case "check":
20
+ case "--check":
21
+ return require("./commands/check").run(args)
22
+ case "--version":
23
+ case "-v":
24
+ console.log(`v${getLocalVersion() || "unknown"}`)
25
+ return
26
+ case "--help":
27
+ case "-h":
28
+ default:
29
+ return showHelp()
30
+ }
31
+ }
32
+
33
+ function showHelp() {
34
+ const v = getLocalVersion() || "unknown"
35
+
36
+ console.log(`
37
+ OpenMoneta Dev Kit v${v}
38
+ ──────────────────────────────────────────────
39
+ Biến Cursor IDE / OpenCode thành team developer hoàn chỉnh.
40
+
41
+ openmoneta install Cài vào Cursor (~/.cursor/)
42
+ openmoneta install --opencode Cài vào OpenCode (~/.config/opencode/)
43
+ openmoneta install --yes Cài không hỏi xác nhận
44
+
45
+ openmoneta init Khởi tạo project (tạo AGENTS.md, docs/INDEX.md, plans/INDEX.md)
46
+ openmoneta init --opencode Init cho OpenCode
47
+ openmoneta init /path/to/proj Init project ở path chỉ định
48
+
49
+ openmoneta update Update global + sync project hiện tại
50
+ openmoneta update --yes Auto-sync, skip nếu đã latest
51
+ openmoneta update --check Chỉ kiểm tra có version mới không
52
+
53
+ openmoneta check Kiểm tra version mới nhất từ npm
54
+
55
+ openmoneta uninstall Gỡ cài đặt
56
+
57
+ Trạng thái: Cursor: ${isInstalled("cursor") ? "đã cài" : "chưa cài"} | OpenCode: ${isInstalled("opencode") ? "đã cài" : "chưa cài"}
58
+
59
+ Docs: https://github.com/rapperkey/OpenMoneta-Dev-Kit
60
+ `)
61
+ }
62
+
63
+ module.exports = { cli }
@@ -0,0 +1,30 @@
1
+ const { getLocalVersion, getLatestVersion } = require("../lib/version")
2
+
3
+ async function run(args) {
4
+ const local = getLocalVersion()
5
+ const latest = getLatestVersion()
6
+
7
+ console.log(`\n OpenMoneta Dev Kit`)
8
+ console.log(` ─────────────────`)
9
+ console.log(` Local : v${local || "unknown"}`)
10
+ console.log(` Latest: v${latest || "không xác định (không có mạng?)"}`)
11
+
12
+ if (!latest) {
13
+ console.log(`\n ❓ Không thể kiểm tra version mới nhất. Kiểm tra kết nối mạng.`)
14
+ return
15
+ }
16
+
17
+ if (!local) {
18
+ console.log(`\n 📦 Chưa cài đặt. Chạy: openmoneta install`)
19
+ return
20
+ }
21
+
22
+ if (local === latest) {
23
+ console.log(`\n ✅ Đã ở phiên bản mới nhất.`)
24
+ } else {
25
+ console.log(`\n 🔔 Có phiên bản mới: v${local} → v${latest}`)
26
+ console.log(` Chạy: openmoneta update`)
27
+ }
28
+ }
29
+
30
+ module.exports = { run }