This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
// SPDX-License-Identifier: LicenseRef-ConusAI-Template-1.0
|
||||
//
|
||||
// The coding-agent contract this template ships: CLAUDE.md imports AGENTS.md instead of repeating it, the
|
||||
// committed Claude Code settings keep secrets unreadable and a push behind a person, the support-report skill is
|
||||
// readable by its tool, and the format-on-edit hook formats only this repository's own source files.
|
||||
|
||||
import { mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs"
|
||||
import { tmpdir } from "node:os"
|
||||
import { join } from "node:path"
|
||||
import { afterEach, describe, expect, it } from "vitest"
|
||||
import { fileToFormat } from "../scripts/agent-format.mjs"
|
||||
|
||||
const APP_ROOT = new URL("..", import.meta.url).pathname
|
||||
const read = (path: string) => readFileSync(join(APP_ROOT, path), "utf8")
|
||||
|
||||
const made: string[] = []
|
||||
afterEach(() => {
|
||||
for (const dir of made.splice(0)) rmSync(dir, { recursive: true, force: true })
|
||||
})
|
||||
|
||||
describe("the coding-agent contract", () => {
|
||||
it("has CLAUDE.md import AGENTS.md, the one source of the rules", () => {
|
||||
expect(read("CLAUDE.md")).toMatch(/^@AGENTS\.md$/m)
|
||||
expect(read("AGENTS.md")).toContain("## Work that starts from a support report")
|
||||
})
|
||||
|
||||
it("commits Claude Code settings that refuse .env reads and ask before a push or a migration run", () => {
|
||||
const settings = JSON.parse(read(".claude/settings.json"))
|
||||
expect(settings.permissions.deny).toEqual(expect.arrayContaining(["Read(/.env)", "Read(/.env.local)"]))
|
||||
expect(settings.permissions.ask).toEqual(expect.arrayContaining(["Bash(git push *)", "Bash(pnpm migrate *)"]))
|
||||
expect(settings.permissions.allow).toContain("Bash(pnpm gate)")
|
||||
// Nothing that publishes or deploys is pre-approved.
|
||||
for (const rule of settings.permissions.allow) expect(rule).not.toMatch(/push|migrate|deploy/)
|
||||
expect(read(".gitignore")).toContain(".claude/settings.local.json")
|
||||
})
|
||||
|
||||
it("ships the support-report skill with the frontmatter its tool reads first", () => {
|
||||
const skill = read(".claude/skills/fix-support-report/SKILL.md")
|
||||
expect(skill.startsWith("---\nname: fix-support-report\ndescription: ")).toBe(true)
|
||||
expect(skill).toMatch(/Reproduce it before changing code/)
|
||||
})
|
||||
})
|
||||
|
||||
describe("the format-on-edit hook", () => {
|
||||
it("names a repository source file Biome formats, and nothing else", () => {
|
||||
const root = mkdtempSync(join(tmpdir(), "agent-format-"))
|
||||
made.push(root)
|
||||
writeFileSync(join(root, "a.ts"), "export const a = 1\n")
|
||||
writeFileSync(join(root, "notes.md"), "# notes\n")
|
||||
expect(fileToFormat({ tool_input: { file_path: join(root, "a.ts") } }, root)).toBe("a.ts")
|
||||
expect(fileToFormat({ tool_input: { file_path: "a.ts" } }, root)).toBe("a.ts")
|
||||
expect(fileToFormat({ tool_input: { file_path: "notes.md" } }, root)).toBeNull()
|
||||
expect(fileToFormat({ tool_input: { file_path: "missing.ts" } }, root)).toBeNull()
|
||||
expect(fileToFormat({ tool_input: { file_path: "../outside.ts" } }, root)).toBeNull()
|
||||
expect(fileToFormat({ tool_input: {} }, root)).toBeNull()
|
||||
expect(fileToFormat(null, root)).toBeNull()
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user