@torus-engineering/tas-kit 1.5.0 → 1.6.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/.claude/agents/README.md +83 -0
- package/.claude/agents/architect.md +53 -0
- package/.claude/agents/aws-reviewer.md +71 -0
- package/.claude/agents/build-resolver.md +59 -0
- package/.claude/agents/code-architect.md +62 -0
- package/.claude/agents/code-explorer.md +63 -0
- package/.claude/agents/code-simplifier.md +53 -0
- package/.claude/agents/comment-analyzer.md +59 -0
- package/.claude/agents/conversation-analyzer.md +57 -0
- package/.claude/agents/csharp-reviewer.md +62 -0
- package/.claude/agents/database-reviewer.md +73 -0
- package/.claude/agents/doc-updater.md +66 -0
- package/.claude/agents/docs-lookup.md +55 -0
- package/.claude/agents/e2e-runner.md +61 -0
- package/.claude/agents/harness-optimizer.md +62 -0
- package/.claude/agents/loop-operator.md +56 -0
- package/.claude/agents/performance-optimizer.md +78 -0
- package/.claude/agents/planner.md +82 -0
- package/.claude/agents/pr-test-analyzer.md +68 -0
- package/.claude/agents/python-reviewer.md +67 -0
- package/.claude/agents/pytorch-build-resolver.md +76 -0
- package/.claude/agents/refactor-cleaner.md +70 -0
- package/.claude/agents/security-reviewer.md +79 -0
- package/.claude/agents/seo-specialist.md +75 -0
- package/.claude/agents/silent-failure-hunter.md +69 -0
- package/.claude/agents/tdd-guide.md +84 -0
- package/.claude/agents/type-design-analyzer.md +75 -0
- package/.claude/agents/typescript-reviewer.md +65 -0
- package/.claude/commands/ado-create.md +2 -1
- package/.claude/commands/ado-delete.md +3 -2
- package/.claude/commands/ado-get.md +2 -1
- package/.claude/commands/ado-status.md +2 -1
- package/.claude/commands/ado-update.md +2 -1
- package/.claude/commands/tas-adr.md +13 -12
- package/.claude/commands/tas-bug.md +97 -50
- package/.claude/commands/tas-design.md +3 -1
- package/.claude/commands/tas-dev.md +115 -0
- package/.claude/commands/tas-epic.md +4 -2
- package/.claude/commands/tas-feature.md +5 -3
- package/.claude/commands/tas-fix.md +47 -0
- package/.claude/commands/tas-plan.md +184 -0
- package/.claude/commands/tas-prd.md +3 -1
- package/.claude/commands/tas-review.md +104 -0
- package/.claude/commands/tas-sad.md +3 -1
- package/.claude/commands/tas-security.md +80 -0
- package/.claude/commands/tas-spec.md +50 -0
- package/.claude/commands/tas-story.md +77 -40
- package/.claude/commands/tas-verify.md +8 -0
- package/.claude/hooks/code-quality.js +127 -0
- package/.claude/hooks/session-end.js +116 -0
- package/.claude/rules/.gitkeep +0 -0
- package/.claude/rules/common/agents.md +65 -0
- package/.claude/rules/common/code-review.md +124 -0
- package/.claude/rules/common/coding-style.md +90 -0
- package/.claude/rules/common/development-workflow.md +44 -0
- package/.claude/rules/common/git-workflow.md +24 -0
- package/.claude/rules/common/hooks.md +30 -0
- package/.claude/rules/common/patterns.md +31 -0
- package/.claude/rules/common/performance.md +55 -0
- package/.claude/rules/common/post-review-agent.md +39 -0
- package/.claude/rules/common/project-status.md +80 -0
- package/.claude/rules/common/security.md +29 -0
- package/.claude/rules/common/stack-detection.md +29 -0
- package/.claude/rules/common/testing.md +57 -0
- package/.claude/rules/csharp/coding-style.md +72 -0
- package/.claude/rules/csharp/hooks.md +25 -0
- package/.claude/rules/csharp/patterns.md +50 -0
- package/.claude/rules/csharp/security.md +58 -0
- package/.claude/rules/csharp/testing.md +46 -0
- package/.claude/rules/python/coding-style.md +42 -0
- package/.claude/rules/python/hooks.md +19 -0
- package/.claude/rules/python/patterns.md +39 -0
- package/.claude/rules/python/security.md +30 -0
- package/.claude/rules/python/testing.md +38 -0
- package/.claude/rules/typescript/coding-style.md +199 -0
- package/.claude/rules/typescript/hooks.md +22 -0
- package/.claude/rules/typescript/patterns.md +52 -0
- package/.claude/rules/typescript/security.md +28 -0
- package/.claude/rules/typescript/testing.md +18 -0
- package/.claude/rules/web/coding-style.md +96 -0
- package/.claude/rules/web/design-quality.md +63 -0
- package/.claude/rules/web/hooks.md +120 -0
- package/.claude/rules/web/patterns.md +79 -0
- package/.claude/rules/web/performance.md +64 -0
- package/.claude/rules/web/security.md +57 -0
- package/.claude/rules/web/testing.md +55 -0
- package/.claude/settings.json +37 -0
- package/.claude/settings.local.json +38 -0
- package/.claude/skills/ado-integration/SKILL.md +44 -1
- package/.claude/skills/agent-harness-construction/SKILL.md +77 -0
- package/.claude/skills/agent-introspection-debugging/SKILL.md +157 -0
- package/.claude/skills/ai-regression-testing/SKILL.md +364 -0
- package/.claude/skills/api-design/SKILL.md +528 -0
- package/.claude/skills/architecture-decision-records/SKILL.md +184 -0
- package/.claude/skills/backend-patterns/SKILL.md +602 -0
- package/.claude/skills/benchmark/SKILL.md +98 -0
- package/.claude/skills/browser-qa/SKILL.md +92 -0
- package/.claude/skills/canary-watch/SKILL.md +104 -0
- package/.claude/skills/tas-conventions/SKILL.md +51 -3
- package/.claude/skills/tas-implementation-complete/SKILL.md +97 -0
- package/.claude/skills/tas-tdd/SKILL.md +72 -16
- package/.tas/README.md +29 -24
- package/.tas/tas-example.yaml +2 -1
- package/.tas/templates/Story.md +18 -18
- package/CLAUDE-Example.md +1 -1
- package/README.md +23 -8
- package/bin/cli.js +4 -4
- package/package.json +1 -1
- package/.claude/commands/tas-dev-story.md +0 -61
- package/.claude/commands/tas-review-code.md +0 -42
- package/.claude/commands/tas-security-check.md +0 -30
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# /tas-review $ARGUMENTS
|
|
2
|
+
|
|
3
|
+
Review code thay đổi gần nhất hoặc một file/PR cụ thể.
|
|
4
|
+
Bao gồm hygiene scan, test run, và parallel multi-agent review.
|
|
5
|
+
|
|
6
|
+
## Stack Detection
|
|
7
|
+
Đọc `.claude/rules/common/stack-detection.md`.
|
|
8
|
+
|
|
9
|
+
## Hành động
|
|
10
|
+
|
|
11
|
+
### Bước 1 — Xác định scope review
|
|
12
|
+
`$ARGUMENTS` có thể là: file path, Story ID, hoặc để trống (review git diff).
|
|
13
|
+
- Nếu trống: lấy `git diff HEAD` (staged + unstaged) hoặc last commit
|
|
14
|
+
- Nếu Story ID: tìm file Story tương ứng để lấy danh sách files đã thay đổi
|
|
15
|
+
- Nếu file path: review trực tiếp file đó
|
|
16
|
+
|
|
17
|
+
### Bước 2 — Pre-checks (PHẢI pass mới tiếp tục)
|
|
18
|
+
|
|
19
|
+
**Hygiene scan** — scan nhanh các files trong scope:
|
|
20
|
+
- Debug code còn sót: `console.log`, `print(`, `Debug.WriteLine`, `debugger`
|
|
21
|
+
- Secrets hardcoded: password/key/token/secret gán bằng string literal
|
|
22
|
+
- Commented-out code block lớn (>5 dòng) không có comment lý do
|
|
23
|
+
|
|
24
|
+
→ Nếu có blocker: liệt kê ngay, yêu cầu fix trước khi tiếp tục.
|
|
25
|
+
|
|
26
|
+
**Run tests** — detect từ project structure:
|
|
27
|
+
- `package.json` → `npm test`
|
|
28
|
+
- `*.csproj` / `*.sln` → `dotnet test`
|
|
29
|
+
- `pytest.ini` / `pyproject.toml` → `python -m pytest`
|
|
30
|
+
|
|
31
|
+
→ Nếu fail: dừng, list lỗi, KHÔNG tiếp tục review.
|
|
32
|
+
→ Nếu không detect được: ghi chú "No test runner detected" và tiếp tục.
|
|
33
|
+
|
|
34
|
+
### Bước 3 — Parallel Multi-Agent Review
|
|
35
|
+
|
|
36
|
+
Launch các agents ĐỒNG THỜI (không chờ nhau):
|
|
37
|
+
|
|
38
|
+
**Agent 1 — `code-reviewer`** (luôn chạy):
|
|
39
|
+
> Review [scope]. Đọc `.tas/checklists/code-review.md` và `.claude/rules/common/code-review.md`.
|
|
40
|
+
> Tập trung: naming, architecture alignment, error handling, DRY, function size, nesting depth.
|
|
41
|
+
> Format: findings nhóm theo Critical / High / Medium / Low, mỗi finding có file:line và fix cụ thể.
|
|
42
|
+
|
|
43
|
+
**Agent 2 — `security-reviewer`** (luôn chạy):
|
|
44
|
+
> Security audit [scope]. Đọc `.claude/rules/common/security.md`.
|
|
45
|
+
> Tập trung: OWASP Top 10, injection, hardcoded secrets, auth/authz, data exposure.
|
|
46
|
+
> Format: findings nhóm theo Critical / High / Medium / Low, mỗi finding có file:line và remediation.
|
|
47
|
+
|
|
48
|
+
**Agent 3 — Language reviewer** (dựa theo `lang_agent` từ stack detection):
|
|
49
|
+
> Language-specific review [scope].
|
|
50
|
+
> Đọc `.claude/rules/[stack]/coding-style.md` và `.claude/rules/[stack]/patterns.md`.
|
|
51
|
+
> Tập trung: async/await patterns, null handling, type safety, anti-patterns đặc thù của stack.
|
|
52
|
+
> Format: findings theo Critical / High / Medium / Low với file:line.
|
|
53
|
+
|
|
54
|
+
**Agent 4 — `aws-reviewer`** (chỉ khi `infra_agent = aws-reviewer`):
|
|
55
|
+
> AWS infrastructure review [scope].
|
|
56
|
+
> Tập trung: IAM policies, secrets trong env/config, S3 permissions, Lambda security.
|
|
57
|
+
> Format: findings theo Critical / High / Medium / Low.
|
|
58
|
+
|
|
59
|
+
Chờ TẤT CẢ agents hoàn thành, sau đó tổng hợp.
|
|
60
|
+
|
|
61
|
+
### Bước 4 — Tổng hợp kết quả
|
|
62
|
+
|
|
63
|
+
Gộp findings từ tất cả agents, deduplicate (cùng file:line từ nhiều agent → gộp lại), sort theo severity:
|
|
64
|
+
|
|
65
|
+
```
|
|
66
|
+
## Review Summary
|
|
67
|
+
|
|
68
|
+
### Critical (phải fix trước khi merge)
|
|
69
|
+
- [file:line] Issue — Fix: ...
|
|
70
|
+
|
|
71
|
+
### High (nên fix trước khi merge)
|
|
72
|
+
- [file:line] Issue — Fix: ...
|
|
73
|
+
|
|
74
|
+
### Medium (cân nhắc fix)
|
|
75
|
+
- [file:line] Issue — Fix: ...
|
|
76
|
+
|
|
77
|
+
### Low / Info (optional)
|
|
78
|
+
- [file:line] Issue — Fix: ...
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Sau khi review
|
|
82
|
+
|
|
83
|
+
**Nếu có Critical/High:**
|
|
84
|
+
→ Liệt kê rõ, yêu cầu human fix. KHÔNG tiếp tục flow.
|
|
85
|
+
|
|
86
|
+
**Nếu chỉ có Medium/Low:**
|
|
87
|
+
→ List gợi ý, hỏi human có muốn fix không, sau đó tiếp tục.
|
|
88
|
+
|
|
89
|
+
**Khi human xác nhận đã fix:**
|
|
90
|
+
1. Tick `- [x] Code review passed` trong section `## Definition of Done` của Story
|
|
91
|
+
2. Hỏi: "Bạn đã tự test lại ở local chưa? Nếu OK, có muốn chuyển ticket sang Deploy Test không?"
|
|
92
|
+
3. Nếu Yes:
|
|
93
|
+
a. Cập nhật `Status:` trong Story → `Deploy Test`
|
|
94
|
+
b. Thêm dòng Changelog trong Story: ngày, "Code review passed, moved to Deploy Test"
|
|
95
|
+
c. Cập nhật `Status:` trong Feature cha → `In Progress`, update bảng Stories
|
|
96
|
+
d. Thêm Changelog trong Feature
|
|
97
|
+
e. Cập nhật `project-status.yaml`
|
|
98
|
+
f. Gợi ý: chạy `/ado-update story <ado-id> --status "Deploy Test"` nếu dùng ADO
|
|
99
|
+
|
|
100
|
+
## Nguyên tắc
|
|
101
|
+
- Review khách quan — chỉ ra file:line cụ thể và lý do
|
|
102
|
+
- Đề xuất fix cụ thể, không chỉ nói "code xấu"
|
|
103
|
+
- Check xem code có vi phạm ADR nào không (đọc từ Technical Notes trong Story)
|
|
104
|
+
- KHÔNG tự động chuyển status mà không có xác nhận của human
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
# /tas-sad $ARGUMENTS
|
|
2
2
|
|
|
3
3
|
Vai trò: SE - Software Engineer
|
|
4
4
|
Tạo hoặc cập nhật Solution Architecture Document.
|
|
@@ -15,6 +15,7 @@ Tạo hoặc cập nhật Solution Architecture Document.
|
|
|
15
15
|
### Chế độ CREATE (file chưa tồn tại):
|
|
16
16
|
5. Cần context từ .tas/templates/SAD.md
|
|
17
17
|
6. Tạo file docs/sad.md theo template SAD của Torus
|
|
18
|
+
7. Cập nhật `project-status.yaml` theo `.claude/rules/common/project-status.md` — thêm `artifacts.sad`.
|
|
18
19
|
|
|
19
20
|
### Chế độ UPDATE (file đã tồn tại):
|
|
20
21
|
5. Cần context từ docs/sad.md hiện tại
|
|
@@ -22,6 +23,7 @@ Tạo hoặc cập nhật Solution Architecture Document.
|
|
|
22
23
|
7. Cập nhật file, giữ nguyên các section không thay đổi
|
|
23
24
|
8. Thêm dòng vào section Changelog cuối file
|
|
24
25
|
9. Nếu thay đổi là quyết định kiến trúc quan trọng, gợi ý user chạy /tas-adr
|
|
26
|
+
10. Cập nhật `project-status.yaml` theo `.claude/rules/common/project-status.md` — cập nhật `artifacts.sad`.
|
|
25
27
|
|
|
26
28
|
## Quy tắc Mermaid
|
|
27
29
|
- Các sơ đồ C4 PHẢI dùng Mermaid flow diagram
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# /tas-security $ARGUMENTS
|
|
2
|
+
|
|
3
|
+
Kiểm tra bảo mật codebase, lưu báo cáo vào docs/security-report.md.
|
|
4
|
+
|
|
5
|
+
## Stack Detection
|
|
6
|
+
Đọc `.claude/rules/common/stack-detection.md`.
|
|
7
|
+
|
|
8
|
+
## Hành động
|
|
9
|
+
|
|
10
|
+
### Bước 1 — Xác định scope
|
|
11
|
+
`$ARGUMENTS` có thể là: file path, directory, hoặc để trống (scan toàn bộ codebase).
|
|
12
|
+
Đọc `.tas/checklists/security.md` để lấy checklist.
|
|
13
|
+
|
|
14
|
+
### Bước 2 — Parallel Security Scan
|
|
15
|
+
|
|
16
|
+
Launch các agents ĐỒNG THỜI dựa theo stack:
|
|
17
|
+
|
|
18
|
+
**Agent 1 — `security-reviewer`** (luôn chạy):
|
|
19
|
+
> Security audit [scope].
|
|
20
|
+
> Đọc `.claude/rules/common/security.md`.
|
|
21
|
+
> Kiểm tra OWASP Top 10: injection, broken auth, XSS, IDOR, security misconfiguration,
|
|
22
|
+
> sensitive data exposure, insecure deserialization, vulnerable components, logging/monitoring.
|
|
23
|
+
> Kiểm tra thêm: hardcoded secrets, CORS config, anti-forgery tokens, rate limiting.
|
|
24
|
+
> Format: findings theo Critical / High / Medium / Low với file:line và remediation cụ thể.
|
|
25
|
+
> Mỗi finding có: status = Open.
|
|
26
|
+
|
|
27
|
+
**Agent 2 — `database-reviewer`** (chỉ khi `db_agent = database-reviewer`):
|
|
28
|
+
> Database security review [scope].
|
|
29
|
+
> Tập trung: parameterized queries vs string concatenation, ORM raw query usage,
|
|
30
|
+
> sensitive data stored in plaintext, missing field-level encryption, excessive permissions.
|
|
31
|
+
> Format: findings theo Critical / High / Medium / Low với file:line và remediation.
|
|
32
|
+
|
|
33
|
+
**Agent 3 — `aws-reviewer`** (chỉ khi `infra_agent = aws-reviewer`):
|
|
34
|
+
> AWS infrastructure security review [scope].
|
|
35
|
+
> Tập trung: IAM overpermission, S3 public access, secrets trong env/config/code,
|
|
36
|
+
> Lambda environment variables, API Gateway auth, VPC security groups.
|
|
37
|
+
> Format: findings theo Critical / High / Medium / Low với file:line và remediation.
|
|
38
|
+
|
|
39
|
+
Chờ TẤT CẢ agents hoàn thành.
|
|
40
|
+
|
|
41
|
+
### Bước 3 — Tổng hợp và lưu báo cáo
|
|
42
|
+
|
|
43
|
+
Gộp findings từ tất cả agents, deduplicate (cùng file:line → gộp), sort theo severity.
|
|
44
|
+
|
|
45
|
+
Kiểm tra `docs/security-report.md`:
|
|
46
|
+
- **Chưa có**: tạo mới theo template `.tas/templates/Security-Report.md`
|
|
47
|
+
- **Đã có**: append report mới, cập nhật status findings cũ nếu đã được fix
|
|
48
|
+
|
|
49
|
+
Nội dung report bao gồm:
|
|
50
|
+
- Scan date, scope, stack
|
|
51
|
+
- Findings theo Critical / High / Medium / Low
|
|
52
|
+
- Mỗi finding: file:line, mô tả, remediation, status (Open / Fixed / Accepted Risk)
|
|
53
|
+
- Summary: tổng số findings mỗi severity, số đã fix vs còn open
|
|
54
|
+
|
|
55
|
+
### Bước 4 — Cập nhật project-status.yaml
|
|
56
|
+
|
|
57
|
+
```yaml
|
|
58
|
+
artifacts:
|
|
59
|
+
security_report:
|
|
60
|
+
file: docs/security-report.md
|
|
61
|
+
status: [Critical findings present | Clean]
|
|
62
|
+
last_updated: [ngày hôm nay]
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### Bước 5 — Hành động tiếp theo
|
|
66
|
+
|
|
67
|
+
Nếu có **Critical findings**:
|
|
68
|
+
→ Liệt kê rõ, yêu cầu fix ngay trước khi deploy bất kỳ môi trường nào.
|
|
69
|
+
|
|
70
|
+
Nếu có **High findings**:
|
|
71
|
+
→ Liệt kê, khuyến nghị fix trước khi merge vào main.
|
|
72
|
+
|
|
73
|
+
Nếu chỉ có **Medium/Low**:
|
|
74
|
+
→ Tóm tắt, gợi ý fix theo thứ tự ưu tiên.
|
|
75
|
+
|
|
76
|
+
## Nguyên tắc
|
|
77
|
+
- Phân loại: Critical / High / Medium / Low
|
|
78
|
+
- Mỗi finding phải có recommended fix cụ thể
|
|
79
|
+
- Finding có status: Open | In Progress | Fixed | Accepted Risk
|
|
80
|
+
- KHÔNG hardcode fix — đề xuất remediation pattern, không viết code thay thế
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# /tas-spec $ARGUMENTS
|
|
2
|
+
|
|
3
|
+
Tạo lightweight spec trước khi code — cho solo dev, prototype, spike, internal tool.
|
|
4
|
+
Khác với `/tas-fix`: có spec document, phù hợp task > 2 giờ hoặc cần track AC.
|
|
5
|
+
|
|
6
|
+
## Steps
|
|
7
|
+
|
|
8
|
+
### 1 — Thu thập thông tin
|
|
9
|
+
`$ARGUMENTS` là mô tả task. Nếu chưa đủ rõ, hỏi tối đa 3 câu:
|
|
10
|
+
- **Goal**: Build cái gì? Giải quyết vấn đề gì?
|
|
11
|
+
- **AC**: Done trông như thế nào? (2-5 criteria cụ thể, testable)
|
|
12
|
+
- **Constraints**: Tech constraints, out of scope?
|
|
13
|
+
|
|
14
|
+
Không hỏi nếu $ARGUMENTS đã đủ rõ.
|
|
15
|
+
|
|
16
|
+
### 2 — Tạo SPEC.md
|
|
17
|
+
Tạo file `SPEC.md` ở project root:
|
|
18
|
+
|
|
19
|
+
```markdown
|
|
20
|
+
# {Title}
|
|
21
|
+
> {one-line summary}
|
|
22
|
+
|
|
23
|
+
**Status:** Draft | **Date:** {today}
|
|
24
|
+
|
|
25
|
+
## Goal
|
|
26
|
+
{Vấn đề cần giải quyết — không phải solution}
|
|
27
|
+
|
|
28
|
+
## Acceptance Criteria
|
|
29
|
+
- [ ] {Given/When/Then hoặc testable statement}
|
|
30
|
+
- [ ] ...
|
|
31
|
+
|
|
32
|
+
## Out of Scope
|
|
33
|
+
- {Gì sẽ không làm}
|
|
34
|
+
|
|
35
|
+
## Constraints
|
|
36
|
+
{Tech constraints, patterns phải follow — bỏ qua nếu không có}
|
|
37
|
+
|
|
38
|
+
## Open Questions
|
|
39
|
+
{Câu hỏi chưa có câu trả lời — bỏ qua nếu không có}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### 3 — Next step
|
|
43
|
+
> "SPEC.md đã tạo.
|
|
44
|
+
> - Plan kỹ hơn: `/tas-plan SPEC.md`
|
|
45
|
+
> - Code ngay: `/tas-dev` (cần `require_plan: false` trong tas.yaml)"
|
|
46
|
+
|
|
47
|
+
## Principles
|
|
48
|
+
- SPEC.md là single source of truth — không tạo thêm file khác
|
|
49
|
+
- Giữ ngắn: mục tiêu < 1 trang
|
|
50
|
+
- AC > 8 items hoặc task > 1 ngày → gợi ý dùng `/tas-story` thay thế
|
|
@@ -1,50 +1,87 @@
|
|
|
1
|
-
|
|
1
|
+
# /tas-story $ARGUMENTS
|
|
2
2
|
|
|
3
3
|
Vai trò: PE - Product Engineer
|
|
4
4
|
Tạo mới hoặc cập nhật User Story document.
|
|
5
5
|
|
|
6
|
+
**Phạm vi:** Nghiệp vụ, trải nghiệm người dùng, acceptance criteria, test cases.
|
|
7
|
+
**Không thuộc phạm vi:** Kỹ thuật implement, files cần sửa, database schema — đó là việc của `/tas-plan`.
|
|
8
|
+
|
|
9
|
+
## Always / Ask / Never
|
|
10
|
+
|
|
11
|
+
| | Hành động |
|
|
12
|
+
|---|---|
|
|
13
|
+
| **Always** | Viết AC dạng Given/When/Then |
|
|
14
|
+
| **Always** | Set `plan_status: pending` cho Story mới |
|
|
15
|
+
| **Ask** | Khi Story > 8h — gợi ý tách nhỏ |
|
|
16
|
+
| **Never** | Đọc SAD, ADR — kỹ thuật là việc của `/tas-plan` |
|
|
17
|
+
|
|
6
18
|
## Prerequisite
|
|
7
19
|
- Ít nhất một Feature phải tồn tại
|
|
8
20
|
|
|
9
21
|
## Hành động
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
22
|
+
|
|
23
|
+
### Chế độ CREATE ($ARGUMENTS là mô tả Story mới, hoặc không có $ARGUMENTS)
|
|
24
|
+
|
|
25
|
+
**Bước 1 — Xác định Feature**
|
|
26
|
+
- Đọc `project.code` từ root/`tas.yaml`
|
|
27
|
+
- Ưu tiên theo thứ tự:
|
|
28
|
+
1. Nếu `$ARGUMENTS` chứa Feature ID → dùng luôn
|
|
29
|
+
2. Nếu context có `parent_id` → dùng luôn
|
|
30
|
+
3. Hỏi user: "Story này thuộc Feature nào?" — không quét thư mục
|
|
31
|
+
|
|
32
|
+
**Bước 2 — Thu thập context nghiệp vụ**
|
|
33
|
+
- Đọc file Feature đã xác định (lấy business context, scope, danh sách Stories hiện có)
|
|
34
|
+
- Đọc PRD (nếu có) — chỉ lấy business requirements, user goals
|
|
35
|
+
|
|
36
|
+
**Bước 3 — Xác định Story ID**
|
|
37
|
+
- Đọc section Stories trong Feature file → xác định index tiếp theo từ danh sách đó
|
|
38
|
+
- KHÔNG quét thư mục
|
|
39
|
+
|
|
40
|
+
**Bước 4 — Soạn Story với user**
|
|
41
|
+
|
|
42
|
+
Thảo luận để điền đầy đủ:
|
|
43
|
+
|
|
44
|
+
a) **User Story**: "As a [role], I want [goal], so that [benefit]"
|
|
45
|
+
|
|
46
|
+
b) **Business Requirements** (nếu có): business rules đặc thù, constraints từ stakeholders
|
|
47
|
+
|
|
48
|
+
c) **Design Notes** (nếu có): UI/UX specs, mockup links, flow diagrams
|
|
49
|
+
|
|
50
|
+
d) **Prerequisites** (nếu có): Stories khác phải done trước
|
|
51
|
+
|
|
52
|
+
e) **Acceptance Criteria**: mỗi AC một kịch bản Given/When/Then rõ ràng
|
|
53
|
+
|
|
54
|
+
**Bước 5 — Test Case Prompting**
|
|
55
|
+
|
|
56
|
+
Sau khi AC được xác nhận, hỏi thêm:
|
|
57
|
+
- "Ngoài happy path, có edge case nào cần test không?" (input rỗng, giá trị biên, concurrent)
|
|
58
|
+
- "Có negative case nào cần cover?" (unauthorized, invalid data, timeout, not found)
|
|
59
|
+
- "Có external dependency nào cần mock khi test?" (API bên ngoài, database state)
|
|
60
|
+
|
|
61
|
+
Ghi tất cả vào section `## Unit Test Cases`.
|
|
62
|
+
|
|
63
|
+
**Bước 6 — Tạo file**
|
|
64
|
+
- Đọc `.tas/templates/Story.md` để lấy format
|
|
65
|
+
- Tạo `docs/epics/{code}-Epic-{NNN}-{slug}/{code}-Feature-{NNN}-{slug}/{code}-Story-{NNN}-{slug}.md`
|
|
66
|
+
- Frontmatter: `plan_status: pending`, `plan_date:` để trống
|
|
67
|
+
|
|
68
|
+
**Bước 7 — Cập nhật project-status.yaml**
|
|
69
|
+
Theo `.claude/rules/common/project-status.md` — thêm entry vào `epics.{EPIC_ID}.features.{FEATURE_ID}.stories`.
|
|
70
|
+
|
|
71
|
+
**Bước 8 — Thông báo next step**
|
|
72
|
+
> "Story đã tạo. Trước khi SE bắt đầu code, cần chạy `/tas-plan {Story-ID}` để lập kế hoạch kỹ thuật."
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
### Chế độ UPDATE ($ARGUMENTS là Story ID, ví dụ: "Story-005")
|
|
77
|
+
|
|
78
|
+
1. Tìm file qua glob `docs/epics/**/{code}-Story-{ID}-*.md`
|
|
79
|
+
2. Đọc file Story hiện tại
|
|
80
|
+
3. Hỏi user cần thay đổi gì (cập nhật AC, đổi status, thêm test cases, sửa business rule...)
|
|
81
|
+
4. Cập nhật file, thêm entry vào Changelog
|
|
82
|
+
5. Cập nhật `project-status.yaml` theo `.claude/rules/common/project-status.md`.
|
|
43
83
|
|
|
44
84
|
## Nguyên tắc
|
|
45
|
-
- Story phải nhỏ
|
|
46
|
-
-
|
|
47
|
-
-
|
|
48
|
-
- Chỉ nhúng thông tin liên quan, không dư thừa - linh hoạt theo từng Story
|
|
49
|
-
- Unit Test Cases PHẢI cover: happy path, edge cases, negative cases
|
|
50
|
-
- Story status: New -> Committed -> In Progress -> Deploy Test -> Verify Test -> Deploy Stag -> Verify Stag -> Deploy Prod | Verify Prod -> Done
|
|
85
|
+
- Story phải đủ nhỏ để hoàn thành trong **4-8 giờ**; nếu lớn hơn → tách thành nhiều Stories
|
|
86
|
+
- Story file = **product artifact**: mô tả *what* và *why*, không phải *how*
|
|
87
|
+
- Story status: New → Committed → In Progress → Deploy Test → Verify Test → Deploy Stag → Verify Stag → Deploy Prod → Verify Prod → Done
|
|
@@ -14,6 +14,14 @@ Verify Feature trên môi trường Staging (Phase 2).
|
|
|
14
14
|
4. Cần context từ file Feature hiện tại (đặc biệt section Integration Test Cases và E2E Test Cases)
|
|
15
15
|
|
|
16
16
|
### Workflow verify:
|
|
17
|
+
4.5. **Launch `e2e-runner`** (nếu Feature có E2E / Acceptance Test Cases):
|
|
18
|
+
> E2E verification cho Feature {ID}.
|
|
19
|
+
> Đọc section `## E2E / Acceptance Test Cases` từ Feature file — list từng test case.
|
|
20
|
+
> Chạy các test cases đó, báo cáo kết quả: Pass/Fail per test case với lý do nếu Fail.
|
|
21
|
+
> Không tự động fix lỗi — chỉ báo cáo kết quả để PE xác nhận.
|
|
22
|
+
|
|
23
|
+
Dùng kết quả từ `e2e-runner` làm input cho bước 5.
|
|
24
|
+
|
|
17
25
|
5. Hiển thị checklist từ 2 section test trong Feature:
|
|
18
26
|
a. **Integration Test Cases**: Liệt kê từng test case, hỏi PE kết quả (Pass/Fail)
|
|
19
27
|
b. **E2E / Acceptance Test Cases**: Liệt kê từng test case, hỏi PE kết quả (Pass/Fail)
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* PostToolUse Hook: Auto format/lint source files after Write/Edit/MultiEdit
|
|
4
|
+
*
|
|
5
|
+
* Detects file extension and runs the appropriate formatter using project-local tools:
|
|
6
|
+
* .ts/.tsx/.js/.jsx → prettier (via npx/yarn)
|
|
7
|
+
* .py → ruff format (preferred) or black
|
|
8
|
+
* .cs → dotnet format --include <file>
|
|
9
|
+
*
|
|
10
|
+
* Uses project-local binaries only — never installs packages globally.
|
|
11
|
+
* Silently skips if the tool is not installed in the project.
|
|
12
|
+
*
|
|
13
|
+
* Hook input (stdin): JSON with tool_input.file_path
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
'use strict';
|
|
17
|
+
|
|
18
|
+
const fs = require('fs');
|
|
19
|
+
const path = require('path');
|
|
20
|
+
const { execSync } = require('child_process');
|
|
21
|
+
|
|
22
|
+
// --- Read hook input ---
|
|
23
|
+
let input;
|
|
24
|
+
try {
|
|
25
|
+
const raw = fs.readFileSync('/dev/stdin', 'utf8');
|
|
26
|
+
input = JSON.parse(raw);
|
|
27
|
+
} catch {
|
|
28
|
+
process.exit(0);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const filePath = (input.tool_input || {}).file_path || '';
|
|
32
|
+
if (!filePath) process.exit(0);
|
|
33
|
+
|
|
34
|
+
const ext = path.extname(filePath).toLowerCase();
|
|
35
|
+
const fileName = path.basename(filePath);
|
|
36
|
+
|
|
37
|
+
// Skip non-source files (markdown, yaml, json config, etc.)
|
|
38
|
+
const SOURCE_EXTS = new Set(['.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs', '.py', '.cs']);
|
|
39
|
+
if (!SOURCE_EXTS.has(ext)) process.exit(0);
|
|
40
|
+
|
|
41
|
+
// --- Helper: run command, return true on success ---
|
|
42
|
+
function run(cmd, cwd) {
|
|
43
|
+
try {
|
|
44
|
+
execSync(cmd, { cwd, stdio: 'pipe' });
|
|
45
|
+
return true;
|
|
46
|
+
} catch {
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// --- Helper: find repo root (where package.json / pyproject.toml / *.sln lives) ---
|
|
52
|
+
function findRoot(startDir, markers) {
|
|
53
|
+
let dir = path.resolve(startDir);
|
|
54
|
+
for (let i = 0; i < 10; i++) {
|
|
55
|
+
if (markers.some(m => fs.existsSync(path.join(dir, m)))) return dir;
|
|
56
|
+
const parent = path.dirname(dir);
|
|
57
|
+
if (parent === dir) break;
|
|
58
|
+
dir = parent;
|
|
59
|
+
}
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// ─── TypeScript / JavaScript ─────────────────────────────────────────────────
|
|
64
|
+
if (['.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs'].includes(ext)) {
|
|
65
|
+
const root = findRoot(path.dirname(filePath), ['package.json']);
|
|
66
|
+
if (!root) process.exit(0);
|
|
67
|
+
|
|
68
|
+
const pkg = path.join(root, 'package.json');
|
|
69
|
+
let hasScript = false;
|
|
70
|
+
try {
|
|
71
|
+
const pkgJson = JSON.parse(fs.readFileSync(pkg, 'utf8'));
|
|
72
|
+
hasScript = !!(pkgJson.scripts && pkgJson.scripts.format);
|
|
73
|
+
} catch { /* ignore */ }
|
|
74
|
+
|
|
75
|
+
// Prefer project format script → npx prettier → yarn prettier
|
|
76
|
+
const formatted =
|
|
77
|
+
(hasScript && run(`npm run format -- --write "${filePath}"`, root)) ||
|
|
78
|
+
run(`npx --no-install prettier --write "${filePath}"`, root) ||
|
|
79
|
+
run(`yarn prettier --write "${filePath}"`, root);
|
|
80
|
+
|
|
81
|
+
if (formatted) {
|
|
82
|
+
console.log(`[Format] ${fileName}`);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// ─── Python ──────────────────────────────────────────────────────────────────
|
|
87
|
+
else if (ext === '.py') {
|
|
88
|
+
const root = findRoot(path.dirname(filePath), ['pyproject.toml', 'setup.py', 'setup.cfg', 'requirements.txt']);
|
|
89
|
+
const cwd = root || path.dirname(filePath);
|
|
90
|
+
|
|
91
|
+
const formatted =
|
|
92
|
+
run(`ruff format "${filePath}"`, cwd) ||
|
|
93
|
+
run(`python -m ruff format "${filePath}"`, cwd) ||
|
|
94
|
+
run(`black "${filePath}"`, cwd) ||
|
|
95
|
+
run(`python -m black "${filePath}"`, cwd);
|
|
96
|
+
|
|
97
|
+
if (formatted) {
|
|
98
|
+
console.log(`[Format] ${fileName}`);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// ─── C# ──────────────────────────────────────────────────────────────────────
|
|
103
|
+
else if (ext === '.cs') {
|
|
104
|
+
// Find nearest .csproj
|
|
105
|
+
function findCsproj(startDir) {
|
|
106
|
+
let dir = path.resolve(startDir);
|
|
107
|
+
for (let i = 0; i < 8; i++) {
|
|
108
|
+
const files = fs.readdirSync(dir).filter(f => f.endsWith('.csproj'));
|
|
109
|
+
if (files.length > 0) return { cwd: dir, proj: path.join(dir, files[0]) };
|
|
110
|
+
const parent = path.dirname(dir);
|
|
111
|
+
if (parent === dir) break;
|
|
112
|
+
dir = parent;
|
|
113
|
+
}
|
|
114
|
+
return null;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const result = findCsproj(path.dirname(filePath));
|
|
118
|
+
if (!result) process.exit(0);
|
|
119
|
+
|
|
120
|
+
const formatted = run(
|
|
121
|
+
`dotnet format "${result.proj}" --include "${filePath}" --no-restore`,
|
|
122
|
+
result.cwd
|
|
123
|
+
);
|
|
124
|
+
if (formatted) {
|
|
125
|
+
console.log(`[Format] ${fileName}`);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Stop Hook: End-of-session verification
|
|
4
|
+
*
|
|
5
|
+
* Runs when Claude Code session ends. Performs:
|
|
6
|
+
* 1. Auto-detects test runner and runs the test suite
|
|
7
|
+
* 2. Checks if project-status.yaml was updated today
|
|
8
|
+
* 3. Prints a summary of pass/fail checks
|
|
9
|
+
*
|
|
10
|
+
* Designed to be non-blocking — all failures are reported as warnings,
|
|
11
|
+
* not hard errors, so the session can still end cleanly.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
'use strict';
|
|
15
|
+
|
|
16
|
+
const fs = require('fs');
|
|
17
|
+
const path = require('path');
|
|
18
|
+
const { execSync } = require('child_process');
|
|
19
|
+
|
|
20
|
+
const checks = [];
|
|
21
|
+
|
|
22
|
+
// --- Helper: run command, return { ok, output } ---
|
|
23
|
+
function run(cmd, cwd) {
|
|
24
|
+
try {
|
|
25
|
+
const output = execSync(cmd, { cwd, stdio: 'pipe', timeout: 60_000 }).toString();
|
|
26
|
+
return { ok: true, output };
|
|
27
|
+
} catch (err) {
|
|
28
|
+
return { ok: false, output: (err.stderr || err.stdout || err.message || '').toString() };
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// --- Find repo root (cwd of the session) ---
|
|
33
|
+
const cwd = process.cwd();
|
|
34
|
+
|
|
35
|
+
// ─── 1. Run test suite ────────────────────────────────────────────────────────
|
|
36
|
+
let testRan = false;
|
|
37
|
+
|
|
38
|
+
// Node.js / npm
|
|
39
|
+
if (fs.existsSync(path.join(cwd, 'package.json'))) {
|
|
40
|
+
let hasTestScript = false;
|
|
41
|
+
try {
|
|
42
|
+
const pkg = JSON.parse(fs.readFileSync(path.join(cwd, 'package.json'), 'utf8'));
|
|
43
|
+
hasTestScript = !!(pkg.scripts && pkg.scripts.test &&
|
|
44
|
+
pkg.scripts.test !== 'echo "Error: no test specified" && exit 1');
|
|
45
|
+
} catch { /* ignore */ }
|
|
46
|
+
|
|
47
|
+
if (hasTestScript) {
|
|
48
|
+
const result = run('npm test -- --passWithNoTests 2>&1', cwd);
|
|
49
|
+
checks.push(result.ok
|
|
50
|
+
? '✓ Tests passed (npm test)'
|
|
51
|
+
: '✗ Tests FAILED (npm test) — fix before committing'
|
|
52
|
+
);
|
|
53
|
+
testRan = true;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// .NET
|
|
58
|
+
if (!testRan) {
|
|
59
|
+
const csprojFiles = (() => {
|
|
60
|
+
try {
|
|
61
|
+
return fs.readdirSync(cwd).filter(f => f.endsWith('.csproj') || f.endsWith('.sln'));
|
|
62
|
+
} catch { return []; }
|
|
63
|
+
})();
|
|
64
|
+
|
|
65
|
+
if (csprojFiles.length > 0) {
|
|
66
|
+
const result = run('dotnet test --no-build --logger "console;verbosity=minimal" 2>&1', cwd);
|
|
67
|
+
checks.push(result.ok
|
|
68
|
+
? '✓ Tests passed (dotnet test)'
|
|
69
|
+
: '✗ Tests FAILED (dotnet test) — fix before committing'
|
|
70
|
+
);
|
|
71
|
+
testRan = true;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Python (pytest)
|
|
76
|
+
if (!testRan) {
|
|
77
|
+
const hasPytest =
|
|
78
|
+
fs.existsSync(path.join(cwd, 'pytest.ini')) ||
|
|
79
|
+
fs.existsSync(path.join(cwd, 'pyproject.toml')) ||
|
|
80
|
+
fs.existsSync(path.join(cwd, 'setup.cfg'));
|
|
81
|
+
|
|
82
|
+
if (hasPytest) {
|
|
83
|
+
const result = run('python -m pytest -q --tb=no 2>&1', cwd);
|
|
84
|
+
checks.push(result.ok
|
|
85
|
+
? '✓ Tests passed (pytest)'
|
|
86
|
+
: '✗ Tests FAILED (pytest) — fix before committing'
|
|
87
|
+
);
|
|
88
|
+
testRan = true;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// ─── 2. Check project-status.yaml updated today ──────────────────────────────
|
|
93
|
+
const statusFile = path.join(cwd, 'project-status.yaml');
|
|
94
|
+
if (fs.existsSync(statusFile)) {
|
|
95
|
+
const today = new Date().toISOString().split('T')[0]; // YYYY-MM-DD
|
|
96
|
+
try {
|
|
97
|
+
const content = fs.readFileSync(statusFile, 'utf8');
|
|
98
|
+
if (content.includes(today)) {
|
|
99
|
+
checks.push('✓ project-status.yaml updated today');
|
|
100
|
+
} else {
|
|
101
|
+
checks.push('⚠ project-status.yaml not updated today — run /tas-status to sync');
|
|
102
|
+
}
|
|
103
|
+
} catch {
|
|
104
|
+
checks.push('⚠ Could not read project-status.yaml');
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// ─── 3. Remind about story status ────────────────────────────────────────────
|
|
109
|
+
checks.push('→ Next: /tas-review-code before moving story to Deploy Test');
|
|
110
|
+
|
|
111
|
+
// ─── Output ──────────────────────────────────────────────────────────────────
|
|
112
|
+
if (checks.length > 0) {
|
|
113
|
+
console.log('\n[TAS] Session end checks:');
|
|
114
|
+
checks.forEach(c => console.log(' ' + c));
|
|
115
|
+
console.log('');
|
|
116
|
+
}
|
|
File without changes
|