pan-stack-cli 0.1.5 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/README.md +572 -24
  2. package/bin/pan.js +204 -21
  3. package/lib/ai-skills.js +829 -0
  4. package/lib/create.js +22 -4
  5. package/lib/discover.js +59 -1
  6. package/lib/git/git-checkout.js +395 -0
  7. package/lib/git/git-clone.js +162 -27
  8. package/lib/git/git-fetch-all.js +100 -33
  9. package/lib/git/git-grv.js +68 -37
  10. package/lib/git/git-gst.js +97 -26
  11. package/lib/git/git-mr.js +546 -0
  12. package/lib/git/git-pull.js +104 -43
  13. package/lib/git/git-push.js +150 -41
  14. package/lib/git/git-sync-main.js +42 -28
  15. package/lib/git/helpers/bulk-report.js +202 -0
  16. package/lib/git/helpers/cli.js +40 -5
  17. package/lib/git/helpers/manifest.js +93 -0
  18. package/lib/git/helpers/repo-select.js +328 -9
  19. package/lib/git/helpers/repo-summary.js +161 -0
  20. package/lib/i18n.js +61 -0
  21. package/lib/inquirer-theme.js +20 -0
  22. package/lib/language.js +121 -0
  23. package/lib/languages.js +14 -0
  24. package/lib/manifest.js +115 -14
  25. package/lib/menu-prompt.js +201 -0
  26. package/lib/menu.js +134 -0
  27. package/lib/messages.js +647 -0
  28. package/lib/run-command.js +173 -52
  29. package/lib/select.js +0 -0
  30. package/lib/serve.js +75 -0
  31. package/lib/skill-registry-client.js +173 -0
  32. package/lib/stats/aggregate.js +51 -0
  33. package/lib/stats/identity.js +20 -0
  34. package/lib/stats/index.js +189 -0
  35. package/lib/stats/parse.js +46 -0
  36. package/lib/stats/range.js +38 -0
  37. package/lib/stats/report.js +264 -0
  38. package/lib/stats/review.js +157 -0
  39. package/lib/stats/scan.js +92 -0
  40. package/lib/stats/serve.js +25 -0
  41. package/lib/ui/api.js +202 -0
  42. package/lib/ui/clone.js +115 -0
  43. package/lib/ui/config.js +182 -0
  44. package/lib/ui/diff.js +128 -0
  45. package/lib/ui/export-gate.js +79 -0
  46. package/lib/ui/gen-react-mobile-code.js +6 -0
  47. package/lib/ui/gen-react-web-code.js +75 -0
  48. package/lib/ui/index.js +89 -0
  49. package/lib/ui/init.js +252 -0
  50. package/lib/ui/login.js +128 -0
  51. package/lib/ui/logout.js +22 -0
  52. package/lib/ui/palettes.js +103 -0
  53. package/lib/ui/published-html.js +24 -0
  54. package/lib/ui/sync.js +137 -0
  55. package/lib/ui/workspace.js +213 -0
  56. package/package.json +10 -3
  57. package/templates/workspace/.claude/skills/writing-guidelines/SKILL.md +0 -48
  58. package/templates/workspace/.codex/skills/writing-guidelines/SKILL.md +0 -48
  59. package/templates/workspace/.cursor/skills/writing-guidelines/SKILL.md +0 -48
  60. package/templates/workspace/.pan.yaml +0 -25
  61. package/templates/workspace/.project.yaml +0 -15
  62. package/templates/workspace/README.md +0 -35
package/README.md CHANGED
@@ -40,12 +40,12 @@ skill pre-installed for all three agent folders.
40
40
  ## Requirements
41
41
 
42
42
  - Node.js 18+
43
- - Git (for `pan clone`, `pull`, `sync-main`, `fetch`, `push`, `grv`, `gst`)
43
+ - Git (for `pan clone`, `pull`, `sync-main`, `fetch`, `push`, `grv`, `gst`, `stats`)
44
44
 
45
45
  ## Windows support
46
46
 
47
- Built-in commands (`create`, `clone`, `pull`, `sync-main`, `push`, `fetch`, `grv`, `gst`) run on
48
- Windows, macOS, and Linux. Notes for Windows:
47
+ Built-in commands (`create`, `clone`, `pull`, `sync-main`, `push`, `fetch`, `mr`, `checkout`,
48
+ `grv`, `gst`) run on Windows, macOS, and Linux. Notes for Windows:
49
49
 
50
50
  - `shell:` blocks in `.pan.yaml` run through **bash** on all platforms (Git Bash on
51
51
  Windows, system bash on macOS/Linux). Use `exec:` for simple one-liners (`npm test`)
@@ -72,14 +72,236 @@ pan install
72
72
 
73
73
  `pan create` fails if the target folder already exists.
74
74
 
