@next-friday/create-app 0.0.0-stage → 1.0.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/LICENSE +21 -0
- package/README.md +94 -2
- package/dist/main.mjs +414 -0
- package/package.json +84 -3
- package/templates/base/.agents/hooks/agent-shell-gate.sh +355 -0
- package/templates/base/.agents/hooks/agent-suppression-gate.sh +45 -0
- package/templates/base/.agents/rules/automation-owned-checks.md +5 -0
- package/templates/base/.agents/rules/code-comments.md +3 -0
- package/templates/base/.agents/rules/current-state-authority.md +17 -0
- package/templates/base/.agents/rules/demand-driven-configuration.md +7 -0
- package/templates/base/.agents/rules/dependency-security.md +5 -0
- package/templates/base/.agents/rules/deterministic-testing.md +15 -0
- package/templates/base/.agents/rules/diagnostics-and-error-handling.md +7 -0
- package/templates/base/.agents/rules/git-workflow.md +10 -0
- package/templates/base/.agents/rules/no-suppression.md +7 -0
- package/templates/base/.agents/rules/script-driven-changes.md +7 -0
- package/templates/base/.agents/rules/single-author-style.md +7 -0
- package/templates/base/.claude/rules/agents-guide.md +1 -0
- package/templates/base/.claude/rules/automation-owned-checks.md +1 -0
- package/templates/base/.claude/rules/code-comments.md +1 -0
- package/templates/base/.claude/rules/current-state-authority.md +1 -0
- package/templates/base/.claude/rules/demand-driven-configuration.md +1 -0
- package/templates/base/.claude/rules/dependency-security.md +12 -0
- package/templates/base/.claude/rules/diagnostics-and-error-handling.md +1 -0
- package/templates/base/.claude/rules/git-workflow.md +1 -0
- package/templates/base/.claude/rules/no-suppression.md +1 -0
- package/templates/base/.claude/rules/script-driven-changes.md +1 -0
- package/templates/base/.claude/rules/single-author-style.md +1 -0
- package/templates/base/.claude/settings.json +61 -0
- package/templates/base/.commitlintrc.json +3 -0
- package/templates/base/.cursor/BUGBOT.md +17 -0
- package/templates/base/.cursor/hooks/agent-constitution-gate.sh +32 -0
- package/templates/base/.cursor/hooks.json +26 -0
- package/templates/base/.cursor/rules/automation-owned-checks.mdc +10 -0
- package/templates/base/.cursor/rules/code-comments.mdc +8 -0
- package/templates/base/.cursor/rules/current-state-authority.mdc +22 -0
- package/templates/base/.cursor/rules/demand-driven-configuration.mdc +12 -0
- package/templates/base/.cursor/rules/dependency-security.mdc +11 -0
- package/templates/base/.cursor/rules/diagnostics-and-error-handling.mdc +12 -0
- package/templates/base/.cursor/rules/git-workflow.mdc +15 -0
- package/templates/base/.cursor/rules/no-suppression.mdc +12 -0
- package/templates/base/.cursor/rules/script-driven-changes.mdc +12 -0
- package/templates/base/.cursor/rules/single-author-style.mdc +12 -0
- package/templates/base/.editorconfig +13 -0
- package/templates/base/.gitattributes +1 -0
- package/templates/base/.github/CODEOWNERS +2 -0
- package/templates/base/.github/ISSUE_TEMPLATE/config.yml +1 -0
- package/templates/base/.github/dependabot.yml +77 -0
- package/templates/base/.github/file-filters.yml +19 -0
- package/templates/base/.github/labeler.yml +25 -0
- package/templates/base/.github/requirements/diff-cover.txt +213 -0
- package/templates/base/.github/workflows/deploy.yml +124 -0
- package/templates/base/.github/workflows/osv-scanner.yml +34 -0
- package/templates/base/.github/workflows/pr-triage.yml +29 -0
- package/templates/base/.github/workflows/secret-scan.yml +50 -0
- package/templates/base/.github/workflows/validate-pr-title.yml +48 -0
- package/templates/base/.github/workflows/zizmor.yml +62 -0
- package/templates/base/.github/zizmor.yml +4 -0
- package/templates/base/.gitleaks.toml +14 -0
- package/templates/base/.husky/commit-msg +3 -0
- package/templates/base/.husky/pre-commit +17 -0
- package/templates/base/.husky/pre-merge-commit +7 -0
- package/templates/base/.husky/pre-push +15 -0
- package/templates/base/.nvmrc +1 -0
- package/templates/base/SECURITY.md +15 -0
- package/templates/base/knip.json +3 -0
- package/templates/base/pnpm-workspace.yaml +18 -0
- package/templates/base/railway.json +9 -0
- package/templates/base/scripts/check-agent-gates.ts +252 -0
- package/templates/base/scripts/sync-agent-rules.ts +121 -0
- package/templates/nestjs/.agents/rules/typescript-first.md +7 -0
- package/templates/nestjs/.agents/rules.json +41 -0
- package/templates/nestjs/.claude/rules/deterministic-testing.md +20 -0
- package/templates/nestjs/.claude/rules/typescript-first.md +13 -0
- package/templates/nestjs/.cursor/rules/deterministic-testing.mdc +21 -0
- package/templates/nestjs/.cursor/rules/typescript-first.mdc +13 -0
- package/templates/nestjs/.dependency-cruiser.json +28 -0
- package/templates/nestjs/.dockerignore +8 -0
- package/templates/nestjs/.env.example +1 -0
- package/templates/nestjs/.github/ISSUE_TEMPLATE/bug.yml +66 -0
- package/templates/nestjs/.github/ISSUE_TEMPLATE/feature.yml +50 -0
- package/templates/nestjs/.github/pull_request_template.md +25 -0
- package/templates/nestjs/.github/workflows/ci.yml +181 -0
- package/templates/nestjs/.github/workflows/sast.yml +45 -0
- package/templates/nestjs/.lintstagedrc.json +10 -0
- package/templates/nestjs/.prettierignore +2 -0
- package/templates/nestjs/.prettierrc.json +1 -0
- package/templates/nestjs/AGENTS.md +8 -0
- package/templates/nestjs/CONTRIBUTING.md +57 -0
- package/templates/nestjs/Dockerfile +27 -0
- package/templates/nestjs/README.md +78 -0
- package/templates/nestjs/_gitignore +47 -0
- package/templates/nestjs/eslint.config.ts +7 -0
- package/templates/nestjs/package.json +83 -0
- package/templates/nestjs/src/app.controller.test.ts +23 -0
- package/templates/nestjs/src/app.controller.ts +13 -0
- package/templates/nestjs/src/app.module.ts +12 -0
- package/templates/nestjs/src/app.service.ts +10 -0
- package/templates/nestjs/src/health/health.controller.test.ts +17 -0
- package/templates/nestjs/src/health/health.controller.ts +14 -0
- package/templates/nestjs/src/health/health.module.ts +10 -0
- package/templates/nestjs/src/main.ts +25 -0
- package/templates/nestjs/src/port.test.ts +29 -0
- package/templates/nestjs/src/port.ts +20 -0
- package/templates/nestjs/test/app.e2e.test.ts +40 -0
- package/templates/nestjs/tsconfig.build.json +9 -0
- package/templates/nestjs/tsconfig.json +20 -0
- package/templates/nestjs/vitest.config.ts +13 -0
- package/templates/nestjs/vitest.e2e.config.ts +8 -0
- package/templates/nextjs/.agents/rules/typescript-first.md +7 -0
- package/templates/nextjs/.agents/rules.json +41 -0
- package/templates/nextjs/.claude/rules/deterministic-testing.md +21 -0
- package/templates/nextjs/.claude/rules/typescript-first.md +15 -0
- package/templates/nextjs/.cursor/rules/deterministic-testing.mdc +21 -0
- package/templates/nextjs/.cursor/rules/typescript-first.mdc +13 -0
- package/templates/nextjs/.dependency-cruiser.json +34 -0
- package/templates/nextjs/.dockerignore +10 -0
- package/templates/nextjs/.env.example +1 -0
- package/templates/nextjs/.github/ISSUE_TEMPLATE/bug.yml +66 -0
- package/templates/nextjs/.github/ISSUE_TEMPLATE/feature.yml +50 -0
- package/templates/nextjs/.github/pull_request_template.md +25 -0
- package/templates/nextjs/.github/workflows/ci.yml +187 -0
- package/templates/nextjs/.github/workflows/sast.yml +46 -0
- package/templates/nextjs/.lintstagedrc.json +10 -0
- package/templates/nextjs/.prettierignore +2 -0
- package/templates/nextjs/AGENTS.md +18 -0
- package/templates/nextjs/CONTRIBUTING.md +57 -0
- package/templates/nextjs/Dockerfile +23 -0
- package/templates/nextjs/README.md +74 -0
- package/templates/nextjs/_gitignore +51 -0
- package/templates/nextjs/app/favicon.ico +0 -0
- package/templates/nextjs/app/globals.css +26 -0
- package/templates/nextjs/app/health/route.test.ts +20 -0
- package/templates/nextjs/app/health/route.ts +23 -0
- package/templates/nextjs/app/layout.tsx +29 -0
- package/templates/nextjs/app/page.test.ts +11 -0
- package/templates/nextjs/app/page.tsx +8 -0
- package/templates/nextjs/eslint.config.ts +32 -0
- package/templates/nextjs/knip.json +4 -0
- package/templates/nextjs/next.config.ts +35 -0
- package/templates/nextjs/package.json +78 -0
- package/templates/nextjs/playwright.config.ts +27 -0
- package/templates/nextjs/postcss.config.mjs +7 -0
- package/templates/nextjs/prettier.config.ts +11 -0
- package/templates/nextjs/test/home.e2e.test.ts +11 -0
- package/templates/nextjs/tsconfig.json +33 -0
- package/templates/nextjs/vitest.config.ts +12 -0
- package/templates/nodejs/.agents/rules/typescript-first.md +7 -0
- package/templates/nodejs/.agents/rules.json +41 -0
- package/templates/nodejs/.claude/rules/deterministic-testing.md +20 -0
- package/templates/nodejs/.claude/rules/typescript-first.md +13 -0
- package/templates/nodejs/.cursor/rules/deterministic-testing.mdc +21 -0
- package/templates/nodejs/.cursor/rules/typescript-first.mdc +13 -0
- package/templates/nodejs/.dependency-cruiser.json +28 -0
- package/templates/nodejs/.dockerignore +8 -0
- package/templates/nodejs/.env.example +1 -0
- package/templates/nodejs/.github/ISSUE_TEMPLATE/bug.yml +66 -0
- package/templates/nodejs/.github/ISSUE_TEMPLATE/feature.yml +50 -0
- package/templates/nodejs/.github/pull_request_template.md +25 -0
- package/templates/nodejs/.github/workflows/ci.yml +179 -0
- package/templates/nodejs/.github/workflows/sast.yml +45 -0
- package/templates/nodejs/.lintstagedrc.json +10 -0
- package/templates/nodejs/.prettierignore +2 -0
- package/templates/nodejs/.prettierrc.json +1 -0
- package/templates/nodejs/AGENTS.md +8 -0
- package/templates/nodejs/CONTRIBUTING.md +56 -0
- package/templates/nodejs/Dockerfile +27 -0
- package/templates/nodejs/README.md +74 -0
- package/templates/nodejs/_gitignore +47 -0
- package/templates/nodejs/eslint.config.ts +7 -0
- package/templates/nodejs/package.json +66 -0
- package/templates/nodejs/src/main.ts +22 -0
- package/templates/nodejs/src/port.test.ts +30 -0
- package/templates/nodejs/src/port.ts +20 -0
- package/templates/nodejs/src/server.test.ts +60 -0
- package/templates/nodejs/src/server.ts +37 -0
- package/templates/nodejs/tsconfig.build.json +9 -0
- package/templates/nodejs/tsconfig.json +19 -0
- package/templates/nodejs/vitest.config.ts +12 -0
- package/templates/payload/.agents/rules/typescript-first.md +7 -0
- package/templates/payload/.agents/rules.json +41 -0
- package/templates/payload/.claude/rules/deterministic-testing.md +21 -0
- package/templates/payload/.claude/rules/typescript-first.md +15 -0
- package/templates/payload/.cursor/rules/deterministic-testing.mdc +21 -0
- package/templates/payload/.cursor/rules/typescript-first.mdc +13 -0
- package/templates/payload/.dependency-cruiser.json +34 -0
- package/templates/payload/.dockerignore +9 -0
- package/templates/payload/.editorconfig-checker.json +3 -0
- package/templates/payload/.env.example +4 -0
- package/templates/payload/.github/ISSUE_TEMPLATE/bug.yml +66 -0
- package/templates/payload/.github/ISSUE_TEMPLATE/feature.yml +50 -0
- package/templates/payload/.github/pull_request_template.md +25 -0
- package/templates/payload/.github/workflows/ci.yml +204 -0
- package/templates/payload/.github/workflows/sast.yml +46 -0
- package/templates/payload/.lintstagedrc.json +10 -0
- package/templates/payload/.prettierignore +5 -0
- package/templates/payload/.prettierrc.json +1 -0
- package/templates/payload/AGENTS.md +19 -0
- package/templates/payload/CONTRIBUTING.md +58 -0
- package/templates/payload/Dockerfile +26 -0
- package/templates/payload/README.md +98 -0
- package/templates/payload/_gitignore +52 -0
- package/templates/payload/eslint.config.ts +35 -0
- package/templates/payload/next.config.ts +43 -0
- package/templates/payload/package.json +86 -0
- package/templates/payload/playwright.config.ts +27 -0
- package/templates/payload/src/app/(frontend)/layout.tsx +18 -0
- package/templates/payload/src/app/(frontend)/page.test.ts +14 -0
- package/templates/payload/src/app/(frontend)/page.tsx +14 -0
- package/templates/payload/src/app/(frontend)/styles.css +15 -0
- package/templates/payload/src/app/(payload)/admin/[[...segments]]/not-found.tsx +24 -0
- package/templates/payload/src/app/(payload)/admin/[[...segments]]/page.tsx +24 -0
- package/templates/payload/src/app/(payload)/admin/importMap.ts +6 -0
- package/templates/payload/src/app/(payload)/api/[...slug]/route.ts +19 -0
- package/templates/payload/src/app/(payload)/api/graphql/route.ts +8 -0
- package/templates/payload/src/app/(payload)/api/graphql-playground/route.ts +7 -0
- package/templates/payload/src/app/(payload)/custom.scss +0 -0
- package/templates/payload/src/app/(payload)/layout.tsx +31 -0
- package/templates/payload/src/app/health/route.test.ts +20 -0
- package/templates/payload/src/app/health/route.ts +23 -0
- package/templates/payload/src/collections/media.test.ts +27 -0
- package/templates/payload/src/collections/media.ts +18 -0
- package/templates/payload/src/collections/users.test.ts +10 -0
- package/templates/payload/src/collections/users.ts +10 -0
- package/templates/payload/src/environment.test.ts +32 -0
- package/templates/payload/src/environment.ts +14 -0
- package/templates/payload/src/migrations/20261030_005055_initial.json +969 -0
- package/templates/payload/src/migrations/20261030_005055_initial.ts +134 -0
- package/templates/payload/src/migrations/index.ts +9 -0
- package/templates/payload/src/payload-types.ts +339 -0
- package/templates/payload/src/payload.config.ts +47 -0
- package/templates/payload/test/home.e2e.test.ts +16 -0
- package/templates/payload/tsconfig.json +34 -0
- package/templates/payload/vitest.config.ts +19 -0
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
import {spawnSync} from "node:child_process";
|
|
2
|
+
|
|
3
|
+
type GateCase = {
|
|
4
|
+
expectedExit: 0 | 2;
|
|
5
|
+
gate: string;
|
|
6
|
+
input: Record<string, unknown>;
|
|
7
|
+
name: string;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
const shellGate = ".agents/hooks/agent-shell-gate.sh";
|
|
11
|
+
const suppressionGate = ".agents/hooks/agent-suppression-gate.sh";
|
|
12
|
+
const constitutionGate = ".cursor/hooks/agent-constitution-gate.sh";
|
|
13
|
+
const sourceFile = "src/example.ts";
|
|
14
|
+
|
|
15
|
+
const blockedCommands = [
|
|
16
|
+
"git commit -n -m x",
|
|
17
|
+
"git commit -nm x",
|
|
18
|
+
"git commit -a -n -m x",
|
|
19
|
+
"git commit -an",
|
|
20
|
+
"git commit -m x -n",
|
|
21
|
+
"git commit --amend -n",
|
|
22
|
+
"git -C . commit -n",
|
|
23
|
+
"git commit --no-verify -m x",
|
|
24
|
+
"git push --no-verify",
|
|
25
|
+
"HUSKY=0 git commit -m x",
|
|
26
|
+
"export HUSKY=0; git commit -m x",
|
|
27
|
+
"git config core.hooksPath /dev/null",
|
|
28
|
+
"gh repo delete next-friday/example",
|
|
29
|
+
"gh issue delete 1",
|
|
30
|
+
"gh release delete v1",
|
|
31
|
+
"git commit --no-verif -m x",
|
|
32
|
+
"git commit --no-v -m x",
|
|
33
|
+
'git commit "--no-verify" -m x',
|
|
34
|
+
"git commit '-n' -m x",
|
|
35
|
+
'env "HUSKY=0" git commit -m x',
|
|
36
|
+
"git config core.hookspath /dev/null",
|
|
37
|
+
"git -c core.HooksPath=/dev/null commit -m x",
|
|
38
|
+
"git -c alias.c='commit --no-verify' c",
|
|
39
|
+
"git config alias.c commit",
|
|
40
|
+
"git commit-tree HEAD^{tree} -m x",
|
|
41
|
+
"git update-ref refs/heads/main HEAD",
|
|
42
|
+
"printf 'exit 0' > .husky/pre-commit",
|
|
43
|
+
"rm -rf .husky/_",
|
|
44
|
+
"sed -i '' s/gitleaks/true/ .husky/pre-commit",
|
|
45
|
+
"tee .gitleaks.toml < /dev/null",
|
|
46
|
+
"cp /dev/null .agents/hooks/agent-shell-gate.sh",
|
|
47
|
+
"git -c core.hooks\\Path=/dev/null commit -m x",
|
|
48
|
+
"git commit --no-ver\\ify -m x",
|
|
49
|
+
"HU\\SKY=0 git commit -m x",
|
|
50
|
+
"git commit -m x --no-$(echo verify)",
|
|
51
|
+
"/usr/bin/git commit -n -m x",
|
|
52
|
+
"git --git-dir .git commit -n -m x",
|
|
53
|
+
"git commit -n; git status",
|
|
54
|
+
"git commit -m x -n&&git push",
|
|
55
|
+
"rm -rf .husky",
|
|
56
|
+
"mv .husky /tmp/h",
|
|
57
|
+
"sed -e s/a/b/ -i .husky/pre-commit",
|
|
58
|
+
"python3 -c \"open('.husky/pre-commit','w')\"",
|
|
59
|
+
"dd of=.husky/pre-commit",
|
|
60
|
+
"git config core.hooks$X x",
|
|
61
|
+
"cd .husky && python3 -c \"open('pre-commit','w')\"",
|
|
62
|
+
"GIT_CONFIG_KEY_0=core.hooksPath GIT_CONFIG_VALUE_0=/x git commit -m x",
|
|
63
|
+
'bash -c "git commit -n -m x"',
|
|
64
|
+
"eval git commit -n -m x",
|
|
65
|
+
"git checkout -- .husky/pre-commit",
|
|
66
|
+
"echo x >> .claude/settings.local.json",
|
|
67
|
+
"git merge --no-verify feature",
|
|
68
|
+
"$(git commit --no-verify -m x)",
|
|
69
|
+
"echo `git commit -n -m x`",
|
|
70
|
+
'echo "$(rm -rf .husky)"',
|
|
71
|
+
"x=$(echo $(git commit -n -m x))",
|
|
72
|
+
"echo \"$(echo ')'; git commit --no-verify -m x)\"",
|
|
73
|
+
"$(echo \\); git commit -n -m x)",
|
|
74
|
+
"$(echo x # )\ngit commit -n -m x)",
|
|
75
|
+
'echo "$(true&# )\ngit commit -n -m x)"',
|
|
76
|
+
'echo "$(true|# )\ngit commit -n -m x)"',
|
|
77
|
+
'echo "$( (true)# )\ngit commit -n -m x)"',
|
|
78
|
+
];
|
|
79
|
+
|
|
80
|
+
const allowedCommands = [
|
|
81
|
+
'git commit -m "add login"',
|
|
82
|
+
"git commit --signoff -m x",
|
|
83
|
+
"git commit --amend --no-edit",
|
|
84
|
+
"git status",
|
|
85
|
+
"pnpm check",
|
|
86
|
+
"git commit --verbose -m x",
|
|
87
|
+
"cat .husky/pre-commit",
|
|
88
|
+
"git diff .husky/pre-commit",
|
|
89
|
+
'git commit -m "feat(x): y" && git log -n 3',
|
|
90
|
+
"git commit -m x; ls -n",
|
|
91
|
+
"git commit -m \"$(printf 'feat(x): y')\"",
|
|
92
|
+
"echo '$(git commit -n -m x)'",
|
|
93
|
+
'git commit -m "run with -n"',
|
|
94
|
+
'git commit -am "fix: -n flag handling"',
|
|
95
|
+
"git diff .husky/pre-commit > /tmp/x",
|
|
96
|
+
"ls .husky/ ; cp a b",
|
|
97
|
+
'git commit -m "chore: rm .husky/pre-commit file"',
|
|
98
|
+
'gh pr create --title "docs(x): explain core.hooksPath"',
|
|
99
|
+
'gh pr create --title "ci(x): remove HUSKY=0 usage"',
|
|
100
|
+
"git push -n",
|
|
101
|
+
"node scripts/check-agent-gates.ts",
|
|
102
|
+
];
|
|
103
|
+
|
|
104
|
+
const protectedPaths = [
|
|
105
|
+
".agents/rules/code-comments.md",
|
|
106
|
+
".agents/rules.json",
|
|
107
|
+
".agents/hooks/agent-shell-gate.sh",
|
|
108
|
+
".claude/rules/code-comments.md",
|
|
109
|
+
".claude/settings.json",
|
|
110
|
+
".cursor/rules/code-comments.mdc",
|
|
111
|
+
".cursor/hooks.json",
|
|
112
|
+
".cursor/hooks/agent-constitution-gate.sh",
|
|
113
|
+
"scripts/sync-agent-rules.ts",
|
|
114
|
+
"eslint.config.ts",
|
|
115
|
+
".husky/pre-commit",
|
|
116
|
+
".lintstagedrc.json",
|
|
117
|
+
".gitleaks.toml",
|
|
118
|
+
".claude/settings.local.json",
|
|
119
|
+
"src/../.husky/pre-commit",
|
|
120
|
+
];
|
|
121
|
+
|
|
122
|
+
const cases: GateCase[] = [
|
|
123
|
+
...blockedCommands.flatMap(command => [
|
|
124
|
+
{
|
|
125
|
+
gate: shellGate,
|
|
126
|
+
input: {
|
|
127
|
+
command,
|
|
128
|
+
},
|
|
129
|
+
expectedExit: 2 as const,
|
|
130
|
+
name: `Cursor shell: ${command}`,
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
gate: shellGate,
|
|
134
|
+
input: {
|
|
135
|
+
tool_input: {
|
|
136
|
+
command,
|
|
137
|
+
},
|
|
138
|
+
},
|
|
139
|
+
expectedExit: 2 as const,
|
|
140
|
+
name: `Claude Bash: ${command}`,
|
|
141
|
+
},
|
|
142
|
+
]),
|
|
143
|
+
...allowedCommands.map(command => ({
|
|
144
|
+
gate: shellGate,
|
|
145
|
+
input: {
|
|
146
|
+
command,
|
|
147
|
+
},
|
|
148
|
+
expectedExit: 0 as const,
|
|
149
|
+
name: `shell: ${command}`,
|
|
150
|
+
})),
|
|
151
|
+
{
|
|
152
|
+
gate: suppressionGate,
|
|
153
|
+
name: "suppression: eslint-disable",
|
|
154
|
+
expectedExit: 2,
|
|
155
|
+
input: {
|
|
156
|
+
tool_input: {
|
|
157
|
+
file_path: sourceFile,
|
|
158
|
+
content: "// eslint-disable-next-line\n",
|
|
159
|
+
},
|
|
160
|
+
},
|
|
161
|
+
},
|
|
162
|
+
...["// NOSONAR", "# noqa: E501", "# hadolint ignore=DL3008", "# trivy:ignore:AVD-DS-0002"].map(
|
|
163
|
+
content => ({
|
|
164
|
+
gate: suppressionGate,
|
|
165
|
+
input: {
|
|
166
|
+
tool_input: {
|
|
167
|
+
file_path: sourceFile,
|
|
168
|
+
content,
|
|
169
|
+
},
|
|
170
|
+
},
|
|
171
|
+
expectedExit: 2 as const,
|
|
172
|
+
name: `suppression: ${content}`,
|
|
173
|
+
}),
|
|
174
|
+
),
|
|
175
|
+
{
|
|
176
|
+
gate: suppressionGate,
|
|
177
|
+
name: "suppression: noqa inside a word",
|
|
178
|
+
expectedExit: 0,
|
|
179
|
+
input: {
|
|
180
|
+
tool_input: {
|
|
181
|
+
file_path: sourceFile,
|
|
182
|
+
content: "const canoqaValue = 1;\n",
|
|
183
|
+
},
|
|
184
|
+
},
|
|
185
|
+
},
|
|
186
|
+
{
|
|
187
|
+
gate: suppressionGate,
|
|
188
|
+
name: "suppression: exempt directory reached through ..",
|
|
189
|
+
expectedExit: 2,
|
|
190
|
+
input: {
|
|
191
|
+
tool_input: {
|
|
192
|
+
file_path: ".agents/rules/../../src/example.ts",
|
|
193
|
+
content: "// eslint-disable-next-line\n",
|
|
194
|
+
},
|
|
195
|
+
},
|
|
196
|
+
},
|
|
197
|
+
{
|
|
198
|
+
gate: suppressionGate,
|
|
199
|
+
name: "suppression: clean edit",
|
|
200
|
+
expectedExit: 0,
|
|
201
|
+
input: {
|
|
202
|
+
tool_input: {
|
|
203
|
+
file_path: sourceFile,
|
|
204
|
+
content: "export const value = 1;\n",
|
|
205
|
+
},
|
|
206
|
+
},
|
|
207
|
+
},
|
|
208
|
+
...protectedPaths.map(file => ({
|
|
209
|
+
gate: constitutionGate,
|
|
210
|
+
input: {
|
|
211
|
+
tool_input: {
|
|
212
|
+
file_path: file,
|
|
213
|
+
},
|
|
214
|
+
},
|
|
215
|
+
expectedExit: 2 as const,
|
|
216
|
+
name: `constitution: ${file}`,
|
|
217
|
+
})),
|
|
218
|
+
{
|
|
219
|
+
gate: constitutionGate,
|
|
220
|
+
name: "constitution: src file",
|
|
221
|
+
expectedExit: 0,
|
|
222
|
+
input: {
|
|
223
|
+
tool_input: {
|
|
224
|
+
file_path: sourceFile,
|
|
225
|
+
},
|
|
226
|
+
},
|
|
227
|
+
},
|
|
228
|
+
];
|
|
229
|
+
|
|
230
|
+
const failures = cases.filter(gateCase => {
|
|
231
|
+
const result = spawnSync(gateCase.gate, {
|
|
232
|
+
env: {
|
|
233
|
+
...process.env,
|
|
234
|
+
CLAUDE_PROJECT_DIR: process.cwd(),
|
|
235
|
+
CURSOR_PROJECT_DIR: process.cwd(),
|
|
236
|
+
},
|
|
237
|
+
input: JSON.stringify(gateCase.input),
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
return result.status !== gateCase.expectedExit;
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
if (failures.length > 0) {
|
|
244
|
+
const failureLines = failures.map(
|
|
245
|
+
gateCase => `- ${gateCase.name} (expected exit ${gateCase.expectedExit})`,
|
|
246
|
+
);
|
|
247
|
+
|
|
248
|
+
process.stderr.write(`Agent gate checks failed:\n${failureLines.join("\n")}\n`);
|
|
249
|
+
process.exitCode = 1;
|
|
250
|
+
} else {
|
|
251
|
+
process.stdout.write(`Checked ${cases.length} agent gate cases.\n`);
|
|
252
|
+
}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import {existsSync, readdirSync, readFileSync, writeFileSync} from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
|
|
4
|
+
type RuleConfig = {
|
|
5
|
+
description: string;
|
|
6
|
+
globs?: string[];
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
const sourceDirectory = ".agents/rules";
|
|
10
|
+
const configPath = ".agents/rules.json";
|
|
11
|
+
|
|
12
|
+
const claudeExtras: Record<string, string> = {
|
|
13
|
+
"agents-guide.md": "@../../AGENTS.md\n",
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* List the names of files with an extension in a directory.
|
|
18
|
+
* @param directory Directory to read.
|
|
19
|
+
* @param extension File extension, including the dot.
|
|
20
|
+
* @returns File names without the extension.
|
|
21
|
+
*/
|
|
22
|
+
function listNames(directory: string, extension: string): string[] {
|
|
23
|
+
return readdirSync(directory)
|
|
24
|
+
.filter(file => file.endsWith(extension))
|
|
25
|
+
.map(file => file.slice(0, -extension.length));
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Render the Claude Code rule: an import for an always-on rule, the full body behind `paths` for a scoped rule.
|
|
30
|
+
* @param name Rule name.
|
|
31
|
+
* @param rule Rule configuration.
|
|
32
|
+
* @param body Shared rule body.
|
|
33
|
+
* @returns The `.claude/rules` file content.
|
|
34
|
+
*/
|
|
35
|
+
function renderClaudeRule(name: string, rule: RuleConfig, body: string): string {
|
|
36
|
+
if (rule.globs === undefined) {
|
|
37
|
+
return `@../../${sourceDirectory}/${name}.md\n`;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const paths = rule.globs.map(glob => ` - "${glob}"`).join("\n");
|
|
41
|
+
|
|
42
|
+
return `---\npaths:\n${paths}\n---\n\n${body}`;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Render the Cursor rule with the full body, because Cursor does not inline referenced files.
|
|
47
|
+
* @param rule Rule configuration.
|
|
48
|
+
* @param body Shared rule body.
|
|
49
|
+
* @returns The `.cursor/rules` file content.
|
|
50
|
+
*/
|
|
51
|
+
function renderCursorRule(rule: RuleConfig, body: string): string {
|
|
52
|
+
const scope =
|
|
53
|
+
rule.globs === undefined
|
|
54
|
+
? "alwaysApply: true"
|
|
55
|
+
: `globs: "${rule.globs.join(",")}"\nalwaysApply: false`;
|
|
56
|
+
|
|
57
|
+
return `---\ndescription: "${rule.description}"\n${scope}\n---\n\n${body}`;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const config = JSON.parse(readFileSync(configPath, "utf8")) as Record<string, RuleConfig>;
|
|
61
|
+
const configNames = Object.keys(config);
|
|
62
|
+
const sourceNames = listNames(sourceDirectory, ".md");
|
|
63
|
+
const missingConfig = sourceNames.filter(name => !configNames.includes(name));
|
|
64
|
+
const missingSource = configNames.filter(name => !sourceNames.includes(name));
|
|
65
|
+
|
|
66
|
+
if (missingConfig.length > 0 || missingSource.length > 0) {
|
|
67
|
+
throw new Error(
|
|
68
|
+
`${configPath} and ${sourceDirectory} must list the same rules. Missing from ${configPath}: ${missingConfig.join(", ") || "none"}. Missing from ${sourceDirectory}: ${missingSource.join(", ") || "none"}.`,
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const claudeDirectory = ".claude/rules";
|
|
73
|
+
const cursorDirectory = ".cursor/rules";
|
|
74
|
+
const expected = new Map<string, string>();
|
|
75
|
+
|
|
76
|
+
for (const name of configNames) {
|
|
77
|
+
const rule = config[name];
|
|
78
|
+
const body = readFileSync(path.join(sourceDirectory, `${name}.md`), "utf8");
|
|
79
|
+
|
|
80
|
+
expected.set(path.join(claudeDirectory, `${name}.md`), renderClaudeRule(name, rule, body));
|
|
81
|
+
expected.set(path.join(cursorDirectory, `${name}.mdc`), renderCursorRule(rule, body));
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
for (const [file, content] of Object.entries(claudeExtras)) {
|
|
85
|
+
expected.set(path.join(claudeDirectory, file), content);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const orphans = [
|
|
89
|
+
...listNames(claudeDirectory, ".md").map(name => path.join(claudeDirectory, `${name}.md`)),
|
|
90
|
+
...listNames(cursorDirectory, ".mdc").map(name => path.join(cursorDirectory, `${name}.mdc`)),
|
|
91
|
+
].filter(file => !expected.has(file));
|
|
92
|
+
|
|
93
|
+
if (orphans.length > 0) {
|
|
94
|
+
throw new Error(
|
|
95
|
+
`Generated rule files without a source: ${orphans.join(", ")}. Delete them or add the rule to ${configPath}.`,
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const isCheckOnly = process.argv.includes("--check");
|
|
100
|
+
|
|
101
|
+
const staleFiles = [...expected].filter(
|
|
102
|
+
([file, content]) => !existsSync(file) || readFileSync(file, "utf8") !== content,
|
|
103
|
+
);
|
|
104
|
+
|
|
105
|
+
if (!isCheckOnly) {
|
|
106
|
+
for (const [file, content] of staleFiles) {
|
|
107
|
+
writeFileSync(file, content);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (isCheckOnly && staleFiles.length > 0) {
|
|
112
|
+
process.stderr.write(
|
|
113
|
+
`Agent rules are out of date: ${staleFiles.map(([file]) => file).join(", ")}. Run \`pnpm rules:sync\`.\n`,
|
|
114
|
+
);
|
|
115
|
+
|
|
116
|
+
process.exitCode = 1;
|
|
117
|
+
} else {
|
|
118
|
+
process.stdout.write(
|
|
119
|
+
`${isCheckOnly ? "Checked" : "Synced"} ${expected.size} agent rule files; ${staleFiles.length} ${isCheckOnly ? "stale" : "updated"}.\n`,
|
|
120
|
+
);
|
|
121
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# TypeScript-First
|
|
2
|
+
|
|
3
|
+
In a TypeScript-capable app or package, write source, tests, and scripts as `.ts`. Use that extension for new work and for any JavaScript file whose implementation this change already touches, then update its imports, scripts, tests, and configuration in the same change.
|
|
4
|
+
|
|
5
|
+
Keep other languages in separately maintained components. Use a non-TypeScript extension when the runtime, tool, or public contract requires it.
|
|
6
|
+
|
|
7
|
+
_Completion criterion_: Every file this change created or materially rewrote in a TypeScript-capable project uses the TypeScript extension the runtime accepts, and its imports and scripts resolve.
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"automation-owned-checks": {
|
|
3
|
+
"description": "Owned checks: hooks and CI define what must pass; run checks by hand to verify"
|
|
4
|
+
},
|
|
5
|
+
"code-comments": {
|
|
6
|
+
"description": "Required comments: comment only where a tool or rule needs it, or for a reason the code cannot show"
|
|
7
|
+
},
|
|
8
|
+
"current-state-authority": {
|
|
9
|
+
"description": "Current state: implement from user requirements and the working tree"
|
|
10
|
+
},
|
|
11
|
+
"demand-driven-configuration": {
|
|
12
|
+
"description": "Demand-driven configuration: add a setting only for an active requirement"
|
|
13
|
+
},
|
|
14
|
+
"dependency-security": {
|
|
15
|
+
"description": "Dependencies: add a package only when code or a contract uses it",
|
|
16
|
+
"globs": ["package.json", "pnpm-lock.yaml", "pnpm-workspace.yaml"]
|
|
17
|
+
},
|
|
18
|
+
"deterministic-testing": {
|
|
19
|
+
"description": "Test admission: add a case only when it catches a defect current tests miss",
|
|
20
|
+
"globs": ["**/*.test.ts"]
|
|
21
|
+
},
|
|
22
|
+
"diagnostics-and-error-handling": {
|
|
23
|
+
"description": "Diagnostics: fix runtime failures at the source and keep the root cause"
|
|
24
|
+
},
|
|
25
|
+
"git-workflow": {
|
|
26
|
+
"description": "Git workflow: trunk-based branches, commits, and pull requests"
|
|
27
|
+
},
|
|
28
|
+
"no-suppression": {
|
|
29
|
+
"description": "Findings: fix scanner and linter reports without inline suppressions"
|
|
30
|
+
},
|
|
31
|
+
"script-driven-changes": {
|
|
32
|
+
"description": "Scripts: apply a repeated edit across many files with a script"
|
|
33
|
+
},
|
|
34
|
+
"single-author-style": {
|
|
35
|
+
"description": "Sibling style: match layout, naming, and composition in the same project"
|
|
36
|
+
},
|
|
37
|
+
"typescript-first": {
|
|
38
|
+
"description": "TypeScript-first: write source, tests, and scripts as .ts",
|
|
39
|
+
"globs": ["**/*.ts", "**/*.js"]
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
---
|
|
2
|
+
paths:
|
|
3
|
+
- "**/*.test.ts"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Test Admission
|
|
7
|
+
|
|
8
|
+
Keep tests as small, deterministic protections for observable contracts.
|
|
9
|
+
|
|
10
|
+
Name the contract and the distinct defect a proposed test can detect before writing it. Admit a test for externally observable behavior, a public contract, a demonstrated regression, a non-trivial invariant, a meaningful failure mode, or an explicit repository verification requirement.
|
|
11
|
+
|
|
12
|
+
Choose the narrowest existing layer that owns that contract. Give each test one defect to detect. Add a case only when it catches a defect remaining cases miss. Treat coverage percentage as a measurement.
|
|
13
|
+
|
|
14
|
+
Search existing coverage first. Extend the file that already owns the contract. Create a file only when the contract has no owner or needs a different harness. Follow the nearest directory and naming pattern. Keep setup local until multiple tests share live runtime logic, then extract one helper.
|
|
15
|
+
|
|
16
|
+
Use the framework's standard assertions. Use an inline snippet unless filesystem paths, module resolution, or compiler services are the contract. Keep fixtures declarative and read-only.
|
|
17
|
+
|
|
18
|
+
When the user asks to run tests, run the narrowest owning file or filter.
|
|
19
|
+
|
|
20
|
+
_Completion criterion_: Every added or modified case maps to an admitted contract and a defect current cases would miss. Tests stay unchanged when no proposed case survives admission.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
---
|
|
2
|
+
paths:
|
|
3
|
+
- "**/*.ts"
|
|
4
|
+
- "**/*.js"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# TypeScript-First
|
|
8
|
+
|
|
9
|
+
In a TypeScript-capable app or package, write source, tests, and scripts as `.ts`. Use that extension for new work and for any JavaScript file whose implementation this change already touches, then update its imports, scripts, tests, and configuration in the same change.
|
|
10
|
+
|
|
11
|
+
Keep other languages in separately maintained components. Use a non-TypeScript extension when the runtime, tool, or public contract requires it.
|
|
12
|
+
|
|
13
|
+
_Completion criterion_: Every file this change created or materially rewrote in a TypeScript-capable project uses the TypeScript extension the runtime accepts, and its imports and scripts resolve.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "Test admission: add a case only when it catches a defect current tests miss"
|
|
3
|
+
globs: "**/*.test.ts"
|
|
4
|
+
alwaysApply: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Test Admission
|
|
8
|
+
|
|
9
|
+
Keep tests as small, deterministic protections for observable contracts.
|
|
10
|
+
|
|
11
|
+
Name the contract and the distinct defect a proposed test can detect before writing it. Admit a test for externally observable behavior, a public contract, a demonstrated regression, a non-trivial invariant, a meaningful failure mode, or an explicit repository verification requirement.
|
|
12
|
+
|
|
13
|
+
Choose the narrowest existing layer that owns that contract. Give each test one defect to detect. Add a case only when it catches a defect remaining cases miss. Treat coverage percentage as a measurement.
|
|
14
|
+
|
|
15
|
+
Search existing coverage first. Extend the file that already owns the contract. Create a file only when the contract has no owner or needs a different harness. Follow the nearest directory and naming pattern. Keep setup local until multiple tests share live runtime logic, then extract one helper.
|
|
16
|
+
|
|
17
|
+
Use the framework's standard assertions. Use an inline snippet unless filesystem paths, module resolution, or compiler services are the contract. Keep fixtures declarative and read-only.
|
|
18
|
+
|
|
19
|
+
When the user asks to run tests, run the narrowest owning file or filter.
|
|
20
|
+
|
|
21
|
+
_Completion criterion_: Every added or modified case maps to an admitted contract and a defect current cases would miss. Tests stay unchanged when no proposed case survives admission.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "TypeScript-first: write source, tests, and scripts as .ts"
|
|
3
|
+
globs: "**/*.ts,**/*.js"
|
|
4
|
+
alwaysApply: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# TypeScript-First
|
|
8
|
+
|
|
9
|
+
In a TypeScript-capable app or package, write source, tests, and scripts as `.ts`. Use that extension for new work and for any JavaScript file whose implementation this change already touches, then update its imports, scripts, tests, and configuration in the same change.
|
|
10
|
+
|
|
11
|
+
Keep other languages in separately maintained components. Use a non-TypeScript extension when the runtime, tool, or public contract requires it.
|
|
12
|
+
|
|
13
|
+
_Completion criterion_: Every file this change created or materially rewrote in a TypeScript-capable project uses the TypeScript extension the runtime accepts, and its imports and scripts resolve.
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "dependency-cruiser/configs/recommended-strict",
|
|
3
|
+
"forbidden": [
|
|
4
|
+
{
|
|
5
|
+
"name": "no-orphans",
|
|
6
|
+
"to": {},
|
|
7
|
+
"from": {
|
|
8
|
+
"orphan": true,
|
|
9
|
+
"pathNot": [
|
|
10
|
+
"(^|/)tsconfig\\.json$",
|
|
11
|
+
"(^|/)eslint\\.config\\.ts$",
|
|
12
|
+
"(^|/)vitest([.]e2e)?[.]config[.]ts$",
|
|
13
|
+
"[.]test[.]ts$",
|
|
14
|
+
"^src/main[.]ts$"
|
|
15
|
+
]
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
],
|
|
19
|
+
"options": {
|
|
20
|
+
"skipAnalysisNotInRules": true,
|
|
21
|
+
"tsPreCompilationDeps": true,
|
|
22
|
+
"enhancedResolveOptions": {
|
|
23
|
+
"conditionNames": ["import", "require", "node", "default", "types"],
|
|
24
|
+
"exportsFields": ["exports"]
|
|
25
|
+
},
|
|
26
|
+
"exclude": "(^|/)(?:dist|coverage|node_modules)/"
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
PORT=3000
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
name: Bug report
|
|
2
|
+
description: Report crashes, incorrect behavior, or setup problems.
|
|
3
|
+
labels: ["bug", "needs triage"]
|
|
4
|
+
body:
|
|
5
|
+
- type: markdown
|
|
6
|
+
attributes:
|
|
7
|
+
value: |
|
|
8
|
+
Reproduce the issue with the supported Node.js version.
|
|
9
|
+
Remove credentials, secrets, personal or customer data, and proprietary source code before submitting.
|
|
10
|
+
- type: checkboxes
|
|
11
|
+
id: preflight
|
|
12
|
+
attributes:
|
|
13
|
+
label: Before you submit
|
|
14
|
+
description: Confirm these items before submitting the report.
|
|
15
|
+
options:
|
|
16
|
+
- label: I searched existing issues and didn't find a matching report.
|
|
17
|
+
required: true
|
|
18
|
+
- label: I can reproduce this issue on the latest commit of the default branch.
|
|
19
|
+
required: true
|
|
20
|
+
- type: input
|
|
21
|
+
id: version
|
|
22
|
+
attributes:
|
|
23
|
+
label: Commit
|
|
24
|
+
placeholder: 769e0ef
|
|
25
|
+
validations:
|
|
26
|
+
required: true
|
|
27
|
+
- type: textarea
|
|
28
|
+
id: environment
|
|
29
|
+
attributes:
|
|
30
|
+
label: Environment
|
|
31
|
+
description: List Node.js, operating system, package manager, and the request that triggers the issue.
|
|
32
|
+
placeholder: |
|
|
33
|
+
Node.js: 24.22.1
|
|
34
|
+
OS: Ubuntu 24.04 / macOS
|
|
35
|
+
Package manager: pnpm 12.6.0
|
|
36
|
+
Request: curl -i http://localhost:3000/
|
|
37
|
+
validations:
|
|
38
|
+
required: true
|
|
39
|
+
- type: textarea
|
|
40
|
+
id: reproduction
|
|
41
|
+
attributes:
|
|
42
|
+
label: Minimal reproduction
|
|
43
|
+
description: Link to a minimal public reproduction or provide sanitized code and configuration that reproduce the issue.
|
|
44
|
+
validations:
|
|
45
|
+
required: true
|
|
46
|
+
- type: textarea
|
|
47
|
+
id: expected
|
|
48
|
+
attributes:
|
|
49
|
+
label: Expected behavior
|
|
50
|
+
description: Describe the behavior you expected.
|
|
51
|
+
validations:
|
|
52
|
+
required: true
|
|
53
|
+
- type: textarea
|
|
54
|
+
id: actual
|
|
55
|
+
attributes:
|
|
56
|
+
label: Actual behavior
|
|
57
|
+
description: Describe what happened, including the response status, response body, errors, and server logs.
|
|
58
|
+
validations:
|
|
59
|
+
required: true
|
|
60
|
+
- type: checkboxes
|
|
61
|
+
id: safety
|
|
62
|
+
attributes:
|
|
63
|
+
label: Sensitive information
|
|
64
|
+
options:
|
|
65
|
+
- label: I removed credentials, secrets, personal or customer data, and proprietary code from this report.
|
|
66
|
+
required: true
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
name: Feature request
|
|
2
|
+
description: Suggest a specific change to next-friday-template-nestjs.
|
|
3
|
+
labels: ["enhancement", "needs triage"]
|
|
4
|
+
body:
|
|
5
|
+
- type: markdown
|
|
6
|
+
attributes:
|
|
7
|
+
value: |
|
|
8
|
+
Use this form for changes that are ready to evaluate.
|
|
9
|
+
- type: dropdown
|
|
10
|
+
id: scope
|
|
11
|
+
attributes:
|
|
12
|
+
label: Affected area
|
|
13
|
+
description: Select the area this request affects.
|
|
14
|
+
options:
|
|
15
|
+
- Modules and endpoints
|
|
16
|
+
- Configuration and environment
|
|
17
|
+
- Testing
|
|
18
|
+
- Tooling / CI
|
|
19
|
+
- Documentation
|
|
20
|
+
- Repository governance
|
|
21
|
+
validations:
|
|
22
|
+
required: true
|
|
23
|
+
- type: textarea
|
|
24
|
+
id: problem
|
|
25
|
+
attributes:
|
|
26
|
+
label: Problem
|
|
27
|
+
description: Describe the problem or use case.
|
|
28
|
+
validations:
|
|
29
|
+
required: true
|
|
30
|
+
- type: textarea
|
|
31
|
+
id: proposal
|
|
32
|
+
attributes:
|
|
33
|
+
label: Proposed change
|
|
34
|
+
description: Describe the smallest change that solves the problem.
|
|
35
|
+
validations:
|
|
36
|
+
required: true
|
|
37
|
+
- type: textarea
|
|
38
|
+
id: alternatives
|
|
39
|
+
attributes:
|
|
40
|
+
label: Alternatives considered
|
|
41
|
+
description: List existing options you considered.
|
|
42
|
+
validations:
|
|
43
|
+
required: false
|
|
44
|
+
- type: checkboxes
|
|
45
|
+
id: breaking
|
|
46
|
+
attributes:
|
|
47
|
+
label: Breaking change
|
|
48
|
+
description: Indicate whether this request changes behavior for existing users.
|
|
49
|
+
options:
|
|
50
|
+
- label: This request changes an existing endpoint or public contract.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
<!-- Title: `<type>(<scope>): <subject>` with a lowercase scope and a subject of 50 characters or fewer. Repository workflows validate it. The squash merge puts the title on `main`. Delete a section that has nothing to say, except Scope. -->
|
|
2
|
+
|
|
3
|
+
## Why
|
|
4
|
+
|
|
5
|
+
<!-- The problem and the approach in 1-3 short sentences. No SHAs or rebase history. Link a related issue with `Closes #123`. -->
|
|
6
|
+
|
|
7
|
+
## What changed
|
|
8
|
+
|
|
9
|
+
<!-- 1-3 short bullets. Name a symbol or path only when it carries the change, and both sides of a rename. Name every added, changed, or removed endpoint, request or response field, and environment variable. Document new variables in `.env.example`. -->
|
|
10
|
+
|
|
11
|
+
## Scope
|
|
12
|
+
|
|
13
|
+
<!-- 1-3 short items: what this covers and what it deliberately leaves out. -->
|
|
14
|
+
|
|
15
|
+
## Tradeoffs
|
|
16
|
+
|
|
17
|
+
<!-- Only rejected alternatives a reviewer would ask about. -->
|
|
18
|
+
|
|
19
|
+
## Blast Radius
|
|
20
|
+
|
|
21
|
+
<!-- 1-2 sentences on who or what this touches and why that is safe or risky. If main is red, state the cost of leaving it red. -->
|
|
22
|
+
|
|
23
|
+
## Verification
|
|
24
|
+
|
|
25
|
+
<!-- 1-3 bullets, each a check you ran and its outcome. For a perf change, one number as before -> after. After this section, attach videos or screenshots that prove a claim. -->
|