@next-friday/create-app 7.0.0 → 7.1.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/package.json +3 -2
- package/templates/base/.agents/rules/constitution-changes.md +1 -1
- package/templates/base/.agents/skills/sdlc/playbooks/plan.md +5 -3
- package/templates/base/.agents/skills/sdlc/playbooks/question.md +2 -0
- package/templates/base/.claude/skills/sdlc/playbooks/plan.md +5 -3
- package/templates/base/.claude/skills/sdlc/playbooks/question.md +2 -0
- package/templates/base/.cursor/skills/sdlc/playbooks/plan.md +5 -3
- package/templates/base/.cursor/skills/sdlc/playbooks/question.md +2 -0
- package/templates/base/SETUP.md +1 -1
- package/templates/base/scripts/check-human-gates.ts +383 -0
- package/templates/nestjs/.agents/rules.json +1 -1
- package/templates/nestjs/.claude/rules/constitution-changes.md +1 -1
- package/templates/nestjs/.cursor/rules/constitution-changes.mdc +2 -2
- package/templates/nestjs/.github/workflows/ci.yml +2 -0
- package/templates/nestjs/package.json +2 -1
- package/templates/nextjs/.agents/rules.json +1 -1
- package/templates/nextjs/.claude/rules/constitution-changes.md +1 -1
- package/templates/nextjs/.cursor/rules/constitution-changes.mdc +2 -2
- package/templates/nextjs/.github/workflows/ci.yml +2 -0
- package/templates/nextjs/package.json +2 -1
- package/templates/nodejs/.agents/rules.json +1 -1
- package/templates/nodejs/.claude/rules/constitution-changes.md +1 -1
- package/templates/nodejs/.cursor/rules/constitution-changes.mdc +2 -2
- package/templates/nodejs/.github/workflows/ci.yml +2 -0
- package/templates/nodejs/package.json +2 -1
- package/templates/payload/.agents/rules.json +1 -1
- package/templates/payload/.claude/rules/constitution-changes.md +1 -1
- package/templates/payload/.cursor/rules/constitution-changes.mdc +2 -2
- package/templates/payload/.github/workflows/ci.yml +2 -0
- package/templates/payload/package.json +2 -1
- package/templates/turborepo/.agents/rules.json +1 -1
- package/templates/turborepo/.claude/rules/constitution-changes.md +1 -1
- package/templates/turborepo/.cursor/rules/constitution-changes.mdc +2 -2
- package/templates/turborepo/.github/workflows/ci.yml +2 -0
- package/templates/turborepo/package.json +2 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@next-friday/create-app",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.1.0",
|
|
4
4
|
"description": "Create a Next Friday project from a template.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"create",
|
|
@@ -74,6 +74,7 @@
|
|
|
74
74
|
"format": "prettier --write --cache .",
|
|
75
75
|
"format:check": "prettier --check --cache . && editorconfig-checker",
|
|
76
76
|
"gates:check": "node scripts/check-agent-gates.ts",
|
|
77
|
+
"human-gates:check": "node scripts/check-human-gates.ts",
|
|
77
78
|
"knip": "knip",
|
|
78
79
|
"lint": "eslint . --fix --cache --max-warnings=0 --no-inline-config",
|
|
79
80
|
"lint:check": "eslint . --cache --max-warnings=0 --no-inline-config",
|
|
@@ -86,6 +87,6 @@
|
|
|
86
87
|
"test:coverage": "vitest run --coverage",
|
|
87
88
|
"test:watch": "vitest",
|
|
88
89
|
"typecheck": "tsc --noEmit -p tsconfig.json",
|
|
89
|
-
"verify": "pnpm suppressions:check && pnpm rules:check && pnpm gates:check && pnpm lint:check && pnpm format:check && pnpm sort-package-json:check && pnpm typecheck && pnpm test:coverage && pnpm knip && pnpm build && pnpm check:publint"
|
|
90
|
+
"verify": "pnpm suppressions:check && pnpm rules:check && pnpm gates:check && pnpm human-gates:check && pnpm lint:check && pnpm format:check && pnpm sort-package-json:check && pnpm typecheck && pnpm test:coverage && pnpm knip && pnpm build && pnpm check:publint"
|
|
90
91
|
}
|
|
91
92
|
}
|
|
@@ -2,4 +2,4 @@
|
|
|
2
2
|
|
|
3
3
|
The constitution is the set of files that agent settings deny to agents: rules, hooks, lint, format, and commit configuration, and the agent settings themselves. It is company policy.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
The constitution changes in a pull request like any other change, and a code owner approves it in review. Agent settings stop an agent from editing these files. When a task needs a constitution change, write the exact new text and the files it goes in on the pull request; a person commits it to that branch.
|
|
@@ -7,10 +7,12 @@ This playbook writes the intent. The build plan, `intent/<change>/plan.md`, come
|
|
|
7
7
|
3. Interview until the originator has said four things: the problem (who, how often, and a number with its source), the outcome as the user would see it, the constraints, and what is out of scope.
|
|
8
8
|
- **When all four are already said, go to step 4 in the same turn.**
|
|
9
9
|
- **When one is missing, ask and stop.** Write no draft in that turn. Ask in rounds: each round holds only questions that do not depend on another question in the same round, each asks one thing, numbered, each with a concrete answer you recommend, worded so "yes" accepts it. A recommended answer is a fact or a choice, such as "Recommended: only the checkout page", never an instruction to the person. When you have no answer to recommend, write "No recommendation" and ask plainly. Wait for the answers, and build the next round on them.
|
|
10
|
-
4. Write `intent/<change>/intent.md` from the template below, where `<change>` is a short kebab-case name. Write the file in the language of the files already in `intent/`. Use exactly the template's five headings; what is out of scope goes under **Proposed outcome**. Anything else that is unknown, unverified, or not yet decided goes under **Open questions**; write "None" only when nothing is, and never list what the originator already answered. Show the whole draft, and name the file only as `intent/<change>/intent.md`.
|
|
11
|
-
5. **Gate: the originator corrects the draft.** Ask whether it matches what they meant, and revise until they say yes. Commit nothing, push nothing, and open no pull request before that yes.
|
|
10
|
+
4. Write `intent/<change>/intent.md` from the template below, where `<change>` is a short kebab-case name. Write the file in the language of the files already in `intent/`. Use exactly the template's five headings; what is out of scope goes under **Proposed outcome**. Anything else that is unknown, unverified, or not yet decided goes under **Open questions**; write "None" only when nothing is, and never list what the originator already answered. Show the whole draft, and name the file only as `intent/<change>/intent.md`. In plan mode you cannot write the file: show the draft as the plan, and write the file once it is approved.
|
|
11
|
+
5. **Gate: the originator corrects the draft.** Ask whether it matches what they meant, and revise until they say yes. Commit nothing, push nothing, and open no pull request before that yes. In plan mode, the originator approving the plan is that yes.
|
|
12
12
|
6. Commit `intent.md` on a new branch, push it, and open a pull request ready for review, as `AGENTS.md` says for branches and pull requests.
|
|
13
|
-
7. **Gate: the product owner accepts or rejects the intent.** The product owner
|
|
13
|
+
7. **Gate: the product owner accepts or rejects the intent.** The product owner accepts by setting `Status: accepted.` and merging the pull request, or rejects by closing it; you do neither. Report the pull request's URL, keep it green as `AGENTS.md` says, and wait.
|
|
14
|
+
|
|
15
|
+
**Next:** `.agents/skills/write-spec/SKILL.md`; an agent; when the product owner has merged the intent's pull request and a person or a trigger asks for the spec.
|
|
14
16
|
|
|
15
17
|
## Template
|
|
16
18
|
|
|
@@ -4,3 +4,5 @@
|
|
|
4
4
|
2. Answer, citing `path:line` or command output for each claim, as the **Write replies a person can check** convention in `AGENTS.md` says.
|
|
5
5
|
3. Write no file, make no commit, push nothing, and post nothing to GitHub or another service.
|
|
6
6
|
4. When the answer shows work worth doing, offer it in one line, such as "Send `/sdlc write an intent for this` to start the change", and stop.
|
|
7
|
+
|
|
8
|
+
**Next:** none; the person; when they send a new message.
|
|
@@ -7,10 +7,12 @@ This playbook writes the intent. The build plan, `intent/<change>/plan.md`, come
|
|
|
7
7
|
3. Interview until the originator has said four things: the problem (who, how often, and a number with its source), the outcome as the user would see it, the constraints, and what is out of scope.
|
|
8
8
|
- **When all four are already said, go to step 4 in the same turn.**
|
|
9
9
|
- **When one is missing, ask and stop.** Write no draft in that turn. Ask in rounds: each round holds only questions that do not depend on another question in the same round, each asks one thing, numbered, each with a concrete answer you recommend, worded so "yes" accepts it. A recommended answer is a fact or a choice, such as "Recommended: only the checkout page", never an instruction to the person. When you have no answer to recommend, write "No recommendation" and ask plainly. Wait for the answers, and build the next round on them.
|
|
10
|
-
4. Write `intent/<change>/intent.md` from the template below, where `<change>` is a short kebab-case name. Write the file in the language of the files already in `intent/`. Use exactly the template's five headings; what is out of scope goes under **Proposed outcome**. Anything else that is unknown, unverified, or not yet decided goes under **Open questions**; write "None" only when nothing is, and never list what the originator already answered. Show the whole draft, and name the file only as `intent/<change>/intent.md`.
|
|
11
|
-
5. **Gate: the originator corrects the draft.** Ask whether it matches what they meant, and revise until they say yes. Commit nothing, push nothing, and open no pull request before that yes.
|
|
10
|
+
4. Write `intent/<change>/intent.md` from the template below, where `<change>` is a short kebab-case name. Write the file in the language of the files already in `intent/`. Use exactly the template's five headings; what is out of scope goes under **Proposed outcome**. Anything else that is unknown, unverified, or not yet decided goes under **Open questions**; write "None" only when nothing is, and never list what the originator already answered. Show the whole draft, and name the file only as `intent/<change>/intent.md`. In plan mode you cannot write the file: show the draft as the plan, and write the file once it is approved.
|
|
11
|
+
5. **Gate: the originator corrects the draft.** Ask whether it matches what they meant, and revise until they say yes. Commit nothing, push nothing, and open no pull request before that yes. In plan mode, the originator approving the plan is that yes.
|
|
12
12
|
6. Commit `intent.md` on a new branch, push it, and open a pull request ready for review, as `AGENTS.md` says for branches and pull requests.
|
|
13
|
-
7. **Gate: the product owner accepts or rejects the intent.** The product owner
|
|
13
|
+
7. **Gate: the product owner accepts or rejects the intent.** The product owner accepts by setting `Status: accepted.` and merging the pull request, or rejects by closing it; you do neither. Report the pull request's URL, keep it green as `AGENTS.md` says, and wait.
|
|
14
|
+
|
|
15
|
+
**Next:** `.agents/skills/write-spec/SKILL.md`; an agent; when the product owner has merged the intent's pull request and a person or a trigger asks for the spec.
|
|
14
16
|
|
|
15
17
|
## Template
|
|
16
18
|
|
|
@@ -4,3 +4,5 @@
|
|
|
4
4
|
2. Answer, citing `path:line` or command output for each claim, as the **Write replies a person can check** convention in `AGENTS.md` says.
|
|
5
5
|
3. Write no file, make no commit, push nothing, and post nothing to GitHub or another service.
|
|
6
6
|
4. When the answer shows work worth doing, offer it in one line, such as "Send `/sdlc write an intent for this` to start the change", and stop.
|
|
7
|
+
|
|
8
|
+
**Next:** none; the person; when they send a new message.
|
|
@@ -7,10 +7,12 @@ This playbook writes the intent. The build plan, `intent/<change>/plan.md`, come
|
|
|
7
7
|
3. Interview until the originator has said four things: the problem (who, how often, and a number with its source), the outcome as the user would see it, the constraints, and what is out of scope.
|
|
8
8
|
- **When all four are already said, go to step 4 in the same turn.**
|
|
9
9
|
- **When one is missing, ask and stop.** Write no draft in that turn. Ask in rounds: each round holds only questions that do not depend on another question in the same round, each asks one thing, numbered, each with a concrete answer you recommend, worded so "yes" accepts it. A recommended answer is a fact or a choice, such as "Recommended: only the checkout page", never an instruction to the person. When you have no answer to recommend, write "No recommendation" and ask plainly. Wait for the answers, and build the next round on them.
|
|
10
|
-
4. Write `intent/<change>/intent.md` from the template below, where `<change>` is a short kebab-case name. Write the file in the language of the files already in `intent/`. Use exactly the template's five headings; what is out of scope goes under **Proposed outcome**. Anything else that is unknown, unverified, or not yet decided goes under **Open questions**; write "None" only when nothing is, and never list what the originator already answered. Show the whole draft, and name the file only as `intent/<change>/intent.md`.
|
|
11
|
-
5. **Gate: the originator corrects the draft.** Ask whether it matches what they meant, and revise until they say yes. Commit nothing, push nothing, and open no pull request before that yes.
|
|
10
|
+
4. Write `intent/<change>/intent.md` from the template below, where `<change>` is a short kebab-case name. Write the file in the language of the files already in `intent/`. Use exactly the template's five headings; what is out of scope goes under **Proposed outcome**. Anything else that is unknown, unverified, or not yet decided goes under **Open questions**; write "None" only when nothing is, and never list what the originator already answered. Show the whole draft, and name the file only as `intent/<change>/intent.md`. In plan mode you cannot write the file: show the draft as the plan, and write the file once it is approved.
|
|
11
|
+
5. **Gate: the originator corrects the draft.** Ask whether it matches what they meant, and revise until they say yes. Commit nothing, push nothing, and open no pull request before that yes. In plan mode, the originator approving the plan is that yes.
|
|
12
12
|
6. Commit `intent.md` on a new branch, push it, and open a pull request ready for review, as `AGENTS.md` says for branches and pull requests.
|
|
13
|
-
7. **Gate: the product owner accepts or rejects the intent.** The product owner
|
|
13
|
+
7. **Gate: the product owner accepts or rejects the intent.** The product owner accepts by setting `Status: accepted.` and merging the pull request, or rejects by closing it; you do neither. Report the pull request's URL, keep it green as `AGENTS.md` says, and wait.
|
|
14
|
+
|
|
15
|
+
**Next:** `.agents/skills/write-spec/SKILL.md`; an agent; when the product owner has merged the intent's pull request and a person or a trigger asks for the spec.
|
|
14
16
|
|
|
15
17
|
## Template
|
|
16
18
|
|
|
@@ -4,3 +4,5 @@
|
|
|
4
4
|
2. Answer, citing `path:line` or command output for each claim, as the **Write replies a person can check** convention in `AGENTS.md` says.
|
|
5
5
|
3. Write no file, make no commit, push nothing, and post nothing to GitHub or another service.
|
|
6
6
|
4. When the answer shows work worth doing, offer it in one line, such as "Send `/sdlc write an intent for this` to start the change", and stop.
|
|
7
|
+
|
|
8
|
+
**Next:** none; the person; when they send a new message.
|
package/templates/base/SETUP.md
CHANGED
|
@@ -4,7 +4,7 @@ This project follows Anthropic's [AI-native SDLC Playbook](https://claude.com/re
|
|
|
4
4
|
|
|
5
5
|
## How a change flows
|
|
6
6
|
|
|
7
|
-
1. **Plan:** the originator of an idea, a ticket, or an incident sends it with `/sdlc`, which interviews them and writes `intent/<change>/intent.md`. The product owner
|
|
7
|
+
1. **Plan:** the originator of an idea, a ticket, or an incident sends it with `/sdlc`, which interviews them and writes `intent/<change>/intent.md`. The product owner accepts it by merging it with `Status: accepted.`, or rejects it by closing its pull request.
|
|
8
8
|
2. **Design:** `spec.md` is written from the accepted intent with the policy skills loaded (`write-spec` skill). The product owner resolves concerns with the policy owners.
|
|
9
9
|
3. **Build:** the engineer starts in plan mode, approves the plan, and commits it as `plan.md`. A tech lead approves higher-risk plans.
|
|
10
10
|
4. **Test:** the session runs **Verifying your work** in `AGENTS.md`.
|
|
@@ -0,0 +1,383 @@
|
|
|
1
|
+
import {existsSync, readdirSync, readFileSync, statSync} from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
|
|
4
|
+
type Problem = {
|
|
5
|
+
line: number;
|
|
6
|
+
message: string;
|
|
7
|
+
rule: string;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
type Step = {
|
|
11
|
+
line: number;
|
|
12
|
+
text: string;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
type SelfTestCase = {
|
|
16
|
+
expectedRule?: string;
|
|
17
|
+
name: string;
|
|
18
|
+
text: string;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const playbookDirectory = ".agents/skills/sdlc/playbooks";
|
|
22
|
+
const agentOwnedWorkRule = ".agents/rules/agent-owned-work.md";
|
|
23
|
+
const nextMarker = "**Next:**";
|
|
24
|
+
|
|
25
|
+
const humanGateRoles = [
|
|
26
|
+
"originator",
|
|
27
|
+
"product owner",
|
|
28
|
+
"engineer",
|
|
29
|
+
"code owner",
|
|
30
|
+
"release manager",
|
|
31
|
+
"service owner",
|
|
32
|
+
];
|
|
33
|
+
|
|
34
|
+
const roleWords = new RegExp(String.raw`\b(?:${humanGateRoles.join("|")})s?\b`, "i");
|
|
35
|
+
|
|
36
|
+
const waitingWordList = [
|
|
37
|
+
"wait",
|
|
38
|
+
"waits",
|
|
39
|
+
"approve",
|
|
40
|
+
"approves",
|
|
41
|
+
"approval",
|
|
42
|
+
"approved",
|
|
43
|
+
"approving",
|
|
44
|
+
"confirm",
|
|
45
|
+
"confirms",
|
|
46
|
+
"confirmation",
|
|
47
|
+
"permission",
|
|
48
|
+
"sign off",
|
|
49
|
+
];
|
|
50
|
+
|
|
51
|
+
const waitingWords = new RegExp(String.raw`\b(?:${waitingWordList.join("|")})\b`, "i");
|
|
52
|
+
const roleList = humanGateRoles.join(", ");
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Blank every line of a fenced code block, keeping line numbers.
|
|
56
|
+
* @param text Playbook content with LF line endings.
|
|
57
|
+
* @returns The content with fenced lines emptied.
|
|
58
|
+
*/
|
|
59
|
+
function maskFencedBlocks(text: string): string {
|
|
60
|
+
let isFenced = false;
|
|
61
|
+
|
|
62
|
+
return text
|
|
63
|
+
.split("\n")
|
|
64
|
+
.map(line => {
|
|
65
|
+
const isFence = /^\s*(?:```|~~~)/.test(line);
|
|
66
|
+
const isMasked = isFenced || isFence;
|
|
67
|
+
|
|
68
|
+
isFenced = isFence ? !isFenced : isFenced;
|
|
69
|
+
|
|
70
|
+
return isMasked ? "" : line;
|
|
71
|
+
})
|
|
72
|
+
.join("\n");
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Split a playbook into its numbered steps, each with its indented continuation lines.
|
|
77
|
+
* @param text Playbook content.
|
|
78
|
+
* @returns The steps with the line each starts on.
|
|
79
|
+
*/
|
|
80
|
+
function splitSteps(text: string): Step[] {
|
|
81
|
+
return Array.from(text.matchAll(/^\d+\. .*(?:\n[\t ]+\S.*)*/gm), match => ({
|
|
82
|
+
line: text.slice(0, match.index).split("\n").length,
|
|
83
|
+
text: match[0],
|
|
84
|
+
}));
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Find gate lines whose bold sentence names no human gate role.
|
|
89
|
+
* @param lines Playbook lines.
|
|
90
|
+
* @returns One problem per such line.
|
|
91
|
+
*/
|
|
92
|
+
function findGateProblems(lines: string[]): Problem[] {
|
|
93
|
+
return lines
|
|
94
|
+
.map((text, index) => ({
|
|
95
|
+
text,
|
|
96
|
+
line: index + 1,
|
|
97
|
+
}))
|
|
98
|
+
.filter(({text}) => text.includes("**Gate:"))
|
|
99
|
+
.filter(({text}) => !roleWords.test(/\*\*Gate:(.*?)\*\*/.exec(text)?.[1] ?? ""))
|
|
100
|
+
.map(({line}) => ({
|
|
101
|
+
line,
|
|
102
|
+
rule: "A",
|
|
103
|
+
message: `a gate must name one of ${roleList} inside its bold sentence; write "**Gate: the <role> <does what>.**"`,
|
|
104
|
+
}));
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Find steps that wait, approve, or confirm without naming a human gate role.
|
|
109
|
+
* @param text Playbook content.
|
|
110
|
+
* @returns One problem per such step.
|
|
111
|
+
*/
|
|
112
|
+
function findWaitingStepProblems(text: string): Problem[] {
|
|
113
|
+
return splitSteps(text)
|
|
114
|
+
.filter(step => waitingWords.test(step.text) && !roleWords.test(step.text))
|
|
115
|
+
.map(step => ({
|
|
116
|
+
rule: "B",
|
|
117
|
+
line: step.line,
|
|
118
|
+
message: `a step that waits, approves, or confirms must name who does it: one of ${roleList}`,
|
|
119
|
+
}));
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Tell whether a path is a relative path without `..` to an existing regular file.
|
|
124
|
+
* @param targetPath Path from a `**Next:**` target.
|
|
125
|
+
* @returns True when the path is usable.
|
|
126
|
+
*/
|
|
127
|
+
function isProjectFile(targetPath: string): boolean {
|
|
128
|
+
const segments = targetPath.split(/[\\/]/);
|
|
129
|
+
|
|
130
|
+
return (
|
|
131
|
+
!path.isAbsolute(targetPath) &&
|
|
132
|
+
!segments.includes("..") &&
|
|
133
|
+
statSync(targetPath, {
|
|
134
|
+
throwIfNoEntry: false,
|
|
135
|
+
})?.isFile() === true
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Describe what is wrong with the text after a `**Next:**` marker.
|
|
141
|
+
* @param text The text after the marker.
|
|
142
|
+
* @returns The problem, or an empty string when the line is valid.
|
|
143
|
+
*/
|
|
144
|
+
function describeNextProblem(text: string): string {
|
|
145
|
+
const parts = text.replace(/\.\s*$/, "").split(";");
|
|
146
|
+
|
|
147
|
+
if (parts.length !== 3 || parts.some(part => part.trim() === "")) {
|
|
148
|
+
return `"${nextMarker}" needs exactly three non-empty parts separated by ";" and no other ";": the target, who runs it, and what starts it`;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const target = parts.at(0)?.trim() ?? "";
|
|
152
|
+
const targetPath = /^`([^`\s]+)`$/.exec(target)?.[1];
|
|
153
|
+
|
|
154
|
+
return target !== "none" && (targetPath === undefined || !isProjectFile(targetPath))
|
|
155
|
+
? `the "${nextMarker}" target must be "none" or one backticked relative path to an existing file in the project, with no ".." segment, found ${target}`
|
|
156
|
+
: "";
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Find a missing, repeated, or malformed `**Next:**` line.
|
|
161
|
+
* @param lines Playbook lines.
|
|
162
|
+
* @returns The problems with the next-step line.
|
|
163
|
+
*/
|
|
164
|
+
function findNextProblems(lines: string[]): Problem[] {
|
|
165
|
+
const nextLines = lines
|
|
166
|
+
.map((text, index) => ({
|
|
167
|
+
text,
|
|
168
|
+
line: index + 1,
|
|
169
|
+
}))
|
|
170
|
+
.filter(({text}) => text.startsWith(nextMarker));
|
|
171
|
+
|
|
172
|
+
const next = nextLines.at(0);
|
|
173
|
+
|
|
174
|
+
if (next === undefined || nextLines.length !== 1) {
|
|
175
|
+
return [
|
|
176
|
+
{
|
|
177
|
+
rule: "C",
|
|
178
|
+
line: next?.line ?? 1,
|
|
179
|
+
message: `a playbook needs exactly one line starting with "${nextMarker}", found ${nextLines.length}; write "${nextMarker} <target>; <who runs it>; <what starts it>."`,
|
|
180
|
+
},
|
|
181
|
+
];
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
const message = describeNextProblem(next.text.slice(nextMarker.length));
|
|
185
|
+
|
|
186
|
+
return message === ""
|
|
187
|
+
? []
|
|
188
|
+
: [
|
|
189
|
+
{
|
|
190
|
+
message,
|
|
191
|
+
rule: "C",
|
|
192
|
+
line: next.line,
|
|
193
|
+
},
|
|
194
|
+
];
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Check one playbook against rules A, B, and C.
|
|
199
|
+
* @param text Playbook content.
|
|
200
|
+
* @returns Every problem found.
|
|
201
|
+
*/
|
|
202
|
+
function checkPlaybook(text: string): Problem[] {
|
|
203
|
+
const unfenced = maskFencedBlocks(text.replaceAll("\r\n", "\n"));
|
|
204
|
+
const lines = unfenced.split("\n");
|
|
205
|
+
|
|
206
|
+
return [
|
|
207
|
+
...findGateProblems(lines),
|
|
208
|
+
...findWaitingStepProblems(unfenced),
|
|
209
|
+
...findNextProblems(lines),
|
|
210
|
+
];
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* List the human gate roles a rule text does not mention.
|
|
215
|
+
* @param ruleText Content of the agent-owned work rule.
|
|
216
|
+
* @returns The missing roles.
|
|
217
|
+
*/
|
|
218
|
+
function findMissingRoles(ruleText: string): string[] {
|
|
219
|
+
return humanGateRoles.filter(role => !ruleText.toLowerCase().includes(role));
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
const validNext = "**Next:** none; the person; when they write.";
|
|
223
|
+
|
|
224
|
+
const selfTestCases: SelfTestCase[] = [
|
|
225
|
+
{
|
|
226
|
+
name: "gate names a role",
|
|
227
|
+
text: `**Gate: the originator corrects the draft.**\n\n${validNext}`,
|
|
228
|
+
},
|
|
229
|
+
{
|
|
230
|
+
expectedRule: "A",
|
|
231
|
+
name: "gate names no role",
|
|
232
|
+
text: `**Gate: the manager corrects the draft.**\n\n${validNext}`,
|
|
233
|
+
},
|
|
234
|
+
{
|
|
235
|
+
expectedRule: "A",
|
|
236
|
+
name: "role outside the bold gate sentence",
|
|
237
|
+
text: `**Gate: the draft is corrected.** The originator does it.\n\n${validNext}`,
|
|
238
|
+
},
|
|
239
|
+
{
|
|
240
|
+
name: "waiting step names a role",
|
|
241
|
+
text: `1. Wait for the engineer.\n\n${validNext}`,
|
|
242
|
+
},
|
|
243
|
+
...waitingWordList.map(word => ({
|
|
244
|
+
expectedRule: "B",
|
|
245
|
+
name: `waiting word "${word}" names no role`,
|
|
246
|
+
text: `1. Ask, then ${word} for the answer.\n\n${validNext}`,
|
|
247
|
+
})),
|
|
248
|
+
{
|
|
249
|
+
name: "plural role",
|
|
250
|
+
text: `1. Wait for the engineers and the code owners.\n\n${validNext}`,
|
|
251
|
+
},
|
|
252
|
+
{
|
|
253
|
+
expectedRule: "B",
|
|
254
|
+
name: "longer word that starts with a role",
|
|
255
|
+
text: `1. Wait for the engineering team.\n\n${validNext}`,
|
|
256
|
+
},
|
|
257
|
+
{
|
|
258
|
+
name: "CRLF line endings",
|
|
259
|
+
text: `1. Ask, then wait.\r\n - The code owner answers.\r\n\r\n${validNext}\r\n`,
|
|
260
|
+
},
|
|
261
|
+
{
|
|
262
|
+
name: "gate inside a fenced block",
|
|
263
|
+
text: `\`\`\`\n**Gate: the manager corrects the draft.**\n\`\`\`\n\n${validNext}`,
|
|
264
|
+
},
|
|
265
|
+
{
|
|
266
|
+
name: "next inside a fenced block",
|
|
267
|
+
text: `\`\`\`\n**Next:** none; ; x\n\`\`\`\n\n${validNext}`,
|
|
268
|
+
},
|
|
269
|
+
{
|
|
270
|
+
expectedRule: "B",
|
|
271
|
+
name: "waiting word on a continuation line",
|
|
272
|
+
text: `1. Ask.\n - Wait for the answer.\n\n${validNext}`,
|
|
273
|
+
},
|
|
274
|
+
{
|
|
275
|
+
name: "role on a continuation line covers the step",
|
|
276
|
+
text: `1. Ask, then wait.\n - The code owner answers.\n\n${validNext}`,
|
|
277
|
+
},
|
|
278
|
+
{
|
|
279
|
+
name: "target is an existing path",
|
|
280
|
+
text: "**Next:** `package.json`; an agent; when asked.",
|
|
281
|
+
},
|
|
282
|
+
{
|
|
283
|
+
expectedRule: "C",
|
|
284
|
+
name: "target path does not exist",
|
|
285
|
+
text: "**Next:** `missing/file.md`; an agent; when asked.",
|
|
286
|
+
},
|
|
287
|
+
{
|
|
288
|
+
expectedRule: "C",
|
|
289
|
+
name: "target is an absolute path",
|
|
290
|
+
text: "**Next:** `/etc/hostname`; an agent; when asked.",
|
|
291
|
+
},
|
|
292
|
+
{
|
|
293
|
+
expectedRule: "C",
|
|
294
|
+
name: "target has a .. segment",
|
|
295
|
+
text: "**Next:** `.agents/../package.json`; an agent; when asked.",
|
|
296
|
+
},
|
|
297
|
+
{
|
|
298
|
+
expectedRule: "C",
|
|
299
|
+
name: "target is a directory",
|
|
300
|
+
text: "**Next:** `.agents`; an agent; when asked.",
|
|
301
|
+
},
|
|
302
|
+
{
|
|
303
|
+
expectedRule: "C",
|
|
304
|
+
name: "target is not backticked",
|
|
305
|
+
text: "**Next:** package.json; an agent; when asked.",
|
|
306
|
+
},
|
|
307
|
+
{
|
|
308
|
+
expectedRule: "C",
|
|
309
|
+
name: "next has two parts",
|
|
310
|
+
text: "**Next:** none; the person.",
|
|
311
|
+
},
|
|
312
|
+
{
|
|
313
|
+
expectedRule: "C",
|
|
314
|
+
name: "next has an empty part",
|
|
315
|
+
text: "**Next:** none; ; when they write.",
|
|
316
|
+
},
|
|
317
|
+
{
|
|
318
|
+
expectedRule: "C",
|
|
319
|
+
name: "next is missing",
|
|
320
|
+
text: "1. Answer.",
|
|
321
|
+
},
|
|
322
|
+
{
|
|
323
|
+
expectedRule: "C",
|
|
324
|
+
name: "next appears twice",
|
|
325
|
+
text: `${validNext}\n${validNext}`,
|
|
326
|
+
},
|
|
327
|
+
];
|
|
328
|
+
|
|
329
|
+
const selfTestFailures = selfTestCases
|
|
330
|
+
.filter(({expectedRule, text}) => {
|
|
331
|
+
const rules = checkPlaybook(text).map(problem => problem.rule);
|
|
332
|
+
|
|
333
|
+
return expectedRule === undefined ? rules.length > 0 : rules.join(",") !== expectedRule;
|
|
334
|
+
})
|
|
335
|
+
.map(({name}) => name);
|
|
336
|
+
|
|
337
|
+
if (findMissingRoles(humanGateRoles.join(" ")).length > 0) {
|
|
338
|
+
selfTestFailures.push("a rule naming every role has no missing role");
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
if (findMissingRoles("no role").length !== humanGateRoles.length) {
|
|
342
|
+
selfTestFailures.push("a rule naming no role is missing every role");
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
if (existsSync(playbookDirectory) && existsSync(agentOwnedWorkRule)) {
|
|
346
|
+
if (selfTestFailures.length > 0) {
|
|
347
|
+
const failureLines = selfTestFailures.map(name => `- ${name}`);
|
|
348
|
+
|
|
349
|
+
process.stderr.write(`Human gate self-tests failed:\n${failureLines.join("\n")}\n`);
|
|
350
|
+
process.exitCode = 1;
|
|
351
|
+
} else {
|
|
352
|
+
const playbooks = readdirSync(playbookDirectory)
|
|
353
|
+
.filter(name => name.endsWith(".md"))
|
|
354
|
+
.map(name => `${playbookDirectory}/${name}`);
|
|
355
|
+
|
|
356
|
+
const problemLines = [
|
|
357
|
+
...playbooks.flatMap(playbook =>
|
|
358
|
+
checkPlaybook(readFileSync(playbook, "utf8")).map(
|
|
359
|
+
({line, message}) => `${playbook}:${line}: ${message}`,
|
|
360
|
+
),
|
|
361
|
+
),
|
|
362
|
+
...findMissingRoles(readFileSync(agentOwnedWorkRule, "utf8")).map(
|
|
363
|
+
role =>
|
|
364
|
+
`${agentOwnedWorkRule}:1: the human gate role "${role}" is missing; name it in the rule or remove it from scripts/check-human-gates.ts`,
|
|
365
|
+
),
|
|
366
|
+
];
|
|
367
|
+
|
|
368
|
+
if (problemLines.length > 0) {
|
|
369
|
+
process.stderr.write(`${problemLines.join("\n")}\n`);
|
|
370
|
+
process.exitCode = 1;
|
|
371
|
+
} else {
|
|
372
|
+
process.stdout.write(
|
|
373
|
+
`Checked ${playbooks.length} playbooks against ${humanGateRoles.length} human gate roles.\n`,
|
|
374
|
+
);
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
} else {
|
|
378
|
+
process.stderr.write(
|
|
379
|
+
`Run from the project root: ${playbookDirectory} and ${agentOwnedWorkRule} must exist.\n`,
|
|
380
|
+
);
|
|
381
|
+
|
|
382
|
+
process.exitCode = 1;
|
|
383
|
+
}
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"description": "Codebase hygiene: modify existing code instead of accumulating new code"
|
|
13
13
|
},
|
|
14
14
|
"constitution-changes": {
|
|
15
|
-
"description": "Constitution changes: change rules, hooks, and agent settings
|
|
15
|
+
"description": "Constitution changes: change rules, hooks, and agent settings in a pull request a code owner approves",
|
|
16
16
|
"globs": [
|
|
17
17
|
".agents/rules/**",
|
|
18
18
|
".agents/rules.json",
|
|
@@ -22,4 +22,4 @@ paths:
|
|
|
22
22
|
|
|
23
23
|
The constitution is the set of files that agent settings deny to agents: rules, hooks, lint, format, and commit configuration, and the agent settings themselves. It is company policy.
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
The constitution changes in a pull request like any other change, and a code owner approves it in review. Agent settings stop an agent from editing these files. When a task needs a constitution change, write the exact new text and the files it goes in on the pull request; a person commits it to that branch.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: "Constitution changes: change rules, hooks, and agent settings
|
|
2
|
+
description: "Constitution changes: change rules, hooks, and agent settings in a pull request a code owner approves"
|
|
3
3
|
globs: ".agents/rules/**,.agents/rules.json,.agents/hooks/**,.claude/settings.json,.claude/rules/**,.cursor/rules/**,.cursor/hooks/**,.cursor/hooks.json,scripts/sync-agent-rules.ts,scripts/check-agent-gates.ts,.husky/**,.commitlintrc.json,.prettierrc.json,eslint.config.ts,.lintstagedrc.json,.gitleaks.toml"
|
|
4
4
|
alwaysApply: false
|
|
5
5
|
---
|
|
@@ -8,4 +8,4 @@ alwaysApply: false
|
|
|
8
8
|
|
|
9
9
|
The constitution is the set of files that agent settings deny to agents: rules, hooks, lint, format, and commit configuration, and the agent settings themselves. It is company policy.
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
The constitution changes in a pull request like any other change, and a code owner approves it in review. Agent settings stop an agent from editing these files. When a task needs a constitution change, write the exact new text and the files it goes in on the pull request; a person commits it to that branch.
|
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
"format": "prettier --write --cache .",
|
|
23
23
|
"format:check": "prettier --check --cache . && editorconfig-checker",
|
|
24
24
|
"gates:check": "node scripts/check-agent-gates.ts",
|
|
25
|
+
"human-gates:check": "node scripts/check-human-gates.ts",
|
|
25
26
|
"knip": "knip",
|
|
26
27
|
"lint": "eslint . --fix --cache --max-warnings=0 --no-inline-config",
|
|
27
28
|
"lint:check": "eslint . --cache --max-warnings=0 --no-inline-config",
|
|
@@ -43,7 +44,7 @@
|
|
|
43
44
|
"test:watch": "vitest",
|
|
44
45
|
"typecheck": "tsc --noEmit -p tsconfig.json",
|
|
45
46
|
"verify": "pnpm verify:static && pnpm test:coverage && pnpm build",
|
|
46
|
-
"verify:static": "pnpm suppressions:check && pnpm rules:check && pnpm gates:check && pnpm lint:check && pnpm format:check && pnpm sort-package-json:check && pnpm peers:check && pnpm typecheck && pnpm knip && pnpm depcruise"
|
|
47
|
+
"verify:static": "pnpm suppressions:check && pnpm rules:check && pnpm gates:check && pnpm human-gates:check && pnpm lint:check && pnpm format:check && pnpm sort-package-json:check && pnpm peers:check && pnpm typecheck && pnpm knip && pnpm depcruise"
|
|
47
48
|
},
|
|
48
49
|
"dependencies": {
|
|
49
50
|
"@nestjs/common": "12.3.2",
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"description": "Codebase hygiene: modify existing code instead of accumulating new code"
|
|
13
13
|
},
|
|
14
14
|
"constitution-changes": {
|
|
15
|
-
"description": "Constitution changes: change rules, hooks, and agent settings
|
|
15
|
+
"description": "Constitution changes: change rules, hooks, and agent settings in a pull request a code owner approves",
|
|
16
16
|
"globs": [
|
|
17
17
|
".agents/rules/**",
|
|
18
18
|
".agents/rules.json",
|
|
@@ -22,4 +22,4 @@ paths:
|
|
|
22
22
|
|
|
23
23
|
The constitution is the set of files that agent settings deny to agents: rules, hooks, lint, format, and commit configuration, and the agent settings themselves. It is company policy.
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
The constitution changes in a pull request like any other change, and a code owner approves it in review. Agent settings stop an agent from editing these files. When a task needs a constitution change, write the exact new text and the files it goes in on the pull request; a person commits it to that branch.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: "Constitution changes: change rules, hooks, and agent settings
|
|
2
|
+
description: "Constitution changes: change rules, hooks, and agent settings in a pull request a code owner approves"
|
|
3
3
|
globs: ".agents/rules/**,.agents/rules.json,.agents/hooks/**,.claude/settings.json,.claude/rules/**,.cursor/rules/**,.cursor/hooks/**,.cursor/hooks.json,scripts/sync-agent-rules.ts,scripts/check-agent-gates.ts,.husky/**,.commitlintrc.json,prettier.config.ts,eslint.config.ts,.lintstagedrc.json,.gitleaks.toml"
|
|
4
4
|
alwaysApply: false
|
|
5
5
|
---
|
|
@@ -8,4 +8,4 @@ alwaysApply: false
|
|
|
8
8
|
|
|
9
9
|
The constitution is the set of files that agent settings deny to agents: rules, hooks, lint, format, and commit configuration, and the agent settings themselves. It is company policy.
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
The constitution changes in a pull request like any other change, and a code owner approves it in review. Agent settings stop an agent from editing these files. When a task needs a constitution change, write the exact new text and the files it goes in on the pull request; a person commits it to that branch.
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
"format": "prettier --write --cache .",
|
|
20
20
|
"format:check": "prettier --check --cache . && editorconfig-checker",
|
|
21
21
|
"gates:check": "node scripts/check-agent-gates.ts",
|
|
22
|
+
"human-gates:check": "node scripts/check-human-gates.ts",
|
|
22
23
|
"knip": "knip",
|
|
23
24
|
"lint": "eslint . --fix --cache --max-warnings=0 --no-inline-config",
|
|
24
25
|
"lint:check": "eslint . --cache --max-warnings=0 --no-inline-config",
|
|
@@ -37,7 +38,7 @@
|
|
|
37
38
|
"test:watch": "vitest",
|
|
38
39
|
"typecheck": "next typegen && tsc --noEmit -p tsconfig.json",
|
|
39
40
|
"verify": "pnpm verify:static && pnpm test:coverage && pnpm build",
|
|
40
|
-
"verify:static": "pnpm suppressions:check && pnpm rules:check && pnpm gates:check && pnpm lint:check && pnpm format:check && pnpm sort-package-json:check && pnpm peers:check && pnpm typecheck && pnpm knip && pnpm depcruise"
|
|
41
|
+
"verify:static": "pnpm suppressions:check && pnpm rules:check && pnpm gates:check && pnpm human-gates:check && pnpm lint:check && pnpm format:check && pnpm sort-package-json:check && pnpm peers:check && pnpm typecheck && pnpm knip && pnpm depcruise"
|
|
41
42
|
},
|
|
42
43
|
"dependencies": {
|
|
43
44
|
"next": "16.4.3",
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"description": "Codebase hygiene: modify existing code instead of accumulating new code"
|
|
13
13
|
},
|
|
14
14
|
"constitution-changes": {
|
|
15
|
-
"description": "Constitution changes: change rules, hooks, and agent settings
|
|
15
|
+
"description": "Constitution changes: change rules, hooks, and agent settings in a pull request a code owner approves",
|
|
16
16
|
"globs": [
|
|
17
17
|
".agents/rules/**",
|
|
18
18
|
".agents/rules.json",
|
|
@@ -22,4 +22,4 @@ paths:
|
|
|
22
22
|
|
|
23
23
|
The constitution is the set of files that agent settings deny to agents: rules, hooks, lint, format, and commit configuration, and the agent settings themselves. It is company policy.
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
The constitution changes in a pull request like any other change, and a code owner approves it in review. Agent settings stop an agent from editing these files. When a task needs a constitution change, write the exact new text and the files it goes in on the pull request; a person commits it to that branch.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: "Constitution changes: change rules, hooks, and agent settings
|
|
2
|
+
description: "Constitution changes: change rules, hooks, and agent settings in a pull request a code owner approves"
|
|
3
3
|
globs: ".agents/rules/**,.agents/rules.json,.agents/hooks/**,.claude/settings.json,.claude/rules/**,.cursor/rules/**,.cursor/hooks/**,.cursor/hooks.json,scripts/sync-agent-rules.ts,scripts/check-agent-gates.ts,.husky/**,.commitlintrc.json,.prettierrc.json,eslint.config.ts,.lintstagedrc.json,.gitleaks.toml"
|
|
4
4
|
alwaysApply: false
|
|
5
5
|
---
|
|
@@ -8,4 +8,4 @@ alwaysApply: false
|
|
|
8
8
|
|
|
9
9
|
The constitution is the set of files that agent settings deny to agents: rules, hooks, lint, format, and commit configuration, and the agent settings themselves. It is company policy.
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
The constitution changes in a pull request like any other change, and a code owner approves it in review. Agent settings stop an agent from editing these files. When a task needs a constitution change, write the exact new text and the files it goes in on the pull request; a person commits it to that branch.
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
"format": "prettier --write --cache .",
|
|
19
19
|
"format:check": "prettier --check --cache . && editorconfig-checker",
|
|
20
20
|
"gates:check": "node scripts/check-agent-gates.ts",
|
|
21
|
+
"human-gates:check": "node scripts/check-human-gates.ts",
|
|
21
22
|
"knip": "knip",
|
|
22
23
|
"lint": "eslint . --fix --cache --max-warnings=0 --no-inline-config",
|
|
23
24
|
"lint:check": "eslint . --cache --max-warnings=0 --no-inline-config",
|
|
@@ -37,7 +38,7 @@
|
|
|
37
38
|
"test:watch": "vitest",
|
|
38
39
|
"typecheck": "tsc --noEmit -p tsconfig.json",
|
|
39
40
|
"verify": "pnpm verify:static && pnpm test:coverage && pnpm build",
|
|
40
|
-
"verify:static": "pnpm suppressions:check && pnpm rules:check && pnpm gates:check && pnpm lint:check && pnpm format:check && pnpm sort-package-json:check && pnpm peers:check && pnpm typecheck && pnpm knip && pnpm depcruise"
|
|
41
|
+
"verify:static": "pnpm suppressions:check && pnpm rules:check && pnpm gates:check && pnpm human-gates:check && pnpm lint:check && pnpm format:check && pnpm sort-package-json:check && pnpm peers:check && pnpm typecheck && pnpm knip && pnpm depcruise"
|
|
41
42
|
},
|
|
42
43
|
"devDependencies": {
|
|
43
44
|
"@commitlint/cli": "21.2.4",
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"description": "Codebase hygiene: modify existing code instead of accumulating new code"
|
|
13
13
|
},
|
|
14
14
|
"constitution-changes": {
|
|
15
|
-
"description": "Constitution changes: change rules, hooks, and agent settings
|
|
15
|
+
"description": "Constitution changes: change rules, hooks, and agent settings in a pull request a code owner approves",
|
|
16
16
|
"globs": [
|
|
17
17
|
".agents/rules/**",
|
|
18
18
|
".agents/rules.json",
|
|
@@ -22,4 +22,4 @@ paths:
|
|
|
22
22
|
|
|
23
23
|
The constitution is the set of files that agent settings deny to agents: rules, hooks, lint, format, and commit configuration, and the agent settings themselves. It is company policy.
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
The constitution changes in a pull request like any other change, and a code owner approves it in review. Agent settings stop an agent from editing these files. When a task needs a constitution change, write the exact new text and the files it goes in on the pull request; a person commits it to that branch.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: "Constitution changes: change rules, hooks, and agent settings
|
|
2
|
+
description: "Constitution changes: change rules, hooks, and agent settings in a pull request a code owner approves"
|
|
3
3
|
globs: ".agents/rules/**,.agents/rules.json,.agents/hooks/**,.claude/settings.json,.claude/rules/**,.cursor/rules/**,.cursor/hooks/**,.cursor/hooks.json,scripts/sync-agent-rules.ts,scripts/check-agent-gates.ts,.husky/**,.commitlintrc.json,.prettierrc.json,eslint.config.ts,.lintstagedrc.json,.gitleaks.toml"
|
|
4
4
|
alwaysApply: false
|
|
5
5
|
---
|
|
@@ -8,4 +8,4 @@ alwaysApply: false
|
|
|
8
8
|
|
|
9
9
|
The constitution is the set of files that agent settings deny to agents: rules, hooks, lint, format, and commit configuration, and the agent settings themselves. It is company policy.
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
The constitution changes in a pull request like any other change, and a code owner approves it in review. Agent settings stop an agent from editing these files. When a task needs a constitution change, write the exact new text and the files it goes in on the pull request; a person commits it to that branch.
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
"gates:check": "node scripts/check-agent-gates.ts",
|
|
22
22
|
"generate:importmap": "payload generate:importmap",
|
|
23
23
|
"generate:types": "payload generate:types",
|
|
24
|
+
"human-gates:check": "node scripts/check-human-gates.ts",
|
|
24
25
|
"knip": "node --env-file-if-exists=.env node_modules/knip/bin/knip.js",
|
|
25
26
|
"lint": "eslint . --fix --cache --max-warnings=0 --no-inline-config",
|
|
26
27
|
"lint:check": "eslint . --cache --max-warnings=0 --no-inline-config",
|
|
@@ -42,7 +43,7 @@
|
|
|
42
43
|
"test:watch": "vitest",
|
|
43
44
|
"typecheck": "next typegen && tsc --noEmit -p tsconfig.json",
|
|
44
45
|
"verify": "pnpm verify:static && pnpm test:coverage && pnpm build",
|
|
45
|
-
"verify:static": "pnpm suppressions:check && pnpm rules:check && pnpm gates:check && pnpm lint:check && pnpm format:check && pnpm sort-package-json:check && pnpm peers:check && pnpm typecheck && pnpm knip && pnpm depcruise"
|
|
46
|
+
"verify:static": "pnpm suppressions:check && pnpm rules:check && pnpm gates:check && pnpm human-gates:check && pnpm lint:check && pnpm format:check && pnpm sort-package-json:check && pnpm peers:check && pnpm typecheck && pnpm knip && pnpm depcruise"
|
|
46
47
|
},
|
|
47
48
|
"dependencies": {
|
|
48
49
|
"@payloadcms/db-postgres": "3.92.1",
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"description": "Codebase hygiene: modify existing code instead of accumulating new code"
|
|
13
13
|
},
|
|
14
14
|
"constitution-changes": {
|
|
15
|
-
"description": "Constitution changes: change rules, hooks, and agent settings
|
|
15
|
+
"description": "Constitution changes: change rules, hooks, and agent settings in a pull request a code owner approves",
|
|
16
16
|
"globs": [
|
|
17
17
|
".agents/rules/**",
|
|
18
18
|
".agents/rules.json",
|
|
@@ -22,4 +22,4 @@ paths:
|
|
|
22
22
|
|
|
23
23
|
The constitution is the set of files that agent settings deny to agents: rules, hooks, lint, format, and commit configuration, and the agent settings themselves. It is company policy.
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
The constitution changes in a pull request like any other change, and a code owner approves it in review. Agent settings stop an agent from editing these files. When a task needs a constitution change, write the exact new text and the files it goes in on the pull request; a person commits it to that branch.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: "Constitution changes: change rules, hooks, and agent settings
|
|
2
|
+
description: "Constitution changes: change rules, hooks, and agent settings in a pull request a code owner approves"
|
|
3
3
|
globs: ".agents/rules/**,.agents/rules.json,.agents/hooks/**,.claude/settings.json,.claude/rules/**,.cursor/rules/**,.cursor/hooks/**,.cursor/hooks.json,scripts/sync-agent-rules.ts,scripts/check-agent-gates.ts,.husky/**,.commitlintrc.json,prettier.config.ts,eslint.config.ts,.lintstagedrc.json,.gitleaks.toml"
|
|
4
4
|
alwaysApply: false
|
|
5
5
|
---
|
|
@@ -8,4 +8,4 @@ alwaysApply: false
|
|
|
8
8
|
|
|
9
9
|
The constitution is the set of files that agent settings deny to agents: rules, hooks, lint, format, and commit configuration, and the agent settings themselves. It is company policy.
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
The constitution changes in a pull request like any other change, and a code owner approves it in review. Agent settings stop an agent from editing these files. When a task needs a constitution change, write the exact new text and the files it goes in on the pull request; a person commits it to that branch.
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
"gates:check": "node scripts/check-agent-gates.ts",
|
|
22
22
|
"generate:importmap": "pnpm --filter ./apps/backoffice generate:importmap",
|
|
23
23
|
"generate:types": "pnpm --filter ./apps/backoffice generate:types",
|
|
24
|
+
"human-gates:check": "node scripts/check-human-gates.ts",
|
|
24
25
|
"knip": "knip",
|
|
25
26
|
"lint": "eslint . --fix --cache --max-warnings=0 --no-inline-config",
|
|
26
27
|
"lint:check": "eslint . --cache --max-warnings=0 --no-inline-config",
|
|
@@ -41,7 +42,7 @@
|
|
|
41
42
|
"test:watch": "turbo run test:watch --filter=./apps/*",
|
|
42
43
|
"typecheck": "tsc --noEmit -p tsconfig.json && turbo run typecheck ${TURBO_FILTER:-\"--filter=./apps/*\"}",
|
|
43
44
|
"verify": "pnpm verify:static && pnpm test:coverage && pnpm build",
|
|
44
|
-
"verify:static": "pnpm suppressions:check && pnpm rules:check && pnpm gates:check && pnpm lint:check && pnpm format:check && pnpm sort-package-json:check && pnpm peers:check && pnpm typecheck && pnpm knip && pnpm depcruise"
|
|
45
|
+
"verify:static": "pnpm suppressions:check && pnpm rules:check && pnpm gates:check && pnpm human-gates:check && pnpm lint:check && pnpm format:check && pnpm sort-package-json:check && pnpm peers:check && pnpm typecheck && pnpm knip && pnpm depcruise"
|
|
45
46
|
},
|
|
46
47
|
"devDependencies": {
|
|
47
48
|
"@commitlint/cli": "21.2.4",
|