@htechcs/harness-kit 0.1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 HoangTechCS-AIE
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.en.md ADDED
@@ -0,0 +1,139 @@
1
+ <div align="center">
2
+
3
+ # 🛠️ harness-kit
4
+
5
+ **Set up any repo for a coding agent (Claude Code) across the 5 maturity levels of harness engineering — in one command.**
6
+
7
+ [![npm](https://img.shields.io/npm/v/@htechcs/harness-kit?logo=npm&color=cb3837)](https://www.npmjs.com/package/@htechcs/harness-kit)
8
+ [![license](https://img.shields.io/badge/license-MIT-blue)](LICENSE)
9
+ ![node](https://img.shields.io/badge/node-%E2%89%A518-brightgreen)
10
+
11
+ [Tiếng Việt](README.md) · **English**
12
+
13
+ </div>
14
+
15
+ ---
16
+
17
+ **Harness** = everything *around* the model (context, instructions, tools, safety constraints,
18
+ orchestration, measurement) that makes an agent reliable. This kit packages it into installable
19
+ **artifacts** plus a **tutorial** that teaches *when* to use each. The kit ships files; the tutorial
20
+ teaches the discipline.
21
+
22
+ ## ⚙️ How it works
23
+
24
+ ```mermaid
25
+ flowchart LR
26
+ D([You]) -->|"npx @htechcs/harness-kit"| I[["harness-kit<br/>installer"]]
27
+ I --> R1[".claude/<br/>settings.json · agents/"]
28
+ I --> R2["repo root<br/>setup.sh · TASK.md"]
29
+ I --> R3["~/.claude/skills/<br/>init-harness"]
30
+ I --> R4["docs/harness/<br/>tutorial + guides"]
31
+ R1 --> A([Claude Code<br/>reads every session])
32
+ R2 --> A
33
+ R3 --> A
34
+ R4 --> A
35
+ ```
36
+
37
+ One `npx` command drops artifacts in the right places; from there Claude Code reads them every session.
38
+
39
+ ## 🚀 Quick install
40
+
41
+ ```bash
42
+ npx @htechcs/harness-kit # pick levels interactively, then install
43
+ npx @htechcs/harness-kit --all # install all 5 levels
44
+ npx @htechcs/harness-kit --levels=1,3 # specific levels only
45
+ ```
46
+
47
+ Requires **Node ≥18**. The command saves all docs into `docs/harness/` so your team keeps them.
48
+ **Idempotent** — safe to re-run (`--force` to overwrite).
49
+
50
+ ## 🪜 The 5 levels — each prevents a failure mode
51
+
52
+ ```mermaid
53
+ flowchart TD
54
+ L1["Level 1 · Foundation — CLAUDE.md"] --> L2["Level 2 · Clean context"]
55
+ L2 --> L3["Level 3 · Guardrails"]
56
+ L3 --> L4["Level 4 · Long-running"]
57
+ L4 --> L5["Level 5 · Evals & Observability"]
58
+ L5 -.->|"surface a failure → reinforce the harness"| L1
59
+ ```
60
+
61
+ | Level | Without it | Artifact |
62
+ |-------|------------|----------|
63
+ | **1 — Foundation** | the agent has no durable repo guidance | `/init-harness` skill → generates `CLAUDE.md` |
64
+ | **2 — Clean context** | context floods, the agent's attention dilutes | sample subagent + MCP audit checklist |
65
+ | **3 — Guardrails** | agent deletes/pushes by mistake, asks permission nonstop | `settings.json` (deny/ask/allow) |
66
+ | **4 — Long-running** | long tasks break mid-way, can't resume | `setup.sh`, `new-worktree.sh`, `TASK.md` |
67
+ | **5 — Evals & Obs** | no idea whether the agent does well or badly | golden-task template + observability guide |
68
+
69
+ ## 📦 Manual install per level
70
+
71
+ > The installer just automates the `cp` commands below — expand them to understand/do it by hand.
72
+
73
+ <details>
74
+ <summary><b>Level 1 — Foundation · CLAUDE.md</b> &nbsp;<code>[do this first]</code></summary>
75
+
76
+ ```bash
77
+ cp -r skills/init-harness ~/.claude/skills/ # then run /init-harness in the target repo
78
+ ```
79
+ </details>
80
+
81
+ <details>
82
+ <summary><b>Level 2 — Clean context</b></summary>
83
+
84
+ ```bash
85
+ mkdir -p .claude/agents && cp templates/agents/repo-explorer.md .claude/agents/
86
+ ```
87
+ Read `templates/agents/README.md` + `templates/mcp-audit.md`.
88
+ </details>
89
+
90
+ <details>
91
+ <summary><b>Level 3 — Guardrails</b> &nbsp;<code>[points into CLAUDE.md]</code></summary>
92
+
93
+ ```bash
94
+ mkdir -p .claude && cp templates/settings.json .claude/settings.json
95
+ ```
96
+ **First thing to do:** add your repo's test/lint commands to `allow` (see `templates/guardrails/README.md`).
97
+ </details>
98
+
99
+ <details>
100
+ <summary><b>Level 4 — Long-running</b> &nbsp;<code>[points into CLAUDE.md]</code></summary>
101
+
102
+ ```bash
103
+ cp templates/setup.sh templates/new-worktree.sh . && chmod +x setup.sh new-worktree.sh
104
+ cp templates/long-running/TASK.md . # when starting a long task
105
+ ```
106
+ </details>
107
+
108
+ <details>
109
+ <summary><b>Level 5 — Evals & Observability</b> &nbsp;<code>[needs ≥1 level applied to have something to measure]</code></summary>
110
+
111
+ ```bash
112
+ mkdir -p evals/cases && cp templates/evals/cases/example-task.md evals/cases/
113
+ ```
114
+ Read `templates/evals/README.md` (includes a **no-harness baseline** step) + `observability.md`.
115
+ </details>
116
+
117
+ <details>
118
+ <summary><b>+ Specs</b> — the other half of Pillar 2</summary>
119
+
120
+ ```bash
121
+ mkdir -p docs/specs && cp templates/spec/FEATURE.md docs/specs/<feature>.md
122
+ ```
123
+ </details>
124
+
125
+ ## 🔗 Level dependencies
126
+
127
+ - **Level 1 first** — it's the backbone; later levels reference `CLAUDE.md`.
128
+ - **Levels 3 & 4** both "point `CLAUDE.md` to" their artifacts → require Level 1 done.
129
+ - **Level 5** needs at least one level applied to have a change to measure (see the feedback loop above).
130
+
131
+ ## 📚 Docs
132
+
133
+ `docs/harness-engineering-tutorial.en.md` ([Tiếng Việt](docs/harness-engineering-tutorial.md)) — the
134
+ why + *when* to use each piece (after install: `docs/harness/`). Full industry-wide source catalog:
135
+ [Awesome Harness Engineering](https://github.com/walkinglabs/awesome-harness-engineering).
136
+
137
+ ## 📄 License
138
+
139
+ [MIT](LICENSE).
package/README.md ADDED
@@ -0,0 +1,138 @@
1
+ <div align="center">
2
+
3
+ # 🛠️ harness-kit
4
+
5
+ **Thiết lập repo cho coding agent (Claude Code) theo 5 mức trưởng thành của harness engineering — bằng một lệnh.**
6
+
7
+ [![npm](https://img.shields.io/npm/v/@htechcs/harness-kit?logo=npm&color=cb3837)](https://www.npmjs.com/package/@htechcs/harness-kit)
8
+ [![license](https://img.shields.io/badge/license-MIT-blue)](LICENSE)
9
+ ![node](https://img.shields.io/badge/node-%E2%89%A518-brightgreen)
10
+
11
+ **Tiếng Việt** · [English](README.en.md)
12
+
13
+ </div>
14
+
15
+ ---
16
+
17
+ **Harness** = mọi thứ *bao quanh* model (context, chỉ dẫn, tools, ràng buộc an toàn, orchestration,
18
+ đo lường) để agent làm việc đáng tin. Kit này đóng gói nó thành **artifact** cài được + một
19
+ **tutorial** dạy *khi nào* dùng từng thứ. Kit ship file; tutorial dạy kỷ luật.
20
+
21
+ ## ⚙️ Hoạt động thế nào
22
+
23
+ ```mermaid
24
+ flowchart LR
25
+ D([Bạn]) -->|"npx @htechcs/harness-kit"| I[["harness-kit<br/>installer"]]
26
+ I --> R1[".claude/<br/>settings.json · agents/"]
27
+ I --> R2["repo root<br/>setup.sh · TASK.md"]
28
+ I --> R3["~/.claude/skills/<br/>init-harness"]
29
+ I --> R4["docs/harness/<br/>tutorial + guides"]
30
+ R1 --> A([Claude Code<br/>đọc mỗi session])
31
+ R2 --> A
32
+ R3 --> A
33
+ R4 --> A
34
+ ```
35
+
36
+ Một lệnh `npx` rải artifact vào đúng chỗ; từ đó Claude Code đọc chúng ở mọi phiên làm việc.
37
+
38
+ ## 🚀 Cài nhanh
39
+
40
+ ```bash
41
+ npx @htechcs/harness-kit # hỏi chọn mức rồi cài
42
+ npx @htechcs/harness-kit --all # cài cả 5 mức
43
+ npx @htechcs/harness-kit --levels=1,3 # chỉ mức cụ thể
44
+ ```
45
+
46
+ Cần **Node ≥18**. Lệnh lưu toàn bộ tài liệu vào `docs/harness/` để team giữ lại. **Idempotent** —
47
+ chạy lại an toàn (`--force` để ghi đè).
48
+
49
+ ## 🪜 5 mức — mỗi mức chặn một kiểu thất bại
50
+
51
+ ```mermaid
52
+ flowchart TD
53
+ L1["Mức 1 · Nền tảng — CLAUDE.md"] --> L2["Mức 2 · Context sạch"]
54
+ L2 --> L3["Mức 3 · Guardrails"]
55
+ L3 --> L4["Mức 4 · Long-running"]
56
+ L4 --> L5["Mức 5 · Evals & Observability"]
57
+ L5 -.->|"phát hiện lỗi → gia cố harness"| L1
58
+ ```
59
+
60
+ | Mức | Khi không có nó | Artifact |
61
+ |-----|-----------------|----------|
62
+ | **1 — Nền tảng** | agent không có chỉ dẫn repo bền vững | skill `/init-harness` → sinh `CLAUDE.md` |
63
+ | **2 — Context sạch** | context ngập, agent "loãng" sự chú ý | subagent mẫu + checklist rà MCP |
64
+ | **3 — Guardrails** | agent xoá/push nhầm, bị hỏi quyền liên tục | `settings.json` (deny/ask/allow) |
65
+ | **4 — Long-running** | việc dài đứt giữa chừng, không resume | `setup.sh`, `new-worktree.sh`, `TASK.md` |
66
+ | **5 — Evals & Obs** | không biết agent làm tốt hay tệ | golden-task template + guide observability |
67
+
68
+ ## 📦 Cài tay từng mức
69
+
70
+ > Installer chỉ tự động hoá đúng những lệnh `cp` dưới đây — mở ra nếu muốn hiểu/làm thủ công.
71
+
72
+ <details>
73
+ <summary><b>Mức 1 — Nền tảng · CLAUDE.md</b> &nbsp;<code>[làm trước tiên]</code></summary>
74
+
75
+ ```bash
76
+ cp -r skills/init-harness ~/.claude/skills/ # rồi gõ /init-harness trong repo đích
77
+ ```
78
+ </details>
79
+
80
+ <details>
81
+ <summary><b>Mức 2 — Context sạch</b></summary>
82
+
83
+ ```bash
84
+ mkdir -p .claude/agents && cp templates/agents/repo-explorer.md .claude/agents/
85
+ ```
86
+ Đọc `templates/agents/README.md` + `templates/mcp-audit.md`.
87
+ </details>
88
+
89
+ <details>
90
+ <summary><b>Mức 3 — Guardrails</b> &nbsp;<code>[trỏ vào CLAUDE.md]</code></summary>
91
+
92
+ ```bash
93
+ mkdir -p .claude && cp templates/settings.json .claude/settings.json
94
+ ```
95
+ **Việc đầu tiên:** thêm lệnh test/lint của repo vào `allow` (xem `templates/guardrails/README.md`).
96
+ </details>
97
+
98
+ <details>
99
+ <summary><b>Mức 4 — Long-running</b> &nbsp;<code>[trỏ vào CLAUDE.md]</code></summary>
100
+
101
+ ```bash
102
+ cp templates/setup.sh templates/new-worktree.sh . && chmod +x setup.sh new-worktree.sh
103
+ cp templates/long-running/TASK.md . # khi bắt đầu một việc dài
104
+ ```
105
+ </details>
106
+
107
+ <details>
108
+ <summary><b>Mức 5 — Evals & Observability</b> &nbsp;<code>[cần ≥1 mức đã áp để có cái mà đo]</code></summary>
109
+
110
+ ```bash
111
+ mkdir -p evals/cases && cp templates/evals/cases/example-task.md evals/cases/
112
+ ```
113
+ Đọc `templates/evals/README.md` (có bước **baseline không-harness**) + `observability.md`.
114
+ </details>
115
+
116
+ <details>
117
+ <summary><b>+ Specs</b> — nửa còn lại của Trụ cột 2</summary>
118
+
119
+ ```bash
120
+ mkdir -p docs/specs && cp templates/spec/FEATURE.md docs/specs/<feature>.md
121
+ ```
122
+ </details>
123
+
124
+ ## 🔗 Phụ thuộc giữa các mức
125
+
126
+ - **Mức 1 trước hết** — xương sống; các mức sau viện tới `CLAUDE.md`.
127
+ - **Mức 3 & 4** đều "trỏ `CLAUDE.md` tới" artifact của chúng → cần Mức 1 xong.
128
+ - **Mức 5** cần ít nhất một mức đã áp để có thay đổi mà đo (xem vòng feedback ở sơ đồ trên).
129
+
130
+ ## 📚 Tài liệu
131
+
132
+ `docs/harness-engineering-tutorial.md` ([English](docs/harness-engineering-tutorial.en.md)) — vì sao +
133
+ *khi nào* dùng từng thứ (sau khi cài: `docs/harness/`). Danh mục nguồn đầy đủ của cả ngành:
134
+ [Awesome Harness Engineering](https://github.com/walkinglabs/awesome-harness-engineering).
135
+
136
+ ## 📄 License
137
+
138
+ [MIT](LICENSE).
package/bin/cli.js ADDED
@@ -0,0 +1,182 @@
1
+ #!/usr/bin/env node
2
+ 'use strict'
3
+
4
+ // harness-kit — installer cho Harness Engineering starter kit.
5
+ // Chạy: npx harness-kit (hỏi chọn mức)
6
+ // npx harness-kit --all (cài hết, không hỏi)
7
+ // npx harness-kit --levels=1,3,4
8
+ // Cờ phụ: --target=<dir> (mặc định thư mục hiện tại), --force (ghi đè), --help.
9
+ //
10
+ // Nguyên tắc: IDEMPOTENT (chạy lại an toàn — file đã có thì bỏ qua trừ khi --force)
11
+ // và FAIL-SOFT (thiếu một artifact thì cảnh báo, không sập cả lần cài).
12
+
13
+ const fs = require('fs')
14
+ const path = require('path')
15
+ const os = require('os')
16
+ const readline = require('readline')
17
+
18
+ const KIT = path.resolve(__dirname, '..') // gốc package (nơi có templates/, skills/, docs/)
19
+ const HOME = os.homedir()
20
+ let TARGET = process.cwd() // đặt lại trong main(); dùng để hiển thị đường dẫn cho gọn
21
+
22
+ // ---- Bản đồ artifact theo mức: [nguồn-trong-kit, đích]. Đích tuyệt đối = cài cấp user. ----
23
+ const LEVELS = {
24
+ '1': {
25
+ title: 'Mức 1 — Nền tảng (CLAUDE.md)',
26
+ copy: [['skills/init-harness', path.join(HOME, '.claude', 'skills', 'init-harness')]],
27
+ next: 'Gõ /init-harness trong repo đích để sinh CLAUDE.md.',
28
+ },
29
+ '2': {
30
+ title: 'Mức 2 — Context sạch',
31
+ copy: [['templates/agents/repo-explorer.md', '.claude/agents/repo-explorer.md']],
32
+ next: 'Đọc docs/harness/agents-README.md (quy tắc subagent) + mcp-audit.md (rà MCP thừa).',
33
+ },
34
+ '3': {
35
+ title: 'Mức 3 — Guardrails',
36
+ copy: [['templates/settings.json', '.claude/settings.json']],
37
+ next: 'MỞ .claude/settings.json → thêm lệnh test/lint của repo vào "allow" (xem docs/harness/guardrails-README.md). Đây là việc ĐẦU TIÊN.',
38
+ },
39
+ '4': {
40
+ title: 'Mức 4 — Long-running',
41
+ copy: [
42
+ ['templates/setup.sh', 'setup.sh'],
43
+ ['templates/new-worktree.sh', 'new-worktree.sh'],
44
+ ],
45
+ chmod: ['setup.sh', 'new-worktree.sh'],
46
+ next: 'Điền setup.sh cho repo bạn; copy docs/harness/TASK.md ra khi bắt đầu một việc dài.',
47
+ },
48
+ '5': {
49
+ title: 'Mức 5 — Evals & Observability',
50
+ copy: [['templates/evals/cases/example-task.md', 'evals/cases/example-task.md']],
51
+ next: 'Đọc docs/harness/evals-README.md (có bước baseline "không harness") + observability.md.',
52
+ },
53
+ }
54
+
55
+ // ---- Tài liệu hướng dẫn: luôn copy vào <target>/docs/harness/ để team GIỮ LẠI ----
56
+ // (npx cache biến mất sau khi chạy, nên phải đổ guidance vào repo.)
57
+ const GUIDE_DIR = path.join('docs', 'harness')
58
+ const GUIDE = [
59
+ ['docs/harness-engineering-tutorial.md', 'tutorial.md'],
60
+ ['docs/harness-engineering-tutorial.en.md', 'tutorial.en.md'],
61
+ ['README.md', 'kit-README.md'],
62
+ ['templates/agents/README.md', 'agents-README.md'],
63
+ ['templates/mcp-audit.md', 'mcp-audit.md'],
64
+ ['templates/guardrails/README.md', 'guardrails-README.md'],
65
+ ['templates/long-running/README.md', 'long-running-README.md'],
66
+ ['templates/long-running/TASK.md', 'TASK.md'],
67
+ ['templates/evals/README.md', 'evals-README.md'],
68
+ ['templates/evals/observability.md', 'observability.md'],
69
+ ['templates/spec/README.md', 'spec-README.md'],
70
+ ['templates/spec/FEATURE.md', 'FEATURE.md'],
71
+ ]
72
+
73
+ function parseArgs(argv) {
74
+ const o = { levels: null, all: false, force: false, target: process.cwd(), help: false }
75
+ for (const a of argv) {
76
+ if (a === '--all') o.all = true
77
+ else if (a === '--force') o.force = true
78
+ else if (a === '--help' || a === '-h') o.help = true
79
+ else if (a.startsWith('--levels=')) o.levels = a.slice(9).split(',').map((s) => s.trim()).filter(Boolean)
80
+ else if (a.startsWith('--target=')) o.target = path.resolve(a.slice(9))
81
+ }
82
+ return o
83
+ }
84
+
85
+ function showHelp() {
86
+ console.log(`
87
+ harness-kit — thiết lập repo cho coding agent theo 5 mức.
88
+
89
+ npx harness-kit hỏi chọn mức rồi cài
90
+ npx harness-kit --all cài cả 5 mức
91
+ npx harness-kit --levels=1,3 cài mức cụ thể
92
+
93
+ Cờ:
94
+ --target=<dir> thư mục đích (mặc định: thư mục hiện tại)
95
+ --force ghi đè file đã tồn tại (mặc định: bỏ qua)
96
+ --help
97
+
98
+ Mức: 1 Nền tảng · 2 Context · 3 Guardrails · 4 Long-running · 5 Evals.
99
+ Tài liệu luôn được đổ vào <target>/docs/harness/.
100
+ `)
101
+ }
102
+
103
+ function rel(p) {
104
+ if (p.startsWith(HOME)) return '~' + p.slice(HOME.length)
105
+ if (p.startsWith(TARGET)) return path.relative(TARGET, p) || '.'
106
+ return p
107
+ }
108
+
109
+ // Đặt một artifact. destAbs: đường dẫn tuyệt đối đã resolve.
110
+ function place(srcRel, destAbs, force) {
111
+ const src = path.join(KIT, srcRel)
112
+ if (!fs.existsSync(src)) {
113
+ console.log(` ⚠ thiếu trong kit, bỏ qua: ${srcRel}`)
114
+ return false
115
+ }
116
+ if (fs.existsSync(destAbs) && !force) {
117
+ console.log(` • đã có, giữ nguyên: ${rel(destAbs)} (dùng --force để ghi đè)`)
118
+ return false
119
+ }
120
+ fs.mkdirSync(path.dirname(destAbs), { recursive: true })
121
+ fs.cpSync(src, destAbs, { recursive: true })
122
+ console.log(` ✓ ${rel(destAbs)}`)
123
+ return true
124
+ }
125
+
126
+ function installLevel(key, target, force) {
127
+ const lv = LEVELS[key]
128
+ if (!lv) {
129
+ console.log(`\n(bỏ qua mức không hợp lệ: ${key})`)
130
+ return
131
+ }
132
+ console.log(`\n${lv.title}`)
133
+ for (const [srcRel, dest] of lv.copy) {
134
+ const destAbs = path.isAbsolute(dest) ? dest : path.join(target, dest)
135
+ place(srcRel, destAbs, force)
136
+ }
137
+ for (const f of lv.chmod || []) {
138
+ const p = path.join(target, f)
139
+ try { if (fs.existsSync(p)) fs.chmodSync(p, 0o755) } catch (_) {}
140
+ }
141
+ }
142
+
143
+ function installGuide(target, force) {
144
+ console.log(`\nTài liệu hướng dẫn → ${path.join(rel(path.join(target, GUIDE_DIR)))}/`)
145
+ for (const [srcRel, name] of GUIDE) {
146
+ place(srcRel, path.join(target, GUIDE_DIR, name), force)
147
+ }
148
+ }
149
+
150
+ function ask(question) {
151
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout })
152
+ return new Promise((resolve) => rl.question(question, (a) => { rl.close(); resolve(a) }))
153
+ }
154
+
155
+ async function main() {
156
+ const opt = parseArgs(process.argv.slice(2))
157
+ if (opt.help) { showHelp(); return }
158
+
159
+ TARGET = opt.target
160
+ console.log(`harness-kit → cài vào: ${opt.target}`)
161
+
162
+ let levels
163
+ if (opt.all) levels = Object.keys(LEVELS)
164
+ else if (opt.levels) levels = opt.levels
165
+ else if (process.stdin.isTTY) {
166
+ const a = (await ask('\nCài mức nào? [all] hoặc danh sách vd 1,3,4: ')).trim()
167
+ levels = !a || a.toLowerCase() === 'all' ? Object.keys(LEVELS) : a.split(',').map((s) => s.trim()).filter(Boolean)
168
+ } else {
169
+ levels = Object.keys(LEVELS) // không có TTY (CI/pipe) → cài hết
170
+ }
171
+
172
+ for (const k of levels) installLevel(k, opt.target, opt.force)
173
+ installGuide(opt.target, opt.force)
174
+
175
+ console.log('\n— Xong. Bước tiếp theo —')
176
+ for (const k of levels) {
177
+ if (LEVELS[k]) console.log(` [${k}] ${LEVELS[k].next}`)
178
+ }
179
+ console.log('\nĐọc trước hết: docs/harness/tutorial.md (vì sao + KHI NÀO dùng từng thứ).')
180
+ }
181
+
182
+ main().catch((e) => { console.error('harness-kit lỗi:', e.message); process.exit(1) })