@relipa/ai-flow-kit 0.1.7 → 0.1.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/bin/aiflow.js +12 -2
- package/custom/rules/project-conventions.md +1 -1
- package/custom/skills/aiflow-help/SKILL.md +27 -0
- package/custom/skills/review-plan/SKILL.md +1 -1
- package/custom/templates/memory/skeleton/MEMORY.md +1 -1
- package/custom/templates/shared/ak-ask-workflow.md +15 -0
- package/custom/templates/shared/create-spec-workflow.md +1 -1
- package/custom/templates/shared/create-testcase-workflow.md +1 -1
- package/custom/templates/shared/gate-workflow.md +1 -1
- package/custom/templates/tools/claude.md +4 -0
- package/custom/templates/tools/cursor.md +4 -0
- package/custom/templates/tools/gemini.md +4 -0
- package/docs/common/BA-Specs-Structure.md +86 -0
- package/docs/common/CHANGELOG.md +3 -2
- package/docs/common/Coding-Structure.md +179 -0
- package/docs/common/Docs-Management-Flow.md +222 -0
- package/docs/common/INDEX.md +37 -0
- package/docs/common/Memory-Architecture-v1.0.md +664 -0
- package/docs/common/Project-Structure.md +133 -0
- package/docs/common/Testing-Structure.md +124 -0
- package/docs/common/cli-reference.md +82 -28
- package/package.json +1 -1
- package/scripts/ask.js +141 -0
- package/scripts/create-score-excel.js +2 -4
- package/scripts/docs-branch.js +1 -1
- package/scripts/docs-repo.js +1 -1
- package/scripts/hooks/session-start.js +1 -1
- package/scripts/init.js +7 -1
- package/scripts/memory-store.js +1 -1
- package/scripts/memory.js +1 -1
- package/scripts/update.js +5 -1
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# Project Folder Structure
|
|
2
|
+
|
|
3
|
+
> Cấu trúc thư mục chuẩn cho toàn dự án PILOT — áp dụng cho tất cả role: BA, Dev, Tester, PM/BrSE.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Tổng quan
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
{Root}/ ← Thư mục mở bằng VSCode, có thể chứa nhiều source repo
|
|
11
|
+
├── {Source-Repo}/ ← Source code (GitLab repo)
|
|
12
|
+
│
|
|
13
|
+
├── AK-Docs/ ← Tài liệu dự án (GitLab repo riêng)
|
|
14
|
+
│ ├── 00.Project-Overview/
|
|
15
|
+
│ ├── 01.QnA/
|
|
16
|
+
│ ├── 02.BA-Specs/
|
|
17
|
+
│ ├── 03.Testing/
|
|
18
|
+
│ └── 04.Coding/
|
|
19
|
+
│
|
|
20
|
+
└── Shared-Docs/ ← Template dùng chung cho TẤT CẢ dự án (GitLab repo riêng)
|
|
21
|
+
├── Spec-Templates/
|
|
22
|
+
├── QA-Templates/
|
|
23
|
+
├── Testcase-Templates/
|
|
24
|
+
└── Test-Report-Templates/
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
> **Tự động đồng bộ:** Mỗi lần chạy `ak init` hoặc `ak update`, tool sẽ tự kiểm tra `AK-Docs/` và `Shared-Docs/` cạnh source repo — nếu đã tồn tại (và là git repo) sẽ tự `git pull` để lấy bản mới nhất, nếu chưa có sẽ cảnh báo (warning) để bạn clone thủ công.
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## Chi tiết — `AK-Docs/`
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
AK-Docs/
|
|
35
|
+
│
|
|
36
|
+
├── 00.Project-Overview/ ← PM / BrSE quản lý
|
|
37
|
+
│ ├── Project-Summary.md # Goals, scope, background, stack
|
|
38
|
+
│ ├── Function-List.md # F-ID | Feature | BA | Dev | Tester | Status
|
|
39
|
+
│ └── Team.md # Member, role, contact
|
|
40
|
+
│
|
|
41
|
+
├── 01.QnA/ ← Trao đổi với khách hàng (có comtor)
|
|
42
|
+
│ └── QnA-Log.md # 1 file duy nhất cho toàn dự án
|
|
43
|
+
│
|
|
44
|
+
├── 02.BA-Specs/ ← BA quản lý
|
|
45
|
+
│ ├── 00.Requirements/ # Requirements Gathering
|
|
46
|
+
│ ├── 01.Analysis/ # Gate 1: Business Analysis
|
|
47
|
+
│ ├── 02.QnA/ # Gate 2: Q&A nội bộ với stakeholder
|
|
48
|
+
│ ├── 03.UI-Prototypes/ # Gate 3: UI/UX Design
|
|
49
|
+
│ └── 04.UC-Specs/ # Gate 4: Final UC Specification
|
|
50
|
+
│
|
|
51
|
+
├── 03.Testing/ ← Tester quản lý
|
|
52
|
+
│ ├── 00.Strategies/ # Test strategy & approach
|
|
53
|
+
│ ├── 01.Testcases/ # Gate 2: Test cases per feature
|
|
54
|
+
│ ├── 02.Reports/ # Gate 4: Execution & regression reports
|
|
55
|
+
│ ├── 03.Test-Data/ # Test data: CSV, JSON, SQL fixtures
|
|
56
|
+
│ ├── 04.Evidence/ # Gate 3: Screenshots, videos, logs
|
|
57
|
+
│ ├── 05.Scripts/ # Playwright automation scripts
|
|
58
|
+
│ ├── 06.Bugs/ # Gate 3: Bug reports
|
|
59
|
+
│ └── 07.AI-Artifacts/ # AI working docs: Gate 1-2 outputs
|
|
60
|
+
│
|
|
61
|
+
└── 04.Coding/ ← Dev quản lý
|
|
62
|
+
├── 00.Overview/ # Tracker tổng: F-ID | Ticket | Dev | Gate | PR
|
|
63
|
+
├── 01.Requirements/ # Gate 1: AI phân tích ticket + source code
|
|
64
|
+
├── 02.Plans/ # Gate 2: TDD implementation plan
|
|
65
|
+
├── 03.TDD-Notes/ # Gate 3: Test list viết trước + notes
|
|
66
|
+
├── 04.Reviews/ # Gate 4: Self-review + impact analysis
|
|
67
|
+
└── 05.Pull-Requests/ # Gate 5: PR content + review checklist
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## Chi tiết — `Shared-Docs/`
|
|
73
|
+
|
|
74
|
+
> Repo dùng chung cho **TẤT CẢ dự án** — chỉ chứa template gốc, không chứa tài liệu của riêng dự án nào. Chỉ AI Testing Team mới có quyền chỉnh sửa.
|
|
75
|
+
|
|
76
|
+
| Thư mục | Nội dung |
|
|
77
|
+
|---|---|
|
|
78
|
+
| `Spec-Templates/` | Template UC Spec cho BA (Gate 1→4 của `create-spec` workflow) |
|
|
79
|
+
| `QA-Templates/` | Template chiến lược test, checklist review cho Tester |
|
|
80
|
+
| `Testcase-Templates/` | Template bộ Test Case (Gate 1→4 của `create-testcase` workflow) |
|
|
81
|
+
| `Test-Report-Templates/` | Template báo cáo thực thi test (execution report, regression report) |
|
|
82
|
+
|
|
83
|
+
Mỗi dự án khi cần tạo tài liệu mới (UC Spec, Test Case, Test Report...) sẽ copy template tương ứng từ `Shared-Docs/` về đúng thư mục trong `AK-Docs/` của dự án đó rồi điền nội dung.
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
## Quy tắc đặt tên
|
|
88
|
+
|
|
89
|
+
| Element | Convention | Ví dụ |
|
|
90
|
+
|---|---|---|
|
|
91
|
+
| Section folder | `{N}.{Pascal-Case}/` | `00.Requirements/`, `03.TDD-Notes/` |
|
|
92
|
+
| Feature folder | `F-{3-digit}_{Pascal-Case}/` | `F-001_User-Login/` |
|
|
93
|
+
| File có version | `{Pascal-Name}_v{N}.md` | `UC-Spec_v2.md` |
|
|
94
|
+
| File theo ticket | `TICKET-{ID}.md` | `TICKET-100.md` |
|
|
95
|
+
| File archive | `_archive/` subfolder | `04.UC-Specs/F-001/_archive/` |
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## Ai lưu tài liệu ở đâu, khi nào
|
|
100
|
+
|
|
101
|
+
| Vai trò | Lưu vào | Thời điểm |
|
|
102
|
+
|---|---|---|
|
|
103
|
+
| PM / BrSE | `00.Project-Overview/` | Đầu dự án + mỗi sprint |
|
|
104
|
+
| BA / PM / Comtor | `01.QnA/QnA-Log.md` | Khi có câu hỏi từ khách hàng |
|
|
105
|
+
| BA | `02.BA-Specs/` | Sau khi Gate 4 APPROVED |
|
|
106
|
+
| Tester | `03.Testing/` | Sau khi Gate 4 APPROVED |
|
|
107
|
+
| Dev | `04.Coding/` | Trước khi tạo Pull Request |
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
## Luồng tài liệu qua từng vai trò
|
|
112
|
+
|
|
113
|
+
```
|
|
114
|
+
PM tạo ticket (Backlog/Jira)
|
|
115
|
+
│
|
|
116
|
+
▼
|
|
117
|
+
[BA] ak use TICKET-123
|
|
118
|
+
→ 02.BA-Specs/ (Gate 1→4)
|
|
119
|
+
→ Thông báo Dev + Tester sau Gate 4 APPROVED
|
|
120
|
+
│
|
|
121
|
+
├──────────────────────────────────┐
|
|
122
|
+
▼ ▼
|
|
123
|
+
[Tester] Extension sidebar [Dev] ak use TICKET-123
|
|
124
|
+
→ 03.Testing/ (Gate 1→4) → 04.Coding/ (Gate 1→5)
|
|
125
|
+
│ │
|
|
126
|
+
└──────────────┬───────────────────┘
|
|
127
|
+
▼
|
|
128
|
+
Pull Request
|
|
129
|
+
link: UC Spec + Test Case + Dev Plan
|
|
130
|
+
│
|
|
131
|
+
▼
|
|
132
|
+
[PM] Gate 4 Tester → Go / No-Go
|
|
133
|
+
```
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
# Testing — Folder Structure
|
|
2
|
+
|
|
3
|
+
> **Managed by:** Tester
|
|
4
|
+
> **Organized by:** Output Type → Function-ID (Scripts: Repo → Function-ID)
|
|
5
|
+
> **Naming:** Function-ID format `F-001_User-Login`, Evidence by `TICKET-ID_Date`
|
|
6
|
+
> **Note:** Templates are managed in a separate shared repo.
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## Folder Tree
|
|
11
|
+
|
|
12
|
+
```
|
|
13
|
+
03.Testing/
|
|
14
|
+
│
|
|
15
|
+
├── 00.Strategies/ # Test strategy & approach (project-level)
|
|
16
|
+
│ ├── Overview.md
|
|
17
|
+
│ ├── Regression-Strategy.md
|
|
18
|
+
│ └── Execution-Strategy.md
|
|
19
|
+
│
|
|
20
|
+
├── 01.Testcases/ # Gate 2: Test cases per feature
|
|
21
|
+
│ └── F-001_User-Login/
|
|
22
|
+
│ ├── Testcase_v2.md # Current version
|
|
23
|
+
│ └── _archive/
|
|
24
|
+
│ └── Testcase_v1.md
|
|
25
|
+
│
|
|
26
|
+
├── 02.Reports/ # Gate 4: Execution & regression reports
|
|
27
|
+
│ ├── F-001_User-Login/
|
|
28
|
+
│ │ ├── TICKET-100/
|
|
29
|
+
│ │ │ ├── Execution-Report.md
|
|
30
|
+
│ │ │ └── Bug-Summary.md
|
|
31
|
+
│ │ └── TICKET-100_Retest/
|
|
32
|
+
│ │ └── Execution-Report.md
|
|
33
|
+
│ └── Regression/ # Regression runs per sprint
|
|
34
|
+
│ └── Sprint-01_Regression.md
|
|
35
|
+
│
|
|
36
|
+
├── 03.Test-Data/ # Test data: CSV, JSON, SQL fixtures
|
|
37
|
+
│ └── F-001_User-Login/
|
|
38
|
+
│ ├── Users.csv
|
|
39
|
+
│ └── Fixtures.sql
|
|
40
|
+
│
|
|
41
|
+
├── 04.Evidence/ # Gate 3: Screenshots, videos, logs per execution
|
|
42
|
+
│ └── F-001_User-Login/
|
|
43
|
+
│ ├── TICKET-100_2026-06-15/ # Ticket + date to identify execution round
|
|
44
|
+
│ │ ├── TC_001_PASS/
|
|
45
|
+
│ │ │ └── Screenshot.png
|
|
46
|
+
│ │ └── TC_002_FAIL/
|
|
47
|
+
│ │ ├── Screenshot.png
|
|
48
|
+
│ │ └── Video.mp4
|
|
49
|
+
│ └── TICKET-100_Retest_2026-06-18/
|
|
50
|
+
│ └── TC_002_PASS/
|
|
51
|
+
│ └── Screenshot.png
|
|
52
|
+
│
|
|
53
|
+
├── 05.Scripts/ # Playwright automation (by Repo → Feature)
|
|
54
|
+
│ ├── Repo1/ # e.g. frontend app
|
|
55
|
+
│ │ ├── playwright.config.ts # baseURL, browser config for this repo
|
|
56
|
+
│ │ └── F-001_User-Login/
|
|
57
|
+
│ │ └── Login.spec.ts
|
|
58
|
+
│ ├── Repo2/ # e.g. admin app
|
|
59
|
+
│ │ ├── playwright.config.ts
|
|
60
|
+
│ │ └── F-003_Admin-Panel/
|
|
61
|
+
│ │ └── Admin.spec.ts
|
|
62
|
+
│ └── Shared/ # Fixtures, helpers used across repos
|
|
63
|
+
│ ├── Fixtures.ts
|
|
64
|
+
│ └── Helpers.ts
|
|
65
|
+
│
|
|
66
|
+
├── 06.Bugs/ # Gate 3: Bug reports (AI draft on TC fail)
|
|
67
|
+
│ └── F-001_User-Login/
|
|
68
|
+
│ └── BUG-001_Login-Timeout.md
|
|
69
|
+
│
|
|
70
|
+
└── 07.AI-Artifacts/ # AI working docs: Gate 1-2 outputs
|
|
71
|
+
└── F-001_User-Login/
|
|
72
|
+
├── Gate1_Test-Analysis.md # Gate 1: scope, flows, risks
|
|
73
|
+
├── Gate2_QnA.md # Gate 2: Q&A clarification (internal)
|
|
74
|
+
└── Gate2_Coverage-Matrix.md # Gate 2: coverage matrix
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
## File Naming Convention
|
|
80
|
+
|
|
81
|
+
| Element | Convention | Example |
|
|
82
|
+
|---|---|---|
|
|
83
|
+
| Section folder | `{N}.{Pascal-Case}/` | `00.Strategies/`, `04.Evidence/` |
|
|
84
|
+
| Feature folder | `F-{3-digit}_{Pascal-Case}/` | `F-001_User-Login/` |
|
|
85
|
+
| Testcase file | `Testcase_v{N}.md` | `Testcase_v2.md` |
|
|
86
|
+
| Evidence folder | `TICKET-{ID}_{YYYY-MM-DD}/` | `TICKET-100_2026-06-15/` |
|
|
87
|
+
| Retest folder | `TICKET-{ID}_Retest_{YYYY-MM-DD}/` | `TICKET-100_Retest_2026-06-18/` |
|
|
88
|
+
| TC result folder | `TC_{ID}_{PASS\|FAIL}/` | `TC_001_PASS/` |
|
|
89
|
+
| Bug file | `BUG-{ID}_{Pascal-Description}.md` | `BUG-001_Login-Timeout.md` |
|
|
90
|
+
| Script config | `playwright.config.ts` | per Repo folder |
|
|
91
|
+
| Script file | `{Feature}.spec.ts` | `Login.spec.ts` |
|
|
92
|
+
| Archive folder | `_archive/` | inside feature folder |
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## Gate → Folder Mapping
|
|
97
|
+
|
|
98
|
+
### 1. Quy trình Tạo Test Case (`create-testcase`)
|
|
99
|
+
|
|
100
|
+
| Gate | Output | Folder |
|
|
101
|
+
|---|---|---|
|
|
102
|
+
| Gate 1 | Phân tích yêu cầu & Đánh giá rủi ro | `07.AI-Artifacts/[functionId]_01_Requirement_Analysis_Result.md` |
|
|
103
|
+
| Gate 2 | Xây dựng kịch bản (Scenarios) | `07.AI-Artifacts/[functionId]_02_Test_Scenarios_Result.md` |
|
|
104
|
+
| Gate 3 | Thiết kế Test Case chi tiết (Draft) | `07.AI-Artifacts/[functionId]_03_Test_Cases_Draft_Result.md` |
|
|
105
|
+
| Gate 4 | Review & Tối ưu hóa (TestCase chính thức) | `01.Testcases/[Feature]/[functionId]_TestCase.md` & `07.AI-Artifacts/[functionId]_04_Test_Cases_Final_Result.md` |
|
|
106
|
+
|
|
107
|
+
### 2. Quy trình Thực thi Test (`execute-test`)
|
|
108
|
+
|
|
109
|
+
| Gate | Output | Folder |
|
|
110
|
+
|---|---|---|
|
|
111
|
+
| Gate 1 | Chuẩn bị & Lập kế hoạch thực thi | (Console output / Work Plan) |
|
|
112
|
+
| Gate 2 | Đồng bộ kịch bản kiểm thử (Script Sync) | `05.Scripts/[Repo]/[Feature]/[Feature].spec.ts` |
|
|
113
|
+
| Gate 3 | Thực thi test & Thu thập evidence | `04.Evidence/[Feature]/[Ticket]_[Date]/` & `06.Bugs/[Feature]/` |
|
|
114
|
+
| Gate 4 | Báo cáo test & Log bug | `02.Reports/[Feature]/[Ticket]/Execution-Report.md` |
|
|
115
|
+
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
## Rules
|
|
119
|
+
|
|
120
|
+
- Không tự sửa template — template nằm trong shared repo riêng
|
|
121
|
+
- Lưu testcase và kết quả lên GitLab **sau khi Gate 4 được APPROVED**
|
|
122
|
+
- Khi retest: tạo subfolder `TICKET-XXX_Retest_Date/` mới trong Evidence — không ghi đè cũ
|
|
123
|
+
- `05.Scripts/` chỉ chứa `.spec.ts` và `playwright.config.ts` — không chứa testcase `.md`
|
|
124
|
+
- `07.AI-Artifacts/` là working docs của AI — không phải tài liệu chính thức
|
|
@@ -24,15 +24,16 @@ ak <alias> --help # Also works with aliases
|
|
|
24
24
|
| `ak guide` | `ak g` | `ak remove` | `ak rm` |
|
|
25
25
|
| `ak update` | `ak up` | `ak sync-skills` | `ak sync` |
|
|
26
26
|
| `ak doctor` | `ak dr` | `ak telemetry` | `ak tel` |
|
|
27
|
+
| `ak ask` | `ak ask` | | |
|
|
27
28
|
|
|
28
29
|
| `task` sub-command | Short | `memory` sub-command | Short |
|
|
29
30
|
|---|---|---|---|
|
|
30
|
-
| `ak t status` | `ak t st` | `ak mem
|
|
31
|
-
| `ak t list` | `ak t ls` | `ak mem
|
|
32
|
-
| `ak t pause` | `ak t p` | `ak mem
|
|
33
|
-
| `ak t switch` | `ak t sw` | `ak mem
|
|
34
|
-
| `ak t resume` | `ak t r` |
|
|
35
|
-
| `ak t reset` | `ak t rst` |
|
|
31
|
+
| `ak t status` | `ak t st` | `ak mem draft` | `ak mem d` |
|
|
32
|
+
| `ak t list` | `ak t ls` | `ak mem list` | `ak mem ls` |
|
|
33
|
+
| `ak t pause` | `ak t p` | `ak mem submit` | `ak mem sb` |
|
|
34
|
+
| `ak t switch` | `ak t sw` | `ak mem remove` | `ak mem rm` |
|
|
35
|
+
| `ak t resume` | `ak t r` | | |
|
|
36
|
+
| `ak t reset` | `ak t rst` | | |
|
|
36
37
|
| `ak t remove` | `ak t rm` | | |
|
|
37
38
|
| `ak t next` | `ak t n` | | |
|
|
38
39
|
|
|
@@ -588,39 +589,53 @@ ak tel flush # force-send buffered events now
|
|
|
588
589
|
|
|
589
590
|
## memory (alias: `mem`)
|
|
590
591
|
|
|
591
|
-
Manage team knowledge
|
|
592
|
+
Manage the `99.Memory/` Project Brain — a git-based, human-approved team knowledge base living inside `AK-Docs/99.Memory/`. AI (or you) drafts a memory locally, then submits it as a Merge Request for a teammate/PM to approve. See `docs/common/Memory-Architecture-v1.0.md` for the full design.
|
|
593
|
+
|
|
594
|
+
> **Note:** This replaces the older `.aiflow/memory/` JSON store (`save/get/search/delete/clear`) retired in v0.1.7 — that command set no longer exists.
|
|
592
595
|
|
|
593
596
|
```bash
|
|
594
|
-
ak mem s
|
|
595
|
-
ak mem
|
|
596
|
-
ak mem ls
|
|
597
|
-
ak mem
|
|
598
|
-
ak mem
|
|
599
|
-
ak mem cl # clear all (memory clear)
|
|
597
|
+
ak mem d -c 01.Lessons/dev -s prevent-429-error --content "Retry with backoff on 429 from payment gateway" -t payment,retry
|
|
598
|
+
ak mem ls # list local pending drafts (memory list)
|
|
599
|
+
ak mem ls -a # list team-approved memories (--approved)
|
|
600
|
+
ak mem sb 01.Lessons/dev/prevent-429-error.md -t "Add memory: prevent-429-error" # submit a draft (memory submit)
|
|
601
|
+
ak mem rm 01.Lessons/dev/prevent-429-error.md -t "Remove stale memory" --reason "no longer applies" # (memory remove)
|
|
600
602
|
```
|
|
601
603
|
|
|
602
604
|
**Sub-commands (with aliases):**
|
|
603
|
-
- `
|
|
604
|
-
-
|
|
605
|
-
-
|
|
606
|
-
-
|
|
607
|
-
-
|
|
608
|
-
-
|
|
605
|
+
- `draft|d --category <cat> --slug <slug> --content <text> [options]` — Create a local memory draft in `_pending/` (not yet shared with the team)
|
|
606
|
+
- `-c, --category <cat>` — e.g. `00.Shared/architecture`, `01.Lessons/dev`, `02.Instincts/approved`
|
|
607
|
+
- `-s, --slug <slug>` — short kebab-case name, e.g. `prevent-429-error`
|
|
608
|
+
- `--content <text>` — memory body (≤150 words, 1 fact)
|
|
609
|
+
- `-f, --function-id <id>` — functionId this memory is scoped to (omit for a global/cross-project fact)
|
|
610
|
+
- `--scope <scope>` — alternative to `--function-id` for flat categories (glossary/decisions)
|
|
611
|
+
- `-t, --tags <list>` — comma-separated tags the scorer matches on
|
|
612
|
+
- `-w, --workflows <list>` — comma-separated workflows (coding, create-spec, create-testcase, gen-doc, all)
|
|
613
|
+
- `--source <text>` — ticket/Gate this was learned from
|
|
614
|
+
- `--confidence <n>` — AI self-rated 0.3–0.7 (default 0.5)
|
|
615
|
+
- `list|ls [-a, --approved]` — List local pending drafts, or team-approved memories with `--approved`
|
|
616
|
+
- `submit|sb <path> --title <title> [-d <desc>] [-y]` — Move a pending draft (path from `ak mem list`) to its destination in `AK-Docs/99.Memory/` and open a Merge Request
|
|
617
|
+
- `remove|rm <path> --title <title> [--reason <text>] [--hard] [-y]` — Propose removing an approved memory (path from `ak mem list --approved`); soft-remove moves it to `_deprecated/`, `--hard` deletes it outright
|
|
609
618
|
|
|
610
619
|
**What it does:**
|
|
611
|
-
1.
|
|
612
|
-
2.
|
|
620
|
+
1. `draft` writes a frontmatter'd Markdown file to `AK-Docs/99.Memory/_pending/` on your machine only — recallable locally, but not yet shared with the team
|
|
621
|
+
2. `submit` creates a branch in `AK-Docs`, moves the file out of `_pending/` to its real category path, commits, pushes, and opens a Merge Request (same branch+MR flow as `ak docs branch`/`ak docs submit`)
|
|
622
|
+
3. A teammate (PM by convention) reviews and merges the MR — that's the point it becomes recallable for everyone else
|
|
623
|
+
4. `session-start` hook auto-injects the `MEMORY.md` index plus top-N relevant approved memories into every new session — no manual recall needed once merged
|
|
613
624
|
|
|
614
625
|
**Example:**
|
|
615
626
|
```bash
|
|
616
|
-
$
|
|
617
|
-
✓
|
|
627
|
+
$ ak mem d -c 01.Lessons/dev -s prevent-429-error --content "Retry with backoff on 429 from payment gateway" -t payment,retry
|
|
628
|
+
✓ Draft đã tạo: _pending/01.Lessons/dev/prevent-429-error.md
|
|
629
|
+
id: mem-payment-prevent-429-error (local — chỉ máy này recall được cho tới khi submit)
|
|
630
|
+
|
|
631
|
+
$ ak mem ls
|
|
632
|
+
Pending drafts (local):
|
|
633
|
+
mem-payment-prevent-429-error _pending/01.Lessons/dev/prevent-429-error.md
|
|
634
|
+
type=lesson scope=payment workflows=all
|
|
618
635
|
|
|
619
|
-
$
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
2. payment-error-handling
|
|
623
|
-
3. payment-tests
|
|
636
|
+
$ ak mem sb 01.Lessons/dev/prevent-429-error.md -t "Add memory: prevent-429-error"
|
|
637
|
+
✓ Branch memory/prevent-429-error created in AK-Docs
|
|
638
|
+
✓ Merge Request opened — waiting for approval
|
|
624
639
|
```
|
|
625
640
|
|
|
626
641
|
## guide (alias: `g`)
|
|
@@ -639,6 +654,45 @@ ak g -c # command reference only (--comman
|
|
|
639
654
|
|
|
640
655
|
---
|
|
641
656
|
|
|
657
|
+
## ask
|
|
658
|
+
|
|
659
|
+
Search ai-flow-kit's own docs for an answer about the kit itself — install, roles, folder structure, CLI commands, memory draft/submit, troubleshooting. This is the deterministic fallback the `aiflow-help` skill uses (and that works with no LLM at all): local keyword search over `docs/common/*.md`, no network call.
|
|
660
|
+
|
|
661
|
+
```bash
|
|
662
|
+
ak ask "how do I install ai-flow-kit"
|
|
663
|
+
ak ask "submit memory"
|
|
664
|
+
ak ask "switch between cursor and claude code"
|
|
665
|
+
ak ask "some obscure question" -n 5 # show up to 5 results (--limit)
|
|
666
|
+
```
|
|
667
|
+
|
|
668
|
+
**Arguments:**
|
|
669
|
+
- `<question>` — Free-text question (English or Vietnamese)
|
|
670
|
+
|
|
671
|
+
**Options:**
|
|
672
|
+
- `-n, --limit <n>` — Max number of results to show (default 3)
|
|
673
|
+
|
|
674
|
+
**What it does:**
|
|
675
|
+
1. Scans every `docs/common/*.md` file (including `workflows/`)
|
|
676
|
+
2. Scores each file by how many query terms it contains, weighting heading matches higher
|
|
677
|
+
3. Prints the top matches with the nearest heading and a snippet, ranked by score
|
|
678
|
+
|
|
679
|
+
See also `docs/common/INDEX.md` for the curated topic map this search complements, and the `/ak-ask "<question>"` slash command for asking the same kind of question directly inside a Claude Code chat (explicit trigger for the `aiflow-help` skill, no terminal needed).
|
|
680
|
+
|
|
681
|
+
**Example:**
|
|
682
|
+
```bash
|
|
683
|
+
$ ak ask "submit memory"
|
|
684
|
+
|
|
685
|
+
Results for "submit memory":
|
|
686
|
+
|
|
687
|
+
docs/common/cli-reference.md (score 14)
|
|
688
|
+
→ memory (alias: `mem`)
|
|
689
|
+
...`submit|sb <path> --title <title> [-d <desc>] [-y]` — Move a pending draft...
|
|
690
|
+
|
|
691
|
+
See docs/common/INDEX.md for the full topic map.
|
|
692
|
+
```
|
|
693
|
+
|
|
694
|
+
---
|
|
695
|
+
|
|
642
696
|
## gate (AI workflow logging)
|
|
643
697
|
|
|
644
698
|
Called automatically by AI during gate workflow — not intended for manual use.
|
package/package.json
CHANGED
package/scripts/ask.js
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const chalk = require('chalk');
|
|
4
|
+
|
|
5
|
+
// Local, deterministic fallback for "how do I use ai-flow-kit" questions —
|
|
6
|
+
// works without any LLM, and gives the aiflow-help skill a ground-truth
|
|
7
|
+
// search path instead of guessing. Scores docs/common/*.md by simple
|
|
8
|
+
// keyword overlap; no stemming/diacritics-folding (see upgrade-plan #45).
|
|
9
|
+
|
|
10
|
+
const PKG_DIR = path.join(__dirname, '..');
|
|
11
|
+
const DOCS_DIR = path.join(PKG_DIR, 'docs', 'common');
|
|
12
|
+
const SNIPPET_RADIUS = 160;
|
|
13
|
+
|
|
14
|
+
module.exports = function ask(query, options = {}) {
|
|
15
|
+
if (!query || !query.trim()) {
|
|
16
|
+
console.log(chalk.yellow('Usage: ak ask "<question>"'));
|
|
17
|
+
console.log(chalk.gray(' ak ask "how do I install ai-flow-kit"'));
|
|
18
|
+
console.log(chalk.gray(' ak ask "submit memory"'));
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const limit = options.limit ? parseInt(options.limit, 10) : 3;
|
|
23
|
+
const files = walk(DOCS_DIR);
|
|
24
|
+
const terms = tokenize(query);
|
|
25
|
+
|
|
26
|
+
const scored = files
|
|
27
|
+
.map((file) => scoreFile(file, terms))
|
|
28
|
+
.filter((r) => r.score > 0)
|
|
29
|
+
.sort((a, b) => b.score - a.score)
|
|
30
|
+
.slice(0, limit);
|
|
31
|
+
|
|
32
|
+
if (scored.length === 0) {
|
|
33
|
+
console.log(chalk.yellow(`No local match for "${query}" in docs/common/.`));
|
|
34
|
+
console.log(chalk.gray(' Try `ak guide` for the quickstart, or check docs/common/INDEX.md for the full topic map.'));
|
|
35
|
+
return scored;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
console.log(chalk.cyan(`\nResults for "${query}":\n`));
|
|
39
|
+
for (const r of scored) {
|
|
40
|
+
console.log(chalk.bold.white(` ${r.relPath}`) + chalk.gray(` (score ${r.score})`));
|
|
41
|
+
if (r.heading) console.log(chalk.gray(` → ${r.heading}`));
|
|
42
|
+
console.log(` ${r.snippet}\n`);
|
|
43
|
+
}
|
|
44
|
+
console.log(chalk.gray(`See docs/common/INDEX.md for the full topic map.`));
|
|
45
|
+
return scored;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
function walk(dir) {
|
|
49
|
+
let results = [];
|
|
50
|
+
if (!fs.existsSync(dir)) return results;
|
|
51
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
52
|
+
const full = path.join(dir, entry.name);
|
|
53
|
+
if (entry.isDirectory()) {
|
|
54
|
+
results = results.concat(walk(full));
|
|
55
|
+
} else if (entry.isFile() && entry.name.endsWith('.md')) {
|
|
56
|
+
results.push(full);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return results;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Generic connector words — kept out of scoring so a short common word (esp. "ai",
|
|
63
|
+
// which appears in almost every doc via "ai-flow-kit") doesn't drown out real topic terms.
|
|
64
|
+
const STOPWORDS = new Set([
|
|
65
|
+
'a', 'an', 'the', 'this', 'that', 'these', 'those', 'is', 'are', 'was', 'were', 'be', 'been',
|
|
66
|
+
'do', 'does', 'did', 'to', 'of', 'in', 'on', 'at', 'for', 'and', 'or', 'with', 'how', 'what',
|
|
67
|
+
'why', 'when', 'where', 'who', 'which', 'it', 'its', 'my', 'me', 'i', 'you', 'your', 'can',
|
|
68
|
+
'ai',
|
|
69
|
+
'la', 'va', 'cua', 'the', 'nay', 'de', 'thi', 'toi', 'la gi', 'nhu', 'the nao',
|
|
70
|
+
]);
|
|
71
|
+
|
|
72
|
+
function tokenize(text) {
|
|
73
|
+
return text
|
|
74
|
+
.toLowerCase()
|
|
75
|
+
.split(/[^a-z0-9à-ỹ]+/i)
|
|
76
|
+
.filter((t) => t.length > 1 && !STOPWORDS.has(t));
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Two failure modes to guard against: (1) a raw hit count biases toward the longest
|
|
80
|
+
// file regardless of relevance (CHANGELOG.md is 5x getting-started.md) — fixed by
|
|
81
|
+
// normalizing body hits by document length; (2) substring matching false-positives on
|
|
82
|
+
// short queries (query term "flow" matching inside "Workflow") — fixed by comparing
|
|
83
|
+
// whole tokens instead of doing lower.includes(term).
|
|
84
|
+
function scoreFile(file, terms) {
|
|
85
|
+
const content = fs.readFileSync(file, 'utf-8');
|
|
86
|
+
const relPath = path.relative(PKG_DIR, file).replace(/\\/g, '/');
|
|
87
|
+
|
|
88
|
+
const docTokens = tokenizeRaw(content);
|
|
89
|
+
const wordCount = Math.max(1, docTokens.length);
|
|
90
|
+
const freq = {};
|
|
91
|
+
for (const t of docTokens) freq[t] = (freq[t] || 0) + 1;
|
|
92
|
+
|
|
93
|
+
let bodyHits = 0;
|
|
94
|
+
for (const term of terms) bodyHits += freq[term] || 0;
|
|
95
|
+
|
|
96
|
+
let headingHits = 0;
|
|
97
|
+
const headingLines = content.split('\n').filter((l) => l.trim().startsWith('#'));
|
|
98
|
+
for (const line of headingLines) {
|
|
99
|
+
const lineTokens = new Set(tokenizeRaw(line));
|
|
100
|
+
for (const term of terms) {
|
|
101
|
+
if (lineTokens.has(term)) headingHits += 1;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const score = Math.round((bodyHits / wordCount) * 1000 + headingHits * 5);
|
|
106
|
+
|
|
107
|
+
// Snippet position is cosmetic only (not used for scoring), so a plain substring
|
|
108
|
+
// search is fine here even though it may land inside a larger word.
|
|
109
|
+
const lower = content.toLowerCase();
|
|
110
|
+
let firstMatchIndex = -1;
|
|
111
|
+
for (const term of terms) {
|
|
112
|
+
const idx = lower.indexOf(term);
|
|
113
|
+
if (idx !== -1 && (firstMatchIndex === -1 || idx < firstMatchIndex)) firstMatchIndex = idx;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const heading = nearestHeading(content, firstMatchIndex);
|
|
117
|
+
const snippet = firstMatchIndex === -1
|
|
118
|
+
? content.trim().slice(0, SNIPPET_RADIUS).replace(/\n+/g, ' ')
|
|
119
|
+
: buildSnippet(content, firstMatchIndex);
|
|
120
|
+
|
|
121
|
+
return { file, relPath, score, heading, snippet };
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Same splitting rule as tokenize(), but without stopword filtering — used to index
|
|
125
|
+
// document content, where we want an accurate word count and per-word frequency map.
|
|
126
|
+
function tokenizeRaw(text) {
|
|
127
|
+
return text.toLowerCase().split(/[^a-z0-9à-ỹ]+/i).filter((t) => t.length > 1);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function nearestHeading(content, index) {
|
|
131
|
+
if (index === -1) return null;
|
|
132
|
+
const before = content.slice(0, index).split('\n').filter((l) => l.trim().startsWith('#'));
|
|
133
|
+
return before.length ? before[before.length - 1].replace(/^#+\s*/, '').trim() : null;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function buildSnippet(content, index) {
|
|
137
|
+
const start = Math.max(0, index - SNIPPET_RADIUS / 2);
|
|
138
|
+
const end = Math.min(content.length, index + SNIPPET_RADIUS / 2);
|
|
139
|
+
const raw = content.slice(start, end).replace(/\n+/g, ' ').trim();
|
|
140
|
+
return (start > 0 ? '…' : '') + raw + (end < content.length ? '…' : '');
|
|
141
|
+
}
|
|
@@ -25,7 +25,7 @@ function norm(cmd) {
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
// ── Version helpers ─────────────────────────────────────────────────────────
|
|
28
|
-
const CURRENT_VERSION = '0.1.
|
|
28
|
+
const CURRENT_VERSION = '0.1.6';
|
|
29
29
|
|
|
30
30
|
function parseVersion(v) {
|
|
31
31
|
if (!v || v === '-' || v === '' || v.toLowerCase() === 'unknown') return null;
|
|
@@ -407,13 +407,10 @@ async function writeExcelFile(rows, outputPath, sheetLabel, fromLabel, toLabel)
|
|
|
407
407
|
|
|
408
408
|
// ── Canonical user list (fixed order) ─────────────────────────────────────
|
|
409
409
|
const CANONICAL_USERS = [
|
|
410
|
-
'hoangdv@relipasoft.com',
|
|
411
410
|
'chinhtt@relipasoft.com',
|
|
412
411
|
'phongnx@relipasoft.com',
|
|
413
412
|
'dungha@relipasoft.com',
|
|
414
|
-
'thangnv@relipasoft.com',
|
|
415
413
|
'nguyenlt@relipasoft.com',
|
|
416
|
-
'thuongvv@relipasoft.com',
|
|
417
414
|
'yenvtb@relipasoft.com',
|
|
418
415
|
'thainq@relipasoft.com',
|
|
419
416
|
'tuoittx@relipasoft.com',
|
|
@@ -431,6 +428,7 @@ const CANONICAL_USERS = [
|
|
|
431
428
|
'khanhnv@relipasoft.com',
|
|
432
429
|
'namhh@relipasoft.com',
|
|
433
430
|
'tannt@relipasoft.com',
|
|
431
|
+
'khangnv@relipasoft.com',
|
|
434
432
|
];
|
|
435
433
|
|
|
436
434
|
// Log email → canonical email (for slight mismatches)
|
package/scripts/docs-branch.js
CHANGED
|
@@ -5,7 +5,7 @@ const { execSync } = require('child_process');
|
|
|
5
5
|
const { confirm } = require('@inquirer/prompts');
|
|
6
6
|
const { resolveDocsRepoPath, DOC_REPOS } = require('./docs-repo');
|
|
7
7
|
|
|
8
|
-
// Implements the branch + Merge Request half of docs/
|
|
8
|
+
// Implements the branch + Merge Request half of docs/common/Docs-Management-Flow.md:
|
|
9
9
|
// PM reviews & merges into `main`; every other role updates docs on a
|
|
10
10
|
// `feature/<functionId>/<taskId>` branch created from `main`, then submits a MR.
|
|
11
11
|
//
|
package/scripts/docs-repo.js
CHANGED
|
@@ -7,7 +7,7 @@ const { execSync } = require('child_process');
|
|
|
7
7
|
// fixed-name folders living directly under the workspace root — the folder
|
|
8
8
|
// opened in the editor, which contains one or more source repos plus these
|
|
9
9
|
// two docs repos as siblings. `ak` is run from that root, so projectDir
|
|
10
|
-
// (process.cwd()) already IS the root — see docs/
|
|
10
|
+
// (process.cwd()) already IS the root — see docs/common/Project-Structure.md.
|
|
11
11
|
const DOC_REPOS = [
|
|
12
12
|
{ name: 'AK-Docs', purpose: 'tài liệu dự án (Requirements, Specs, Test Cases, Coding docs...)' },
|
|
13
13
|
{ name: 'Shared-Docs', purpose: 'template dùng chung cho tất cả dự án (Spec, QA, Test Case, Test Report...)' },
|
|
@@ -100,7 +100,7 @@ process.stdin.on('end', async () => {
|
|
|
100
100
|
} catch (_) { }
|
|
101
101
|
|
|
102
102
|
// ── 3.5 Load relevant memory (99.Memory/ Project Brain) ────────
|
|
103
|
-
// See docs/
|
|
103
|
+
// See docs/common/Memory-Architecture-v1.0.md — Luồng 3 (Nạp/Sử dụng).
|
|
104
104
|
let memoryBlock = '';
|
|
105
105
|
try {
|
|
106
106
|
const workspaceRoot = resolveWorkspaceRoot(projectRoot);
|
package/scripts/init.js
CHANGED
|
@@ -350,6 +350,11 @@ async function setupClaudeCommands(projectDir) {
|
|
|
350
350
|
dest: 'coding.md',
|
|
351
351
|
description: 'Manual trigger for the DEV 5-Gate Coding Workflow (bug-fix / feature / refactor / investigation / documentation). Use this when the SessionStart auto-start message was missed — e.g. a ticket was loaded with `ak use` while this chat session was already open.',
|
|
352
352
|
},
|
|
353
|
+
{
|
|
354
|
+
src: path.join(PKG_DIR, 'custom', 'templates', 'shared', 'ak-ask-workflow.md'),
|
|
355
|
+
dest: 'ak-ask.md',
|
|
356
|
+
description: 'Ask a question about ai-flow-kit itself (install, roles, folder structure, CLI, memory workflow) — explicit trigger for the aiflow-help self-help skill, for when the question might otherwise be mistaken for ticket work. Usage: /ak-ask "how do I submit a memory".',
|
|
357
|
+
},
|
|
353
358
|
];
|
|
354
359
|
|
|
355
360
|
for (const cmd of commands) {
|
|
@@ -1092,7 +1097,7 @@ async function init(options) {
|
|
|
1092
1097
|
|
|
1093
1098
|
// ── Bootstrap 99.Memory/ skeleton (Luồng 1 — Khởi tạo) ────────
|
|
1094
1099
|
// Free: no reads, no token cost — just an empty folder skeleton if AK-Docs
|
|
1095
|
-
// exists and doesn't have one yet (docs/
|
|
1100
|
+
// exists and doesn't have one yet (docs/common/Memory-Architecture-v1.0.md §4).
|
|
1096
1101
|
const memorySkeleton = await memoryStore.ensureSkeleton(projectDir);
|
|
1097
1102
|
if (memorySkeleton.created) {
|
|
1098
1103
|
console.log(chalk.green('✓ Đã tạo khung 99.Memory/ trong AK-Docs (chưa có ghi nhớ nào).'));
|
|
@@ -1210,6 +1215,7 @@ module.exports.detectRtk = detectRtk;
|
|
|
1210
1215
|
module.exports.isRtkHookConfigured = isRtkHookConfigured;
|
|
1211
1216
|
module.exports.isGitNexusConfigured = isGitNexusConfigured;
|
|
1212
1217
|
module.exports.setupClaudeCommands = setupClaudeCommands;
|
|
1218
|
+
module.exports.copyDocsToProject = copyDocsToProject;
|
|
1213
1219
|
module.exports.setupFramework = setupFramework;
|
|
1214
1220
|
module.exports.ensureAiflowGitignored = ensureAiflowGitignored;
|
|
1215
1221
|
module.exports.resolveWorkflowFile = resolveWorkflowFile;
|
package/scripts/memory-store.js
CHANGED
|
@@ -9,7 +9,7 @@ function resolveDocsRepoPath(projectDir, repoName) {
|
|
|
9
9
|
return path.join(projectDir, repoName);
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
// Engine for the "99.Memory/" Project Brain — see docs/
|
|
12
|
+
// Engine for the "99.Memory/" Project Brain — see docs/common/Memory-Architecture-v1.0.md.
|
|
13
13
|
// Pure functions only (no chalk/console output, no CLI parsing) — scripts/memory.js and
|
|
14
14
|
// scripts/hooks/session-start.js are the callers.
|
|
15
15
|
//
|