@afokapu/atdd-bun 0.1.1 → 0.1.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.md +15 -3
- package/package.json +1 -1
- package/src/agent.ts +10 -0
- package/src/cli.ts +6 -0
- package/src/setup.ts +7 -2
- package/templates/claude/atdd/SKILL.md +16 -0
package/README.md
CHANGED
|
@@ -137,16 +137,18 @@ bun run atdd-bun init
|
|
|
137
137
|
```
|
|
138
138
|
|
|
139
139
|
It creates `.githooks/` dispatchers, sets a worktree-local `core.hooksPath`,
|
|
140
|
-
|
|
141
|
-
|
|
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
|
|
142
143
|
explicitly pass `--replace`. Installing the dependency alone deliberately does
|
|
143
144
|
neither: package installation must not mutate a repository through postinstall.
|
|
144
145
|
|
|
145
|
-
Use `hooks install` or `
|
|
146
|
+
Use `hooks install`, `ci init`, or `agent init` when only one surface is wanted:
|
|
146
147
|
|
|
147
148
|
```sh
|
|
148
149
|
bun run atdd-bun hooks install
|
|
149
150
|
bun run atdd-bun ci init
|
|
151
|
+
bun run atdd-bun agent init
|
|
150
152
|
```
|
|
151
153
|
|
|
152
154
|
The hooks enforce protected-branch blocking, micro-commit limits, mass-delete
|
|
@@ -161,6 +163,16 @@ bun run atdd-bun hooks uninstall
|
|
|
161
163
|
Hooks can be bypassed by Git and therefore are never the merge gate. The CI
|
|
162
164
|
workflow and GitHub branch ruleset are the authority for merging.
|
|
163
165
|
|
|
166
|
+
## Agent skill: the lifecycle in the agent's context
|
|
167
|
+
|
|
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.
|
|
175
|
+
|
|
164
176
|
## CI: the merge gate
|
|
165
177
|
|
|
166
178
|
Generate the repository-owned workflow with:
|
package/package.json
CHANGED
package/src/agent.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
2
|
+
import { existsSync } from "node:fs";
|
|
3
|
+
import { join, resolve } from "node:path";
|
|
4
|
+
|
|
5
|
+
const root = resolve(import.meta.dir, "..");
|
|
6
|
+
const template = join(root, "templates/claude/atdd/SKILL.md");
|
|
7
|
+
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 }; }
|
package/src/cli.ts
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { enforce, profileNames, type Profile } from "./enforce";
|
|
3
3
|
import { finishWorktree, hookEvents, hooksStatus, installHooks, runHook, startWorktree, uninstallHooks, worktreeStatus } from "./hooks";
|
|
4
4
|
import { ciInit, ciStatus } from "./ci";
|
|
5
|
+
import { agentInit, agentStatus } from "./agent";
|
|
5
6
|
import { releaseCheck } from "./release";
|
|
6
7
|
import { initializeRepository } from "./setup";
|
|
7
8
|
|
|
@@ -14,6 +15,7 @@ const usage = {
|
|
|
14
15
|
"atdd-bun hooks <install|uninstall|status> [--replace]",
|
|
15
16
|
"atdd-bun worktree <start|finish|status>",
|
|
16
17
|
"atdd-bun ci <init|status> [--replace]",
|
|
18
|
+
"atdd-bun agent <init|status> [--replace]",
|
|
17
19
|
"atdd-bun release check",
|
|
18
20
|
],
|
|
19
21
|
profiles: profileNames,
|
|
@@ -64,6 +66,10 @@ if (args[0] === "ci") {
|
|
|
64
66
|
const result = args[1] === "init" ? await ciInit(process.cwd(), args.includes("--replace")) : args[1] === "status" ? await ciStatus() : fail("ci requires init or status");
|
|
65
67
|
console[result.ok ? "log" : "error"](result.message); process.exit(result.ok ? 0 : 1);
|
|
66
68
|
}
|
|
69
|
+
if (args[0] === "agent") {
|
|
70
|
+
const result = args[1] === "init" ? await agentInit(process.cwd(), args.includes("--replace")) : args[1] === "status" ? await agentStatus() : fail("agent requires init or status");
|
|
71
|
+
console[result.ok ? "log" : "error"](result.message); process.exit(result.ok ? 0 : 1);
|
|
72
|
+
}
|
|
67
73
|
if (args[0] === "release") {
|
|
68
74
|
if (args[1] !== "check") fail("release requires check");
|
|
69
75
|
const result = await releaseCheck(); console[result.ok ? "log" : "error"](result.message); process.exit(result.ok ? 0 : 1);
|
package/src/setup.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { ciInit, ciStatus } from "./ci";
|
|
2
2
|
import { hooksStatus, installHooks } from "./hooks";
|
|
3
|
+
import { agentInit, agentStatus } from "./agent";
|
|
3
4
|
|
|
4
|
-
/** Install the package's
|
|
5
|
+
/** Install the package's three opt-in local surfaces without touching unrelated
|
|
5
6
|
* workflows or hook paths. Dependency installation itself never calls this. */
|
|
6
7
|
export async function initializeRepository(root = process.cwd(), replace = false) {
|
|
7
8
|
const existingHooks = await hooksStatus(root);
|
|
@@ -11,5 +12,9 @@ export async function initializeRepository(root = process.cwd(), replace = false
|
|
|
11
12
|
const existingCi = await ciStatus(root);
|
|
12
13
|
const ci = replace || !existingCi.ok ? await ciInit(root, replace) : existingCi;
|
|
13
14
|
if (!ci.ok) return { ok: false, message: `CI workflow: ${ci.message}` };
|
|
14
|
-
|
|
15
|
+
|
|
16
|
+
const existingAgent = await agentStatus(root);
|
|
17
|
+
const agent = replace || !existingAgent.ok ? await agentInit(root, replace) : existingAgent;
|
|
18
|
+
if (!agent.ok) return { ok: false, message: `agent skill: ${agent.message}` };
|
|
19
|
+
return { ok: true, message: `hooks: ${hooks.message}\nCI workflow: ${ci.message}\nagent skill: ${agent.message}` };
|
|
15
20
|
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: atdd
|
|
3
|
+
description: Use before writing or changing code, tests, or plan/ files in this repository. New intent is decomposed and delivered through the ATDD lifecycle PLAN → RED → GREEN → SMOKE → REFACTOR → TRACE, each stage gated by atdd-bun. Skip PLAN only when the change fits an acceptance that already exists.
|
|
4
|
+
---
|
|
5
|
+
<!-- Generated by @afokapu/atdd-bun {{VERSION}}. Do not edit; run `atdd-bun agent init --replace`. -->
|
|
6
|
+
|
|
7
|
+
Conventions live in `node_modules/@afokapu/atdd-bun/` (`planner-nodes/nodes/`, `conventions/`). Read the ones a stage names; do not restate them. Finish each stage by passing its gate before starting the next.
|
|
8
|
+
|
|
9
|
+
1. PLAN — Decompose the intent into wagon → WMBT → acceptance → train/interlocking → journey → contract under `plan/`, following `planner.decomposition.*`; every WMBT declares a SMOKE acceptance. Gate: `bun run atdd-bun planner`.
|
|
10
|
+
2. RED — For each acceptance, write a test headed `// URN: test:{wagon}:{feature}:{ACC-ID}` and `// Phase: RED` that fails for the missing behaviour (`tester.bun.red-*`). Gate: `bun run atdd-bun tester`.
|
|
11
|
+
3. GREEN — Write the least code that passes; each source file carries `URN: component:{wagon}:{feature}:{Name}:{side}:{layer}` and a `Tested-By:` block (`coder.bun.green-*`). Gate: `bun test`.
|
|
12
|
+
4. SMOKE — Prove the SMOKE acceptance through the real entry point with no mocks or spies, asserting only on observable output: HTTP, markup, stdout, exit code (`tester.bun.smoke-*`, `planner.smoke.*`). Gate: `bun run atdd-bun tester`.
|
|
13
|
+
5. REFACTOR — With tests green, reduce complexity, fix layering, and remove security faults until the rules pass, without changing behaviour (`coder.bun.complexity-*`, `quality-*`, `composition-*`, `security-*`). Gate: `bun run atdd-bun coder security`.
|
|
14
|
+
6. TRACE — Every acceptance has a test, every test resolves to a declared acceptance, every source file resolves to its tests. Gate: `bun run atdd-bun traceability`, then `bun run atdd-bun all`.
|
|
15
|
+
|
|
16
|
+
When a gate fails, open `<rule_id>.convention.yaml` for the reported rule ID and fix the artifact. Never skip, suppress, or edit a convention to get green.
|