@educa-corp/sdd-framework 0.4.2 → 0.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/bin/build.js +113 -19
- package/bin/gate-trace.js +464 -0
- package/bin/index.js +418 -146
- package/bin/lint-trace.js +602 -0
- package/bin/self-check.js +499 -6
- package/bin/trace-schema.json +1449 -692
- package/commands/debug.md +123 -510
- package/commands/debug.tmpl +3 -0
- package/commands/define-product.md +86 -509
- package/commands/dev-gen-test.md +120 -516
- package/commands/dev-run-test.md +120 -516
- package/commands/dev-smoke-test.md +86 -509
- package/commands/extend-prd.md +486 -0
- package/commands/extend-prd.tmpl +273 -0
- package/commands/fix-bug.md +152 -515
- package/commands/generate-architecture.md +94 -514
- package/commands/generate-architecture.tmpl +3 -0
- package/commands/generate-bdd.md +138 -519
- package/commands/generate-bdd.tmpl +18 -3
- package/commands/generate-code.md +156 -523
- package/commands/generate-code.tmpl +36 -7
- package/commands/generate-design-spec.md +86 -509
- package/commands/generate-prd.md +114 -509
- package/commands/generate-prd.tmpl +28 -0
- package/commands/generate-spec-manifest.md +86 -509
- package/commands/generate-tech-docs.md +86 -509
- package/commands/learn.md +172 -495
- package/commands/learn.tmpl +70 -3
- package/commands/map-testids.md +86 -509
- package/commands/propose-scenario.md +136 -508
- package/commands/propose-scenario.tmpl +52 -1
- package/commands/qc-analyze.md +86 -509
- package/commands/qc-design-test.md +87 -509
- package/commands/qc-design-test.tmpl +1 -0
- package/commands/qc-plan.md +86 -509
- package/commands/qc-report.md +86 -509
- package/commands/qc-review.md +86 -509
- package/commands/qc-run-test.md +133 -517
- package/commands/qc-run-test.tmpl +13 -1
- package/commands/refine-prd.md +99 -519
- package/commands/refine-prd.tmpl +3 -0
- package/commands/report-bug.md +86 -509
- package/commands/review-code.md +127 -513
- package/commands/review-code.tmpl +7 -3
- package/commands/review-context.md +96 -515
- package/commands/review-context.tmpl +6 -2
- package/commands/review-tech-docs.md +90 -510
- package/commands/review-tech-docs.tmpl +3 -0
- package/commands/setup-ai-first.md +166 -137
- package/commands/setup-ai-first.tmpl +72 -0
- package/commands/sync.md +86 -118
- package/commands/sync.tmpl +84 -16
- package/commands/update-framework.md +16 -102
- package/commands/update-framework.tmpl +14 -0
- package/commands/validate-traces.md +458 -531
- package/commands/validate-traces.tmpl +381 -31
- package/core/FRAMEWORK_VERSION +1 -1
- package/core/README.md +20 -0
- package/core/commands/debug.md +123 -510
- package/core/commands/define-product.md +86 -509
- package/core/commands/dev-gen-test.md +120 -516
- package/core/commands/dev-run-test.md +120 -516
- package/core/commands/dev-smoke-test.md +86 -509
- package/core/commands/extend-prd.md +486 -0
- package/core/commands/fix-bug.md +152 -515
- package/core/commands/generate-architecture.md +94 -514
- package/core/commands/generate-bdd.md +138 -519
- package/core/commands/generate-code.md +156 -523
- package/core/commands/generate-design-spec.md +86 -509
- package/core/commands/generate-prd.md +114 -509
- package/core/commands/generate-spec-manifest.md +86 -509
- package/core/commands/generate-tech-docs.md +86 -509
- package/core/commands/learn.md +172 -495
- package/core/commands/map-testids.md +86 -509
- package/core/commands/propose-scenario.md +136 -508
- package/core/commands/qc-analyze.md +86 -509
- package/core/commands/qc-design-test.md +87 -509
- package/core/commands/qc-plan.md +86 -509
- package/core/commands/qc-report.md +86 -509
- package/core/commands/qc-review.md +86 -509
- package/core/commands/qc-run-test.md +133 -517
- package/core/commands/refine-prd.md +99 -519
- package/core/commands/report-bug.md +86 -509
- package/core/commands/review-code.md +127 -513
- package/core/commands/review-context.md +96 -515
- package/core/commands/review-tech-docs.md +90 -510
- package/core/commands/setup-ai-first.md +166 -137
- package/core/commands/sync.md +86 -118
- package/core/commands/update-framework.md +16 -102
- package/core/commands/validate-traces.md +458 -531
- package/core/hooks/data-guard.js +174 -83
- package/core/hooks/settings.json +2 -1
- package/core/rules/workflow.md +48 -4
- package/core/steps/capture-lesson.md +34 -1
- package/core/steps/context-loader.md +24 -3
- package/core/steps/gate.md +92 -35
- package/core/steps/report-footer.md +26 -2
- package/core/steps/trace-mirror.md +34 -7
- package/core/templates/README.md +24 -1
- package/core/templates/ci/trace-gate.yml +146 -0
- package/core/templates/feature.template +1 -1
- package/core/templates/hooks/pre-push +61 -0
- package/docs/01-getting-started/installation.md +18 -1
- package/docs/01-getting-started/what-is-sdd.md +4 -2
- package/docs/02-concepts/architecture.md +48 -5
- package/docs/02-concepts/pipeline-steps/02-specification.md +39 -3
- package/docs/02-concepts/pipeline-steps/04-bdd.md +24 -2
- package/docs/02-concepts/pipeline-steps/05-tech-docs.md +18 -1
- package/docs/02-concepts/pipeline-steps/06-code.md +35 -4
- package/docs/02-concepts/pipeline-steps/09-validate-traces.md +137 -12
- package/docs/02-concepts/pipeline-steps/10-feedback-loop.md +59 -3
- package/docs/02-concepts/roles-and-hitl.md +1 -1
- package/docs/02-concepts/traceability.md +183 -117
- package/docs/03-guides/architect.md +63 -0
- package/docs/03-guides/developer.md +20 -4
- package/docs/03-guides/product-owner.md +72 -68
- package/docs/03-guides/tester-qa.md +81 -70
- package/docs/04-reference/commands.md +134 -105
- package/docs/04-reference/configuration.md +146 -94
- package/docs/04-reference/model-selection.md +32 -19
- package/docs/04-reference/trace-schema.md +26 -9
- package/docs/explain/02-generate-prd.md +80 -78
- package/docs/explain/02b-extend-prd.md +125 -0
- package/docs/explain/03-refine-prd.md +86 -86
- package/docs/explain/04-review-context.md +18 -1
- package/docs/explain/06-generate-bdd.md +23 -0
- package/docs/explain/08-review-tech-docs.md +20 -5
- package/docs/explain/10-review-code.md +36 -2
- package/docs/explain/19-qc-run-test.md +87 -67
- package/docs/explain/21-validate-traces.md +75 -68
- package/docs/explain/23-fix-bug.md +19 -3
- package/docs/explain/26-propose-scenario.md +70 -63
- package/docs/explain/27-learn.md +5 -3
- package/docs/explain/README.md +135 -134
- package/hooks/data-guard.js +174 -83
- package/hooks/settings.json +2 -1
- package/package.json +53 -50
- package/rules/workflow.md +48 -4
- package/steps/capture-lesson.md +34 -1
- package/steps/context-loader.md +24 -3
- package/steps/gate.md +92 -35
- package/steps/report-footer.md +26 -2
- package/steps/trace-mirror.md +34 -7
- package/templates/README.md +24 -1
- package/templates/ci/trace-gate.yml +146 -0
- package/templates/feature.template +1 -1
- package/templates/hooks/pre-push +61 -0
- package/scripts/init.sh +0 -49
- package/scripts/upgrade.sh +0 -94
package/docs/explain/README.md
CHANGED
|
@@ -1,134 +1,135 @@
|
|
|
1
|
-
# 🔬 Explain — Giải phẫu từng command (Command Deep-Dive)
|
|
2
|
-
|
|
3
|
-
> Tài liệu **đi sâu vào bên trong** từng command của pipeline, theo đúng thứ tự thực thi. Mục tiêu: làm **cơ sở review, phân tích và tối ưu** các bước trong pipeline.
|
|
4
|
-
>
|
|
5
|
-
> Khác với [Pipeline Steps](../02-concepts/pipeline-steps/) (tầng khái niệm, gom theo phase), thư mục này bám **logic thực tế trong command file** (`commands/*.md`) — từng bước command làm gì, giải quyết vấn đề gì, và **điểm nào đáng cân nhắc tối ưu**.
|
|
6
|
-
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
## Cách đọc (How to read)
|
|
10
|
-
|
|
11
|
-
Mỗi trang command theo cùng một khuôn:
|
|
12
|
-
|
|
13
|
-
| Mục | Nội dung |
|
|
14
|
-
|-----|----------|
|
|
15
|
-
| **Một câu** | Command làm gì |
|
|
16
|
-
| **Vấn đề giải quyết** | Tại sao command này tồn tại |
|
|
17
|
-
| **Vị trí & tiền đề** | Chạy sau gì, cần gì mở khoá |
|
|
18
|
-
| **Input / Output** | Đầu vào & sản phẩm cụ thể |
|
|
19
|
-
| **Các bước xử lý** | ⭐ Đi từng bước bên trong, dễ hiểu |
|
|
20
|
-
| **Checkpoint & Gate** | Điểm dừng con người |
|
|
21
|
-
| **Cơ chế đặc biệt** | Phần logic riêng đáng chú ý |
|
|
22
|
-
| **👓 Góc nhìn tối ưu** | Điểm review/optimize: chi phí, rủi ro, phụ thuộc |
|
|
23
|
-
| **Kết nối** | Bước trước ← → bước sau |
|
|
24
|
-
|
|
25
|
-
---
|
|
26
|
-
|
|
27
|
-
## ⭐ Bộ khung chung mọi command (Shared Skeleton)
|
|
28
|
-
|
|
29
|
-
**Đọc phần này trước.** Mọi command file được build từ `.tmpl` + `{{include:steps/*.md}}`, nên đều có **cùng một bộ khung** bao quanh logic riêng. Hiểu bộ khung một lần → các trang command chỉ cần nói phần **riêng**.
|
|
30
|
-
|
|
31
|
-
Cấu trúc một command file:
|
|
32
|
-
|
|
33
|
-
```
|
|
34
|
-
┌─ Gate (steps/gate) ──────────── chung, giống hệt mọi lệnh
|
|
35
|
-
├─ Context Loader (steps/context-loader) ── chung, 7 bước
|
|
36
|
-
├─ Business Language Guard (steps/business-language) ── chung, chỉ lệnh viết doc nghiệp vụ
|
|
37
|
-
├─ ★ LOGIC RIÊNG CỦA LỆNH ★ ──── phần mỗi trang explain tập trung
|
|
38
|
-
└─ Report Footer (steps/report-footer) ── chung
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
### 1 · Gate — Cổng vào chuẩn (5 bước con)
|
|
42
|
-
|
|
43
|
-
Chạy **trước** mọi logic riêng:
|
|
44
|
-
|
|
45
|
-
| Bước | Tên | Việc | Ý nghĩa tối ưu |
|
|
46
|
-
|------|-----|------|----------------|
|
|
47
|
-
| 0 | **Sub-agent mode** | Nếu `$ARGUMENTS` là JSON có `_agent_mode` → bỏ Gate 1/2/3, chạy đúng phạm vi orchestrator giao (target_file, uc_id, uc_section, dimension) | Cơ chế fan-out per-UC dùng chính lệnh này làm "worker" |
|
|
48
|
-
| 0-B | **Model check** | Khuyến nghị Opus. `Y`=tiếp · `S`=bỏ qua (⚠️ report) · khác=DỪNG | Checkpoint mềm; sub-agent bỏ qua (orchestrator đã check) |
|
|
49
|
-
| 1 | **Target file** | Phân giải file mục tiêu từ path / UC-ID / ticket bằng glob theo bố cục feature-package; nhiều kết quả → hỏi | Điểm hay tốn 1 vòng hỏi khi `$ARGUMENTS` rỗng |
|
|
50
|
-
| 2 | **Context loader** | Chạy 7 bước nạp context (mục 2 dưới) | Nơi quyết định "đúng-đủ-gọn" — trọng tâm tối ưu |
|
|
51
|
-
| 3 | **CHECKPOINT** | Trình target + scope → chờ `Y` | Read-only command bỏ qua |
|
|
52
|
-
|
|
53
|
-
### 2 · Context Loader — "Thủ thư" (7 bước)
|
|
54
|
-
|
|
55
|
-
Nạp context theo thứ tự chống Lost-in-the-Middle (đầu = "build gì", giữa = ràng buộc, cuối = "follow style này"):
|
|
56
|
-
|
|
57
|
-
| Bước | Nạp gì | Ghi chú |
|
|
58
|
-
|------|--------|---------|
|
|
59
|
-
| 1 | **project-context.yaml** | tech_stack, conventions, domains, paths; trích `domain`/`prd_slug` từ path target |
|
|
60
|
-
| 1.5 | **Service routing** (umbrella) | Khớp domain → service; dạng phẳng (2a) hay map-theo-platform (2b); override paths sang `spec_source` |
|
|
61
|
-
| 1.6 | **Service conventions** (umbrella) | Nạp `build_command`/`test_command` riêng của service; set `service_root` |
|
|
62
|
-
| 2 | **Module stack-profile** | `.agent/modules/{module}/stack-profile.yaml` — layer/test pattern |
|
|
63
|
-
| 3 | **CLAUDE.md phân tầng** | root (BASE) + service overlay (stack) — **overlay thắng**; §2 layer/package, §3 naming, §5 error |
|
|
64
|
-
| 4 | **data-protection** | Pattern file nhạy cảm — cấm truy cập cả phiên |
|
|
65
|
-
| 5 | **Business dictionary** | Canonical + **banned terms** (thực thi chủ động) + enum registry |
|
|
66
|
-
| 6 | **Core entities** | Entity catalog + field registry + relationship map |
|
|
67
|
-
| 6.5 | **platform_type** | Suy `backend`/`web-frontend`/`mobile` từ module |
|
|
68
|
-
| 6.7 | **Project lessons** | Guardrail từ `/learn` — ràng buộc cứng ngang coding standards |
|
|
69
|
-
| 7 | **Recap** | In khối `[CTX LOADED]` — đẩy sự thật quan trọng lên cuối bộ nhớ |
|
|
70
|
-
|
|
71
|
-
> 👓 **Đây là component quyết định 80% chất lượng.** Khi review tối ưu: chú ý `required` vs `optional`, filter theo domain, và budget context (~50% window).
|
|
72
|
-
|
|
73
|
-
### 3 · Business Language Guard (chỉ lệnh viết doc nghiệp vụ)
|
|
74
|
-
|
|
75
|
-
Chặn thuật ngữ kỹ thuật rò vào PRD/BDD/product-definition. 4 nhóm xử lý: (1) tương tác/UI → diễn đạt lại nghiệp vụ · (2) visual thuần → chuyển Design Spec · (3) backend/contract → bỏ về Tech Docs · (4) ẩn dụ dữ liệu → xét ngữ cảnh (không thay máy móc). Áp cho `/define-product`, `/generate-prd`, `/refine-prd`, `/review-context`, `/generate-bdd`.
|
|
76
|
-
|
|
77
|
-
### 4 · Report Footer (mọi lệnh)
|
|
78
|
-
|
|
79
|
-
Kết thúc bằng: **Status badge** (✅/❌/⚠️) · **Output Artifacts** (file tạo/sửa) · **Pipeline Position** (`◀ bạn ở đây`) · **Next command** (gợi ý lệnh kế + tham số).
|
|
80
|
-
|
|
81
|
-
---
|
|
82
|
-
|
|
83
|
-
## Danh sách command theo thứ tự pipeline (Pipeline Order)
|
|
84
|
-
|
|
85
|
-
### Phase Setup & Discovery
|
|
86
|
-
- [00 · `/setup-ai-first`](00-setup-ai-first.md)
|
|
87
|
-
- [00b · `/generate-architecture`](00b-generate-architecture.md)
|
|
88
|
-
- [01 · `/define-product`](01-define-product.md)
|
|
89
|
-
|
|
90
|
-
### Phase Specification (PRD)
|
|
91
|
-
- [02 · `/generate-prd`](02-generate-prd.md)
|
|
92
|
-
- [
|
|
93
|
-
- [
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
- [
|
|
98
|
-
- [
|
|
99
|
-
- [
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
- [
|
|
104
|
-
- [
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
- [
|
|
109
|
-
- [
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
- [
|
|
114
|
-
- [
|
|
115
|
-
- [
|
|
116
|
-
- [
|
|
117
|
-
- [
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
- [
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
- [
|
|
126
|
-
- [
|
|
127
|
-
- [
|
|
128
|
-
- [
|
|
129
|
-
- [
|
|
130
|
-
- [
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
1
|
+
# 🔬 Explain — Giải phẫu từng command (Command Deep-Dive)
|
|
2
|
+
|
|
3
|
+
> Tài liệu **đi sâu vào bên trong** từng command của pipeline, theo đúng thứ tự thực thi. Mục tiêu: làm **cơ sở review, phân tích và tối ưu** các bước trong pipeline.
|
|
4
|
+
>
|
|
5
|
+
> Khác với [Pipeline Steps](../02-concepts/pipeline-steps/) (tầng khái niệm, gom theo phase), thư mục này bám **logic thực tế trong command file** (`commands/*.md`) — từng bước command làm gì, giải quyết vấn đề gì, và **điểm nào đáng cân nhắc tối ưu**.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Cách đọc (How to read)
|
|
10
|
+
|
|
11
|
+
Mỗi trang command theo cùng một khuôn:
|
|
12
|
+
|
|
13
|
+
| Mục | Nội dung |
|
|
14
|
+
|-----|----------|
|
|
15
|
+
| **Một câu** | Command làm gì |
|
|
16
|
+
| **Vấn đề giải quyết** | Tại sao command này tồn tại |
|
|
17
|
+
| **Vị trí & tiền đề** | Chạy sau gì, cần gì mở khoá |
|
|
18
|
+
| **Input / Output** | Đầu vào & sản phẩm cụ thể |
|
|
19
|
+
| **Các bước xử lý** | ⭐ Đi từng bước bên trong, dễ hiểu |
|
|
20
|
+
| **Checkpoint & Gate** | Điểm dừng con người |
|
|
21
|
+
| **Cơ chế đặc biệt** | Phần logic riêng đáng chú ý |
|
|
22
|
+
| **👓 Góc nhìn tối ưu** | Điểm review/optimize: chi phí, rủi ro, phụ thuộc |
|
|
23
|
+
| **Kết nối** | Bước trước ← → bước sau |
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## ⭐ Bộ khung chung mọi command (Shared Skeleton)
|
|
28
|
+
|
|
29
|
+
**Đọc phần này trước.** Mọi command file được build từ `.tmpl` + `{{include:steps/*.md}}`, nên đều có **cùng một bộ khung** bao quanh logic riêng. Hiểu bộ khung một lần → các trang command chỉ cần nói phần **riêng**.
|
|
30
|
+
|
|
31
|
+
Cấu trúc một command file:
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
┌─ Gate (steps/gate) ──────────── chung, giống hệt mọi lệnh
|
|
35
|
+
├─ Context Loader (steps/context-loader) ── chung, 7 bước
|
|
36
|
+
├─ Business Language Guard (steps/business-language) ── chung, chỉ lệnh viết doc nghiệp vụ
|
|
37
|
+
├─ ★ LOGIC RIÊNG CỦA LỆNH ★ ──── phần mỗi trang explain tập trung
|
|
38
|
+
└─ Report Footer (steps/report-footer) ── chung
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### 1 · Gate — Cổng vào chuẩn (5 bước con)
|
|
42
|
+
|
|
43
|
+
Chạy **trước** mọi logic riêng:
|
|
44
|
+
|
|
45
|
+
| Bước | Tên | Việc | Ý nghĩa tối ưu |
|
|
46
|
+
|------|-----|------|----------------|
|
|
47
|
+
| 0 | **Sub-agent mode** | Nếu `$ARGUMENTS` là JSON có `_agent_mode` → bỏ Gate 1/2/3, chạy đúng phạm vi orchestrator giao (target_file, uc_id, uc_section, dimension) | Cơ chế fan-out per-UC dùng chính lệnh này làm "worker" |
|
|
48
|
+
| 0-B | **Model check** | Khuyến nghị Opus. `Y`=tiếp · `S`=bỏ qua (⚠️ report) · khác=DỪNG | Checkpoint mềm; sub-agent bỏ qua (orchestrator đã check) |
|
|
49
|
+
| 1 | **Target file** | Phân giải file mục tiêu từ path / UC-ID / ticket bằng glob theo bố cục feature-package; nhiều kết quả → hỏi | Điểm hay tốn 1 vòng hỏi khi `$ARGUMENTS` rỗng |
|
|
50
|
+
| 2 | **Context loader** | Chạy 7 bước nạp context (mục 2 dưới) | Nơi quyết định "đúng-đủ-gọn" — trọng tâm tối ưu |
|
|
51
|
+
| 3 | **CHECKPOINT** | Trình target + scope → chờ `Y` | Read-only command bỏ qua |
|
|
52
|
+
|
|
53
|
+
### 2 · Context Loader — "Thủ thư" (7 bước)
|
|
54
|
+
|
|
55
|
+
Nạp context theo thứ tự chống Lost-in-the-Middle (đầu = "build gì", giữa = ràng buộc, cuối = "follow style này"):
|
|
56
|
+
|
|
57
|
+
| Bước | Nạp gì | Ghi chú |
|
|
58
|
+
|------|--------|---------|
|
|
59
|
+
| 1 | **project-context.yaml** | tech_stack, conventions, domains, paths; trích `domain`/`prd_slug` từ path target |
|
|
60
|
+
| 1.5 | **Service routing** (umbrella) | Khớp domain → service; dạng phẳng (2a) hay map-theo-platform (2b); override paths sang `spec_source` |
|
|
61
|
+
| 1.6 | **Service conventions** (umbrella) | Nạp `build_command`/`test_command` riêng của service; set `service_root` |
|
|
62
|
+
| 2 | **Module stack-profile** | `.agent/modules/{module}/stack-profile.yaml` — layer/test pattern |
|
|
63
|
+
| 3 | **CLAUDE.md phân tầng** | root (BASE) + service overlay (stack) — **overlay thắng**; §2 layer/package, §3 naming, §5 error |
|
|
64
|
+
| 4 | **data-protection** | Pattern file nhạy cảm — cấm truy cập cả phiên |
|
|
65
|
+
| 5 | **Business dictionary** | Canonical + **banned terms** (thực thi chủ động) + enum registry |
|
|
66
|
+
| 6 | **Core entities** | Entity catalog + field registry + relationship map |
|
|
67
|
+
| 6.5 | **platform_type** | Suy `backend`/`web-frontend`/`mobile` từ module |
|
|
68
|
+
| 6.7 | **Project lessons** | Guardrail từ `/learn` — ràng buộc cứng ngang coding standards |
|
|
69
|
+
| 7 | **Recap** | In khối `[CTX LOADED]` — đẩy sự thật quan trọng lên cuối bộ nhớ |
|
|
70
|
+
|
|
71
|
+
> 👓 **Đây là component quyết định 80% chất lượng.** Khi review tối ưu: chú ý `required` vs `optional`, filter theo domain, và budget context (~50% window).
|
|
72
|
+
|
|
73
|
+
### 3 · Business Language Guard (chỉ lệnh viết doc nghiệp vụ)
|
|
74
|
+
|
|
75
|
+
Chặn thuật ngữ kỹ thuật rò vào PRD/BDD/product-definition. 4 nhóm xử lý: (1) tương tác/UI → diễn đạt lại nghiệp vụ · (2) visual thuần → chuyển Design Spec · (3) backend/contract → bỏ về Tech Docs · (4) ẩn dụ dữ liệu → xét ngữ cảnh (không thay máy móc). Áp cho `/define-product`, `/generate-prd`, `/refine-prd`, `/review-context`, `/generate-bdd`.
|
|
76
|
+
|
|
77
|
+
### 4 · Report Footer (mọi lệnh)
|
|
78
|
+
|
|
79
|
+
Kết thúc bằng: **Status badge** (✅/❌/⚠️) · **Output Artifacts** (file tạo/sửa) · **Pipeline Position** (`◀ bạn ở đây`) · **Next command** (gợi ý lệnh kế + tham số).
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## Danh sách command theo thứ tự pipeline (Pipeline Order)
|
|
84
|
+
|
|
85
|
+
### Phase Setup & Discovery
|
|
86
|
+
- [00 · `/setup-ai-first`](00-setup-ai-first.md)
|
|
87
|
+
- [00b · `/generate-architecture`](00b-generate-architecture.md)
|
|
88
|
+
- [01 · `/define-product`](01-define-product.md)
|
|
89
|
+
|
|
90
|
+
### Phase Specification (PRD)
|
|
91
|
+
- [02 · `/generate-prd`](02-generate-prd.md)
|
|
92
|
+
- [02b · `/extend-prd`](02b-extend-prd.md) — thêm yêu cầu vào PRD **đã duyệt**
|
|
93
|
+
- [03 · `/refine-prd`](03-refine-prd.md)
|
|
94
|
+
- [04 · `/review-context`](04-review-context.md) *(dùng cho cả PRD & BDD)*
|
|
95
|
+
|
|
96
|
+
### Phase Design
|
|
97
|
+
- [05 · `/generate-design-spec`](05-generate-design-spec.md)
|
|
98
|
+
- [06 · `/generate-bdd`](06-generate-bdd.md)
|
|
99
|
+
- [07 · `/generate-tech-docs`](07-generate-tech-docs.md)
|
|
100
|
+
- [08 · `/review-tech-docs`](08-review-tech-docs.md)
|
|
101
|
+
|
|
102
|
+
### Phase Implementation
|
|
103
|
+
- [09 · `/generate-code`](09-generate-code.md)
|
|
104
|
+
- [10 · `/review-code`](10-review-code.md)
|
|
105
|
+
- [11 · `/map-testids`](11-map-testids.md)
|
|
106
|
+
|
|
107
|
+
### Phase Dev Self-Test
|
|
108
|
+
- [12 · `/dev-gen-test`](12-dev-gen-test.md)
|
|
109
|
+
- [13 · `/dev-run-test`](13-dev-run-test.md)
|
|
110
|
+
- [14 · `/dev-smoke-test`](14-dev-smoke-test.md)
|
|
111
|
+
|
|
112
|
+
### Phase QC Automation
|
|
113
|
+
- [15 · `/qc-analyze`](15-qc-analyze.md)
|
|
114
|
+
- [16 · `/qc-plan`](16-qc-plan.md)
|
|
115
|
+
- [17 · `/qc-design-test`](17-qc-design-test.md)
|
|
116
|
+
- [18 · `/qc-review`](18-qc-review.md)
|
|
117
|
+
- [19 · `/qc-run-test`](19-qc-run-test.md)
|
|
118
|
+
- [20 · `/qc-report`](20-qc-report.md)
|
|
119
|
+
|
|
120
|
+
### Phase Trace & Quality
|
|
121
|
+
- [21 · `/validate-traces`](21-validate-traces.md)
|
|
122
|
+
- [22 · `/generate-spec-manifest`](22-generate-spec-manifest.md)
|
|
123
|
+
|
|
124
|
+
### Lệnh xuyên suốt (Cross-cutting)
|
|
125
|
+
- [23 · `/fix-bug`](23-fix-bug.md)
|
|
126
|
+
- [24 · `/debug`](24-debug.md)
|
|
127
|
+
- [25 · `/report-bug`](25-report-bug.md)
|
|
128
|
+
- [26 · `/propose-scenario`](26-propose-scenario.md)
|
|
129
|
+
- [27 · `/learn`](27-learn.md)
|
|
130
|
+
- [28 · `/sync`](28-sync.md)
|
|
131
|
+
- [29 · `/update-framework`](29-update-framework.md)
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
*Nguồn: `commands/*.md` (build từ `.tmpl` + `steps/`). Khi command đổi, cập nhật trang tương ứng ở đây.*
|
package/hooks/data-guard.js
CHANGED
|
@@ -2,28 +2,90 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* data-guard.js — Claude Code PreToolUse Hook
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
* sensitive files (credentials, secrets, private keys, .env, etc.)
|
|
5
|
+
* Chặn AI đọc/ghi/thực thi trên file nhạy cảm (credential, secret, private key, .env…).
|
|
7
6
|
*
|
|
8
|
-
*
|
|
9
|
-
* (
|
|
7
|
+
* Cài: copy vào project + đăng ký trong .claude/settings.json
|
|
8
|
+
* (mẫu: hooks/settings.json — hoặc dùng `npx @educa-corp/sdd-framework --hooks`)
|
|
10
9
|
*
|
|
11
|
-
* Exit
|
|
12
|
-
* 0 =
|
|
13
|
-
* 2 =
|
|
10
|
+
* Exit code:
|
|
11
|
+
* 0 = cho phép
|
|
12
|
+
* 2 = chặn cứng (Claude Code hiểu mã này là block)
|
|
13
|
+
*
|
|
14
|
+
* ── VÌ SAO BẢN NÀY KHÁC BẢN ĐẦU (GAPS-v3 G42) ────────────────────────────────
|
|
15
|
+
*
|
|
16
|
+
* Bản đầu có ba lỗi độc lập; hai trong số đó chặn đúng công việc mà framework tồn
|
|
17
|
+
* tại để làm, và cái còn lại làm lời hứa bảo mật không đúng:
|
|
18
|
+
*
|
|
19
|
+
* (a) matcher thiếu `Grep` — `Grep` với output_mode:"content" trên `.env` TRẢ VỀ
|
|
20
|
+
* nội dung file và không đi qua hook. Nên câu "AI will be blocked from reading
|
|
21
|
+
* .env" là sai.
|
|
22
|
+
* (b) pattern soi CẢ PATH, không neo. `/password/i` khớp
|
|
23
|
+
* `specs/auth/forgot-password/UC1.feature` và `src/auth/PasswordResetController.java`
|
|
24
|
+
* ⇒ một framework sinh code từ spec KHÔNG LÀM NỔI feature auth khi bật hook
|
|
25
|
+
* của chính nó.
|
|
26
|
+
* (c) Bash soi cả command string ⇒ `git commit -m "feat: password reset UC1"` bị
|
|
27
|
+
* chặn — đúng câu commit mà các lệnh hướng dẫn chạy ở cuối pipeline.
|
|
28
|
+
*
|
|
29
|
+
* Cả hai đường đều dẫn tới cùng một kết cục: người dùng TẮT HOOK, và mất luôn phần
|
|
30
|
+
* bảo vệ thật. Một guard bị tắt bảo vệ bằng không.
|
|
31
|
+
*
|
|
32
|
+
* ── MÔ HÌNH MỚI ──────────────────────────────────────────────────────────────
|
|
33
|
+
*
|
|
34
|
+
* Secret sống trong file CẤU HÌNH/DỮ LIỆU, không sống trong file MÃ NGUỒN.
|
|
35
|
+
* `secrets.json` là kho bí mật; `PasswordResetController.java` là code.
|
|
36
|
+
* Nên pattern chung (secret/credential/password/token/api-key) chỉ áp cho file
|
|
37
|
+
* KHÔNG phải mã nguồn. Pattern cứng (.env, .pem, .key…) áp cho mọi file.
|
|
38
|
+
* Cộng thêm allowlist thư mục làm việc của framework (specs/, .trace/, docs/…).
|
|
14
39
|
*/
|
|
15
40
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
//
|
|
41
|
+
// ── Thư mục làm việc của framework — không bao giờ chứa secret thật ───────────
|
|
42
|
+
// Tên feature ("forgot-password", "api-key-rotation") hay khớp pattern chung, và
|
|
43
|
+
// đây chính là chỗ ca (b) nổ. Cho qua TRƯỚC khi soi.
|
|
44
|
+
const SAFE_DIR_PREFIXES = [
|
|
45
|
+
'specs/', '.trace/', '.trace-mirror/', '.living-docs/',
|
|
46
|
+
'docs/', '.agent/', 'feedback/', '.claude/',
|
|
47
|
+
];
|
|
19
48
|
|
|
20
|
-
|
|
21
|
-
|
|
49
|
+
// ── Đuôi file MÃ NGUỒN — pattern chung không áp ───────────────────────────────
|
|
50
|
+
// Một file .java/.ts/.dart tên gì đi nữa cũng là code, không phải kho secret.
|
|
51
|
+
// (Pattern CỨNG bên dưới vẫn áp — nhưng .pem/.key không nằm trong danh sách này.)
|
|
52
|
+
const CODE_EXT = new Set([
|
|
53
|
+
'java', 'kt', 'kts', 'scala', 'groovy',
|
|
54
|
+
'ts', 'tsx', 'js', 'jsx', 'mjs', 'cjs', 'vue', 'svelte',
|
|
55
|
+
'py', 'go', 'rs', 'rb', 'php', 'cs', 'fs', 'vb',
|
|
56
|
+
'swift', 'm', 'mm', 'dart', 'c', 'h', 'cpp', 'hpp', 'cc',
|
|
57
|
+
'sql', 'graphql', 'proto', 'feature', 'md', 'mdx', 'txt',
|
|
58
|
+
'html', 'css', 'scss', 'less', 'tsv', 'csv',
|
|
59
|
+
]);
|
|
60
|
+
|
|
61
|
+
// ── Pattern CỨNG — áp cho mọi file, soi TÊN FILE ─────────────────────────────
|
|
62
|
+
const SENSITIVE_NAME_HARD = [
|
|
22
63
|
/^\.env$/i,
|
|
23
64
|
/^\.env\./i,
|
|
24
65
|
/\.env$/i,
|
|
25
66
|
|
|
26
|
-
|
|
67
|
+
/\.key$/i,
|
|
68
|
+
/\.pem$/i,
|
|
69
|
+
/\.p12$/i,
|
|
70
|
+
/\.pfx$/i,
|
|
71
|
+
/\.jks$/i,
|
|
72
|
+
/\.keystore$/i,
|
|
73
|
+
/^id_rsa$/i,
|
|
74
|
+
/^id_ed25519$/i,
|
|
75
|
+
|
|
76
|
+
/^application-(prod|production|staging)\.(yml|yaml|properties)$/i,
|
|
77
|
+
/^appsettings\.(Production|Staging)\.json$/i,
|
|
78
|
+
/^database\.yml$/i,
|
|
79
|
+
/^master\.key$/i,
|
|
80
|
+
/^oauth-private\.key$/i,
|
|
81
|
+
/^credentials$/i,
|
|
82
|
+
/^\.npmrc$/i,
|
|
83
|
+
/^\.pypirc$/i,
|
|
84
|
+
/^\.netrc$/i,
|
|
85
|
+
];
|
|
86
|
+
|
|
87
|
+
// ── Pattern CHUNG — chỉ áp cho file KHÔNG phải mã nguồn, soi TÊN FILE ────────
|
|
88
|
+
const SENSITIVE_NAME_SOFT = [
|
|
27
89
|
/secret/i,
|
|
28
90
|
/credential/i,
|
|
29
91
|
/password/i,
|
|
@@ -32,60 +94,84 @@ const SENSITIVE_PATH_PATTERNS = [
|
|
|
32
94
|
/api[_-]?key/i,
|
|
33
95
|
/access[_-]?token/i,
|
|
34
96
|
/auth[_-]?token/i,
|
|
97
|
+
];
|
|
35
98
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
// Framework-specific prod configs
|
|
45
|
-
/application-(prod|production|staging)\.(yml|yaml|properties)$/i,
|
|
46
|
-
/appsettings\.(Production|Staging)\.json$/i,
|
|
47
|
-
/database\.yml$/i,
|
|
48
|
-
/config\/master\.key$/i,
|
|
49
|
-
/storage\/oauth-private\.key$/i,
|
|
50
|
-
|
|
51
|
-
// Secret directories
|
|
52
|
-
/^secrets\//i,
|
|
53
|
-
/\/secrets\//i,
|
|
54
|
-
/^\.secrets\//i,
|
|
99
|
+
// ── Pattern THƯ MỤC — soi cả path ────────────────────────────────────────────
|
|
100
|
+
const SENSITIVE_DIR = [
|
|
101
|
+
/(^|\/)secrets?\//i,
|
|
102
|
+
/(^|\/)\.secrets?\//i,
|
|
103
|
+
/(^|\/)\.ssh\//i,
|
|
104
|
+
/(^|\/)\.aws\//i,
|
|
105
|
+
/(^|\/)\.gnupg\//i,
|
|
55
106
|
];
|
|
56
107
|
|
|
57
|
-
|
|
108
|
+
// ── Lệnh bash nguy hiểm bất kể path ──────────────────────────────────────────
|
|
109
|
+
const SENSITIVE_BASH = [
|
|
58
110
|
/\bprintenv\b/i,
|
|
59
|
-
/\benv\b
|
|
60
|
-
/
|
|
61
|
-
|
|
62
|
-
|
|
111
|
+
/\benv\b\s*(\||$)/i,
|
|
112
|
+
/kubectl\s+get\s+secrets?\b[^|]*-o\s*(yaml|json)/i,
|
|
113
|
+
/\baws\s+secretsmanager\s+get-secret-value/i,
|
|
114
|
+
/\bgcloud\s+secrets\s+versions\s+access/i,
|
|
115
|
+
/\bvault\s+(read|kv\s+get)\b/i,
|
|
116
|
+
// `docker inspect` KHÔNG chặn cả cụm (lệnh debug thường dùng) — chỉ chặn khi nó
|
|
117
|
+
// thực sự moi Env ra. Bản đầu chặn cả cụm và đó là ma sát không đổi lấy gì.
|
|
118
|
+
/docker\s+inspect[^|]*\.Config\.Env/i,
|
|
63
119
|
];
|
|
64
120
|
|
|
65
|
-
// ── Helpers
|
|
121
|
+
// ── Helpers ──────────────────────────────────────────────────────────────────
|
|
122
|
+
|
|
123
|
+
function normalize(p) {
|
|
124
|
+
return String(p).replace(/\\/g, '/').replace(/^\.\//, '');
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function extOf(base) {
|
|
128
|
+
const i = base.lastIndexOf('.');
|
|
129
|
+
return i > 0 ? base.slice(i + 1).toLowerCase() : '';
|
|
130
|
+
}
|
|
66
131
|
|
|
67
132
|
function isSensitivePath(filePath) {
|
|
68
133
|
if (!filePath) return false;
|
|
69
|
-
const
|
|
70
|
-
|
|
134
|
+
const p = normalize(filePath);
|
|
135
|
+
|
|
136
|
+
// Vùng làm việc của framework — spec/trace/doc không chứa secret thật, và tên
|
|
137
|
+
// feature ở đó hay khớp pattern chung. Bỏ cả tiền tố tuyệt đối trước khi so.
|
|
138
|
+
const relish = p.replace(/^([a-zA-Z]:)?\/+/, '');
|
|
139
|
+
if (SAFE_DIR_PREFIXES.some(d => relish.startsWith(d) || relish.includes('/' + d))) return false;
|
|
140
|
+
|
|
141
|
+
if (SENSITIVE_DIR.some(re => re.test(p))) return true;
|
|
142
|
+
|
|
143
|
+
const base = p.split('/').pop() || '';
|
|
144
|
+
if (SENSITIVE_NAME_HARD.some(re => re.test(base))) return true;
|
|
145
|
+
|
|
146
|
+
// Pattern chung: bỏ qua mã nguồn. Đây là chỗ bản đầu chặn PasswordResetController.java.
|
|
147
|
+
if (CODE_EXT.has(extOf(base))) return false;
|
|
148
|
+
return SENSITIVE_NAME_SOFT.some(re => re.test(base));
|
|
71
149
|
}
|
|
72
150
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
151
|
+
/**
|
|
152
|
+
* Tách các token TRÔNG GIỐNG PATH ra khỏi một command line.
|
|
153
|
+
* Bản đầu soi cả chuỗi lệnh nên `git commit -m "feat: password reset"` bị chặn.
|
|
154
|
+
*/
|
|
155
|
+
function pathishTokens(command) {
|
|
156
|
+
return String(command)
|
|
157
|
+
.split(/[\s;|&()<>]+/)
|
|
158
|
+
.map(t => t.replace(/^["']|["']$/g, ''))
|
|
159
|
+
.filter(t => t && !t.startsWith('-') && /[\/.]/.test(t) && !/^-{1,2}/.test(t));
|
|
76
160
|
}
|
|
77
161
|
|
|
78
|
-
function block(reason) {
|
|
79
|
-
console.error(`\n🔒 DATA GUARD — BLOCKED\n${reason}
|
|
80
|
-
console.error(
|
|
81
|
-
console.error('
|
|
162
|
+
function block(reason, detail) {
|
|
163
|
+
console.error(`\n🔒 DATA GUARD — BLOCKED\n${reason}`);
|
|
164
|
+
if (detail) console.error(detail);
|
|
165
|
+
console.error('\nCần giá trị cấu hình? Mô tả thứ bạn cần mà KHÔNG đưa secret thật;');
|
|
166
|
+
console.error('dùng placeholder trong code sinh ra.');
|
|
167
|
+
console.error('Nghĩ đây là chặn nhầm? Vùng specs/ .trace/ docs/ .agent/ luôn được cho qua,');
|
|
168
|
+
console.error('và file mã nguồn (.java/.ts/.dart…) không bị pattern chung đụng tới.\n');
|
|
82
169
|
process.exit(2);
|
|
83
170
|
}
|
|
84
171
|
|
|
85
|
-
// ── Main
|
|
172
|
+
// ── Main ─────────────────────────────────────────────────────────────────────
|
|
86
173
|
|
|
87
174
|
let rawInput = '';
|
|
88
|
-
|
|
89
175
|
process.stdin.setEncoding('utf8');
|
|
90
176
|
process.stdin.on('data', chunk => { rawInput += chunk; });
|
|
91
177
|
process.stdin.on('end', () => {
|
|
@@ -93,49 +179,54 @@ process.stdin.on('end', () => {
|
|
|
93
179
|
try {
|
|
94
180
|
input = JSON.parse(rawInput);
|
|
95
181
|
} catch {
|
|
96
|
-
//
|
|
182
|
+
// Fail-open CÓ CHỦ Ý: hook parse lỗi mà chặn hết thì làm cả project đứng máy.
|
|
183
|
+
// Nhưng không im lặng — im lặng là cách một guard chết mà không ai biết.
|
|
184
|
+
console.error('⚠️ data-guard: không parse được input hook — CHO QUA (fail-open).');
|
|
97
185
|
process.exit(0);
|
|
98
186
|
}
|
|
99
187
|
|
|
100
|
-
const
|
|
101
|
-
const
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
// ── Write tool ────────────────────────────────────────────────────────
|
|
112
|
-
if (toolName === 'Write') {
|
|
113
|
-
const filePath = toolInput.file_path || '';
|
|
114
|
-
if (isSensitivePath(filePath)) {
|
|
115
|
-
block(`Attempted to WRITE to sensitive file: ${filePath}`);
|
|
188
|
+
const tool = input.tool_name || '';
|
|
189
|
+
const arg = input.tool_input || {};
|
|
190
|
+
|
|
191
|
+
switch (tool) {
|
|
192
|
+
case 'Read':
|
|
193
|
+
case 'Write':
|
|
194
|
+
case 'Edit':
|
|
195
|
+
case 'NotebookEdit': {
|
|
196
|
+
const f = arg.file_path || arg.notebook_path || '';
|
|
197
|
+
if (isSensitivePath(f)) block(`Thao tác ${tool} trên file nhạy cảm: ${f}`);
|
|
198
|
+
break;
|
|
116
199
|
}
|
|
117
|
-
}
|
|
118
200
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
201
|
+
// Grep ĐỌC ĐƯỢC NỘI DUNG (output_mode: "content"). Thiếu nhánh này thì mọi thứ
|
|
202
|
+
// ở trên chỉ là cửa trước, còn cửa sau mở toang — chính là lỗi (a) của G42.
|
|
203
|
+
case 'Grep': {
|
|
204
|
+
const target = arg.path || '';
|
|
205
|
+
if (target && isSensitivePath(target)) {
|
|
206
|
+
block(`Grep nhắm vào path nhạy cảm: ${target}`);
|
|
207
|
+
}
|
|
208
|
+
if (arg.glob && isSensitivePath(String(arg.glob).replace(/\*/g, 'x'))) {
|
|
209
|
+
block(`Grep dùng glob nhắm vào file nhạy cảm: ${arg.glob}`);
|
|
210
|
+
}
|
|
211
|
+
// Đang đi TÌM chính chuỗi secret — chặn kèm lý do khác hẳn.
|
|
212
|
+
if (arg.pattern && /\b(BEGIN [A-Z ]*PRIVATE KEY|aws_secret_access_key|sk-[A-Za-z0-9]{16,})/i
|
|
213
|
+
.test(String(arg.pattern))) {
|
|
214
|
+
block(`Grep đang tìm chính giá trị bí mật: ${String(arg.pattern).slice(0, 40)}…`);
|
|
215
|
+
}
|
|
216
|
+
break;
|
|
124
217
|
}
|
|
125
|
-
}
|
|
126
218
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
219
|
+
case 'Bash': {
|
|
220
|
+
const cmd = arg.command || '';
|
|
221
|
+
if (SENSITIVE_BASH.some(re => re.test(cmd))) {
|
|
222
|
+
block(`Lệnh moi secret: ${cmd.slice(0, 120)}`);
|
|
223
|
+
}
|
|
224
|
+
// CHỈ soi token trông giống path — không soi cả chuỗi lệnh (lỗi (c) của G42).
|
|
225
|
+
const hit = pathishTokens(cmd).find(isSensitivePath);
|
|
226
|
+
if (hit) block(`Lệnh bash chạm file nhạy cảm: ${hit}`, ` (trong: ${cmd.slice(0, 120)})`);
|
|
227
|
+
break;
|
|
136
228
|
}
|
|
137
229
|
}
|
|
138
230
|
|
|
139
|
-
// Allow all other tool calls
|
|
140
231
|
process.exit(0);
|
|
141
232
|
});
|
package/hooks/settings.json
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"_comment": "Claude Code hook registration template. Copy this content into your project's .claude/settings.json",
|
|
3
|
+
"_matcher_note": "Grep BẮT BUỘC có trong matcher: Grep với output_mode:content ĐỌC ĐƯỢC nội dung file, nên thiếu nó thì việc chặn Read chỉ là cửa trước (GAPS-v3 G42a).",
|
|
3
4
|
"_docs": "https://docs.anthropic.com/claude/claude-code/hooks",
|
|
4
5
|
|
|
5
6
|
"hooks": {
|
|
6
7
|
"PreToolUse": [
|
|
7
8
|
{
|
|
8
|
-
"matcher": "Read|Write|Edit|Bash",
|
|
9
|
+
"matcher": "Read|Write|Edit|Grep|NotebookEdit|Bash",
|
|
9
10
|
"hooks": [
|
|
10
11
|
{
|
|
11
12
|
"type": "command",
|