@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 +21 -0
- package/README.en.md +139 -0
- package/README.md +138 -0
- package/bin/cli.js +182 -0
- package/docs/harness-engineering-tutorial.en.md +322 -0
- package/docs/harness-engineering-tutorial.md +322 -0
- package/package.json +38 -0
- package/skills/init-harness/SKILL.md +121 -0
- package/templates/agents/README.md +43 -0
- package/templates/agents/repo-explorer.md +27 -0
- package/templates/evals/README.md +51 -0
- package/templates/evals/cases/example-task.md +33 -0
- package/templates/evals/observability.md +42 -0
- package/templates/guardrails/README.md +120 -0
- package/templates/long-running/README.md +48 -0
- package/templates/long-running/TASK.md +33 -0
- package/templates/mcp-audit.md +26 -0
- package/templates/new-worktree.sh +35 -0
- package/templates/settings.json +24 -0
- package/templates/setup.sh +51 -0
- package/templates/spec/FEATURE.md +40 -0
- package/templates/spec/README.md +34 -0
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
|
+
[](https://www.npmjs.com/package/@htechcs/harness-kit)
|
|
8
|
+
[](LICENSE)
|
|
9
|
+

|
|
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> <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> <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> <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> <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
|
+
[](https://www.npmjs.com/package/@htechcs/harness-kit)
|
|
8
|
+
[](LICENSE)
|
|
9
|
+

|
|
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> <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> <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> <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> <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) })
|