create-harness-vibe-coding 0.8.0 → 0.8.2
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-CN.md +40 -24
- package/README.md +44 -20
- package/package.json +1 -1
- package/src/generator.js +1 -1
- package/src/index.js +211 -11
- package/src/prompts.js +1 -1
- package/templates/common/.claude/agents/tdd-guide.md +55 -0
- package/templates/common/.claude/settings.json +22 -0
- package/templates/common/.claude/skills/tdd/SKILL.md +30 -0
- package/templates/common/.claude/skills/wf-auto/SKILL.md +107 -0
- package/templates/common/.claude/skills/wf-auto-spark/SKILL.md +39 -0
- package/templates/common/.claude/skills/wf-max/SKILL.md +10 -2
- package/templates/common/.claude/skills/wf-remove/SKILL.md +12 -5
- package/templates/common/.claude/skills/wf-update/SKILL.md +12 -5
- package/templates/common/.codex/hooks.json +59 -37
- package/templates/common/.harness-version +48 -25
- package/templates/common/AGENTS.md +5 -5
- package/templates/common/CLAUDE.md +12 -17
- package/templates/common/Harness/ECC-GUIDE.md +246 -0
- package/templates/common/Harness/README.md +129 -130
- package/templates/common/Harness/TDD-GUIDE.md +83 -0
- package/templates/common/Harness/WF-AUTO-SPARK.md +297 -0
- package/templates/common/Harness/WF-AUTO.md +508 -0
- package/templates/common/Harness/WF-MAX.md +24 -0
- package/templates/common/Harness/context-loading.md +38 -1
- package/templates/common/Harness/dispatch.md +40 -40
- package/templates/common/Harness/subagents.md +7 -21
- package/templates/common/Harness/tasks/_template/NAMING.md +47 -0
- package/templates/common/MEMORY.md +73 -66
- package/templates/common/SETUP.md +98 -63
- package/templates/common/scripts/validate-harness.mjs +92 -58
- package/templates/common/scripts/wf-mode-hook.mjs +895 -318
- package/templates/common/scripts/wf-remove.mjs +301 -81
- package/templates/common/scripts/wf-statusline.ps1 +62 -38
- package/templates/common/scripts/wf-statusline.sh +67 -48
- package/templates/common/scripts/wf-update-check.mjs +179 -81
- package/templates/optional/catalog.json +5 -5
package/README-CN.md
CHANGED
|
@@ -15,9 +15,11 @@ npx create-harness-vibe-coding@latest my-project
|
|
|
15
15
|
已有项目时,不要让 agent 猜。把这句话贴给它:
|
|
16
16
|
|
|
17
17
|
```text
|
|
18
|
-
|
|
18
|
+
请完整阅读并严格遵循 https://github.com/zingspark/create-harness-vibe-coding,为当前项目配置 create-harness-vibe-coding。
|
|
19
19
|
```
|
|
20
20
|
|
|
21
|
+
复杂规则不塞进这句话里。README 和生成后的 `Harness/SETUP.md` 才是安装、升级、合并和可选能力选择的准则。
|
|
22
|
+
|
|
21
23
|
## 你会得到什么
|
|
22
24
|
|
|
23
25
|
| 文件/能力 | 作用 |
|
|
@@ -25,8 +27,8 @@ npx create-harness-vibe-coding@latest my-project
|
|
|
25
27
|
| `CLAUDE.md` + `AGENTS.md` | 根目录 agent 入口 |
|
|
26
28
|
| `Harness/README.md` | Harness 路由器 |
|
|
27
29
|
| `Harness/tasks/` + `Harness/PROGRESS.md` | 跨会话任务状态 |
|
|
28
|
-
| `.claude/skills/` | Claude Code
|
|
29
|
-
| `.agents/skills/` | Codex
|
|
30
|
+
| `.claude/skills/` | Claude Code workflow skill 入口 |
|
|
31
|
+
| `.agents/skills/` | Codex repo skill 入口 |
|
|
30
32
|
| `.codex/` | Codex hooks/config |
|
|
31
33
|
| `/wf` / `$wf` | 长任务 workflow |
|
|
32
34
|
| `/wf-max` / `$wf-max` | 最大并行 workflow |
|
|
@@ -41,29 +43,31 @@ Claude Code 和 Codex 共用同一套核心 Harness 文档,但发现入口不
|
|
|
41
43
|
- Codex:`.agents/skills/<name>/SKILL.md`,通常用 `$wf` 或 `/skills` 调用。
|
|
42
44
|
- `.codex/` 只放 Codex 配置和 hooks;不要再使用根目录 `commands/*.toml` 伪装 Codex slash command。
|
|
43
45
|
|
|
44
|
-
##
|
|
46
|
+
## 安装或升级路径
|
|
45
47
|
|
|
46
|
-
|
|
47
|
-
npx create-harness-vibe-coding@latest my-project
|
|
48
|
-
cd my-project
|
|
49
|
-
```
|
|
48
|
+
写文件前,agent 必须先判断当前项目属于哪一种:
|
|
50
49
|
|
|
51
|
-
|
|
50
|
+
| 项目状态 | 必须怎么做 |
|
|
51
|
+
|---|---|
|
|
52
|
+
| 空项目或新项目 | 运行脚手架,然后遵循 `Harness/SETUP.md` 做 0-1 bootstrap |
|
|
53
|
+
| 已有项目,没有 `Harness/` | 先扫描项目事实,先 `--dry-run`,保留现有文件,只合并缺失的 Harness 指南 |
|
|
54
|
+
| 老项目或老架构迁移 | 现有代码和文档是事实来源,先 dry-run,再用 `Harness/SETUP.md` 从事实中补 PRD、研究、架构和任务计划 |
|
|
55
|
+
| 已经有 `Harness/` | 不要把 `npx` 当更新器;先问用户是运行 `/wf-update` / `$wf-update` / `node Harness/scripts/wf-update-check.mjs`,保持不动,还是批准后移除重装 |
|
|
52
56
|
|
|
53
|
-
|
|
54
|
-
读 Harness/SETUP.md。把这个项目从想法引导到第一个 vertical slice。
|
|
55
|
-
```
|
|
57
|
+
根目录扫描必须包括:顶层文件、`CLAUDE.md`、`AGENTS.md`、`.claude/`、`.agents/`、`.codex/`、`Harness/`、package 文件、CI 文件、应用入口、测试/构建命令、已有文档、已经安装的 skills/plugins/rules。推荐可选能力前,必须先排除已经安装的能力,避免重复推荐。
|
|
56
58
|
|
|
57
59
|
## 已有项目安全合并
|
|
58
60
|
|
|
59
61
|
```bash
|
|
60
|
-
#
|
|
61
|
-
npx create-harness-vibe-coding@latest my-app . -y --dry-run
|
|
62
|
+
# 先用机器可读预览,不写文件
|
|
63
|
+
npx create-harness-vibe-coding@latest my-app . -y --dry-run --json
|
|
62
64
|
|
|
63
65
|
# 只补缺失文件,不覆盖已有文件
|
|
64
|
-
npx create-harness-vibe-coding@latest my-app . -y --on-conflict skip
|
|
66
|
+
npx create-harness-vibe-coding@latest my-app . -y --on-conflict skip --json
|
|
65
67
|
```
|
|
66
68
|
|
|
69
|
+
JSON 输出就是 agent 的安装报告:`scan` 代替手写根目录探测,`plan.create` 交给脚本处理,只有 `agent.aiMergeRequired` 里的文件需要 AI 语义比较和用户监督合并。除非这个列表里出现冲突文件,否则不要读取包源码或模板。
|
|
70
|
+
|
|
67
71
|
`npx` 是安装和安全补缺入口,不是已安装 Harness 的同步更新器。项目里已经有 `Harness/` 后,Claude Code 用 `/wf-update`,Codex 用 `$wf-update`,或者直接运行:
|
|
68
72
|
|
|
69
73
|
```bash
|
|
@@ -90,33 +94,45 @@ npx create-harness-vibe-coding@latest my-app -y --recommend superpowers,codegrap
|
|
|
90
94
|
|
|
91
95
|
本地 workflow:`browser-e2e`、`ui-ux-review`、`ts-react-frontend`、`python-backend`、`github-pr-review`。
|
|
92
96
|
|
|
93
|
-
外部建议只写入 `Harness/SETUP.md
|
|
97
|
+
外部建议只写入 `Harness/SETUP.md`,不会自动安装第三方技能:
|
|
98
|
+
|
|
99
|
+
| 建议 | 用途 | 链接 |
|
|
100
|
+
|---|---|---|
|
|
101
|
+
| `superpowers` | 社区 skill registry 和 agent workflow | <https://github.com/obra/Superpowers> |
|
|
102
|
+
| `caveman` | 简洁低 token 的 agent 行为和记忆压缩 | <https://github.com/JuliusBrussee/caveman> |
|
|
103
|
+
| `agent-research` | 文献、产品、依赖和生态研究类 agent skills | <https://github.com/lingzhi227/agent-research-skills> |
|
|
104
|
+
| `codegraph` | 代码图谱或仓库地图工具 | <https://github.com/colbymchenry/codegraph> |
|
|
105
|
+
|
|
106
|
+
这些只是给用户 agent 自行评估的 GitHub 链接。脚手架不维护第三方安装步骤,只在确认项目尚未安装同类能力后记录用户选择。
|
|
94
107
|
|
|
95
108
|
不加 `-y` 时,CLI 会提供 checkbox/multiselect 选择。
|
|
96
109
|
|
|
97
110
|
## Agent-link 安装前置问题
|
|
98
111
|
|
|
99
|
-
Agent
|
|
112
|
+
Agent 应先拿机器可读安装报告,再最多问 3 个阻塞问题:
|
|
100
113
|
|
|
101
|
-
|
|
102
|
-
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
114
|
+
```bash
|
|
115
|
+
npx create-harness-vibe-coding@latest my-app . -y --dry-run --json
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
使用 `scan.markers`,不要手写一串根目录探测命令。`plan.create` 由脚本处理;只有 `agent.aiMergeRequired` 里的文件需要 AI 比较并由用户监督合并。
|
|
106
119
|
|
|
107
120
|
只在影响写入时提问:
|
|
108
121
|
|
|
109
122
|
- 已有 `CLAUDE.md` 或 `AGENTS.md`:合并缺失 Harness 指南、保持不动,还是跳过?
|
|
110
123
|
- 已有 `Harness/`:走 `/wf-update` / `$wf-update`、dry-run 补缺、保持不动,还是批准后移除重装?
|
|
111
|
-
-
|
|
124
|
+
- 排除已安装能力后,还要启用哪些本地 workflow,或只记录哪些外部 GitHub 推荐链接?
|
|
112
125
|
|
|
113
126
|
默认策略:保留已有文件,只补缺失内容。
|
|
114
127
|
|
|
115
128
|
## 验证
|
|
116
129
|
|
|
117
130
|
```bash
|
|
131
|
+
# 当前脚手架仓库
|
|
118
132
|
npm test
|
|
119
|
-
|
|
133
|
+
|
|
134
|
+
# 生成后的项目完成 bootstrap 后
|
|
135
|
+
node Harness/scripts/validate-harness.mjs --strict
|
|
120
136
|
```
|
|
121
137
|
|
|
122
138
|
## 项目结构
|
package/README.md
CHANGED
|
@@ -21,7 +21,7 @@ npx create-harness-vibe-coding@latest my-project
|
|
|
21
21
|
Already have a project? **Don't read the docs**. Paste this sentence. Your agent handles the rest.
|
|
22
22
|
|
|
23
23
|
```text
|
|
24
|
-
|
|
24
|
+
Read and follow https://github.com/zingspark/create-harness-vibe-coding exactly to configure this project with create-harness-vibe-coding.
|
|
25
25
|
```
|
|
26
26
|
|
|
27
27
|
That's it. Two paths into the harness — you type `npx`, or your agent reads the sentence.
|
|
@@ -104,16 +104,31 @@ cd my-project
|
|
|
104
104
|
# Your agent reads Harness/SETUP.md. Done.
|
|
105
105
|
```
|
|
106
106
|
|
|
107
|
+
### Install or Upgrade Path
|
|
108
|
+
|
|
109
|
+
Before writing, the agent must identify which path applies:
|
|
110
|
+
|
|
111
|
+
| Project state | Required action |
|
|
112
|
+
|---------------|-----------------|
|
|
113
|
+
| Empty or new project | Run the scaffold, then follow `Harness/SETUP.md` for 0-1 bootstrap |
|
|
114
|
+
| Existing project, no `Harness/` | Scan project facts first, run `--dry-run`, preserve existing files, merge only missing Harness guidance |
|
|
115
|
+
| Legacy architecture or older project docs | Treat existing code/docs as source of truth, dry-run first, then use `Harness/SETUP.md` to fill facts from observed project reality |
|
|
116
|
+
| Existing `Harness/` | Do not use `npx` as an updater; ask whether to run `/wf-update`, `$wf-update`, `node Harness/scripts/wf-update-check.mjs`, keep untouched, or remove/reinstall after approval |
|
|
117
|
+
|
|
118
|
+
Root scan must include top-level files, `CLAUDE.md`, `AGENTS.md`, `.claude/`, `.agents/`, `.codex/`, `Harness/`, package files, CI files, app entry points, test/build commands, existing docs, and already-installed skills/plugins/rules. Use that scan before recommending optional capabilities so you do not suggest duplicates.
|
|
119
|
+
|
|
107
120
|
### Existing project — safe merge
|
|
108
121
|
|
|
109
122
|
```bash
|
|
110
|
-
#
|
|
111
|
-
npx create-harness-vibe-coding@latest my-app . -y --dry-run
|
|
112
|
-
|
|
123
|
+
# Machine-readable preview first. Always.
|
|
124
|
+
npx create-harness-vibe-coding@latest my-app . -y --dry-run --json
|
|
125
|
+
|
|
113
126
|
# Add only what's missing. Never overwrite.
|
|
114
|
-
npx create-harness-vibe-coding@latest my-app . -y --on-conflict skip
|
|
127
|
+
npx create-harness-vibe-coding@latest my-app . -y --on-conflict skip --json
|
|
115
128
|
```
|
|
116
129
|
|
|
130
|
+
The JSON output is the agent's install report: `scan` replaces hand-written root probes, `plan.create` is script-owned, and `agent.aiMergeRequired` is the only list that needs semantic AI review. Do not read package source or templates unless `agent.aiMergeRequired` names a conflicting file.
|
|
131
|
+
|
|
117
132
|
`npx` is an install and safe-merge entry, not an update engine for an already installed Harness. Once `Harness/` exists, use `/wf-update` in Claude Code, `$wf-update` in Codex, or `node Harness/scripts/wf-update-check.mjs`; root entry conflicts such as `CLAUDE.md`, `AGENTS.md`, `.claude/`, `.agents/`, `.codex/`, and local Harness docs need agent-mediated merge decisions.
|
|
118
133
|
|
|
119
134
|
| Flag | Does |
|
|
@@ -148,24 +163,30 @@ npx create-harness-vibe-coding@latest my-app -y --recommend superpowers,codegrap
|
|
|
148
163
|
|
|
149
164
|
External recommendations are recorded in `Harness/SETUP.md` but not installed automatically:
|
|
150
165
|
|
|
151
|
-
| Recommendation | For |
|
|
152
|
-
|
|
153
|
-
| `superpowers` | Community skill registry and agent workflows |
|
|
154
|
-
| `caveman` |
|
|
155
|
-
| `agent-research` |
|
|
156
|
-
| `codegraph` | Code graph or repository-map tooling |
|
|
166
|
+
| Recommendation | For | Source |
|
|
167
|
+
|----------------|-----|--------|
|
|
168
|
+
| `superpowers` | Community skill registry and agent workflows | <https://github.com/obra/Superpowers> |
|
|
169
|
+
| `caveman` | Terse, low-token agent behavior and memory compression | <https://github.com/JuliusBrussee/caveman> |
|
|
170
|
+
| `agent-research` | Research-agent skills for literature, product, dependency, and ecosystem investigation | <https://github.com/lingzhi227/agent-research-skills> |
|
|
171
|
+
| `codegraph` | Code graph or repository-map tooling | <https://github.com/colbymchenry/codegraph> |
|
|
172
|
+
|
|
173
|
+
These are links for the user's agent to evaluate. The scaffold does not maintain third-party install steps; it only records selected recommendations after checking what is already installed.
|
|
157
174
|
|
|
158
175
|
### Agent-link intake
|
|
159
176
|
|
|
160
|
-
When your agent reads the one-sentence prompt above, it
|
|
177
|
+
When your agent reads the one-sentence prompt above, it should get the machine-readable install report before asking broad questions:
|
|
178
|
+
|
|
179
|
+
```bash
|
|
180
|
+
npx create-harness-vibe-coding@latest my-app . -y --dry-run --json
|
|
181
|
+
```
|
|
161
182
|
|
|
162
|
-
|
|
183
|
+
Use `scan.markers` instead of manual top-level probes. Ask **at most 3 blocking questions** before touching files. Files in `plan.create` are handled by the script; only files in `agent.aiMergeRequired` need AI comparison and user-supervised merge decisions.
|
|
163
184
|
|
|
164
185
|
Ask these only when they affect writes:
|
|
165
186
|
|
|
166
187
|
- If `CLAUDE.md` or `AGENTS.md` already exists, should missing Harness guidance be merged, kept separate, or skipped?
|
|
167
188
|
- If `Harness/` already exists, should the agent run update/dry-run, merge missing files, keep it untouched, or remove/reinstall after approval?
|
|
168
|
-
- Which optional capabilities should be enabled: local workflows (`browser-e2e`, `ui-ux-review`, `ts-react-frontend`, `python-backend`, `github-pr-review`) and recommendation-only external
|
|
189
|
+
- Which optional capabilities should be enabled, after excluding capabilities already installed: local workflows (`browser-e2e`, `ui-ux-review`, `ts-react-frontend`, `python-backend`, `github-pr-review`) and recommendation-only external links (`Superpowers`, `Caveman`, `agent research`, `code graph`)?
|
|
169
190
|
|
|
170
191
|
Harness docs always live in root `Harness/`; do not route Harness files through `docs/`. If a file already exists, the agent asks first. The default is always **preserve**.
|
|
171
192
|
|
|
@@ -178,12 +199,15 @@ Harness docs always live in root `Harness/`; do not route Harness files through
|
|
|
178
199
|
"/wf-update" or "$wf-update" # pull latest harness improvements
|
|
179
200
|
```
|
|
180
201
|
|
|
181
|
-
### Verify
|
|
182
|
-
|
|
183
|
-
```bash
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
202
|
+
### Verify
|
|
203
|
+
|
|
204
|
+
```bash
|
|
205
|
+
# In this package repo
|
|
206
|
+
npm test
|
|
207
|
+
|
|
208
|
+
# In a generated project after bootstrap
|
|
209
|
+
node Harness/scripts/validate-harness.mjs --strict
|
|
210
|
+
```
|
|
187
211
|
|
|
188
212
|
---
|
|
189
213
|
|
package/package.json
CHANGED
package/src/generator.js
CHANGED
|
@@ -377,7 +377,7 @@ function registerExternalRecommendations(file, content, selectedRecommendations)
|
|
|
377
377
|
if (!selectedRecommendations.length || file !== 'Harness/SETUP.md') return content;
|
|
378
378
|
|
|
379
379
|
const lines = selectedRecommendations.map(item => (
|
|
380
|
-
`- \`${item.id}\` - ${item.description} Recommendation only; not installed by this scaffold.
|
|
380
|
+
`- \`${item.id}\` - ${item.description} Recommendation only; not installed by this scaffold. Source: ${item.url}`
|
|
381
381
|
));
|
|
382
382
|
|
|
383
383
|
return `${content.trimEnd()}\n\n## Selected External Recommendations\n\n${lines.join('\n')}\n`;
|
package/src/index.js
CHANGED
|
@@ -81,11 +81,19 @@ const generationOptions = {
|
|
|
81
81
|
const DEFAULT_NAME = 'my-vibe-project';
|
|
82
82
|
|
|
83
83
|
// --json: machine-readable output, no prompts, no decorative output
|
|
84
|
-
if (generationOptions.json) {
|
|
85
|
-
const projectName = argName || DEFAULT_NAME;
|
|
86
|
-
const targetDir = argDir || `./${projectName}`;
|
|
87
|
-
const
|
|
88
|
-
|
|
84
|
+
if (generationOptions.json) {
|
|
85
|
+
const projectName = argName || DEFAULT_NAME;
|
|
86
|
+
const targetDir = argDir || `./${projectName}`;
|
|
87
|
+
const scan = scanTarget(targetDir);
|
|
88
|
+
const result = generate({ projectName, targetDir, ...generationOptions });
|
|
89
|
+
result.scan = createJsonScan(scan);
|
|
90
|
+
result.agent = createAgentGuidance(result, {
|
|
91
|
+
projectName,
|
|
92
|
+
targetDir,
|
|
93
|
+
options: generationOptions,
|
|
94
|
+
scan,
|
|
95
|
+
});
|
|
96
|
+
printJsonResult(result);
|
|
89
97
|
// printJsonResult exits with 1 on failure; we only reach here on success
|
|
90
98
|
process.exit(0);
|
|
91
99
|
}
|
|
@@ -377,7 +385,7 @@ function printOptions() {
|
|
|
377
385
|
console.log('');
|
|
378
386
|
console.log(pc.bold('External recommendations:'));
|
|
379
387
|
for (const item of catalog.externalRecommendations) {
|
|
380
|
-
console.log(` ${pc.cyan(item.id)} - ${item.description} (${item.installMode})
|
|
388
|
+
console.log(` ${pc.cyan(item.id)} - ${item.description} (${item.installMode}) ${item.url || ''}`.trimEnd());
|
|
381
389
|
}
|
|
382
390
|
}
|
|
383
391
|
console.log('');
|
|
@@ -429,6 +437,17 @@ function scanTarget(targetDir) {
|
|
|
429
437
|
? fs.readdirSync(resolvedDir)
|
|
430
438
|
: [];
|
|
431
439
|
const hasHarness = isDirectory && fs.existsSync(path.join(resolvedDir, 'Harness'));
|
|
440
|
+
const hasClaude = isDirectory && fs.existsSync(path.join(resolvedDir, 'CLAUDE.md'));
|
|
441
|
+
const hasAgents = isDirectory && fs.existsSync(path.join(resolvedDir, 'AGENTS.md'));
|
|
442
|
+
const hasAgentSkills = isDirectory && fs.existsSync(path.join(resolvedDir, '.agents'));
|
|
443
|
+
const hasCodex = isDirectory && fs.existsSync(path.join(resolvedDir, '.codex'));
|
|
444
|
+
const hasDocs = isDirectory && fs.existsSync(path.join(resolvedDir, 'docs'));
|
|
445
|
+
const hasReadme = isDirectory && fs.existsSync(path.join(resolvedDir, 'README.md'));
|
|
446
|
+
const hasPackageJson = isDirectory && fs.existsSync(path.join(resolvedDir, 'package.json'));
|
|
447
|
+
const hasPyproject = isDirectory && fs.existsSync(path.join(resolvedDir, 'pyproject.toml'));
|
|
448
|
+
const hasGoMod = isDirectory && fs.existsSync(path.join(resolvedDir, 'go.mod'));
|
|
449
|
+
const hasGithub = isDirectory && fs.existsSync(path.join(resolvedDir, '.github'));
|
|
450
|
+
const hasGitignore = isDirectory && fs.existsSync(path.join(resolvedDir, '.gitignore'));
|
|
432
451
|
|
|
433
452
|
return {
|
|
434
453
|
resolvedDir,
|
|
@@ -436,15 +455,196 @@ function scanTarget(targetDir) {
|
|
|
436
455
|
isDirectory,
|
|
437
456
|
entries,
|
|
438
457
|
hasHarness,
|
|
439
|
-
hasClaude
|
|
440
|
-
hasAgents
|
|
441
|
-
hasAgentSkills
|
|
442
|
-
hasCodex
|
|
443
|
-
hasDocs
|
|
458
|
+
hasClaude,
|
|
459
|
+
hasAgents,
|
|
460
|
+
hasAgentSkills,
|
|
461
|
+
hasCodex,
|
|
462
|
+
hasDocs,
|
|
463
|
+
hasReadme,
|
|
464
|
+
hasPackageJson,
|
|
465
|
+
hasPyproject,
|
|
466
|
+
hasGoMod,
|
|
467
|
+
hasGithub,
|
|
468
|
+
hasGitignore,
|
|
444
469
|
needsConflictPolicy: exists && (!isDirectory || entries.length > 0 || hasHarness),
|
|
445
470
|
};
|
|
446
471
|
}
|
|
447
472
|
|
|
473
|
+
function createJsonScan(scan) {
|
|
474
|
+
const topLevelEntries = scan.entries.slice(0, 50);
|
|
475
|
+
|
|
476
|
+
return {
|
|
477
|
+
resolvedDir: scan.resolvedDir,
|
|
478
|
+
exists: scan.exists,
|
|
479
|
+
isDirectory: scan.isDirectory,
|
|
480
|
+
entryCount: scan.entries.length,
|
|
481
|
+
topLevelEntries,
|
|
482
|
+
topLevelEntriesTruncated: scan.entries.length > topLevelEntries.length,
|
|
483
|
+
needsConflictPolicy: scan.needsConflictPolicy,
|
|
484
|
+
markers: {
|
|
485
|
+
hasHarness: scan.hasHarness,
|
|
486
|
+
hasClaude: scan.hasClaude,
|
|
487
|
+
hasAgents: scan.hasAgents,
|
|
488
|
+
hasAgentSkills: scan.hasAgentSkills,
|
|
489
|
+
hasCodex: scan.hasCodex,
|
|
490
|
+
hasDocs: scan.hasDocs,
|
|
491
|
+
hasReadme: scan.hasReadme,
|
|
492
|
+
hasPackageJson: scan.hasPackageJson,
|
|
493
|
+
hasPyproject: scan.hasPyproject,
|
|
494
|
+
hasGoMod: scan.hasGoMod,
|
|
495
|
+
hasGithub: scan.hasGithub,
|
|
496
|
+
hasGitignore: scan.hasGitignore,
|
|
497
|
+
},
|
|
498
|
+
};
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
function createAgentGuidance(result, { projectName, targetDir, options, scan }) {
|
|
502
|
+
const attentionFiles = [...new Set([
|
|
503
|
+
...(result.plan?.conflict || []),
|
|
504
|
+
...(result.plan?.skip || []),
|
|
505
|
+
])].sort();
|
|
506
|
+
const aiMergeRequired = attentionFiles.map(file => createFileGuidance(file));
|
|
507
|
+
const hasBlockingConflicts = (result.plan?.conflict || []).length > 0;
|
|
508
|
+
const safeMergeCommand = commandFor(projectName, targetDir, {
|
|
509
|
+
...options,
|
|
510
|
+
dryRun: false,
|
|
511
|
+
onConflict: 'skip',
|
|
512
|
+
json: true,
|
|
513
|
+
});
|
|
514
|
+
const previewCommand = commandFor(projectName, targetDir, {
|
|
515
|
+
...options,
|
|
516
|
+
dryRun: true,
|
|
517
|
+
json: true,
|
|
518
|
+
});
|
|
519
|
+
const next = [];
|
|
520
|
+
|
|
521
|
+
if (scan.hasHarness) {
|
|
522
|
+
next.push({
|
|
523
|
+
action: 'stop',
|
|
524
|
+
reason: 'Harness already exists; use wf-update or Harness/scripts/wf-update-check.mjs instead of reinstalling blindly.',
|
|
525
|
+
});
|
|
526
|
+
} else if (result.dryRun && !hasBlockingConflicts) {
|
|
527
|
+
next.push({
|
|
528
|
+
action: 'install',
|
|
529
|
+
command: safeMergeCommand,
|
|
530
|
+
reason: 'Dry-run has no blocking conflicts; let the script create missing files.',
|
|
531
|
+
});
|
|
532
|
+
} else if (result.dryRun && hasBlockingConflicts) {
|
|
533
|
+
next.push({
|
|
534
|
+
action: 'safe-merge',
|
|
535
|
+
command: safeMergeCommand,
|
|
536
|
+
reason: 'Default dry-run found existing files; rerun with --on-conflict skip so the script creates missing files and preserves existing ones.',
|
|
537
|
+
});
|
|
538
|
+
} else if (result.success) {
|
|
539
|
+
next.push({
|
|
540
|
+
action: 'bootstrap',
|
|
541
|
+
command: 'Read Harness/SETUP.md and use this JSON plan before opening any package templates.',
|
|
542
|
+
reason: 'Scaffold files were written; bootstrap project facts from local evidence.',
|
|
543
|
+
});
|
|
544
|
+
} else {
|
|
545
|
+
next.push({
|
|
546
|
+
action: 'inspect-errors',
|
|
547
|
+
reason: 'Generation failed before safe scaffold output was available.',
|
|
548
|
+
});
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
if (aiMergeRequired.length > 0) {
|
|
552
|
+
next.push({
|
|
553
|
+
action: 'ai-merge',
|
|
554
|
+
files: aiMergeRequired.map(item => item.file),
|
|
555
|
+
reason: 'Only these existing/conflicting files need semantic review. Files in plan.create are script-owned.',
|
|
556
|
+
});
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
return {
|
|
560
|
+
sourceOfTruth: 'Use this JSON scan/plan first. Do not read package source or templates unless aiMergeRequired lists a file.',
|
|
561
|
+
previewCommand,
|
|
562
|
+
safeMergeCommand,
|
|
563
|
+
scriptHandled: {
|
|
564
|
+
create: result.plan?.create?.length || 0,
|
|
565
|
+
mkdir: result.plan?.mkdir?.length || 0,
|
|
566
|
+
backup: result.plan?.backup?.length || 0,
|
|
567
|
+
overwrite: result.plan?.overwrite?.length || 0,
|
|
568
|
+
},
|
|
569
|
+
aiMergeRequired,
|
|
570
|
+
next,
|
|
571
|
+
};
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
function createFileGuidance(file) {
|
|
575
|
+
const normalized = file.replace(/\\/g, '/');
|
|
576
|
+
const guidance = {
|
|
577
|
+
file: normalized,
|
|
578
|
+
templateHint: templateHintFor(normalized),
|
|
579
|
+
requiresUserConsent: false,
|
|
580
|
+
defaultAction: 'preserve',
|
|
581
|
+
reason: 'Existing file or path needs semantic review before any merge.',
|
|
582
|
+
};
|
|
583
|
+
|
|
584
|
+
if (normalized.endsWith('/')) {
|
|
585
|
+
return {
|
|
586
|
+
...guidance,
|
|
587
|
+
templateHint: null,
|
|
588
|
+
defaultAction: 'stop',
|
|
589
|
+
reason: 'A file blocks a required scaffold directory. Stop and ask before moving or replacing it.',
|
|
590
|
+
};
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
if (normalized === 'CLAUDE.md' || normalized === 'AGENTS.md') {
|
|
594
|
+
return {
|
|
595
|
+
...guidance,
|
|
596
|
+
requiresUserConsent: true,
|
|
597
|
+
reason: 'Root agent entry contract. Preserve project rules and ask before merging Harness startup guidance.',
|
|
598
|
+
};
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
if (normalized === 'README.md') {
|
|
602
|
+
return {
|
|
603
|
+
...guidance,
|
|
604
|
+
reason: 'Project-owned public/development documentation. Preserve by default; append development notes only after review.',
|
|
605
|
+
};
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
if (normalized === 'Harness/README.md' || normalized === 'Harness/MEMORY.md') {
|
|
609
|
+
return {
|
|
610
|
+
...guidance,
|
|
611
|
+
reason: 'Harness router/registry conflict. Merge only missing routing or registration entries.',
|
|
612
|
+
};
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
return guidance;
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
function templateHintFor(file) {
|
|
619
|
+
if (file === 'Harness/SETUP.md') return 'templates/common/SETUP.md';
|
|
620
|
+
return `templates/common/${file}`;
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
function commandFor(projectName, targetDir, options) {
|
|
624
|
+
const args = [
|
|
625
|
+
'npx',
|
|
626
|
+
'create-harness-vibe-coding@latest',
|
|
627
|
+
projectName,
|
|
628
|
+
targetDir,
|
|
629
|
+
'-y',
|
|
630
|
+
];
|
|
631
|
+
|
|
632
|
+
if (options.dryRun) args.push('--dry-run');
|
|
633
|
+
if (options.onConflict) args.push('--on-conflict', options.onConflict);
|
|
634
|
+
if (options.withOptions?.length) args.push('--with', options.withOptions.join(','));
|
|
635
|
+
if (options.withoutOptions?.length) args.push('--without', options.withoutOptions.join(','));
|
|
636
|
+
if (options.externalOptions?.length) args.push('--recommend', options.externalOptions.join(','));
|
|
637
|
+
if (options.preset) args.push('--preset', options.preset);
|
|
638
|
+
if (options.json) args.push('--json');
|
|
639
|
+
|
|
640
|
+
return args.map(shellQuoteArg).join(' ');
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
function shellQuoteArg(arg) {
|
|
644
|
+
if (/^[A-Za-z0-9@._/\\:-]+$/.test(arg)) return arg;
|
|
645
|
+
return JSON.stringify(arg);
|
|
646
|
+
}
|
|
647
|
+
|
|
448
648
|
function printScan(scan) {
|
|
449
649
|
if (!scan.exists) return;
|
|
450
650
|
|
package/src/prompts.js
CHANGED
|
@@ -73,7 +73,7 @@ export async function askOptionalSelections(catalog) {
|
|
|
73
73
|
const externalOptions = (catalog.externalRecommendations || []).map(item => ({
|
|
74
74
|
value: item.id,
|
|
75
75
|
label: item.title,
|
|
76
|
-
hint: `${item.description} Recommendation only.`,
|
|
76
|
+
hint: item.url ? `${item.description} ${item.url}` : `${item.description} Recommendation only.`,
|
|
77
77
|
}));
|
|
78
78
|
|
|
79
79
|
const selectedLocal = localOptions.length
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: tdd-guide
|
|
3
|
+
description: Test-Driven Development specialist enforcing write-tests-first methodology. Use PROACTIVELY when writing new features, fixing bugs, or refactoring code. Ensures 80%+ test coverage.
|
|
4
|
+
tools: Read, Write, Edit, Bash, Grep, Glob
|
|
5
|
+
model: sonnet
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# TDD Guide Agent
|
|
9
|
+
|
|
10
|
+
Enforces TDD workflow. Load `Harness/TDD-GUIDE.md` first, then ECC testing rules for the project stack.
|
|
11
|
+
|
|
12
|
+
## Inputs Required
|
|
13
|
+
|
|
14
|
+
- Task description and acceptance criteria from PLAN.md
|
|
15
|
+
- Current test coverage status
|
|
16
|
+
- Stack-specific testing tools (Jest, Pytest, Go test, etc.)
|
|
17
|
+
|
|
18
|
+
## Workflow
|
|
19
|
+
|
|
20
|
+
1. READ acceptance criteria
|
|
21
|
+
2. WRITE failing test (RED)
|
|
22
|
+
3. VERIFY test fails for expected reason
|
|
23
|
+
4. Report test file path and expected failure to Implementer
|
|
24
|
+
|
|
25
|
+
Do NOT write implementation code. Only tests.
|
|
26
|
+
|
|
27
|
+
## Allowed Write Set
|
|
28
|
+
|
|
29
|
+
- Test files only (`*.test.ts`, `*.test.tsx`, `test_*.py`, `*_test.go`, etc.)
|
|
30
|
+
- Test fixtures and mocks
|
|
31
|
+
- Test configuration files
|
|
32
|
+
|
|
33
|
+
## Forbidden
|
|
34
|
+
|
|
35
|
+
- Production/source code changes
|
|
36
|
+
- Loosening existing test assertions
|
|
37
|
+
- Deleting existing tests without explicit approval
|
|
38
|
+
|
|
39
|
+
## Verification
|
|
40
|
+
|
|
41
|
+
- Test MUST fail before handing off to Implementer
|
|
42
|
+
- Test MUST cover acceptance criteria + error paths
|
|
43
|
+
- Run `node Harness/scripts/validate-harness.mjs` after significant test additions
|
|
44
|
+
|
|
45
|
+
## Return Format
|
|
46
|
+
|
|
47
|
+
```text
|
|
48
|
+
Agent: tdd-guide
|
|
49
|
+
Task: <task-id>
|
|
50
|
+
Tests written: <file paths>
|
|
51
|
+
Coverage before: X%
|
|
52
|
+
Expected coverage after: Y%
|
|
53
|
+
Failing tests: <list of test names and expected failure reasons>
|
|
54
|
+
Next: Dispatch Implementer to make tests pass
|
|
55
|
+
```
|
|
@@ -63,6 +63,28 @@
|
|
|
63
63
|
}
|
|
64
64
|
]
|
|
65
65
|
}
|
|
66
|
+
],
|
|
67
|
+
"PostToolUse": [
|
|
68
|
+
{
|
|
69
|
+
"matcher": "",
|
|
70
|
+
"hooks": [
|
|
71
|
+
{
|
|
72
|
+
"type": "command",
|
|
73
|
+
"command": "node Harness/scripts/wf-mode-hook.mjs"
|
|
74
|
+
}
|
|
75
|
+
]
|
|
76
|
+
}
|
|
77
|
+
],
|
|
78
|
+
"Stop": [
|
|
79
|
+
{
|
|
80
|
+
"matcher": "",
|
|
81
|
+
"hooks": [
|
|
82
|
+
{
|
|
83
|
+
"type": "command",
|
|
84
|
+
"command": "node Harness/scripts/wf-mode-hook.mjs"
|
|
85
|
+
}
|
|
86
|
+
]
|
|
87
|
+
}
|
|
66
88
|
]
|
|
67
89
|
}
|
|
68
90
|
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: tdd
|
|
3
|
+
description: Test-driven development. Use when the user wants to build features or fix bugs test-first, mentions "red-green-refactor", or wants integration tests.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# TDD Adapter
|
|
7
|
+
|
|
8
|
+
Thin tool adapter. Authoritative guide: `Harness/TDD-GUIDE.md`.
|
|
9
|
+
|
|
10
|
+
## Invocation
|
|
11
|
+
|
|
12
|
+
- Claude Code: use `/tdd` or select the `tdd` skill.
|
|
13
|
+
- Codex CLI or IDE: use `$tdd` or `/skills` then choose `tdd`.
|
|
14
|
+
|
|
15
|
+
## Load
|
|
16
|
+
|
|
17
|
+
1. `Harness/TDD-GUIDE.md`
|
|
18
|
+
2. ECC stack-specific testing rules (e.g., `typescript/testing.md`, `python/testing.md`)
|
|
19
|
+
3. Current task `PLAN.md`
|
|
20
|
+
|
|
21
|
+
## Rules
|
|
22
|
+
|
|
23
|
+
1. **RED first**: Write failing test before ANY implementation code.
|
|
24
|
+
2. **GREEN minimal**: Write only enough code to pass the test.
|
|
25
|
+
3. **REFACTOR safe**: Improve code while keeping all tests green.
|
|
26
|
+
4. **Coverage gate**: ≥80% before marking task complete.
|
|
27
|
+
5. **Test names**: Describe behavior — `test('returns X when Y')`.
|
|
28
|
+
6. **AAA structure**: Arrange → Act → Assert.
|
|
29
|
+
7. **Error paths**: Test failure cases, not just happy path.
|
|
30
|
+
8. **WF-MAX**: Test Writer agent dispatched BEFORE Implementer in every wave.
|