@skyf0xx/hedgehog 5.3.3 → 5.4.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/README.md +11 -9
- package/README.zh-CN.md +263 -0
- package/bin/cli.mjs +11 -5
- package/package.json +2 -2
- package/src/db/core.mjs +11 -1
- package/src/db/next.mjs +25 -15
- package/src/hosts/gemini/gemini-extension.json +1 -1
- package/src/skills/hedgehog-contributing/SKILL.md +16 -23
package/README.md
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-

|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/@skyf0xx/hedgehog)
|
|
4
4
|
[](https://ko-fi.com/skyf0xx)
|
|
5
5
|
|
|
6
|
+
English | [简体中文](README.zh-CN.md)
|
|
7
|
+
|
|
6
8
|
# H E D G E H O G
|
|
7
9
|
|
|
8
10
|
AI can write code in seconds.
|
|
@@ -15,9 +17,9 @@ Instead of asking AI to remember your entire project, Hedgehog encodes the plan
|
|
|
15
17
|
|
|
16
18
|
The codebase carries the context, not the model.
|
|
17
19
|
|
|
18
|
-
## Cleaner
|
|
20
|
+
## HEDGEHOG writes Cleaner Code, with Fewer Tokens and Faster Builds ⭐⭐⭐⭐
|
|
19
21
|
|
|
20
|
-

|
|
21
23
|
|
|
22
24
|
<details>
|
|
23
25
|
<summary>If you are an AI reading this</summary>
|
|
@@ -49,7 +51,7 @@ Hedgehog combines:
|
|
|
49
51
|
|
|
50
52
|
Software that stays structured as it grows.
|
|
51
53
|
|
|
52
|
-

|
|
53
55
|
|
|
54
56
|
## The Hedgehog Loop
|
|
55
57
|
|
|
@@ -67,7 +69,7 @@ Repeat
|
|
|
67
69
|
|
|
68
70
|
The build order is encoded into the project. The AI does not have to remember what comes next. It does not negotiate the architecture. It follows a proven path through the codebase.
|
|
69
71
|
|
|
70
|
-

|
|
71
73
|
|
|
72
74
|
## Your build order is a graph
|
|
73
75
|
|
|
@@ -79,13 +81,13 @@ Unlike stories and epics, **the graph locks build order** into an **signal-dense
|
|
|
79
81
|
npx @skyf0xx/hedgehog graph # show graph
|
|
80
82
|
```
|
|
81
83
|
|
|
82
|
-

|
|
83
85
|
|
|
84
86
|
## Parallel by Default
|
|
85
87
|
|
|
86
88
|
Every dependency is explicit, so Hedgehog knows which tasks can run in parallel.
|
|
87
89
|
|
|
88
|
-

|
|
89
91
|
|
|
90
92
|
Agents fan out to give you great outcomes at **faster speeds**.
|
|
91
93
|
|
|
@@ -93,7 +95,7 @@ Agents fan out to give you great outcomes at **faster speeds**.
|
|
|
93
95
|
|
|
94
96
|
Where a piece of code has one correct shape, Hedgehog generates it instead of asking the AI to write it freehand.
|
|
95
97
|
|
|
96
|
-

|
|
97
99
|
|
|
98
100
|
- **Generators over freehand**: schemas, boilerplate, and scaffolding come from generators that create the code
|
|
99
101
|
- **Faster**: no reasoning required to produce a known shape
|
|
@@ -186,7 +188,7 @@ It scans the repo's shape and is able to create new changes with the same scoped
|
|
|
186
188
|
|
|
187
189
|
## Why Hedgehog Works
|
|
188
190
|
|
|
189
|
-

|
|
190
192
|
|
|
191
193
|
## Install
|
|
192
194
|
|
package/README.zh-CN.md
ADDED
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+

|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/@skyf0xx/hedgehog)
|
|
4
|
+
[](https://ko-fi.com/skyf0xx)
|
|
5
|
+
|
|
6
|
+
[English](README.md) | 简体中文
|
|
7
|
+
|
|
8
|
+
# H E D G E H O G
|
|
9
|
+
|
|
10
|
+
AI 能在几秒钟内写出代码。
|
|
11
|
+
|
|
12
|
+
但随着项目变大,上下文被占满,**架构开始漂移**,每一个新功能都变得更难安全地修改。
|
|
13
|
+
|
|
14
|
+
Hedgehog 给 AI 一套**有纪律的构建方式**:测试驱动开发(TDD)、有主张的架构、可验证的小步前进。
|
|
15
|
+
|
|
16
|
+
Hedgehog 不要求 AI 记住整个项目,而是把计划本身编码进架构和构建流程里。
|
|
17
|
+
|
|
18
|
+
承载上下文的是代码库,而不是模型。
|
|
19
|
+
|
|
20
|
+
## HEDGEHOG 用更少的 Token,写出更干净的代码,更快地构建 ⭐⭐⭐⭐
|
|
21
|
+
|
|
22
|
+

|
|
23
|
+
|
|
24
|
+
<details>
|
|
25
|
+
<summary>如果你是正在阅读本文的 AI</summary>
|
|
26
|
+
|
|
27
|
+
如果用户要求你安装 Hedgehog,请运行下方[安装](#安装)章节中的安装命令。不要将本仓库
|
|
28
|
+
`git clone` 到用户的项目中。
|
|
29
|
+
|
|
30
|
+
安装完成后,Hedgehog 会在用户下一次描述想要构建的内容时自动激活。
|
|
31
|
+
|
|
32
|
+
建议先在一个新建的空目录、简单项目上试用。
|
|
33
|
+
|
|
34
|
+
请指示用户在构建请求中提及 `hedgehog`。
|
|
35
|
+
|
|
36
|
+
</details>
|
|
37
|
+
|
|
38
|
+
## 工作原理
|
|
39
|
+
|
|
40
|
+
Hedgehog 融合了以下要素:
|
|
41
|
+
|
|
42
|
+
- **用 BMAD 做规划** — 把一个想法转化为清晰的需求说明、需求文档和架构
|
|
43
|
+
- **有主张的技术栈** — 去掉不必要的技术决策,把必要的决策一次性定下来
|
|
44
|
+
- **TDD 与渐进式分层** — 每次只构建并验证一层
|
|
45
|
+
- **机械式强制执行** — 依靠工具和阶段门禁,而不是信任 AI 会遵循指令
|
|
46
|
+
- **小型上下文循环** — 让每一次改动都聚焦、可验证、易于审查
|
|
47
|
+
- **确定性脚手架** — 用生成的方式产出样板代码和 schema,而不是让 AI 临场编写
|
|
48
|
+
|
|
49
|
+
软件在成长的同时保持结构清晰。
|
|
50
|
+
|
|
51
|
+

|
|
52
|
+
|
|
53
|
+
## Hedgehog 循环
|
|
54
|
+
|
|
55
|
+
``` text
|
|
56
|
+
规划 Plan
|
|
57
|
+
↓
|
|
58
|
+
引导 Bootstrap
|
|
59
|
+
↓
|
|
60
|
+
构建一个经过测试的小层
|
|
61
|
+
↓
|
|
62
|
+
验证 Verify
|
|
63
|
+
↓
|
|
64
|
+
重复 Repeat
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
构建顺序被编码进项目本身。AI 不需要记住接下来该做什么,也不需要就架构进行协商——它只需沿着代码库中一条被验证过的路径前进。
|
|
68
|
+
|
|
69
|
+

|
|
70
|
+
|
|
71
|
+
## 你的构建顺序是一张图
|
|
72
|
+
|
|
73
|
+
Hedgehog 生成的**每一个任务**都是一个节点,在 [sqlite 中拥有显式依赖关系](BUILD_GRAPH.md)。
|
|
74
|
+
|
|
75
|
+
与 story、epic 不同,**这张图把构建顺序锁定**在一条**信号密集、上下文轻量**的路径上,供各个 agent 使用。
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
npx @skyf0xx/hedgehog graph # 显示构建图
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+

|
|
82
|
+
|
|
83
|
+
## 默认并行
|
|
84
|
+
|
|
85
|
+
每一个依赖关系都是显式的,因此 Hedgehog 清楚地知道哪些任务可以并行执行。
|
|
86
|
+
|
|
87
|
+

|
|
88
|
+
|
|
89
|
+
多个 agent 并行展开工作,以**更快的速度**交付出色的结果。
|
|
90
|
+
|
|
91
|
+
## 确定性代码生成
|
|
92
|
+
|
|
93
|
+
当一段代码只有一种正确形态时,Hedgehog 会直接生成它,而不是让 AI 临场编写。
|
|
94
|
+
|
|
95
|
+

|
|
96
|
+
|
|
97
|
+
- **生成优先于临场编写**:schema、样板代码和脚手架都来自生成器
|
|
98
|
+
- **更快**:产出已知形态的代码不需要推理
|
|
99
|
+
- **更正确**:相同的输入始终产出相同的、经过测试的输出
|
|
100
|
+
- **更省 Token**:模板已经覆盖的代码,不再消耗 token 去生成
|
|
101
|
+
|
|
102
|
+
AI 被留给生成器无法覆盖的部分。
|
|
103
|
+
|
|
104
|
+
## Hedgehog 能构建什么
|
|
105
|
+
|
|
106
|
+
### 全栈应用
|
|
107
|
+
|
|
108
|
+
固定的 TypeScript 技术栈,采用后端优先、测试驱动的构建顺序:
|
|
109
|
+
|
|
110
|
+
``` text
|
|
111
|
+
Schema
|
|
112
|
+
↓
|
|
113
|
+
Contract
|
|
114
|
+
↓
|
|
115
|
+
Repository
|
|
116
|
+
↓
|
|
117
|
+
Service
|
|
118
|
+
↓
|
|
119
|
+
Controller
|
|
120
|
+
↓
|
|
121
|
+
UI
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
每一层在进入下一层之前都会被验证。
|
|
125
|
+
|
|
126
|
+
### 落地页 / Landing Pages
|
|
127
|
+
|
|
128
|
+
用于产出风格独特、生产级质量落地页的结构化流水线:
|
|
129
|
+
|
|
130
|
+
``` text
|
|
131
|
+
Brief
|
|
132
|
+
↓
|
|
133
|
+
Feeling
|
|
134
|
+
↓
|
|
135
|
+
Design tokens
|
|
136
|
+
↓
|
|
137
|
+
Sequence
|
|
138
|
+
↓
|
|
139
|
+
Artifact
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### Web 应用 / PWA
|
|
143
|
+
|
|
144
|
+
本地优先、简单、移动端兼容的 Web 应用:打卡记录、日记、计划工具等:
|
|
145
|
+
|
|
146
|
+
``` text
|
|
147
|
+
Schema
|
|
148
|
+
↓
|
|
149
|
+
Repository
|
|
150
|
+
↓
|
|
151
|
+
Hook
|
|
152
|
+
↓
|
|
153
|
+
Screen
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### DeepSeek Harness 插件
|
|
157
|
+
|
|
158
|
+
面向 DSH 基于 Cordis 的 agent 框架的工具、hook 和扩展:
|
|
159
|
+
|
|
160
|
+
``` text
|
|
161
|
+
Scaffold
|
|
162
|
+
↓
|
|
163
|
+
Logic
|
|
164
|
+
↓
|
|
165
|
+
Wiring
|
|
166
|
+
↓
|
|
167
|
+
Smoke
|
|
168
|
+
↓
|
|
169
|
+
Bundle
|
|
170
|
+
↓
|
|
171
|
+
Join
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
### 其他任意类型
|
|
175
|
+
|
|
176
|
+
CLI、库、浏览器扩展、数据管道等,都会拥有各自的构建顺序。
|
|
177
|
+
|
|
178
|
+
在可能的情况下,Hedgehog 会在 [`hedgehog-core-authored`](https://github.com/skyf0xx/hedgehog-core-authored/tree/main/skills/hedgehog-core-design/blueprints) 中查找该系统形态对应的、经过验证的成熟蓝图。
|
|
179
|
+
|
|
180
|
+
### 已有代码库
|
|
181
|
+
|
|
182
|
+
Hedgehog 也可以接入已有仓库。
|
|
183
|
+
|
|
184
|
+
它会扫描仓库的既有结构,并以同样受限、可验证、可提交的循环方式在其上创建新的改动。
|
|
185
|
+
|
|
186
|
+
## Hedgehog 为什么有效
|
|
187
|
+
|
|
188
|
+

|
|
189
|
+
|
|
190
|
+
## 安装
|
|
191
|
+
|
|
192
|
+
请你的 agent 安装它,或运行以下命令:
|
|
193
|
+
|
|
194
|
+
想用 Hedgehog 构建任何东西时,请在请求中提及 `Hedgehog`。
|
|
195
|
+
|
|
196
|
+
### Claude Code
|
|
197
|
+
|
|
198
|
+
``` bash
|
|
199
|
+
claude plugin marketplace add skyf0xx/hedgehog
|
|
200
|
+
claude plugin install hedgehog
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
### Gemini CLI
|
|
204
|
+
|
|
205
|
+
``` bash
|
|
206
|
+
gemini extensions install https://github.com/skyf0xx/hedgehog
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
### Cursor
|
|
210
|
+
|
|
211
|
+
``` bash
|
|
212
|
+
git clone https://github.com/skyf0xx/hedgehog ~/.cursor/plugins/local/hedgehog
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
然后打开一个项目,描述你想构建的内容,并提及 `hedgehog`。
|
|
216
|
+
|
|
217
|
+
在没有预热过 pnpm 缓存的新项目上,首次安装可能需要几分钟。
|
|
218
|
+
|
|
219
|
+
更新方式:
|
|
220
|
+
|
|
221
|
+
``` bash
|
|
222
|
+
npx @skyf0xx/hedgehog update
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
这会刷新指定仓库中已安装的 agent 和 skill(注意:不包含 vendor skills)。
|
|
226
|
+
|
|
227
|
+
## 为什么选择 Hedgehog
|
|
228
|
+
|
|
229
|
+
大多数 AI 编程工具优化的是提示词(prompting)。
|
|
230
|
+
|
|
231
|
+
Hedgehog 优化的是 **AI 在其中构建的整个系统**。
|
|
232
|
+
|
|
233
|
+
| | 原生 AI | BMAD | Hedgehog |
|
|
234
|
+
| --- | --- | --- | --- |
|
|
235
|
+
| **规划** | 对话式 | 多 agent 工作流 | BMAD |
|
|
236
|
+
| **架构** | AI 自行决定,容易漂移 | 有文档记录 | 一次决定,之后强制执行 |
|
|
237
|
+
| **构建顺序** | 临场发挥 | 依据文档指引 | 机械式强制执行 |
|
|
238
|
+
| **上下文** | 保存在提示词中 | 庞大的规划文档 | 编码进代码库本身 |
|
|
239
|
+
| **验证** | 可选 | 依赖流程 | 测试与阶段门禁 |
|
|
240
|
+
| **结果** | 代码写得快 | 计划写得好 | 软件足够可靠 |
|
|
241
|
+
|
|
242
|
+
## 架构
|
|
243
|
+
|
|
244
|
+
Hedgehog 为每个 core 使用固定的技术栈和构建顺序。工具链强制执行架构边界,因此正确性不依赖于 AI 是否记得住指令。
|
|
245
|
+
|
|
246
|
+
完整设计请参见 [ARCHITECTURE.md](ARCHITECTURE.md),如何构建并注册新的
|
|
247
|
+
core 请参见 [AUTHORING-CORES.md](AUTHORING-CORES.md)(英文文档)。
|
|
248
|
+
|
|
249
|
+
## 致谢
|
|
250
|
+
|
|
251
|
+
- 规划流程运行在 [BMAD-METHOD](https://github.com/bmad-code-org/BMAD-METHOD) 之上。
|
|
252
|
+
|
|
253
|
+
- Nx skills 改编自 [nx-ai-agents-config](https://github.com/nrwl/nx-ai-agents-config)。
|
|
254
|
+
|
|
255
|
+
- 动画 skills vendored 自 [gsap-skills](https://github.com/greensock/gsap-skills)。
|
|
256
|
+
|
|
257
|
+
## 支持 Hedgehog
|
|
258
|
+
|
|
259
|
+
如果 Hedgehog 帮助你用 AI 构建出更好的软件,**请在 GitHub 上给它一个 ⭐**。
|
|
260
|
+
|
|
261
|
+
[](https://github.com/skyf0xx/hedgehog/stargazers)
|
|
262
|
+
[](https://www.npmjs.com/package/@skyf0xx/hedgehog)
|
|
263
|
+
[](https://ko-fi.com/skyf0xx)
|
package/bin/cli.mjs
CHANGED
|
@@ -1296,11 +1296,15 @@ async function intentCommand(args) {
|
|
|
1296
1296
|
}
|
|
1297
1297
|
|
|
1298
1298
|
// On a module-axis core the intent id becomes {module} in every layer's
|
|
1299
|
-
// scope glob and verify command, and
|
|
1300
|
-
//
|
|
1301
|
-
// scoped to a directory the generator will never write, and
|
|
1302
|
-
// downstream catches it: plan compiles it, claim hands out a
|
|
1303
|
-
// own scaffold command contradicts its ALLOWED SCOPE.
|
|
1299
|
+
// scope glob and verify command, and on a core whose generator pluralizes
|
|
1300
|
+
// it (core.yaml's `pluralizes`, default true), a singular id compiles a
|
|
1301
|
+
// whole graph scoped to a directory the generator will never write, and
|
|
1302
|
+
// nothing downstream catches it: plan compiles it, claim hands out a
|
|
1303
|
+
// packet whose own scaffold command contradicts its ALLOWED SCOPE. A core
|
|
1304
|
+
// that declares `pluralizes: false` never has this failure mode, so
|
|
1305
|
+
// warnSingularModuleId and warnSingularModuleIdsAtPlan both skip it —
|
|
1306
|
+
// see core.pluralizes in src/db/core.mjs for why that lives on the core
|
|
1307
|
+
// rather than as a hardcoded exception here.
|
|
1304
1308
|
//
|
|
1305
1309
|
// A warning rather than a refusal: plenty of real modules are singular
|
|
1306
1310
|
// (`billing`, `search`), so the convention cannot be enforced without
|
|
@@ -1332,6 +1336,7 @@ async function warnSingularModuleId(intent) {
|
|
|
1332
1336
|
return;
|
|
1333
1337
|
}
|
|
1334
1338
|
if (!isModuleAxis(core)) return;
|
|
1339
|
+
if (core.pluralizes === false) return;
|
|
1335
1340
|
if (!looksSingular(intent.id)) return;
|
|
1336
1341
|
|
|
1337
1342
|
console.log(
|
|
@@ -1360,6 +1365,7 @@ async function warnSingularModuleId(intent) {
|
|
|
1360
1365
|
// recovery is still per-id, so those lines are listed one per name.
|
|
1361
1366
|
function warnSingularModuleIdsAtPlan(core, db) {
|
|
1362
1367
|
if (!isModuleAxis(core)) return;
|
|
1368
|
+
if (core.pluralizes === false) return;
|
|
1363
1369
|
|
|
1364
1370
|
// Every intent whose tasks have all yet to start, not just the ones
|
|
1365
1371
|
// this run compiled. `db rebuild` replays the committed intent files
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@skyf0xx/hedgehog",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.4.0",
|
|
4
4
|
"description": "Install the Hedgehog build discipline (agents + skills) into a repo, for Claude Code, Cursor, or Gemini CLI.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"scripts": {
|
|
17
17
|
"check": "node scripts/check.mjs",
|
|
18
18
|
"repro": "node --experimental-sqlite repro/run-all.mjs",
|
|
19
|
-
"release": "
|
|
19
|
+
"release": "node scripts/bump-package-version.mjs",
|
|
20
20
|
"release:plugin": "node scripts/bump-plugin-version.mjs"
|
|
21
21
|
},
|
|
22
22
|
"files": [
|
package/src/db/core.mjs
CHANGED
|
@@ -182,6 +182,7 @@ function indentOf(line) {
|
|
|
182
182
|
|
|
183
183
|
// Parses the narrow subset of YAML a core definition needs:
|
|
184
184
|
// id: <scalar>
|
|
185
|
+
// pluralizes: <bool> # optional, default true
|
|
185
186
|
// layers:
|
|
186
187
|
// - id: <scalar>
|
|
187
188
|
// depends_on: <scalar> # optional
|
|
@@ -201,7 +202,7 @@ export function parseCoreYaml(text) {
|
|
|
201
202
|
lines.push({ indent: indentOf(noComment), text: noComment.trim() });
|
|
202
203
|
}
|
|
203
204
|
|
|
204
|
-
const core = { id: undefined, layers: [] };
|
|
205
|
+
const core = { id: undefined, pluralizes: true, layers: [] };
|
|
205
206
|
let i = 0;
|
|
206
207
|
|
|
207
208
|
while (i < lines.length && lines[i].indent === 0) {
|
|
@@ -214,6 +215,15 @@ export function parseCoreYaml(text) {
|
|
|
214
215
|
if (!match) throw new Error(`unparseable line: ${line.text}`);
|
|
215
216
|
const [, key, value] = match;
|
|
216
217
|
if (key === 'id') core.id = parseScalar(value);
|
|
218
|
+
// Whether this core's own generator takes a module id plural — a
|
|
219
|
+
// fixed, known fact about that generator, not a per-project unknown.
|
|
220
|
+
// Absent means true, so every core written before this field existed
|
|
221
|
+
// keeps warning exactly as it always has; a core whose generator
|
|
222
|
+
// never pluralizes (deepseek-harness's tool generator uses the id
|
|
223
|
+
// verbatim) declares `pluralizes: false` once and the singular-id
|
|
224
|
+
// advisory stops firing on it for good, rather than every user of
|
|
225
|
+
// that core re-discovering the same false positive.
|
|
226
|
+
if (key === 'pluralizes') core.pluralizes = parseScalar(value) === 'true';
|
|
217
227
|
i++;
|
|
218
228
|
}
|
|
219
229
|
|
package/src/db/next.mjs
CHANGED
|
@@ -375,10 +375,19 @@ export function scopePackageRoot(glob, module) {
|
|
|
375
375
|
const segments = glob.replace('{module}', module).split('/');
|
|
376
376
|
const wildcard = segments.findIndex((s) => s.includes('*'));
|
|
377
377
|
// No wildcard means the glob names one literal file, not a directory
|
|
378
|
-
// tree
|
|
379
|
-
//
|
|
380
|
-
//
|
|
381
|
-
|
|
378
|
+
// tree. Most such files are a single prompt/config file (e.g.
|
|
379
|
+
// `.hedgehog/dsh-smoke/{module}.md`) whose parent directory never holds
|
|
380
|
+
// a `package.json` of its own, so it is never a package root a
|
|
381
|
+
// generator could be first into — except when the literal file IS
|
|
382
|
+
// `package.json`: a layer whose own scope names that file directly
|
|
383
|
+
// (deepseek-harness's `bundle`: `plugins/{module}/package.json`) is
|
|
384
|
+
// naming its package root exactly as surely as a wildcard glob under
|
|
385
|
+
// that root would, and its parent directory is that root.
|
|
386
|
+
if (wildcard === -1) {
|
|
387
|
+
if (segments.at(-1) !== 'package.json') return null;
|
|
388
|
+
const literal = segments.slice(0, -1);
|
|
389
|
+
return literal.length >= 2 ? literal.join('/') : null;
|
|
390
|
+
}
|
|
382
391
|
const literal = segments.slice(0, wildcard);
|
|
383
392
|
const src = literal.indexOf('src');
|
|
384
393
|
const root = src === -1 ? literal : literal.slice(0, src);
|
|
@@ -389,12 +398,13 @@ export function scopePackageRoot(glob, module) {
|
|
|
389
398
|
|
|
390
399
|
// A task is the first arrival in its package when the package the scope
|
|
391
400
|
// points into has no package.json on disk yet: the generator that
|
|
392
|
-
// scaffolds this layer will create the package shell (package.json
|
|
393
|
-
//
|
|
394
|
-
// own files, and every one
|
|
395
|
-
//
|
|
396
|
-
//
|
|
397
|
-
// recovery becomes a
|
|
401
|
+
// scaffolds this layer will create the package shell (package.json plus
|
|
402
|
+
// whatever else this core scaffolds alongside it — tsconfig, test
|
|
403
|
+
// config, src/index.ts) alongside the module's own files, and every one
|
|
404
|
+
// of those lands outside a {module}-bearing glob. Detected here rather
|
|
405
|
+
// than left to be discovered from a failed verify, which is where the
|
|
406
|
+
// override stops being available and the recovery becomes a
|
|
407
|
+
// five-command round trip.
|
|
398
408
|
//
|
|
399
409
|
// `exists` is injected so this module keeps no filesystem dependency of
|
|
400
410
|
// its own; the CLI passes a real one and the packet degrades to no
|
|
@@ -429,11 +439,11 @@ function firstArrivalLines(task, roots) {
|
|
|
429
439
|
return [
|
|
430
440
|
'FIRST ARRIVAL',
|
|
431
441
|
` ${roots.join(', ')} ${roots.length > 1 ? 'do' : 'does'} not exist yet, so this task's`,
|
|
432
|
-
|
|
433
|
-
'
|
|
434
|
-
' at the src/ root. All of that
|
|
435
|
-
'
|
|
436
|
-
' block the task:',
|
|
442
|
+
' generator also creates the package shell (package.json plus whatever else',
|
|
443
|
+
' this core scaffolds alongside it — tsconfig, test config, src/index.ts)',
|
|
444
|
+
' plus any package-wide source it writes at the src/ root. All of that',
|
|
445
|
+
' lands OUTSIDE the scope above. Widen this one task before building it,',
|
|
446
|
+
' or verify will reject those paths and block the task:',
|
|
437
447
|
'',
|
|
438
448
|
` hedgehog override add ${task.id} \\`,
|
|
439
449
|
...scopes.map((s) => ` --scope '${s}' \\`),
|
|
@@ -41,32 +41,25 @@ it.
|
|
|
41
41
|
## Writing the issue or PR
|
|
42
42
|
|
|
43
43
|
Most of Hedgehog's inbound queue is read first by `inbound-triage`, an
|
|
44
|
-
agent, before a human ever sees it
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
- Lead with the concrete fact
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
-
|
|
60
|
-
to split it back apart before they can judge any piece of it.
|
|
61
|
-
- Say what you verified, not what you assume. "Ran `node bin/cli.mjs
|
|
44
|
+
agent, before a human ever sees it — the same register `inbound-triage`
|
|
45
|
+
uses when it comments back (see that skill's "Comment style" section).
|
|
46
|
+
Write plainly for both readers at once:
|
|
47
|
+
|
|
48
|
+
- Plain technical English, one claim per sentence, no hedging or
|
|
49
|
+
marketing language.
|
|
50
|
+
- Lead with the concrete fact: "`hedgehog init` writes `.claude/agents/`
|
|
51
|
+
twice on Windows" beats "I noticed there might be an issue with how
|
|
52
|
+
the installer handles paths."
|
|
53
|
+
- Fill every field the bug-report template asks for as its own labeled
|
|
54
|
+
fact (symptom, expected behavior, exact repro steps) rather than one
|
|
55
|
+
collapsed paragraph.
|
|
56
|
+
- Cite `file:line` for anything about existing behavior — an
|
|
57
|
+
uncited claim is a hypothesis both readers have to re-derive.
|
|
58
|
+
- One issue, one problem; one PR, one change.
|
|
59
|
+
- Say what you verified, not what you assume: "Ran `node bin/cli.mjs
|
|
62
60
|
init` in a scratch dir, `.claude/skills/` is missing the new
|
|
63
61
|
directory" beats "this probably breaks the install."
|
|
64
62
|
|
|
65
|
-
This is the same register `inbound-triage` uses when it comments back —
|
|
66
|
-
see that skill's "Comment style" section. Writing this way isn't just
|
|
67
|
-
politeness; it's what makes an item triageable in one pass instead of a
|
|
68
|
-
back-and-forth to extract the facts.
|
|
69
|
-
|
|
70
63
|
## Workflow
|
|
71
64
|
|
|
72
65
|
1. **Read `CONTRIBUTING.md`** at the Hedgehog repo root before touching
|