dw-sdlc 0.0.0-stage → 0.2.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 +63 -2
- package/config/agentic.config.schema.json +375 -0
- package/config/references.schema.json +56 -0
- package/dist/agentic-config.d.ts +167 -0
- package/dist/agentic-config.js +305 -0
- package/dist/catalogue.d.ts +36 -0
- package/dist/catalogue.js +74 -0
- package/dist/checks/agents-map.d.ts +7 -0
- package/dist/checks/agents-map.js +159 -0
- package/dist/checks/check.d.ts +27 -0
- package/dist/checks/check.js +21 -0
- package/dist/checks/comment-budget.d.ts +6 -0
- package/dist/checks/comment-budget.js +141 -0
- package/dist/checks/decision-records.d.ts +6 -0
- package/dist/checks/decision-records.js +105 -0
- package/dist/checks/file-size-ratchet.d.ts +10 -0
- package/dist/checks/file-size-ratchet.js +194 -0
- package/dist/checks/index.d.ts +12 -0
- package/dist/checks/index.js +42 -0
- package/dist/checks/markdown-budget.d.ts +15 -0
- package/dist/checks/markdown-budget.js +42 -0
- package/dist/checks/markdown-refs.d.ts +6 -0
- package/dist/checks/markdown-refs.js +73 -0
- package/dist/checks/primitives.d.ts +8 -0
- package/dist/checks/primitives.js +103 -0
- package/dist/checks/temporal-language.d.ts +6 -0
- package/dist/checks/temporal-language.js +58 -0
- package/dist/checks/tree.d.ts +8 -0
- package/dist/checks/tree.js +30 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +43 -0
- package/dist/commands/config.d.ts +2 -0
- package/dist/commands/config.js +76 -0
- package/dist/commands/doctor.d.ts +57 -0
- package/dist/commands/doctor.js +341 -0
- package/dist/commands/gate.d.ts +2 -0
- package/dist/commands/gate.js +231 -0
- package/dist/commands/primitives.d.ts +2 -0
- package/dist/commands/primitives.js +106 -0
- package/dist/commands/references-setup.d.ts +2 -0
- package/dist/commands/references-setup.js +202 -0
- package/dist/commands/references-sync.d.ts +2 -0
- package/dist/commands/references-sync.js +341 -0
- package/dist/commands/setup.d.ts +30 -0
- package/dist/commands/setup.js +352 -0
- package/dist/json-schema.d.ts +8 -0
- package/dist/json-schema.js +226 -0
- package/dist/markdown.d.ts +31 -0
- package/dist/markdown.js +115 -0
- package/dist/pins.d.ts +16 -0
- package/dist/pins.js +82 -0
- package/dist/references-key.d.ts +31 -0
- package/dist/references-key.js +149 -0
- package/dist/report.d.ts +13 -0
- package/dist/report.js +29 -0
- package/dist/router-block.d.ts +13 -0
- package/dist/router-block.js +60 -0
- package/dist/setup-rules.d.ts +22 -0
- package/dist/setup-rules.js +98 -0
- package/package.json +30 -3
- package/templates/router.md +38 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Dominik Woźniak
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,64 @@
|
|
|
1
|
-
#
|
|
1
|
+
# dw-sdlc
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
The Gate and the agentic config of a repository. `.ai/agentic.config.json` declares how a repository
|
|
4
|
+
works for an agent: its package manager, protected branches, env-file policy, commit convention and
|
|
5
|
+
the Gate. The package ships the `dw-sdlc` bin that runs on that file, its JSON Schema, and the
|
|
6
|
+
resolver of its layers.
|
|
7
|
+
|
|
8
|
+
## Install
|
|
9
|
+
|
|
10
|
+
Node 24 or later.
|
|
11
|
+
|
|
12
|
+
```sh
|
|
13
|
+
pnpm add -D dw-sdlc
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## The Gate
|
|
17
|
+
|
|
18
|
+
`dw-sdlc gate` runs the Steps under `gate.steps` in order from the repository root, then every Check
|
|
19
|
+
under `gate.checks`. It exits 0 when everything passes, 1 when a Step or a Check fails, and 2 when the
|
|
20
|
+
Gate cannot run. `--json` prints the result as one document.
|
|
21
|
+
|
|
22
|
+
```json
|
|
23
|
+
{
|
|
24
|
+
"$schema": "../node_modules/dw-sdlc/config/agentic.config.schema.json",
|
|
25
|
+
"version": 1,
|
|
26
|
+
"gate": {
|
|
27
|
+
"steps": ["pnpm lint", "pnpm typecheck", "pnpm test"]
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
```json
|
|
33
|
+
{ "scripts": { "check": "dw-sdlc gate" } }
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Commands
|
|
37
|
+
|
|
38
|
+
| command | what it does |
|
|
39
|
+
| ------------------ | ----------------------------------------------------------------------------------- |
|
|
40
|
+
| `gate` | the Steps of `gate.steps` in order, then every Check under `gate.checks` |
|
|
41
|
+
| `primitives` | the Primitives that own each path, with their summaries and documents |
|
|
42
|
+
| `setup` | this machine's local config layer, the git excludes and the permission rules |
|
|
43
|
+
| `doctor` | one PASS / WARN / FAIL line per machine check the guardrails rely on |
|
|
44
|
+
| `config` | the resolved agentic config, or one file validated against the schema |
|
|
45
|
+
| `references sync` | every declared Reference brought to its ref under `references/` |
|
|
46
|
+
| `references setup` | the Router, its table and the ignore rules a repository needs to declare References |
|
|
47
|
+
|
|
48
|
+
`dw-sdlc <command> --help` gives each one's options.
|
|
49
|
+
|
|
50
|
+
## The resolver
|
|
51
|
+
|
|
52
|
+
```ts
|
|
53
|
+
import { resolveConfig } from "dw-sdlc"
|
|
54
|
+
|
|
55
|
+
const { config, problems } = resolveConfig(process.cwd())
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
`resolveConfig` merges the committed `.ai/agentic.config.json`, the machine's
|
|
59
|
+
`.ai/agentic.config.local.json` and what it infers from the repository. `problems` names each layer
|
|
60
|
+
that fails the schema; an invalid layer is dropped whole.
|
|
61
|
+
|
|
62
|
+
## License
|
|
63
|
+
|
|
64
|
+
MIT
|
|
@@ -0,0 +1,375 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://raw.githubusercontent.com/dominikwozniak/dw-sdlc/main/plugins/guardrails/config/agentic.config.schema.json",
|
|
4
|
+
"title": "agentic.config",
|
|
5
|
+
"description": "How a repository works for an agent. `.ai/agentic.config.json` is committed; `.ai/agentic.config.local.json` overrides it on one machine and may tighten `guardrails` but never loosen it. A key neither file sets is inferred: the Node package manager from the lockfile, the `conventional` commit preset, and `gate.command` from the manifest's `check` script. Unknown top-level keys are tolerated so other tool families can share the file; the keys named here refuse unknown children.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"properties": {
|
|
8
|
+
"$schema": {
|
|
9
|
+
"type": "string"
|
|
10
|
+
},
|
|
11
|
+
"version": {
|
|
12
|
+
"const": 1
|
|
13
|
+
},
|
|
14
|
+
"baseBranch": {
|
|
15
|
+
"description": "The branch pull requests target; `auto` reads the remote's default branch.",
|
|
16
|
+
"type": "string",
|
|
17
|
+
"minLength": 1
|
|
18
|
+
},
|
|
19
|
+
"packageManagers": {
|
|
20
|
+
"type": "object",
|
|
21
|
+
"properties": {
|
|
22
|
+
"node": {
|
|
23
|
+
"description": "Inferred from the lockfile. The package-manager guard refuses the other Node package managers only when this is `pnpm`.",
|
|
24
|
+
"enum": ["pnpm", "npm", "yarn", "bun"]
|
|
25
|
+
},
|
|
26
|
+
"ruby": {
|
|
27
|
+
"description": "Accepted so a repository can declare it; no guard reads it and nothing infers it.",
|
|
28
|
+
"enum": ["bundler"]
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
"additionalProperties": false
|
|
32
|
+
},
|
|
33
|
+
"guardrails": {
|
|
34
|
+
"description": "Policy the local override may tighten and never loosen. Every enum lists its strictest value first.",
|
|
35
|
+
"type": "object",
|
|
36
|
+
"properties": {
|
|
37
|
+
"forcePush": {
|
|
38
|
+
"description": "`deny` refuses every force push. `lease` lets `--force-with-lease` and `--force-if-includes` through to a branch outside `protectedBranches`; bare `--force` and `-f` stay refused. `ask` is `lease` with a permission prompt for each lease push it lets through. Strictest first: deny, ask, lease.",
|
|
39
|
+
"enum": ["deny", "ask", "lease"]
|
|
40
|
+
},
|
|
41
|
+
"commitOnProtected": {
|
|
42
|
+
"description": "`deny` refuses a `git commit`, `merge`, `cherry-pick` or `revert` on a branch listed in `protectedBranches`, so every change starts on a branch of its own. `allow` lets it through, for a repository that commits small fixes on its protected branch and pushes them from a person's terminal. Default `allow`. Strictest first: deny, allow.",
|
|
43
|
+
"enum": ["deny", "allow"]
|
|
44
|
+
},
|
|
45
|
+
"envFiles": {
|
|
46
|
+
"description": "Which env files (`.env`, `.env.*`, `.envrc`) an agent may read, edit or write. A candidate is judged in this order: listed in `deny` → refused; listed in `allow` → readable; `policy` `deny` → refused; `policy` `git` → readable when git tracks it, refused when git ignores it or does not know it. Entries are globs against the path relative to the repository root: `*` and `?` as in a shell pattern (`*` crosses `/`), a leading `**/` means at any depth, so `.env` is the one in the root and `**/.env.example` every file of that name. No brace groups. A path outside the repository root, or outside any repository, is judged by its basename against the `**/` entries alone. Defaults: policy `git`, allow the `.env.example`, `.env.sample` and `.env.template` names anywhere, deny nothing. The local override may drop `allow` entries and add `deny` entries, never the reverse.",
|
|
47
|
+
"type": "object",
|
|
48
|
+
"properties": {
|
|
49
|
+
"policy": {
|
|
50
|
+
"description": "What decides a candidate no list names. `deny` refuses it; `git` asks git: tracked passes, ignored or unknown is refused.",
|
|
51
|
+
"enum": ["deny", "git"]
|
|
52
|
+
},
|
|
53
|
+
"allow": {
|
|
54
|
+
"description": "Globs of the env files that are readable regardless of `policy`.",
|
|
55
|
+
"type": "array",
|
|
56
|
+
"items": {
|
|
57
|
+
"type": "string",
|
|
58
|
+
"minLength": 1
|
|
59
|
+
},
|
|
60
|
+
"uniqueItems": true
|
|
61
|
+
},
|
|
62
|
+
"deny": {
|
|
63
|
+
"description": "Globs of the env files that are refused regardless of `policy`; wins over `allow`.",
|
|
64
|
+
"type": "array",
|
|
65
|
+
"items": {
|
|
66
|
+
"type": "string",
|
|
67
|
+
"minLength": 1
|
|
68
|
+
},
|
|
69
|
+
"uniqueItems": true
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
"additionalProperties": false
|
|
73
|
+
},
|
|
74
|
+
"protectedBranches": {
|
|
75
|
+
"description": "Branches the guards refuse every push to: plain, lease or force. Under `commitOnProtected: deny` they refuse a commit, merge, cherry-pick or revert on one too. The local override may add to this list, never remove from it.",
|
|
76
|
+
"type": "array",
|
|
77
|
+
"items": {
|
|
78
|
+
"type": "string",
|
|
79
|
+
"minLength": 1
|
|
80
|
+
},
|
|
81
|
+
"uniqueItems": true
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
"additionalProperties": false
|
|
85
|
+
},
|
|
86
|
+
"commit": {
|
|
87
|
+
"type": "object",
|
|
88
|
+
"properties": {
|
|
89
|
+
"convention": {
|
|
90
|
+
"description": "The subject preset `pattern` falls back to. `ticket-key`: `[KEY-123] type: subject`, the tracker's key in brackets before a type from a fixed list. `conventional`: Conventional Commits; inferred when no layer sets either.",
|
|
91
|
+
"enum": ["ticket-key", "conventional"]
|
|
92
|
+
},
|
|
93
|
+
"pattern": {
|
|
94
|
+
"description": "POSIX ERE the commit subject must match; set, it wins over `convention`. `grep -E` runs it, so no `\\d`, `\\s`, `\\w`, `\\b` or `(?…)`. `.+` accepts any subject.",
|
|
95
|
+
"type": "string",
|
|
96
|
+
"minLength": 1,
|
|
97
|
+
"format": "regex"
|
|
98
|
+
},
|
|
99
|
+
"trailer": {
|
|
100
|
+
"description": "A trailer key, such as `Co-Authored-By`, that every commit message must carry on a line of its own.",
|
|
101
|
+
"type": "string",
|
|
102
|
+
"pattern": "^[A-Za-z][A-Za-z0-9-]*$"
|
|
103
|
+
}
|
|
104
|
+
},
|
|
105
|
+
"additionalProperties": false
|
|
106
|
+
},
|
|
107
|
+
"gate": {
|
|
108
|
+
"description": "The Gate `dw-sdlc gate` runs: the Steps under `steps` in order, then every Check under `checks`.",
|
|
109
|
+
"type": "object",
|
|
110
|
+
"properties": {
|
|
111
|
+
"command": {
|
|
112
|
+
"description": "The one command that runs the Gate, the same in a terminal and in CI. Inferred as `pnpm check` where `package.json` has a `check` script.",
|
|
113
|
+
"type": "string",
|
|
114
|
+
"minLength": 1
|
|
115
|
+
},
|
|
116
|
+
"steps": {
|
|
117
|
+
"description": "The Steps: toolchain commands run in order from the repository root through `sh -c`, each one's output passed through; the first that fails ends the Gate and no Check runs. A command the shell cannot find (exit 127) or execute (126) means the Gate cannot run.",
|
|
118
|
+
"type": "array",
|
|
119
|
+
"items": {
|
|
120
|
+
"type": "string",
|
|
121
|
+
"minLength": 1
|
|
122
|
+
}
|
|
123
|
+
},
|
|
124
|
+
"checks": {
|
|
125
|
+
"description": "The Checks the Gate runs after its steps, every one even when another fails: the `run` scripts first, then the Checks the package ships, in the order listed here. A Check the package ships is `true` for its defaults, an options object over them, or `false` to stay off. A key names a Check the package ships, and a name it does not ship is refused.",
|
|
126
|
+
"type": "object",
|
|
127
|
+
"properties": {
|
|
128
|
+
"run": {
|
|
129
|
+
"description": "The repository's own scripts, each run like a Step and reported as a Check under its `name`: exit 0 passes, 127 or 126 means the Gate cannot run, any other code fails.",
|
|
130
|
+
"type": "array",
|
|
131
|
+
"items": {
|
|
132
|
+
"type": "object",
|
|
133
|
+
"properties": {
|
|
134
|
+
"name": {
|
|
135
|
+
"description": "The Check's name, which each of its failure lines carries: lowercase words joined by hyphens.",
|
|
136
|
+
"type": "string",
|
|
137
|
+
"pattern": "^[a-z][a-z0-9]*(-[a-z0-9]+)*$"
|
|
138
|
+
},
|
|
139
|
+
"command": {
|
|
140
|
+
"type": "string",
|
|
141
|
+
"minLength": 1
|
|
142
|
+
}
|
|
143
|
+
},
|
|
144
|
+
"required": ["name", "command"],
|
|
145
|
+
"additionalProperties": false
|
|
146
|
+
}
|
|
147
|
+
},
|
|
148
|
+
"primitives": {
|
|
149
|
+
"description": "The Primitives catalogue: unique ids, each in a group `groups` lists, a summary of one line within 120 characters, every `code` path on disk, every `docs` path on disk with its heading anchor resolving, and every file under `roots` named by the `code` of a Primitive, itself or a directory above it. A test file, under a `test`, `tests` or `__tests__` directory or named `*.test.*` or `*.spec.*`, needs no Primitive.",
|
|
150
|
+
"type": ["boolean", "object"],
|
|
151
|
+
"properties": {
|
|
152
|
+
"file": {
|
|
153
|
+
"description": "The catalogue, relative to the repository root. Default `.ai/primitives.json`.",
|
|
154
|
+
"type": "string",
|
|
155
|
+
"minLength": 1
|
|
156
|
+
},
|
|
157
|
+
"roots": {
|
|
158
|
+
"description": "The directories whose every file a Primitive names, relative to the repository root; one that does not exist names no file. Default `packages`, `plugins`, `scripts` and `src`.",
|
|
159
|
+
"type": "array",
|
|
160
|
+
"items": {
|
|
161
|
+
"type": "string",
|
|
162
|
+
"minLength": 1
|
|
163
|
+
},
|
|
164
|
+
"uniqueItems": true
|
|
165
|
+
}
|
|
166
|
+
},
|
|
167
|
+
"additionalProperties": false
|
|
168
|
+
},
|
|
169
|
+
"agents-map": {
|
|
170
|
+
"description": "The agent map: within its line and byte budget, naming the resolved `gate.command`, carrying a Task Router row to the Primitives catalogue where there is one, every path the Task Router points at existing, and the skills directory, `skills-lock.json` and the `.claude/skills` links in step where the repository has them.",
|
|
171
|
+
"type": ["boolean", "object"],
|
|
172
|
+
"properties": {
|
|
173
|
+
"file": {
|
|
174
|
+
"description": "The map, relative to the repository root. Default `AGENTS.md`.",
|
|
175
|
+
"type": "string",
|
|
176
|
+
"minLength": 1
|
|
177
|
+
},
|
|
178
|
+
"maxLines": {
|
|
179
|
+
"description": "Default 150.",
|
|
180
|
+
"type": "integer",
|
|
181
|
+
"minimum": 1
|
|
182
|
+
},
|
|
183
|
+
"maxBytes": {
|
|
184
|
+
"description": "Default 10240.",
|
|
185
|
+
"type": "integer",
|
|
186
|
+
"minimum": 1
|
|
187
|
+
}
|
|
188
|
+
},
|
|
189
|
+
"additionalProperties": false
|
|
190
|
+
},
|
|
191
|
+
"markdown-budget": {
|
|
192
|
+
"description": "Each file a glob of `budgets` matches within that glob's `maxLines` and `maxBytes`, and every glob matching a file. A glob matches the files git tracks or would track, a symbolic link left out when the file it points at is matched too; `*` and `**` skip a name that starts with a dot.",
|
|
193
|
+
"type": ["boolean", "object"],
|
|
194
|
+
"properties": {
|
|
195
|
+
"budgets": {
|
|
196
|
+
"description": "Default `docs/agents/*.md` within 100 lines and 6144 bytes; a list replaces the default.",
|
|
197
|
+
"type": "array",
|
|
198
|
+
"items": {
|
|
199
|
+
"type": "object",
|
|
200
|
+
"properties": {
|
|
201
|
+
"glob": {
|
|
202
|
+
"type": "string",
|
|
203
|
+
"minLength": 1
|
|
204
|
+
},
|
|
205
|
+
"maxLines": {
|
|
206
|
+
"type": "integer",
|
|
207
|
+
"minimum": 1
|
|
208
|
+
},
|
|
209
|
+
"maxBytes": {
|
|
210
|
+
"type": "integer",
|
|
211
|
+
"minimum": 1
|
|
212
|
+
}
|
|
213
|
+
},
|
|
214
|
+
"required": ["glob", "maxLines", "maxBytes"],
|
|
215
|
+
"additionalProperties": false
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
},
|
|
219
|
+
"additionalProperties": false
|
|
220
|
+
},
|
|
221
|
+
"markdown-refs": {
|
|
222
|
+
"description": "Every relative link and image in the markdown files resolves: its path to a file or directory git tracks or would track, its heading anchor to a heading of the markdown file it names, and `#anchor` alone to a heading of its own file. A link with a scheme, such as `https:`, and a link inside code are not judged.",
|
|
223
|
+
"type": ["boolean", "object"],
|
|
224
|
+
"properties": {
|
|
225
|
+
"files": {
|
|
226
|
+
"description": "Globs of the markdown files whose links are judged, against the files git tracks or would track; `*` and `**` skip a name that starts with a dot. Default `**/*.md`.",
|
|
227
|
+
"type": "array",
|
|
228
|
+
"items": {
|
|
229
|
+
"type": "string",
|
|
230
|
+
"minLength": 1
|
|
231
|
+
},
|
|
232
|
+
"uniqueItems": true
|
|
233
|
+
},
|
|
234
|
+
"exempt": {
|
|
235
|
+
"description": "Globs of the files left out. Default none.",
|
|
236
|
+
"type": "array",
|
|
237
|
+
"items": {
|
|
238
|
+
"type": "string",
|
|
239
|
+
"minLength": 1
|
|
240
|
+
},
|
|
241
|
+
"uniqueItems": true
|
|
242
|
+
}
|
|
243
|
+
},
|
|
244
|
+
"additionalProperties": false
|
|
245
|
+
},
|
|
246
|
+
"temporal-language": {
|
|
247
|
+
"description": "No changelog phrase in a durable document, matched across a line break and never inside code: `now we`,`we now`, `we no longer`, `previously we`, `as before`, `were removed`, `was` or `were retired`, `no longer` before `support`, `accept`, `require`, `use`, `fan`, `carry`, `replay`, `incur`, `authoritative`, `insert` or `needed`,`is now a` or `the`, `are now`, `previously a` or `the`, `recently` before `changed`, `added`, `updated`, `removed` or `introduced`, and `used to support` or `require`.",
|
|
248
|
+
"type": ["boolean", "object"],
|
|
249
|
+
"properties": {
|
|
250
|
+
"files": {
|
|
251
|
+
"description": "Globs of the durable documents, against the files git tracks or would track; `*` and `**` skip a name that starts with a dot. Default `**/*.md`.",
|
|
252
|
+
"type": "array",
|
|
253
|
+
"items": {
|
|
254
|
+
"type": "string",
|
|
255
|
+
"minLength": 1
|
|
256
|
+
},
|
|
257
|
+
"uniqueItems": true
|
|
258
|
+
},
|
|
259
|
+
"exempt": {
|
|
260
|
+
"description": "Globs of the files that record a point in time. Default `docs/adr/**`, `docs/decisions/**`, `docs/research/**` and `**/CHANGELOG.md`; a list replaces the default.",
|
|
261
|
+
"type": "array",
|
|
262
|
+
"items": {
|
|
263
|
+
"type": "string",
|
|
264
|
+
"minLength": 1
|
|
265
|
+
},
|
|
266
|
+
"uniqueItems": true
|
|
267
|
+
}
|
|
268
|
+
},
|
|
269
|
+
"additionalProperties": false
|
|
270
|
+
},
|
|
271
|
+
"decision-records": {
|
|
272
|
+
"description": "The records of each directory of `dirs` that exists, the files in it git tracks or would track named `<number>-<slug>.md`: numbered from 1 with no gap and no number taken twice, each with a level-1 heading for its title and a frontmatter `status` whose first word is one of `statuses`, so `superseded by ADR 0008` reads as `superseded`. The Gate cannot run when none of `dirs` exists.",
|
|
273
|
+
"type": ["boolean", "object"],
|
|
274
|
+
"properties": {
|
|
275
|
+
"dirs": {
|
|
276
|
+
"description": "The directories of the records, relative to the repository root; one that does not exist holds none. Default `docs/adr` and `docs/decisions`.",
|
|
277
|
+
"type": "array",
|
|
278
|
+
"items": {
|
|
279
|
+
"type": "string",
|
|
280
|
+
"minLength": 1
|
|
281
|
+
},
|
|
282
|
+
"uniqueItems": true
|
|
283
|
+
},
|
|
284
|
+
"statuses": {
|
|
285
|
+
"description": "Default `proposed`, `accepted`, `active`, `deprecated` and `superseded`.",
|
|
286
|
+
"type": "array",
|
|
287
|
+
"items": {
|
|
288
|
+
"type": "string",
|
|
289
|
+
"minLength": 1
|
|
290
|
+
},
|
|
291
|
+
"uniqueItems": true
|
|
292
|
+
}
|
|
293
|
+
},
|
|
294
|
+
"additionalProperties": false
|
|
295
|
+
},
|
|
296
|
+
"file-size-ratchet": {
|
|
297
|
+
"description": "The file-size Ratchet: each file git tracks or would track within the line limit of its group, or, where `.ai/file-size-ratchet.baseline.json` lists it, within the count recorded there. A file belongs to the first group with a glob that matches it; a file no group matches has no limit, and a symbolic link is left out when the file it points at is matched too. The baseline is committed and lists the files over their limit; one that lists a file twice, at a count within its group's limit or in no group fails the Check. `dw-sdlc gate --update-baseline` records it where there is none and otherwise only tightens it, and only when every Step and every other Check passes: a file within its limit leaves it, a count that shrank is lowered, and no file joins.",
|
|
298
|
+
"type": ["boolean", "object"],
|
|
299
|
+
"properties": {
|
|
300
|
+
"groups": {
|
|
301
|
+
"description": "Default, in this order: `tests`, 2000 lines, a file under a `test`, `tests` or `__tests__` directory or named `*.test.*` or `*.spec.*`; `agent-docs`, 120 lines, `AGENTS.md`, `CLAUDE.md` and `GLOSSARY.md` anywhere and the markdown under `docs/agents`; `source`, 500 lines, JavaScript, TypeScript and shell.",
|
|
302
|
+
"type": "array",
|
|
303
|
+
"items": {
|
|
304
|
+
"type": "object",
|
|
305
|
+
"properties": {
|
|
306
|
+
"name": {
|
|
307
|
+
"description": "The group's name, which its failure lines carry: lowercase words joined by hyphens.",
|
|
308
|
+
"type": "string",
|
|
309
|
+
"pattern": "^[a-z][a-z0-9]*(-[a-z0-9]+)*$"
|
|
310
|
+
},
|
|
311
|
+
"maxLines": {
|
|
312
|
+
"type": "integer",
|
|
313
|
+
"minimum": 1
|
|
314
|
+
},
|
|
315
|
+
"files": {
|
|
316
|
+
"description": "Globs against the path from the repository root, as Node's `path.matchesGlob` reads them: `**` crosses directories, but no `*` matches a name that starts with a dot.",
|
|
317
|
+
"type": "array",
|
|
318
|
+
"items": {
|
|
319
|
+
"type": "string",
|
|
320
|
+
"minLength": 1
|
|
321
|
+
},
|
|
322
|
+
"minItems": 1,
|
|
323
|
+
"uniqueItems": true
|
|
324
|
+
}
|
|
325
|
+
},
|
|
326
|
+
"required": ["name", "maxLines", "files"],
|
|
327
|
+
"additionalProperties": false
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
},
|
|
331
|
+
"additionalProperties": false
|
|
332
|
+
},
|
|
333
|
+
"comment-budget": {
|
|
334
|
+
"description": "The comment budget: each comment block in the JavaScript and TypeScript files under `roots` carries at most `maxProseLines` lines of prose, a line with a letter or a digit once the comment markers are off. A block is one `/* … */` comment or a run of `//` comments each alone on consecutive lines; a comment after code on its line is none.",
|
|
335
|
+
"type": ["boolean", "object"],
|
|
336
|
+
"properties": {
|
|
337
|
+
"maxProseLines": {
|
|
338
|
+
"description": "Default 3.",
|
|
339
|
+
"type": "integer",
|
|
340
|
+
"minimum": 1
|
|
341
|
+
},
|
|
342
|
+
"roots": {
|
|
343
|
+
"description": "The directories whose files it reads, relative to the repository root; one that does not exist holds no file. Default `packages`, `plugins`, `scripts` and `src`.",
|
|
344
|
+
"type": "array",
|
|
345
|
+
"items": {
|
|
346
|
+
"type": "string",
|
|
347
|
+
"minLength": 1
|
|
348
|
+
},
|
|
349
|
+
"uniqueItems": true
|
|
350
|
+
}
|
|
351
|
+
},
|
|
352
|
+
"additionalProperties": false
|
|
353
|
+
}
|
|
354
|
+
},
|
|
355
|
+
"additionalProperties": false
|
|
356
|
+
}
|
|
357
|
+
},
|
|
358
|
+
"additionalProperties": false
|
|
359
|
+
},
|
|
360
|
+
"worktree": {
|
|
361
|
+
"type": "object",
|
|
362
|
+
"properties": {
|
|
363
|
+
"setup": {
|
|
364
|
+
"description": "Commands a fresh linked worktree needs before work starts. Reported at session start, not run.",
|
|
365
|
+
"type": "array",
|
|
366
|
+
"items": {
|
|
367
|
+
"type": "string",
|
|
368
|
+
"minLength": 1
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
},
|
|
372
|
+
"additionalProperties": false
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://raw.githubusercontent.com/dominikwozniak/dw-sdlc/main/plugins/references/config/references.schema.json",
|
|
4
|
+
"title": "references",
|
|
5
|
+
"description": "The `references` key of `.ai/agentic.config.json`: the repositories an agent reads to see how a problem was solved before, each brought to its ref under `references/<dir>` by the Sync. Only the committed file is read; the local layer adds no References. Every `dir` is unique in the list, which this schema cannot say and the Sync refuses. A key the Sync refuses syncs nothing.",
|
|
6
|
+
"type": "array",
|
|
7
|
+
"items": {
|
|
8
|
+
"type": "object",
|
|
9
|
+
"properties": {
|
|
10
|
+
"dir": {
|
|
11
|
+
"description": "The one directory under `references/` the clone lives in: letters, digits, `_`, `.` and `-`, not starting with `.` or `-`.",
|
|
12
|
+
"type": "string",
|
|
13
|
+
"pattern": "^[A-Za-z0-9_][A-Za-z0-9_.-]*$"
|
|
14
|
+
},
|
|
15
|
+
"repository": {
|
|
16
|
+
"description": "A URL `git` can fetch. A `https://github.com/` one fetches with the GitHub CLI's credentials. No whitespace, and no leading `-`, which `git` would read as an option.",
|
|
17
|
+
"type": "string",
|
|
18
|
+
"pattern": "^[^\\s-]\\S*$"
|
|
19
|
+
},
|
|
20
|
+
"ref": {
|
|
21
|
+
"description": "A branch, whose head the clone moves to, or a tag. `{name}` in it stands for the exact version the root `package.json` pins for package `name`, read through the default catalog of `pnpm-workspace.yaml` when the pin says `catalog:` or `catalog:default`. No whitespace, and no leading `-`.",
|
|
22
|
+
"type": "string",
|
|
23
|
+
"pattern": "^[^\\s-]\\S*$"
|
|
24
|
+
},
|
|
25
|
+
"only": {
|
|
26
|
+
"description": "Paths the sparse checkout holds beside the repository's top-level files, relative to the clone and inside it; a directory ends in `/`. Absent, the whole tree is checked out. Present, it names at least one path, and a path the ref's tree lacks fails the Reference.",
|
|
27
|
+
"type": "array",
|
|
28
|
+
"minItems": 1,
|
|
29
|
+
"items": {
|
|
30
|
+
"type": "string",
|
|
31
|
+
"pattern": "^(?!/)(?!(?:.*/)?\\.\\.(?:/|$)).+$"
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
"skip": {
|
|
35
|
+
"description": "Paths the sparse checkout leaves out, relative to the clone and inside it. Empty or absent, nothing is left out. With `only`, each lies inside one of its paths, which this schema cannot say and the Sync refuses.",
|
|
36
|
+
"type": "array",
|
|
37
|
+
"items": {
|
|
38
|
+
"type": "string",
|
|
39
|
+
"pattern": "^(?!/)(?!(?:.*/)?\\.\\.(?:/|$)).+$"
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
"what": {
|
|
43
|
+
"description": "What the Reference is.",
|
|
44
|
+
"type": "string",
|
|
45
|
+
"minLength": 1
|
|
46
|
+
},
|
|
47
|
+
"when": {
|
|
48
|
+
"description": "When an agent reaches for it.",
|
|
49
|
+
"type": "string",
|
|
50
|
+
"minLength": 1
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
"required": ["dir", "repository", "ref", "what", "when"],
|
|
54
|
+
"additionalProperties": false
|
|
55
|
+
}
|
|
56
|
+
}
|