75
+ **Cần registry server**: scaffold template (`workspace`) không còn bundle sẵn trong
76
+ `pan-stack-cli` — `pan create` tải template qua `apps/pan-agent-skill-registry`
77
+ (`PAN_SKILL_REGISTRY_URL`, mặc định `http://localhost:4600`), giống cơ chế
78
+ `pan ai install`. Server không chạy được → `pan create` báo lỗi rõ, không scaffold
79
+ được (không có fallback local).
80
+
81
+ ## Agent skills — `pan ai`
82
+
83
+ Builtin (không cần khai báo trong `.pan.yaml`). Quét skill ở **workspace root**
84
+ (thư mục chứa `.project.yaml`): `.claude/skills`, `.cursor/skills`, `.codex/skills`.
85
+ Gộp theo tên skill — bật/tắt đồng bộ cả ba agent folder. Disable đổi tên
86
+ `SKILL.md` → `SKILL.md.disabled` (và `AGENTS.md` tương tự); enable đổi ngược lại.
87
+
88
+ ```bash
89
+ pan ai # tương tác: Disable | Enable | List | Install | Update
90
+ pan ai --list # chỉ xem trạng thái
91
+ pan ai --disable writing-guidelines
92
+ pan ai --enable writing-guidelines
93
+ pan ai --disable ux-audit --dry-run
94
+ pan skills --list # alias
95
+ ```
96
+
97
+ > Menu tương tác của `pan ai` theo đúng [quy ước chung](#quy-ước-chung-cho-mọi-menu-tương-tác-trong-pan):
98
+ > `x` thoát ở mọi bước, `b` quay lại menu action từ bước chọn skill, `a`/`i` khi chọn nhiều skill.
99
+
100
+ ### Install / Update — cài & cập nhật skill/agent từ registry server
101
+
102
+ Hai action mới trong menu `pan ai` gọi tới registry server (`apps/pan-agent-skill-registry`)
103
+ để tải skill/agent đóng gói dạng zip:
104
+
105
+ - **Install**: liệt kê package chưa cài (từ `GET {baseUrl}/api/registry`), cho chọn nhiều,
106
+ tự phát hiện agent dir sẵn có (`.claude`/`.cursor`/`.codex` đã tồn tại ở workspace root) để
107
+ cài luôn; nếu chưa có agent dir nào thì hỏi chọn agent đích trước khi cài. Nếu server báo có
108
+ bản cập nhật cho package đã cài, item đầu danh sách cho phép nhảy sang luồng Update.
109
+ - **Update**: liệt kê package đã cài nhưng có version mới hơn, cho chọn (hoặc "Update all"),
110
+ tải lại đúng các agent dir đã cài trước đó (ghi trong lockfile).
111
+
112
+ Config base URL bằng env `PAN_SKILL_REGISTRY_URL` (mặc định `http://localhost:4600`).
113
+ Trạng thái "đã cài gì, version nào, cài vào agent dir nào" lưu ở
114
+ `<workspaceRoot>/.pan/skills-lock.json` (không commit — thêm vào `.gitignore` nếu cần).
115
+
116
+ Nếu chạy `pan ai` mà KHÔNG đứng trong 1 workspace pan-stack (không tìm thấy `.project.yaml`
117
+ walk-up từ cwd) và đang ở TTY tương tác, CLI hỏi có muốn tạo dự án mới ngay tại thư mục hiện
118
+ tại không — lựa chọn **"Không" luôn đứng trước "Có"** trong menu. Chọn "Có" thì tạo ngay
119
+ `.project.yaml` (3 dòng: `project`, `language: vi`, `managed_by` lấy từ `git config user.name`
120
+
121
+ - `user.email`, thiếu thì ghi `YourName`) rồi tiếp tục `pan ai` như đang ở trong workspace đó.
122
+
123
+ ## `pan language` (`pan lang`) — đổi ngôn ngữ CLI
124
+
125
+ Danh sách ngôn ngữ available định nghĩa ở 2 nơi (đi cùng nhau khi thêm ngôn ngữ mới):
126
+
127
+ - `lib/messages.js` — nguồn thật của **mã ngôn ngữ hợp lệ** (1 object con `en: {...}`,
128
+ `vi: {...}`, … — mỗi key là 1 message theo mã đó). `availableLangs()` (`lib/i18n.js`)
129
+ đọc `Object.keys(messages.js)`.
130
+ - `lib/languages.js` — **tên hiển thị** cho mỗi mã (vd `vi` → "Tiếng Việt"), dùng bởi
131
+ menu `pan language`. Thiếu dòng ở đây thì menu vẫn hiện, chỉ dùng luôn mã thay tên.
132
+
133
+ ```bash
134
+ pan language # menu tương tác: chọn ngôn ngữ (đánh dấu ngôn ngữ hiện tại)
135
+ pan language vi # đặt trực tiếp, không cần menu
136
+ pan lang en # alias
137
+ ```
138
+
139
+ Ghi `language: <mã>` vào `.project.yaml` gần nhất (walk-up từ cwd); chưa có key → thêm,
140
+ đã có → cập nhật. Không có `.project.yaml` → `pan language <mã>` báo lỗi (cần workspace
141
+ để lưu), còn `pan language` (xem/không đổi) vẫn chạy, dùng mã mặc định/env (`PAN_LANG`).
142
+
143
+ Menu chọn ngôn ngữ theo đúng [quy ước chung](#quy-ước-chung-cho-mọi-menu-tương-tác-trong-pan):
144
+ `↑↓` di chuyển · gõ chữ nhảy tới item · `Enter` chọn (áp dụng ngay) · `b` quay lại (không đổi
145
+ gì) · `x` thoát hẳn CLI.
146
+
147
+ ## `pan ui` — đồng bộ Pan Studio
148
+
149
+ Đồng bộ dự án panui giữa **local ↔ Pan Studio backend**: đăng nhập, clone, đẩy thay
150
+ đổi lên, publish HTML, sinh mã React.
151
+
152
+ ```bash
153
+ pan ui # menu tương tác
154
+ pan ui login # đăng nhập (mở trình duyệt, device-flow)
155
+ pan ui logout # đăng xuất, xóa key local
156
+ pan ui clone # tải dự án về local
157
+ pan ui sync # đẩy thay đổi local → backend
158
+ pan ui published-html # publish trang HTML công khai
159
+ pan ui gen-react-web-code # sinh mã React web (.tar.gz)
160
+ pan ui gen-react-mobile-code # coming soon — chỉ in "Đang phát triển"
161
+ ```
162
+
163
+ > Menu `pan ui` (chọn subcommand) và cascade 4 bước của `pan ui init` (Design System → loại →
164
+ > template → bảng màu) theo [quy ước chung](#quy-ước-chung-cho-mọi-menu-tương-tác-trong-pan): `x`
165
+ > thoát mọi bước, `b` quay lại bước trước trong `pan ui init`.
166
+
167
+ ### `init` — tạo dự án panui mẫu
168
+
169
+ Vì hiện có **2 design system**, bước đầu tiên của `pan ui init` luôn là **chọn Design
170
+ System** — trước cả bước chọn loại/template/bảng màu:
171
+
172
+ ```
173
+ ? Chọn Design System:
174
+ ❯ shadcn ui (Recommended)
175
+ antd
176
+ ```
177
+
178
+ - **`shadcn ui` (Recommended)** — đứng đầu danh sách, là lựa chọn mặc định.
179
+ - **`antd`** — lựa chọn thứ hai.
180
+
181
+ Sau khi chọn Design System, cascade tiếp tục như cũ: **loại** (Web landing / Mobile /
182
+ CMS) → **template** → **bảng màu** → nhập tên/đường dẫn dự án. `b` quay lại bước trước
183
+ (kể cả quay lại bước chọn Design System từ bước chọn loại), `x` thoát hẳn — theo
184
+ [quy ước chung](#quy-ước-chung-cho-mọi-menu-tương-tác-trong-pan).
185
+
186
+ **Cần registry server**: các template pan-ui (landing-glass, mobile-app,...) không còn
187
+ bundle sẵn — danh sách loại/template lấy từ `apps/pan-agent-skill-registry`
188
+ (`PAN_SKILL_REGISTRY_URL`, mặc định `http://localhost:4600`); chỉ tải zip của
189
+ ĐÚNG template user chọn (không tải hết). Server không chạy được → báo lỗi rõ.
190
+
191
+ ### `login` — đăng nhập (device-flow)
192
+
193
+ Giống `claude` / `gh auth login`: không nhập user/password trong terminal. CLI gọi
194
+ `POST /auth/device/start`, mở trình duyệt tại trang `/cli-auth` để đăng nhập + bấm
195
+ "Approve" (fallback: dán URL tay nếu không tự mở được browser), rồi poll
196
+ `/auth/device/poll` tới khi được duyệt. Key nhận về dạng `pmcp_...`, hạn dùng 90
197
+ ngày, lưu tại `~/.pan/credentials.json` (quyền file `600`). Hết hạn → chạy lại
198
+ `pan ui login`. (`pan ui init` vẫn chạy được như alias của `login`.)
199
+
200
+ Đã có key **còn hạn** cho đúng `apiUrl` hiện tại → `pan ui login` KHÔNG tự chạy lại
201
+ device-flow, chỉ in info (email + hạn dùng) và hướng dẫn:
202
+ `pan ui logout` rồi `pan ui login` lại, hoặc `pan ui login --force` (`-f`) để
203
+ đăng nhập lại ngay, ghi đè key hiện tại.
204
+
205
+ ### `logout`
206
+
207
+ Xóa key local (`~/.pan/credentials.json`) cho API hiện tại. Token trên backend vẫn
208
+ còn hạn — thu hồi ở UI/`me/mcp-tokens` nếu cần.
209
+
210
+ ### `clone`
211
+
212
+ Chọn dự án theo danh sách lấy từ backend (key phải hợp lệ), sau đó hỏi **thư mục
213
+ đích** (mặc định `pan-ui`). Nếu thư mục đã tồn tại → **báo lỗi, không tự xóa** —
214
+ phải xóa thủ công rồi chạy lại. Tải toàn bộ cây file về local và ghi
215
+ `backend: { id, apiUrl }` vào `app.panui.yaml` (định danh dự án dùng cho `sync`
216
+ sau này).
217
+
218
+ ### `sync` — push local → backend
219
+
220
+ Đọc `backend.id` trong `app.panui.yaml` (thiếu → gợi ý chạy `clone` trước). So
221
+ sánh (diff) local với backend: file thêm / đổi / xóa. Trước khi đẩy sẽ:
222
+
223
+ 1. Hiện tên + id dự án và hỏi xác nhận **đúng dự án** (tránh đẩy nhầm).
224
+ 2. Hiện bảng diff và hỏi xác nhận **trước khi đẩy**.
225
+ 3. File xóa ở local → hỏi riêng trước khi xóa trên backend.
226
+
227
+ Đây hiện là chiều **push-only** (local → backend); pull để sau.
228
+
229
+ ### `published-html` / `gen-react-web-code` — publish & sinh mã
230
+
231
+ Cả hai đều **GATE bằng sync**: nếu local khác backend, CLI báo và hỏi sync ngay
232
+ (hoặc dừng để bạn tự `pan ui sync`) trước khi build. Chỉ khi local đã khớp
233
+ backend mới build tiếp.
234
+
235
+ - `published-html`: gọi build HTML trên backend, chờ xong, in URL công khai
236
+ dạng `<apiUrl>/p/<prefix>`.
237
+ - `gen-react-web-code`: gọi build React trên backend, chờ xong, tải `.tar.gz` và
238
+ giải nén vào thư mục đích (mặc định `pan-ui-react`; đã tồn tại → báo lỗi, không
239
+ tự xóa). Máy không có lệnh `tar` hệ thống → chỉ lưu file `.tar.gz` và in hướng
240
+ dẫn giải nén thủ công.
241
+ - `gen-react-mobile-code`: chưa làm — chỉ in "Đang phát triển".
242
+
243
+ Mỗi lần build tạo một `ExportVersion` mới trên backend (version bump); artifact
244
+ build không đè lên file nguồn.
245
+
246
+ ### Cấu hình
247
+
248
+ `PAN_STUDIO_API_URL` / `PAN_STUDIO_WEB_URL` — ưu tiên (cao → thấp):
249
+
250
+ 1. biến môi trường (`PAN_STUDIO_API_URL=...`)
251
+ 2. file `.pan-env-build.yaml` ở workspace root:
252
+ ```yaml
253
+ PAN_STUDIO_API_URL: http://localhost:3001
254
+ PAN_STUDIO_WEB_URL: http://localhost:3001
255
+ ```
256
+ 3. Trỏ về Pan Studio backend dev
257
+
258
+ `PAN_STUDIO_WEB_URL` thiếu ở cả 3 mức trên thì lấy luôn giá trị `PAN_STUDIO_API_URL`
259
+ đã resolve.
260
+
261
+ ### Monorepo — nhiều dự án panui
262
+
263
+ `sync`/`published-html`/`gen-react-web-code` quét mọi `app.panui.yaml` từ
264
+ `.project.yaml` root, tối đa **5 cấp** thư mục (bỏ qua `node_modules`, `.git`,
265
+ `dist`). Tìm thấy nhiều dự án → hỏi chọn; chỉ 1 dự án → dùng luôn, không hỏi.
266
+
267
+ > ⚠️ Lưu ý: block `.html` (liên kết html-ui) chỉ được đặt trong thư mục
268
+ > `components/` của dự án panui.
269
+
270
+ ## Static server — `pan serve`
271
+
272
+ Phục vụ một thư mục build tĩnh qua HTTP (SPA mode). Hữu ích để xem web demo do
273
+ `pnpm panui:gen` (Pan Design System) sinh ra, hoặc bất kỳ thư mục `dist` nào.
274
+
275
+ ```bash
276
+ pan serve <dir> [options]
277
+
278
+ pan serve ./panui-demo # → http://localhost:3000
279
+ pan serve ./panui-demo -p 8080 # đổi cổng
280
+ pan serve # phục vụ thư mục hiện tại
281
+ ```
282
+
283
+ Options: `-p, --port <port>` (mặc định 3000) · `-h, --help`.
284
+
285
+ Bọc package [`serve`](https://www.npmjs.com/package/serve) với cờ `-s` (single-page:
286
+ route sâu / refresh vẫn trả `index.html`). Ưu tiên bản cài trong pan-stack-cli; nếu
287
+ chưa cài thì tự chạy qua `npx serve` (tải lần đầu). Chạy trên Windows/macOS/Linux.
288
+
289
+ Ví dụ luồng "build + xem" web demo panui:
290
+
291
+ ```bash
292
+ # trong repo Pan Design System:
293
+ pnpm panui:gen pan-design-system-markdown/examples/blog-project -o ./panui-demo
294
+ pan serve ./panui-demo
295
+ ```
296
+
75
297
  ## Configuration files
76
298
 
77
299
  Two files drive the CLI. Keep responsibilities separate:
78
300
 
79
- | File | Role |
80
- |------|------|
301
+ | File | Role |
302
+ | --------------- | ----------------------------------------------------------------------------- |
81
303
  | `.project.yaml` | Workspace manifest — lists `repositories` (name, url, path). **No commands.** |
82
- | `.pan.yaml` | `pan` commands — at workspace root and/or inside each child repo |
304
+ | `.pan.yaml` | `pan` commands — at workspace root and/or inside each child repo |
83
305
 
84
306
  ### `.project.yaml` example
85
307
 
@@ -101,6 +323,29 @@ repositories:
101
323
  path: apps/api
102
324
  ```
103
325
 
326
+ ### `.project.local.yaml` — repo riêng, không commit
327
+
328
+ Muốn tự thêm repo riêng (thử nghiệm, fork cá nhân, repo nội bộ chỉ mình bạn cần…)
329
+ mà không đụng `.project.yaml` chung của team? Tạo `.project.local.yaml` cùng thư
330
+ mục — chỉ cần field `repositories:` (không cần `project:`/`stack:`/gì khác):
331
+
332
+ ```yaml
333
+ # .project.local.yaml — KHÔNG commit (đã có trong .gitignore của 'pan create')
334
+ repositories:
335
+ - name: my-experiment
336
+ url: https://github.com/you/my-experiment.git
337
+ path: apps/my-experiment
338
+ ```
339
+
340
+ Mọi lệnh đọc `repositories` (`pan clone|pull|push|fetch|grv|gst|sync-main|mr|checkout`,
341
+ `pan stats`, và cả danh sách lệnh `.pan.yaml` theo từng repo) tự động **gộp thêm**
342
+ repo từ file này vào `.project.yaml` chung — không cần khai báo/sửa gì thêm ở
343
+ nơi khác. Có repo local → mỗi lần chạy in 1 dòng gợi ý `ℹ️ +N repo từ
344
+ .project.local.yaml` để bạn biết đang có repo riêng đang hoạt động.
345
+
346
+ `pan create` scaffold sẵn `.gitignore` chứa dòng `.project.local.yaml` — workspace
347
+ cũ (tạo trước khi có tính năng này) tự thêm dòng đó vào `.gitignore` của mình.
348
+
104
349
  ### `.pan.yaml` — workspace root
105
350
 
106
351
  Orchestration commands. Paths are relative to the workspace root. Use
@@ -150,19 +395,146 @@ commands:
150
395
 
151
396
  Aliases: `alias: i` or `aliases: i, ins` (comma-separated).
152
397
 
398
+ ### `sequence` — gom nhiều lệnh lẻ chạy TUẦN TỰ (vd "build all")
399
+
400
+ Có nhiều lệnh `exec`/`shell` lẻ (build-fe, build-be, build-extension, …) trong CÙNG 1
401
+ file `.pan.yaml`, muốn có thêm 1 lệnh "chạy tất cả theo thứ tự" mà không copy lại
402
+ script? Khai báo field `sequence` (thay cho `exec`/`shell`) — mỗi dòng 1 bước, chạy
403
+ đúng thứ tự viết, dừng ngay khi 1 bước lỗi:
404
+
405
+ ```yaml
406
+ commands:
407
+ build-fe:
408
+ exec: pnpm --filter web build
409
+
410
+ build-be:
411
+ default: dev
412
+ targets:
413
+ dev:
414
+ exec: pnpm --filter api build:dev
415
+ prod:
416
+ exec: pnpm --filter api build:prod
417
+
418
+ build-extension:
419
+ shell: |
420
+ cd tools/vscode-pan-uispec && npm run package
421
+
422
+ build-all:
423
+ description: Build FE + BE(prod) + extension theo đúng thứ tự
424
+ sequence: |
425
+ build-fe
426
+ MODE=prod build-be:prod
427
+ build-extension?
428
+ ```
429
+
430
+ Cú pháp 1 dòng: `[KEY=VAL ...] tênLệnh[:target][?]`
431
+
432
+ - **`tênLệnh`** — phải là 1 command khác **đã khai báo trong cùng file `.pan.yaml`
433
+ này** (không gọi chéo sang `.pan.yaml` của repo khác).
434
+ - **`:target`** — chọn target nếu lệnh đó có `targets:` (giống cách gọi `pan build-be prod`).
435
+ - **`KEY=VAL ...`** (đặt trước tên lệnh) — biến môi trường chỉ áp dụng cho **riêng bước
436
+ đó**, không ảnh hưởng các bước khác hay sequence gọi nó.
437
+ - **`?`** cuối tên lệnh — bước lỗi (exit code ≠ 0) chỉ in cảnh báo rồi **chạy tiếp**
438
+ bước sau, thay vì dừng cả sequence (mặc định KHÔNG có `?` = lỗi là dừng ngay, exit
439
+ code của sequence = exit code bước lỗi đó).
440
+ - Cũng chấp nhận 1 dòng, phân tách bởi `,` khi không cần set biến: `sequence: build-fe, build-be`.
441
+ - `pan build-all` chạy như 1 lệnh bình thường (không có tham số riêng cho sequence);
442
+ từng bước bên trong dùng target/biến đã khai báo sẵn trong `sequence:`.
443
+
444
+ ### Interactive select — chọn nhiều/một khi chạy lệnh
445
+
446
+ Bất kỳ command nào (mọi stack: Node/Java/.NET…) khai báo `select*` → `pan` **render picker tương tác**
447
+ (checkbox @inquirer, ⭐TẤT CẢ trên đỉnh) và truyền lựa chọn vào `shell`/`exec` qua **env `PAN_SELECTED`**
448
+ (mỗi dòng 1 giá trị) + `PAN_SELECTED_COUNT`. Script chỉ là shell THUẦN — không cần thêm dependency.
449
+
450
+ | Field | Ý nghĩa |
451
+ | --------------- | ----------------------------------------------------------------------------------------------------------------------------- |
452
+ | `selectFrom` | Lệnh shell; **mỗi dòng stdout = 1 choice** (`label<TAB>value` để đặt nhãn riêng). Vd `ls -1 *.yaml`, `oc get deploy -o name`. |
453
+ | `selectChoices` | Danh sách tĩnh, phân tách bởi `,` hoặc newline (thay cho `selectFrom`). |
454
+ | `selectMessage` | Câu hỏi hiển thị. |
455
+ | `selectMulti` | `true` (mặc định, checkbox nhiều) · `false` (chọn một). |
456
+ | `selectAll` | `true` (mặc định, thêm ⭐TẤT CẢ) · `false`. |
457
+
458
+ `all` (arg) / `PAN_ALL=1` / non-TTY (CI) ⇒ **chọn hết** (bỏ qua picker). Không chọn gì ⇒ thoát.
459
+
460
+ ```yaml
461
+ commands:
462
+ deploy:
463
+ description: "Apply manifest (chọn) — hoặc: pan deploy all"
464
+ selectMessage: "Chọn manifest apply:"
465
+ selectFrom: "ls -1 k8s/*.yaml"
466
+ shell: |
467
+ set -euo pipefail
468
+ while IFS= read -r f; do [ -n "$f" ] && kubectl apply -f "$f"; done <<< "${PAN_SELECTED:-}"
469
+ ```
470
+
471
+ **Primitive `pan select`** — cho script chủ động bắt lựa chọn qua stdout (picker render trên stderr):
472
+
473
+ ```bash
474
+ sel=$(pan select --multi --all --from "ls -1 k8s/*.yaml" --message "Chọn manifest:")
475
+ for f in $sel; do kubectl apply -f "$f"; done
476
+ # pan select --single a b c # chọn một trong inline choices
477
+ ```
478
+
479
+ ### Quy ước chung cho MỌI menu tương tác trong `pan`
480
+
481
+ Toàn bộ picker/menu trong CLI (menu gốc `pan` trống, `pan ai`, `pan ui`, `pan mr`, `pan checkout`,
482
+ git repo picker, v.v.) đều dùng chung 2 prompt nội bộ `menuSelect`/`menuCheckbox`
483
+ (`lib/menu-prompt.js`, cần `@inquirer/core`) và tuân theo cùng một bộ phím:
484
+
485
+ | Phím | Ý nghĩa | Áp dụng |
486
+ | ---------------- | ------------------------------------------------------ | ------------------------------------- |
487
+ | `Enter` | Xác nhận lựa chọn hiện tại | Mọi menu |
488
+ | `↑`/`↓` + gõ chữ | Di chuyển / gõ nhảy tới item | Mọi menu |
489
+ | `b` | **Quay lại** menu cấp trước (không thoát chương trình) | Menu cấp con (sau khi đã chọn ≥1 cấp) |
490
+ | `x` | **Thoát hẳn** CLI (`process.exit(0)` sạch) | Mọi menu, kể cả menu gốc |
491
+ | `space` | Tick/bỏ tick 1 dòng | Menu chọn nhiều (`menuCheckbox`) |
492
+ | `a` | Chọn tất cả / bỏ chọn tất cả (toggle) | Menu chọn nhiều |
493
+ | `i` | Đảo chọn (invert) | Menu chọn nhiều |
494
+
495
+ Thiếu `@inquirer/core` (dep không cài) → mọi picker fallback sang `@inquirer/prompts`
496
+ (`select`/`checkbox` thô) + thêm item ẩn ở cuối danh sách cho `b`/`x` (không phải hotkey nhấn-1-phím,
497
+ nhưng vẫn chọn được bằng Enter) để giữ đúng hành vi quay lại/thoát dù thiếu dependency.
498
+
499
+ Không có nơi nào trong CLI tự chế cách chọn riêng (loop `readline` tay chỉ còn là fallback CUỐI CÙNG
500
+ khi thiếu cả `@inquirer/core` lẫn `@inquirer/prompts`). `pan ai`, `pan ui` (kể cả cascade
501
+ loại→template→bảng màu của `pan ui init`), `pan mr`, `pan checkout` đều đã áp dụng quy ước này —
502
+ nếu bạn thấy hành vi phím tắt khác trước đây (vd `pan mr`/`pan checkout` giờ có thêm `x` thoát ở
503
+ bước chọn repo, `pan ui init` giờ có `b` quay lại giữa 3 bước chọn), đó là do đồng bộ theo quy ước
504
+ chung này.
505
+
506
+ ## `pan git` — menu chọn lệnh git (đỡ nhớ tên/xem help dài)
507
+
508
+ Các lệnh git ở dưới đây (clone/pull/push/fetch/sync-main/mr/checkout/grv/gst) và cả
509
+ `stats` (cũng là 1 dạng thống kê Git từ log) nằm **rải rác** — không nhớ hết tên thì
510
+ gõ `pan git` để xem menu chọn:
511
+
512
+ ```bash
513
+ pan git # TTY: menu tương tác chọn 1 lệnh git rồi chạy ngay (x thoát)
514
+ # không TTY: in danh sách lệnh rồi thoát (không lỗi)
515
+ pan git pull # có sẵn tên → chạy thẳng, y hệt gõ 'pan pull' (chỉ là lối gõ khác)
516
+ pan git -h # in danh sách lệnh + mô tả
517
+ ```
518
+
519
+ Đây chỉ là **lối vào phụ** (discoverability) — hành vi/tham số của từng lệnh (`--dry-run`,
520
+ `--base-dir`, target tương tác…) không đổi gì so với gõ thẳng `pan <command>`.
521
+
153
522
  ## Built-in git commands
154
523
 
155
524
  Read `repositories` from the nearest `.project.yaml` (walk-up from cwd):
156
525
 
157
- | Command | Action |
158
- |---------|--------|
159
- | `pan clone` | Clone all repositories in the manifest |
160
- | `pan pull` | Pull all cloned repositories |
161
- | `pan sync-main [repo\|all]` (`pan sm`) | Fetch + merge `origin/main` into current branch (interactive picker; conflict summary) |
162
- | `pan fetch` | Fetch all remotes |
163
- | `pan push` | Push all repos (`-u origin HEAD` by default) |
164
- | `pan grv` | `git remote -v` for workspace + each child repo |
165
- | `pan gst` | `git status` for workspace + each child repo |
526
+ | Command | Action |
527
+ | ------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
528
+ | `pan clone` | Clone all repositories in the manifest — bảng tổng hợp `repo · result · note` (cloned · already exists · no access · not found · failed; KHÔNG dừng ở lỗi đầu tiên, clone hết rồi mới tổng hợp) |
529
+ | `pan clone <git-url>` | **Thêm 1 repo mới** — tự tách tên dự án từ URL (bỏ đuôi `.git`, lấy phần cuối path/scp-like), **ghi thêm entry vào `.project.yaml`** (path mặc định `apps/<tên>`), rồi clone ngay repo đó. Đã có tên đó trong manifest → dùng lại entry cũ, không thêm trùng. Xem [chi tiết](#pan-clone-url--thêm-repo-mới-tiện-như-git-clone) |
530
+ | `pan pull` | Pull all cloned repositories — bảng tổng hợp `repo · branch · result · changes · conflict` |
531
+ | `pan sync-main [repo\|all]` (`pan sm`) | Fetch + merge `origin/main` into current branch (interactive picker; conflict summary) |
532
+ | `pan fetch` (`pan gfa`) | Fetch all remotes — bảng tổng hợp `repo · branch · result · behind/ahead · new refs` |
533
+ | `pan push` | Push all repos (`-u origin HEAD` by default) — bảng tổng hợp `repo · branch · result · commits · changes · MR/PR link` |
534
+ | `pan mr [target] [repo\|all\|list]` | Create GitLab Merge Requests (interactive multi-select; target defaults to `main`) |
535
+ | `pan checkout [-b\|-B] <branch> [repo\|all\|list]` (`pan co`) | Switch/create branch across repos (interactive multi-select) |
536
+ | `pan grv` | `git remote -v` for workspace + each child repo — bảng tổng hợp `repo · branch · remote · fetch · push` (`push` = `=` khi giống `fetch`; nhiều remote thì gộp `origin (+N)`) |
537
+ | `pan gst` | Bảng tổng hợp repos dirty: `repo · branch · state · breakdown · behind/ahead` (repo sạch được ẩn; `--verbose` hoặc `-sb` để in `git status` đầy đủ) |
166
538
 
167
539
  Git options:
168
540
 
@@ -170,6 +542,176 @@ Git options:
170
542
  - `--dry-run` — print commands only
171
543
  - `[manifest]` — manifest path (default: `.project.yaml`)
172
544
 
545
+ ### `pan clone <url>` — thêm repo mới, tiện như `git clone`
546
+
547
+ `pan clone` không tham số = clone TẤT CẢ repo trong manifest (như cũ). Truyền
548
+ thêm 1 **git URL** (`https://...`, `git@host:group/repo.git`, hoặc bất kỳ
549
+ chuỗi kết thúc `.git`) thì `pan clone` xử lý khác hẳn:
550
+
551
+ ```bash
552
+ pan clone https://github.com/you/my-repo.git
553
+ # 1. Tách tên dự án từ URL: "my-repo"
554
+ # 2. Ghi thêm vào .project.yaml (KHÔNG phải .project.local.yaml):
555
+ # - name: my-repo
556
+ # url: https://github.com/you/my-repo.git
557
+ # path: apps/my-repo
558
+ # 3. git clone ngay repo đó vào apps/my-repo/
559
+ ```
560
+
561
+ - Giống hệt `git clone <url>` về công dụng, nhưng **tự ghi lại vào manifest** —
562
+ không cần tay chỉnh `.project.yaml` rồi chạy lại `pan clone`.
563
+ - Đã có repo TÊN ĐÓ trong manifest rồi (kể cả khai ở `.project.local.yaml`) →
564
+ **không thêm trùng**, dùng lại URL/path đã khai, chỉ clone (idempotent — chạy
565
+ lại nhiều lần an toàn).
566
+ - `--dry-run` → in ra sẽ ghi gì / clone gì, KHÔNG đụng file `.project.yaml` và
567
+ không clone thật.
568
+ - `--base-dir DIR` áp dụng như các lệnh git khác (path tương đối tính từ đây).
569
+ - Muốn thêm repo riêng, không muốn commit chung với team? Đừng dùng cách này —
570
+ tự thêm tay vào `.project.local.yaml` (xem mục riêng phía trên) thay vào đó.
571
+
572
+ **Không có `.project.yaml`?** Mọi lệnh git ở trên (trừ `pan clone` — cần `url`
573
+ khai báo trong manifest, không tự suy ra được) vẫn chạy: nếu walk-up từ cwd
574
+ không thấy `.project.yaml`, CLI **fallback** coi **chính thư mục đang gõ
575
+ lệnh** là gốc dự án và quét git repo con bên trong (giống cách `pan stats`
576
+ fallback — pwd + tối đa 2 cấp con, bỏ qua `node_modules`/`.git`/`dist`/…). Nhờ
577
+ vậy dùng được `pan pull|push|fetch|checkout|sync-main|mr|grv|gst` ngay cả khi
578
+ chưa có/không dùng workspace pan-stack, miễn thư mục gốc chứa các repo git con.
579
+
580
+ ### Bảng tổng hợp `pull` / `push` / `fetch` / `gst` / `clone` / `grv`
581
+
582
+ 6 lệnh trên chạy git **im lặng** (không xả output raw của từng repo), in một dòng
583
+ tiến trình gọn cho mỗi repo (` ↻ csdl-cc-backend (main) ... fast-forward`), rồi
584
+ đóng bằng **bảng tổng hợp** ở cuối để bạn nhìn được ngay bức tranh tổng:
585
+
586
+ - **`pull`** — cột `result` (`up-to-date · fast-forward · merge · rebase · conflict · failed`), `changes` (`N files +add −del`), `conflict` (danh sách file mâu thuẫn ở footer nếu có).
587
+ - **`push`** — cột `result` (`pushed · up-to-date · rejected`), `commits` (số commit `ahead` trước push), `changes` (tổng `N files +add −del` cộng từ mọi commit sắp đẩy), `MR/PR link` (parse URL merge_request/pull do GitLab/GitHub in ở stderr; footer có tổng dòng đã push).
588
+ - **`fetch`** — chạy `git fetch --all --prune`, cột `behind/ahead` so upstream sau fetch (↓ = có commit mới ở remote → gợi ý `pan pull`), `new refs` (new / updated / tags / pruned).
589
+ - **`gst`** — chỉ liệt kê repo dirty / đang merge-rebase / lỗi; hiển thị `state`, `breakdown` (staged/unstaged/untracked), `behind/ahead`; repo sạch được đếm ẩn.
590
+ - **`clone`** — cột `result` (`cloned · already exists · no access · not found · failed`), `note` (dòng lỗi ngắn gọn — chỉ lấy dòng `fatal:`/`remote:`, KHÔNG in nguyên message thô/đường dẫn dài). Clone HẾT các repo rồi mới tổng hợp — 1 repo không có quyền/không tồn tại KHÔNG chặn các repo còn lại.
591
+ - **`grv`** — cột `remote` (tên remote, `origin (+N)` nếu có nhiều remote), `fetch`/`push` (URL; `push` in `=` khi giống hệt `fetch` cho gọn bảng).
592
+
593
+ Muốn xem output raw thô như trước? Dùng `--verbose` với `gst` (hoặc chạy `git`
594
+ trực tiếp trong repo).
595
+
596
+ ## `pan stats` — Git contribution stats
597
+
598
+ Thống kê đóng góp Git cho các repo trong `.project.yaml` (đọc `git log`). Vì
599
+ PAN Stack là **vỏ bọc** và không phải ai cũng clone đủ repo, repo nào **thiếu /
600
+ không đọc được** sẽ được **báo lên report** (khung cảnh báo) thay vì làm hỏng
601
+ thống kê. Alias `pan graph`.
602
+
603
+ **Không có `.project.yaml`?** `pan stats` vẫn chạy: nếu walk-up không thấy
604
+ `.project.yaml`, nó **fallback** quét git từ **chính `pwd` xuống tối đa 2 cấp
605
+ con** (gồm bản thân `pwd`, thư mục con trực tiếp, và 1 cấp con nữa — đủ bắt
606
+ submodule), không đọc sâu hơn. Nhờ vậy dùng được kể cả khi chưa `pan create`/init
607
+ workspace.
608
+
609
+ | Command | Action |
610
+ | -------------------- | ------------------------------------------------------------------------------------------------ |
611
+ | `pan stats [report]` | Quét → dựng báo cáo HTML (Tailwind CDN, bảng màu FPT) → serve `localhost:4321` và mở trình duyệt |
612
+ | `pan stats people` | Liệt kê thành viên tham gia (gộp theo email) |
613
+ | `pan stats review` | Xuất Markdown code-change của 1 thành viên × 1 dự án cho AI review/chấm điểm |
614
+
615
+ Bộ lọc thời gian (dùng chung cho mọi lệnh):
616
+
617
+ - `--since <n>` — preset ngày: `1 2 3 4 5 7 14 30` (30 = "1 tháng")
618
+ - `--from <YYYY-MM-DD> --to <YYYY-MM-DD>` — khoảng ngày tuỳ chọn
619
+ - Không truyền → toàn bộ lịch sử
620
+
621
+ Options khác:
622
+
623
+ - `-m, --member <email|tên>` — lọc theo thành viên (bắt buộc với `review`)
624
+ - `-p, --project <tên repo>` — lọc theo dự án (bắt buộc với `review`)
625
+ - `--port <n>` — cổng serve (mặc định `4321`)
626
+ - `--no-open` — không tự mở trình duyệt
627
+ - `-o, --out <file>` — nơi ghi HTML/Markdown
628
+ - `--no-diff` — (`review`) chỉ tóm tắt, bỏ diff
629
+ - `--max-diff-lines <n>` — (`review`) giới hạn số dòng diff (mặc định `6000`)
630
+ - `--head-only` — chỉ quét HEAD hiện tại. **Mặc định** dùng `git log --all` để
631
+ gộp commit từ **mọi nhánh** (local + remote-tracking + tags), git tự dedupe
632
+ theo hash. Nếu đồng đội commit ở nhánh chưa có bản sao remote-tracking, chạy
633
+ `pan fetch` trước để cập nhật.
634
+
635
+ Báo cáo HTML tương tác (lọc chạy phía client trên toàn bộ commit đã nhúng):
636
+
637
+ - **Bộ lọc thời gian ngay trên trang**: nút preset `Tất cả · 1n · 2n · 3n · 4n ·
638
+ 5n · 7n · 14n · 1 tháng` + ô `from → to` (Áp dụng) cho khoảng ngày tuỳ chọn.
639
+ - **Dropdown chọn thành viên (multi-select)**: checkbox từng người, "Chọn tất
640
+ cả / Bỏ chọn"; rỗng = tất cả. (Thay cho ô lọc text.)
641
+ - Mỗi thành viên một **card** (1/3 desktop · 50% tablet · full mobile), bấm để
642
+ bung danh sách dự án với commit + `+add`/`−del`; nút **"Mở tất cả"**.
643
+ - **Bảng tổng hợp** cuối trang có hàng TỔNG — tự cập nhật theo bộ lọc.
644
+
645
+ Các cờ CLI `--since/--from/--to/--member` chỉ đặt **giá trị khởi tạo** cho báo
646
+ cáo; sau đó lọc trực tiếp trên trình duyệt. (Merge commit bị loại; danh tính gộp
647
+ theo email — sửa tay qua `~/.pan-code-graph/alias-map.json`.)
648
+
649
+ `pan stats review` xuất file `.md` gồm bảng commit + diff, kèm sẵn **prompt chấm
650
+ điểm 1–10** (đúng đắn · chất lượng · an toàn · test · nhất quán) để dán cho AI.
651
+
652
+ Đầu ra lưu tại `~/.pan-code-graph/` (`report.html`, `review-*.md`, `alias-map.json`).
653
+
654
+ Ví dụ:
655
+
656
+ ```bash
657
+ pan stats --since 7 # báo cáo 7 ngày gần đây
658
+ pan stats report --from 2026-07-01 --to 2026-07-22 # khoảng ngày tuỳ chọn
659
+ pan stats people --since 30 # ai tham gia trong 1 tháng
660
+ pan stats review -m an@fpt.com -p csdl-cc-backend --since 7 -o review.md
661
+ ```
662
+
663
+ ### `pan mr` — GitLab Merge Requests
664
+
665
+ Creates Merge Requests for the workspace stack root + each repo in `.project.yaml`
666
+ that has commits ahead of `origin/<target>`. Does NOT auto-push — run `pan push`
667
+ first if HEAD is not on the remote yet. Selection modes:
668
+
669
+ - `pan mr` — interactive checkbox picker (target = `main`)
670
+ - `pan mr develop` — interactive checkbox picker (target = `develop`)
671
+ - `pan mr main all` — non-interactive, all repos
672
+ - `pan mr main csdl-cc-backend,csdl-cc-b-frontend` — comma/space list
673
+ - `pan mr main csdl-cc-backend` — single repo
674
+
675
+ Interactive picker theo [quy ước chung](#quy-ước-chung-cho-mọi-menu-tương-tác-trong-pan) (`menuCheckbox`):
676
+ `↑↓` di chuyển · `space` chọn · `a` chọn tất cả · `i` đảo chọn · `x` thoát · `Enter` xác nhận
677
+ (nếu thiếu `@inquirer/core`, tự fallback `@inquirer/prompts` rồi readline nhập số).
678
+
679
+ Result rows: `✓` (new MR) · `=` (existing open MR) · `!` (needs `pan push` first) ·
680
+ `-` (skipped: no commits ahead / detached HEAD / already on target) · `✗` (error).
681
+
682
+ Token resolution: `--token` flag → `GITLAB_TOKEN` env var →
683
+ `<workspace>/.pan-env-build.yaml`. GitLab host is derived per-repo from the
684
+ `origin` remote URL; override with `--gitlab-host HOST` if needed.
685
+
686
+ ### `pan checkout` — switch/create branches across repos
687
+
688
+ Chuyển hoặc tạo nhánh trên workspace stack root + các repo con trong `.project.yaml`.
689
+ Interactive checkbox picker (arrow keys + space) khi chạy trong TTY và không
690
+ truyền lựa chọn.
691
+
692
+ - `pan co main` — switch tất cả (tương tác chọn repo)
693
+ - `pan co -b feat/#1234` — tạo nhánh mới từ HEAD (tương tác chọn repo)
694
+ - `pan co -b feat/#1234 all` — tạo trên tất cả repo
695
+ - `pan co -b feat/#1234 csdl-cc-backend,csdl-cc-b-frontend` — tạo trên list cụ thể
696
+ - `pan co -B hotfix/x --start-point origin/main` — force-reset `hotfix/x` từ `origin/main`
697
+ - `pan co develop csdl-cc-backend` — switch một repo
698
+
699
+ Picker theo [quy ước chung](#quy-ước-chung-cho-mọi-menu-tương-tác-trong-pan): `↑↓` di chuyển ·
700
+ `space` chọn · `a` chọn tất cả · `i` đảo chọn · `x` thoát · `Enter` xác nhận. Non-TTY (stdin bị
701
+ pipe) hoặc CI thì bắt buộc truyền `all` / tên repo / list.
702
+
703
+ Flags:
704
+
705
+ - `-b <branch>` — `git checkout -b` (fail nếu nhánh đã tồn tại local)
706
+ - `-B <branch>` — `git checkout -B` (tạo hoặc reset về `--start-point`)
707
+ - `--start-point REF` — base ref cho `-b`/`-B` (default: HEAD hiện tại)
708
+ - `--no-workspace` — bỏ qua workspace stack root
709
+
710
+ Result rows: `✓` (chuyển/tạo mới) · `=` (đã ở nhánh đó) · `!` (nhánh đã tồn tại
711
+ khi dùng `-b` — dùng `-B` để reset hoặc bỏ `-b` để switch) · `-` (skipped: chưa
712
+ clone / dry-run) · `✗` (lỗi: branch không tồn tại, dirty tree conflict, start-point
713
+ không hợp lệ, v.v.). Không tự stash — commit hoặc `git stash` trước nếu dirty.
714
+
173
715
  Works from child repo directories — the CLI walks up to find `.project.yaml`.
174
716
 
175
717
  ## Project commands
@@ -180,12 +722,12 @@ use `--project <name>` or pick interactively.
180
722
 
181
723
  ### Environment variables
182
724
 
183
- | Variable | Meaning |
184
- |----------|---------|
185
- | `PAN_WORKSPACE_ROOT` | Directory containing `.project.yaml` |
186
- | `PAN_REPO_ROOT` | Directory containing the active `.pan.yaml` |
187
- | `PAN_PROJECT_ROOT` | Alias of `PAN_WORKSPACE_ROOT` |
188
- | `PAN_ARG_1`, … | Arguments after the command name |
725
+ | Variable | Meaning |
726
+ | -------------------- | ------------------------------------------- |
727
+ | `PAN_WORKSPACE_ROOT` | Directory containing `.project.yaml` |
728
+ | `PAN_REPO_ROOT` | Directory containing the active `.pan.yaml` |
729
+ | `PAN_PROJECT_ROOT` | Alias of `PAN_WORKSPACE_ROOT` |
730
+ | `PAN_ARG_1`, … | Arguments after the command name |
189
731
 
190
732
  ### Registry (optional)
191
733
 
@@ -203,11 +745,17 @@ pan-stack-cli/
203
745
  platform.js # Windows/cross-platform helpers
204
746
  manifest.js # YAML parsing
205
747
  run-command.js # command execution
206
- git/ # clone, pull, sync-main, push, fetch, grv, gst
207
- templates/workspace/ # pan create template
208
- references/ # npm publish docs
748
+ git/ # clone, pull, sync-main, push, fetch, mr, checkout, grv, gst
749
+ stats/ # pan stats: scan git log → report HTML / people / review md
750
+ skill-registry-client.js # HTTP client cho registry server (fetch/download/extract — dùng
751
+ # chung bởi `pan ai install/update`, `pan create`, `pan ui init`)
752
+ references/ # npm publish docs (KHÔNG publish lên npm — xem package.json "files")
209
753
  ```
210
754
 
755
+ Template (`pan create` scaffold + `pan ui init` mẫu landing/mobile/cms) **KHÔNG còn nằm
756
+ trong package này** — sống ở `apps/pan-agent-skill-registry/registry/templates/` và được
757
+ tải qua registry server lúc chạy (xem 2 mục ở trên).
758
+
211
759
  ## Local development
212
760
 
213
761
  Install globally from source: [references/npm-development.md](references/npm-development.md).