@afokapu/atdd-bun 0.1.2 → 0.1.3
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 +18 -11
- package/package.json +1 -1
- package/src/agent.ts +26 -5
- package/templates/agents/AGENTS.block.md +5 -0
- /package/templates/{claude → agents}/atdd/SKILL.md +0 -0
package/README.md
CHANGED
|
@@ -137,10 +137,9 @@ bun run atdd-bun init
|
|
|
137
137
|
```
|
|
138
138
|
|
|
139
139
|
It creates `.githooks/` dispatchers, sets a worktree-local `core.hooksPath`,
|
|
140
|
-
generates `.github/workflows/atdd-bun.yml`, and
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
explicitly pass `--replace`. Installing the dependency alone deliberately does
|
|
140
|
+
generates `.github/workflows/atdd-bun.yml`, and installs the coding-agent skill
|
|
141
|
+
when they are absent. It never overwrites another hook path, an existing
|
|
142
|
+
generated workflow, or an existing skill unless you explicitly pass `--replace`. Installing the dependency alone deliberately does
|
|
144
143
|
neither: package installation must not mutate a repository through postinstall.
|
|
145
144
|
|
|
146
145
|
Use `hooks install`, `ci init`, or `agent init` when only one surface is wanted:
|
|
@@ -165,13 +164,21 @@ workflow and GitHub branch ruleset are the authority for merging.
|
|
|
165
164
|
|
|
166
165
|
## Agent skill: the lifecycle in the agent's context
|
|
167
166
|
|
|
168
|
-
`agent init`
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
167
|
+
`agent init` gives every coding agent the same short ATDD skill:
|
|
168
|
+
|
|
169
|
+
- `.agents/skills/atdd/SKILL.md`: the vendor-neutral Agent Skills path (Codex,
|
|
170
|
+
GitHub Copilot, Cursor, Gemini CLI, and others);
|
|
171
|
+
- `.claude/skills/atdd/SKILL.md`: Claude Code;
|
|
172
|
+
- a managed `<!-- atdd-bun:start -->` block in `AGENTS.md` pointing at the skill,
|
|
173
|
+
for agents that read `AGENTS.md` but not skills. The rest of `AGENTS.md` is
|
|
174
|
+
never touched.
|
|
175
|
+
|
|
176
|
+
The skill names the lifecycle PLAN → RED → GREEN → SMOKE → REFACTOR → TRACE, the
|
|
177
|
+
conventions each stage follows, and the `atdd-bun` profile that gates it. It
|
|
178
|
+
points at the conventions shipped in this package instead of restating them, so
|
|
179
|
+
it stays correct as they change; after upgrading, refresh it with
|
|
180
|
+
`bun run atdd-bun agent init --replace`. The skill steers the agent; the
|
|
181
|
+
profiles, hooks, and CI remain the enforcement.
|
|
175
182
|
|
|
176
183
|
## CI: the merge gate
|
|
177
184
|
|
package/package.json
CHANGED
package/src/agent.ts
CHANGED
|
@@ -1,10 +1,31 @@
|
|
|
1
1
|
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
2
2
|
import { existsSync } from "node:fs";
|
|
3
|
-
import { join, resolve } from "node:path";
|
|
3
|
+
import { dirname, join, resolve } from "node:path";
|
|
4
4
|
|
|
5
5
|
const root = resolve(import.meta.dir, "..");
|
|
6
|
-
const template = join(root, "templates/claude/atdd/SKILL.md");
|
|
7
6
|
const version = (await Bun.file(join(root, "package.json")).json() as { version: string }).version;
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
const render = async (path: string) => (await readFile(join(root, "templates/agents", path), "utf8")).replace("{{VERSION}}", version);
|
|
8
|
+
// .agents/skills is the vendor-neutral Agent Skills path (Codex, Copilot, Cursor, Gemini CLI, …); .claude/skills is Claude Code's.
|
|
9
|
+
const skillPaths = [".agents/skills/atdd/SKILL.md", ".claude/skills/atdd/SKILL.md"];
|
|
10
|
+
const block = /<!-- atdd-bun:start[\s\S]*?<!-- atdd-bun:end -->\n?/;
|
|
11
|
+
|
|
12
|
+
/** Write the ATDD skill for every agent and a managed pointer block in AGENTS.md. Existing files and an
|
|
13
|
+
* existing block are kept unless `replace`; the rest of AGENTS.md is never touched. */
|
|
14
|
+
export async function agentInit(repo = process.cwd(), replace = false) {
|
|
15
|
+
const written: string[] = [], kept: string[] = [];
|
|
16
|
+
for (const path of skillPaths) {
|
|
17
|
+
const output = join(repo, path);
|
|
18
|
+
if (existsSync(output) && !replace) { kept.push(output); continue; }
|
|
19
|
+
await mkdir(dirname(output), { recursive: true }); await writeFile(output, await render("atdd/SKILL.md")); written.push(output);
|
|
20
|
+
}
|
|
21
|
+
const agents = join(repo, "AGENTS.md"), current = existsSync(agents) ? await readFile(agents, "utf8") : "", managed = await render("AGENTS.block.md");
|
|
22
|
+
if (block.test(current) && !replace) kept.push(agents);
|
|
23
|
+
else { await writeFile(agents, block.test(current) ? current.replace(block, managed) : current + (current && !current.endsWith("\n\n") ? (current.endsWith("\n") ? "\n" : "\n\n") : "") + managed); written.push(agents); }
|
|
24
|
+
if (!written.length) return { ok: false, message: `${kept.join(", ")} exist; use --replace` };
|
|
25
|
+
return { ok: true, message: written.join("\n") };
|
|
26
|
+
}
|
|
27
|
+
export async function agentStatus(repo = process.cwd()) {
|
|
28
|
+
const agents = join(repo, "AGENTS.md"), missing = skillPaths.map(path => join(repo, path)).filter(path => !existsSync(path));
|
|
29
|
+
if (!existsSync(agents) || !block.test(await readFile(agents, "utf8"))) missing.push(`${agents} (atdd-bun block)`);
|
|
30
|
+
return { ok: !missing.length, message: missing.length ? `missing: ${missing.join(", ")}` : [...skillPaths, "AGENTS.md"].map(path => join(repo, path)).join("\n") };
|
|
31
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
<!-- atdd-bun:start — generated by @afokapu/atdd-bun {{VERSION}}; run `atdd-bun agent init --replace` to refresh -->
|
|
2
|
+
## ATDD lifecycle
|
|
3
|
+
|
|
4
|
+
Before changing code, tests, or `plan/`, follow `.agents/skills/atdd/SKILL.md`: PLAN → RED → GREEN → SMOKE → REFACTOR → TRACE, passing each stage's `atdd-bun` gate before starting the next.
|
|
5
|
+
<!-- atdd-bun:end -->
|
|
File without changes
|