@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 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 writes the coding-agent skill
141
- `.claude/skills/atdd/SKILL.md` when they are absent. It never overwrites another
142
- hook path, an existing generated workflow, or an existing skill unless you
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` writes `.claude/skills/atdd/SKILL.md`, a short skill that coding
169
- agents load before changing code, tests, or `plan/`. It names the lifecycle
170
- PLAN → RED → GREEN → SMOKE → REFACTOR → TRACE, the conventions each stage
171
- follows, and the `atdd-bun` profile that gates it. It points at the conventions
172
- shipped in this package instead of restating them, so it stays correct as they
173
- change; after upgrading, refresh it with `bun run atdd-bun agent init --replace`.
174
- The skill steers the agent; the profiles, hooks, and CI remain the enforcement.
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@afokapu/atdd-bun",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/afokapu/atdd-bun.git"
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 skillDir = (repo: string) => join(repo, ".claude/skills/atdd");
9
- export async function agentInit(repo = process.cwd(), replace = false) { const output = join(skillDir(repo), "SKILL.md"); if (existsSync(output) && !replace) return { ok: false, message: `${output} exists; use --replace` }; await mkdir(skillDir(repo), { recursive: true }); await writeFile(output, (await readFile(template, "utf8")).replace("{{VERSION}}", version)); return { ok: true, message: output }; }
10
- export async function agentStatus(repo = process.cwd()) { const output = join(skillDir(repo), "SKILL.md"); return { ok: existsSync(output), message: output }; }
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