jackherd 0.0.1 → 1.0.1

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.
Files changed (250) hide show
  1. package/CHANGELOG.md +65 -0
  2. package/LICENSE +21 -0
  3. package/NOTICE +38 -0
  4. package/README.md +1122 -3
  5. package/assets/branding/README.md +62 -0
  6. package/assets/branding/jackherd-icon-256.png +0 -0
  7. package/assets/branding/jackherd-icon-512.png +0 -0
  8. package/assets/branding/jackherd-icon-64.png +0 -0
  9. package/assets/branding/jackherd-icon-small-32.png +0 -0
  10. package/assets/branding/jackherd-icon-small-64.png +0 -0
  11. package/assets/branding/jackherd-icon-small.svg +1 -0
  12. package/assets/branding/jackherd-icon.svg +1 -0
  13. package/assets/branding/jackherd-logo-1024.png +0 -0
  14. package/assets/branding/jackherd-logo-512.png +0 -0
  15. package/assets/branding/jackherd-logo-dark-1024.png +0 -0
  16. package/assets/branding/jackherd-logo-dark-512.png +0 -0
  17. package/assets/branding/jackherd-logo-dark.svg +1 -0
  18. package/assets/branding/jackherd-logo-mark-1024.png +0 -0
  19. package/assets/branding/jackherd-logo-mark-512.png +0 -0
  20. package/assets/branding/jackherd-logo-mark.svg +1 -0
  21. package/assets/branding/jackherd-logo.svg +1 -0
  22. package/dist/chunk-R6MGHCD7.js +93 -0
  23. package/dist/config.d.ts +167 -0
  24. package/dist/config.js +401 -0
  25. package/dist/plan-format.d.ts +325 -0
  26. package/dist/plan-format.js +636 -0
  27. package/docs/lanes.mmd +9 -0
  28. package/docs/lanes.svg +1 -0
  29. package/docs/skills.mmd +10 -0
  30. package/docs/skills.svg +1 -0
  31. package/docs/workflow.svg +172 -0
  32. package/herdr-plugin/herdr-plugin.toml +22 -0
  33. package/herdr-plugin/open-plans.ts +43 -0
  34. package/herdr-plugin/restore-plans.ts +107 -0
  35. package/install.sh +157 -0
  36. package/kit/hooks/hooks/git-guard/decision.ts +438 -0
  37. package/kit/hooks/hooks/git-guard/index.ts +38 -0
  38. package/kit/hooks/hooks/git-guard/shell.ts +407 -0
  39. package/kit/hooks/hooks/watch-guard/background.ts +36 -0
  40. package/kit/hooks/hooks/watch-guard/decision.ts +53 -0
  41. package/kit/hooks/hooks/watch-guard/index.ts +11 -0
  42. package/kit/hooks/hooks/watch-guard/shell-input.ts +32 -0
  43. package/kit/hooks/hooks/watch-guard/starts.ts +154 -0
  44. package/kit/hooks/hooks/watch-guard/text-fallback.ts +40 -0
  45. package/kit/hooks/hooks.json +30 -0
  46. package/kit/hooks/statusline.sh +72 -0
  47. package/kit/review/agents/devops.md +11 -0
  48. package/kit/review/agents/public-content.md +39 -0
  49. package/kit/review/agents/security-audit.md +11 -0
  50. package/kit/review/agents/uncle-bob.md +11 -0
  51. package/kit/review/skills/devops/SKILL.md +50 -0
  52. package/kit/review/skills/diagnose/SKILL.md +140 -0
  53. package/kit/review/skills/diagnose/references/feedback-loops.md +59 -0
  54. package/kit/review/skills/diagnose/scripts/hitl-loop.template.sh +71 -0
  55. package/kit/review/skills/pre-commit/SKILL.md +100 -0
  56. package/kit/review/skills/review/SKILL.md +43 -0
  57. package/kit/review/skills/security-audit/SKILL.md +65 -0
  58. package/kit/review/skills/uncle-bob/SKILL.md +43 -0
  59. package/kit/rules/rules/kit/arc42.md +89 -0
  60. package/kit/rules/rules/kit/architecture-files.md +87 -0
  61. package/kit/rules/rules/kit/code-style.md +159 -0
  62. package/kit/rules/rules/kit/pull-requests.md +59 -0
  63. package/kit/rules/rules/kit/testing.md +91 -0
  64. package/kit/rules/rules/kit/writing-for-agents.md +110 -0
  65. package/kit/workflow/agents/explore.md +25 -0
  66. package/kit/workflow/agents/implement.md +16 -0
  67. package/kit/workflow/agents/plan.md +13 -0
  68. package/kit/workflow/agents/spec-review.md +96 -0
  69. package/kit/workflow/skills/follow/SKILL.md +48 -0
  70. package/kit/workflow/skills/grill/SKILL.md +60 -0
  71. package/kit/workflow/skills/implement/SKILL.md +107 -0
  72. package/kit/workflow/skills/orchestrate/SKILL.md +565 -0
  73. package/kit/workflow/skills/orchestrate/handover/decision.ts +247 -0
  74. package/kit/workflow/skills/orchestrate/handover/index.ts +171 -0
  75. package/kit/workflow/skills/plan/SKILL.md +118 -0
  76. package/kit/workflow/skills/plan/references/template-English.md +92 -0
  77. package/kit/workflow/skills/plan/references/template-German.md +92 -0
  78. package/kit/workflow/skills/start/SKILL.md +47 -0
  79. package/package.json +63 -5
  80. package/schemas/jackherd.schema.json +601 -0
  81. package/src/check/changes.ts +45 -0
  82. package/src/check/command-line.ts +12 -0
  83. package/src/check/command.ts +136 -0
  84. package/src/check/deferral-arrows.ts +41 -0
  85. package/src/check/execute.ts +29 -0
  86. package/src/check/glob.ts +15 -0
  87. package/src/check/plan-structure-check.ts +135 -0
  88. package/src/check/plan.ts +106 -0
  89. package/src/check/public-content-check.ts +32 -0
  90. package/src/check/public-content-facts.ts +177 -0
  91. package/src/check/public-content.ts +216 -0
  92. package/src/check/report.ts +55 -0
  93. package/src/check/result.ts +42 -0
  94. package/src/check/roots.ts +36 -0
  95. package/src/check/routing.ts +22 -0
  96. package/src/check/schema.ts +83 -0
  97. package/src/check/settings.ts +44 -0
  98. package/src/claude/paths.ts +14 -0
  99. package/src/cli.ts +46 -0
  100. package/src/config/command.ts +45 -0
  101. package/src/config/detect.ts +196 -0
  102. package/src/config/index.ts +2 -0
  103. package/src/config/json-schema.ts +5 -0
  104. package/src/config/legacy-names.ts +56 -0
  105. package/src/config/link-kinds.ts +25 -0
  106. package/src/config/location.ts +46 -0
  107. package/src/config/read-config.ts +42 -0
  108. package/src/config/repository-facts.ts +19 -0
  109. package/src/config/repository-values.ts +46 -0
  110. package/src/config/schema.ts +302 -0
  111. package/src/context/command.ts +39 -0
  112. package/src/context/coordinator-name.ts +16 -0
  113. package/src/context/fill.ts +69 -0
  114. package/src/context/index.ts +10 -0
  115. package/src/context/level.ts +22 -0
  116. package/src/context/options.ts +29 -0
  117. package/src/context/report.ts +42 -0
  118. package/src/context/session-log.ts +91 -0
  119. package/src/plan-format/drift.ts +69 -0
  120. package/src/plan-format/header.ts +27 -0
  121. package/src/plan-format/index.ts +9 -0
  122. package/src/plan-format/lanes.ts +128 -0
  123. package/src/plan-format/markdown.ts +98 -0
  124. package/src/plan-format/phase-tally.ts +55 -0
  125. package/src/plan-format/phases.ts +224 -0
  126. package/src/plan-format/plan-structure.ts +150 -0
  127. package/src/plan-format/progress.ts +202 -0
  128. package/src/plan-format/sprint-document.ts +69 -0
  129. package/src/plan-format/terminal-text.ts +28 -0
  130. package/src/plans/board-choice.ts +60 -0
  131. package/src/plans/board-pick.ts +72 -0
  132. package/src/plans/board-rows.ts +62 -0
  133. package/src/plans/command.ts +60 -0
  134. package/src/plans/ensure-panes.ts +71 -0
  135. package/src/plans/error-text.ts +5 -0
  136. package/src/plans/fetch.ts +96 -0
  137. package/src/plans/git.ts +145 -0
  138. package/src/plans/github.ts +35 -0
  139. package/src/plans/lane-discovery.ts +34 -0
  140. package/src/plans/lane-plans.ts +80 -0
  141. package/src/plans/layout.ts +881 -0
  142. package/src/plans/link-chips.ts +74 -0
  143. package/src/plans/live.ts +336 -0
  144. package/src/plans/markdown-html.ts +140 -0
  145. package/src/plans/options.ts +15 -0
  146. package/src/plans/phase-source.ts +71 -0
  147. package/src/plans/plan-chips.ts +75 -0
  148. package/src/plans/plan-panes.ts +206 -0
  149. package/src/plans/planned.ts +117 -0
  150. package/src/plans/pull-requests.ts +107 -0
  151. package/src/plans/restart-decision.ts +42 -0
  152. package/src/plans/selection.ts +352 -0
  153. package/src/plans/settings.ts +68 -0
  154. package/src/plans/single-flight.ts +25 -0
  155. package/src/plans/snapshot.ts +300 -0
  156. package/src/plans/sprint-export.ts +103 -0
  157. package/src/plans/sprint-html.ts +301 -0
  158. package/src/plans/sprint-page.ts +287 -0
  159. package/src/plans/supervisor.ts +124 -0
  160. package/src/plans/symbols.ts +54 -0
  161. package/src/plans/texts.ts +103 -0
  162. package/src/plans/unlisted-lanes.ts +45 -0
  163. package/src/plans/view.ts +68 -0
  164. package/src/plans/worked-phases.ts +53 -0
  165. package/src/sync/checksum.ts +13 -0
  166. package/src/sync/choice.ts +14 -0
  167. package/src/sync/command-context.ts +113 -0
  168. package/src/sync/command.ts +94 -0
  169. package/src/sync/error-message.ts +1 -0
  170. package/src/sync/gitignore.ts +45 -0
  171. package/src/sync/global-kit.ts +176 -0
  172. package/src/sync/herdr-plugin.ts +175 -0
  173. package/src/sync/if-changed.ts +109 -0
  174. package/src/sync/init-command.ts +239 -0
  175. package/src/sync/init.ts +136 -0
  176. package/src/sync/kit-hooks.ts +18 -0
  177. package/src/sync/kit-path.ts +77 -0
  178. package/src/sync/kit-source.ts +169 -0
  179. package/src/sync/kit.ts +9 -0
  180. package/src/sync/legacy-files.ts +116 -0
  181. package/src/sync/manifest.ts +44 -0
  182. package/src/sync/next-steps.ts +42 -0
  183. package/src/sync/plan-file.ts +154 -0
  184. package/src/sync/plan-hooks.ts +165 -0
  185. package/src/sync/project-fs.ts +132 -0
  186. package/src/sync/render.ts +60 -0
  187. package/src/sync/report.ts +96 -0
  188. package/src/sync/settings-hooks.ts +90 -0
  189. package/src/sync/settings-migration.ts +94 -0
  190. package/src/sync/settings-offer.ts +168 -0
  191. package/src/sync/setup-questions.ts +70 -0
  192. package/src/sync/setup.ts +52 -0
  193. package/src/sync/sync-plan.ts +120 -0
  194. package/src/sync/sync-result.ts +9 -0
  195. package/src/sync/sync.ts +307 -0
  196. package/src/sync/tools.ts +52 -0
  197. package/src/terminal/herdr.ts +91 -0
  198. package/src/terminal/index.ts +13 -0
  199. package/src/terminal/none.ts +7 -0
  200. package/src/terminal/open.ts +39 -0
  201. package/src/terminal/text.ts +159 -0
  202. package/src/terminal/types.ts +30 -0
  203. package/src/terminal/width.ts +90 -0
  204. package/src/update/command.ts +65 -0
  205. package/src/update/package-manager.ts +56 -0
  206. package/src/update/update.ts +105 -0
  207. package/src/version/installed-version.ts +32 -0
  208. package/src/version/release.ts +22 -0
  209. package/src/version/skill-diff.ts +63 -0
  210. package/src/version/started-kit.ts +14 -0
  211. package/src/vocabulary/index.ts +132 -0
  212. package/src/watch/base-tip.ts +18 -0
  213. package/src/watch/command.ts +919 -0
  214. package/src/watch/coordinator-fill.ts +76 -0
  215. package/src/watch/feedback-read.ts +73 -0
  216. package/src/watch/feedback.ts +308 -0
  217. package/src/watch/gh.ts +22 -0
  218. package/src/watch/github-read.ts +175 -0
  219. package/src/watch/herdr.ts +11 -0
  220. package/src/watch/json-guards.ts +9 -0
  221. package/src/watch/kit-update.ts +18 -0
  222. package/src/watch/lane-fill.ts +36 -0
  223. package/src/watch/lane-message.ts +99 -0
  224. package/src/watch/lane-progress.ts +44 -0
  225. package/src/watch/lane-report-file.ts +53 -0
  226. package/src/watch/lane-report.ts +270 -0
  227. package/src/watch/lane-search.ts +41 -0
  228. package/src/watch/lane-sources.ts +46 -0
  229. package/src/watch/lane-watch.ts +121 -0
  230. package/src/watch/monitor-tool.ts +19 -0
  231. package/src/watch/options.ts +79 -0
  232. package/src/watch/plan-badges-read.ts +30 -0
  233. package/src/watch/plan-badges.ts +66 -0
  234. package/src/watch/plan-views.ts +59 -0
  235. package/src/watch/preview-read.ts +60 -0
  236. package/src/watch/previews.ts +234 -0
  237. package/src/watch/pull-requests.ts +117 -0
  238. package/src/watch/single-report.ts +15 -0
  239. package/src/watch/skill-change.ts +61 -0
  240. package/src/watch/source-dry-run-command.ts +35 -0
  241. package/src/watch/source-dry-run.ts +124 -0
  242. package/src/watch/source-fields.ts +9 -0
  243. package/src/watch/source-path.ts +40 -0
  244. package/src/watch/source-run.ts +90 -0
  245. package/src/watch/sources.ts +344 -0
  246. package/src/watch/stream-output.ts +14 -0
  247. package/src/watch/texts.ts +76 -0
  248. package/src/watch/watch-events.ts +399 -0
  249. package/src/watch/watcher-lock.ts +145 -0
  250. package/src/watch/workflow-runs.ts +96 -0
@@ -0,0 +1,601 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "type": "object",
4
+ "properties": {
5
+ "$schema": {
6
+ "type": "string"
7
+ },
8
+ "responseLanguage": {
9
+ "default": "en",
10
+ "type": "string",
11
+ "enum": [
12
+ "de",
13
+ "en"
14
+ ]
15
+ },
16
+ "planLanguage": {
17
+ "default": "en",
18
+ "type": "string",
19
+ "enum": [
20
+ "de",
21
+ "en"
22
+ ]
23
+ },
24
+ "planDirectory": {
25
+ "default": "docs/plans",
26
+ "type": "string",
27
+ "minLength": 1
28
+ },
29
+ "board": {
30
+ "default": {},
31
+ "type": "object",
32
+ "properties": {
33
+ "pattern": {
34
+ "default": "board-*",
35
+ "type": "string",
36
+ "pattern": "^(?![-.])[A-Za-z0-9._*?-]+$"
37
+ },
38
+ "file": {
39
+ "default": "board.md",
40
+ "type": "string",
41
+ "pattern": "^(?![-.])[A-Za-z0-9._-]+\\.md$"
42
+ },
43
+ "term": {
44
+ "default": "board",
45
+ "type": "string",
46
+ "minLength": 1
47
+ }
48
+ },
49
+ "additionalProperties": false
50
+ },
51
+ "sprintPattern": {
52
+ "not": {}
53
+ },
54
+ "worktreeDirectory": {
55
+ "default": ".claude/worktrees",
56
+ "type": "string",
57
+ "minLength": 1
58
+ },
59
+ "baseBranch": {
60
+ "default": "main",
61
+ "type": "string",
62
+ "pattern": "^(?![-/.])(?!.*(?:\\.\\.|\\/\\/|@\\{|\\.lock(?:\\/|$)))[A-Za-z0-9._/-]+(?<![./])$"
63
+ },
64
+ "skillPrefix": {
65
+ "default": "",
66
+ "anyOf": [
67
+ {
68
+ "type": "string",
69
+ "const": ""
70
+ },
71
+ {
72
+ "type": "string",
73
+ "pattern": "^[a-z0-9]+-$"
74
+ }
75
+ ]
76
+ },
77
+ "commands": {
78
+ "default": {},
79
+ "type": "object",
80
+ "properties": {
81
+ "test": {
82
+ "default": "bun test",
83
+ "type": "string",
84
+ "minLength": 1
85
+ },
86
+ "typecheck": {
87
+ "default": "bunx -p typescript tsc --noEmit",
88
+ "type": "string",
89
+ "minLength": 1
90
+ },
91
+ "lint": {
92
+ "default": "bunx @biomejs/biome check .",
93
+ "type": "string",
94
+ "minLength": 1
95
+ },
96
+ "format": {
97
+ "default": "bunx @biomejs/biome format --write .",
98
+ "type": "string",
99
+ "minLength": 1
100
+ },
101
+ "install": {
102
+ "default": "bun install",
103
+ "type": "string",
104
+ "minLength": 1
105
+ },
106
+ "dev": {
107
+ "default": "bun run dev",
108
+ "type": "string",
109
+ "minLength": 1
110
+ }
111
+ },
112
+ "additionalProperties": false
113
+ },
114
+ "lanes": {
115
+ "default": {},
116
+ "type": "object",
117
+ "properties": {
118
+ "copy": {
119
+ "default": [],
120
+ "type": "array",
121
+ "items": {
122
+ "type": "string",
123
+ "pattern": "^(?![/-])(?!(?:.*\\/)?\\.\\.(?:\\/|$))[^'\\x00-\\x1f\\x7f]+$"
124
+ }
125
+ },
126
+ "lockFile": {
127
+ "default": "bun.lock",
128
+ "type": "string",
129
+ "pattern": "^(?![/-])(?!(?:.*\\/)?\\.\\.(?:\\/|$))[A-Za-z0-9._/-]+$"
130
+ }
131
+ },
132
+ "additionalProperties": false
133
+ },
134
+ "models": {
135
+ "type": "object",
136
+ "propertyNames": {
137
+ "type": "string",
138
+ "enum": [
139
+ "plan",
140
+ "implement",
141
+ "review",
142
+ "explore",
143
+ "orchestrate"
144
+ ]
145
+ },
146
+ "additionalProperties": {
147
+ "type": "string",
148
+ "pattern": "^claude-[a-z0-9][a-z0-9.-]*$"
149
+ },
150
+ "required": [
151
+ "plan",
152
+ "implement",
153
+ "review",
154
+ "explore",
155
+ "orchestrate"
156
+ ]
157
+ },
158
+ "terminal": {
159
+ "default": {},
160
+ "type": "object",
161
+ "properties": {
162
+ "adapter": {
163
+ "default": "none",
164
+ "type": "string",
165
+ "enum": [
166
+ "none",
167
+ "herdr"
168
+ ]
169
+ }
170
+ },
171
+ "additionalProperties": false
172
+ },
173
+ "plans": {
174
+ "default": {},
175
+ "type": "object",
176
+ "properties": {
177
+ "fetchIntervalMinutes": {
178
+ "default": 5,
179
+ "type": "number",
180
+ "minimum": 0
181
+ },
182
+ "linkKinds": {
183
+ "default": [
184
+ {
185
+ "pattern": "^https://github\\.com/[^/]+/[^/]+/(pull|issues)/\\d+",
186
+ "label": "GitHub",
187
+ "icon": "⑂"
188
+ },
189
+ {
190
+ "pattern": "^https://(www\\.)?figma\\.com/",
191
+ "label": "Figma",
192
+ "icon": "◈"
193
+ },
194
+ {
195
+ "pattern": "^https://claude\\.ai/(code/)?artifact/",
196
+ "label": "Artifact",
197
+ "icon": "✦"
198
+ }
199
+ ],
200
+ "type": "array",
201
+ "items": {
202
+ "type": "object",
203
+ "properties": {
204
+ "pattern": {
205
+ "type": "string",
206
+ "minLength": 1
207
+ },
208
+ "label": {
209
+ "type": "string",
210
+ "minLength": 1
211
+ },
212
+ "icon": {
213
+ "type": "string",
214
+ "minLength": 1
215
+ }
216
+ },
217
+ "required": [
218
+ "pattern",
219
+ "label",
220
+ "icon"
221
+ ],
222
+ "additionalProperties": false
223
+ }
224
+ },
225
+ "context": {
226
+ "default": {},
227
+ "type": "object",
228
+ "properties": {
229
+ "warnAt": {
230
+ "default": 0.6,
231
+ "type": "number",
232
+ "exclusiveMinimum": 0,
233
+ "exclusiveMaximum": 1
234
+ },
235
+ "alertAt": {
236
+ "default": 0.8,
237
+ "type": "number",
238
+ "exclusiveMinimum": 0,
239
+ "exclusiveMaximum": 1
240
+ },
241
+ "windows": {
242
+ "default": {},
243
+ "type": "object",
244
+ "propertyNames": {
245
+ "type": "string",
246
+ "pattern": "^claude-[a-z0-9][a-z0-9.-]*$"
247
+ },
248
+ "additionalProperties": {
249
+ "type": "integer",
250
+ "exclusiveMinimum": 0,
251
+ "maximum": 9007199254740991
252
+ }
253
+ },
254
+ "defaultWindow": {
255
+ "default": 200000,
256
+ "type": "integer",
257
+ "exclusiveMinimum": 0,
258
+ "maximum": 9007199254740991
259
+ },
260
+ "coordinator": {
261
+ "default": {},
262
+ "type": "object",
263
+ "properties": {
264
+ "warnAt": {
265
+ "default": 0.5,
266
+ "type": "number",
267
+ "exclusiveMinimum": 0,
268
+ "exclusiveMaximum": 1
269
+ },
270
+ "alertAt": {
271
+ "default": 0.7,
272
+ "type": "number",
273
+ "exclusiveMinimum": 0,
274
+ "exclusiveMaximum": 1
275
+ }
276
+ },
277
+ "additionalProperties": false
278
+ }
279
+ },
280
+ "additionalProperties": false
281
+ }
282
+ },
283
+ "additionalProperties": false
284
+ },
285
+ "watch": {
286
+ "default": {},
287
+ "type": "object",
288
+ "properties": {
289
+ "deploy": {
290
+ "type": "object",
291
+ "properties": {
292
+ "workflow": {
293
+ "type": "string",
294
+ "pattern": "^(?![-.])[A-Za-z0-9._-]+\\.ya?ml$"
295
+ },
296
+ "environments": {
297
+ "minItems": 1,
298
+ "type": "array",
299
+ "items": {
300
+ "type": "string",
301
+ "minLength": 1
302
+ }
303
+ }
304
+ },
305
+ "required": [
306
+ "workflow",
307
+ "environments"
308
+ ],
309
+ "additionalProperties": false
310
+ },
311
+ "feedback": {
312
+ "default": {
313
+ "ignore": []
314
+ },
315
+ "anyOf": [
316
+ {
317
+ "type": "boolean",
318
+ "const": false
319
+ },
320
+ {
321
+ "type": "object",
322
+ "properties": {
323
+ "ignore": {
324
+ "default": [],
325
+ "type": "array",
326
+ "items": {
327
+ "type": "string",
328
+ "minLength": 1
329
+ }
330
+ }
331
+ },
332
+ "additionalProperties": false
333
+ }
334
+ ]
335
+ },
336
+ "previews": {
337
+ "type": "object",
338
+ "properties": {
339
+ "deployments": {
340
+ "default": false,
341
+ "type": "boolean"
342
+ },
343
+ "authors": {
344
+ "default": [],
345
+ "type": "array",
346
+ "items": {
347
+ "type": "string",
348
+ "minLength": 1
349
+ }
350
+ },
351
+ "urlPattern": {
352
+ "type": "string",
353
+ "minLength": 1
354
+ }
355
+ },
356
+ "additionalProperties": false
357
+ },
358
+ "sources": {
359
+ "default": [],
360
+ "type": "array",
361
+ "items": {
362
+ "type": "object",
363
+ "properties": {
364
+ "name": {
365
+ "type": "string",
366
+ "pattern": "^[A-Za-z0-9][\\w.-]*$"
367
+ },
368
+ "command": {
369
+ "minItems": 1,
370
+ "type": "array",
371
+ "items": {
372
+ "type": "string",
373
+ "minLength": 1
374
+ }
375
+ },
376
+ "every": {
377
+ "default": 5,
378
+ "type": "integer",
379
+ "minimum": 1,
380
+ "maximum": 9007199254740991
381
+ },
382
+ "items": {
383
+ "type": "string"
384
+ },
385
+ "map": {
386
+ "type": "object",
387
+ "properties": {
388
+ "id": {
389
+ "type": "string"
390
+ },
391
+ "updatedAt": {
392
+ "type": "string"
393
+ },
394
+ "title": {
395
+ "type": "string"
396
+ },
397
+ "url": {
398
+ "type": "string"
399
+ },
400
+ "body": {
401
+ "type": "string"
402
+ },
403
+ "author": {
404
+ "type": "string"
405
+ }
406
+ },
407
+ "required": [
408
+ "id",
409
+ "updatedAt"
410
+ ],
411
+ "additionalProperties": {
412
+ "type": "string"
413
+ }
414
+ },
415
+ "ignoreAuthors": {
416
+ "default": [],
417
+ "type": "array",
418
+ "items": {
419
+ "type": "string",
420
+ "minLength": 1
421
+ }
422
+ },
423
+ "reportLimit": {
424
+ "default": 5,
425
+ "type": "integer",
426
+ "minimum": 1,
427
+ "maximum": 9007199254740991
428
+ },
429
+ "lane": {
430
+ "type": "string",
431
+ "minLength": 1
432
+ },
433
+ "reportOn": {
434
+ "minItems": 1,
435
+ "maxItems": 10,
436
+ "type": "array",
437
+ "items": {
438
+ "type": "string",
439
+ "minLength": 1
440
+ }
441
+ }
442
+ },
443
+ "required": [
444
+ "name",
445
+ "command",
446
+ "map"
447
+ ],
448
+ "additionalProperties": false
449
+ }
450
+ }
451
+ },
452
+ "additionalProperties": false
453
+ },
454
+ "check": {
455
+ "type": "object",
456
+ "properties": {
457
+ "lintFilesCommand": {
458
+ "default": "bunx @biomejs/biome check --no-errors-on-unmatched",
459
+ "type": "string",
460
+ "minLength": 1
461
+ },
462
+ "checks": {
463
+ "default": [],
464
+ "type": "array",
465
+ "items": {
466
+ "type": "object",
467
+ "properties": {
468
+ "name": {
469
+ "type": "string",
470
+ "minLength": 1
471
+ },
472
+ "command": {
473
+ "type": "string",
474
+ "minLength": 1
475
+ },
476
+ "globs": {
477
+ "minItems": 1,
478
+ "type": "array",
479
+ "items": {
480
+ "type": "string",
481
+ "minLength": 1
482
+ }
483
+ }
484
+ },
485
+ "required": [
486
+ "name",
487
+ "command"
488
+ ],
489
+ "additionalProperties": false
490
+ }
491
+ },
492
+ "generatorOwned": {
493
+ "default": [],
494
+ "type": "array",
495
+ "items": {
496
+ "type": "object",
497
+ "properties": {
498
+ "glob": {
499
+ "type": "string",
500
+ "minLength": 1
501
+ },
502
+ "generator": {
503
+ "type": "string",
504
+ "minLength": 1
505
+ }
506
+ },
507
+ "required": [
508
+ "glob",
509
+ "generator"
510
+ ],
511
+ "additionalProperties": false
512
+ }
513
+ },
514
+ "buildArtifacts": {
515
+ "default": [
516
+ "**/tsup.config.bundled_*",
517
+ "**/dist/**",
518
+ "**/.turbo/**",
519
+ "**/node_modules/**",
520
+ "**/*.tsbuildinfo"
521
+ ],
522
+ "type": "array",
523
+ "items": {
524
+ "type": "string",
525
+ "minLength": 1
526
+ }
527
+ },
528
+ "reviewerRoutes": {
529
+ "default": [],
530
+ "type": "array",
531
+ "items": {
532
+ "type": "object",
533
+ "properties": {
534
+ "reviewer": {
535
+ "type": "string",
536
+ "minLength": 1
537
+ },
538
+ "globs": {
539
+ "minItems": 1,
540
+ "type": "array",
541
+ "items": {
542
+ "type": "string",
543
+ "minLength": 1
544
+ }
545
+ },
546
+ "why": {
547
+ "type": "string",
548
+ "minLength": 1
549
+ }
550
+ },
551
+ "required": [
552
+ "reviewer",
553
+ "globs",
554
+ "why"
555
+ ],
556
+ "additionalProperties": false
557
+ }
558
+ },
559
+ "publicContent": {
560
+ "type": "object",
561
+ "properties": {
562
+ "globs": {
563
+ "minItems": 1,
564
+ "type": "array",
565
+ "items": {
566
+ "type": "string",
567
+ "minLength": 1
568
+ }
569
+ },
570
+ "exclude": {
571
+ "default": [],
572
+ "type": "array",
573
+ "items": {
574
+ "type": "string",
575
+ "minLength": 1
576
+ }
577
+ },
578
+ "reviewer": {
579
+ "default": "public-content",
580
+ "type": "string",
581
+ "minLength": 1
582
+ }
583
+ },
584
+ "required": [
585
+ "globs"
586
+ ],
587
+ "additionalProperties": false
588
+ },
589
+ "looseTests": {
590
+ "default": false,
591
+ "type": "boolean"
592
+ }
593
+ },
594
+ "additionalProperties": false
595
+ }
596
+ },
597
+ "required": [
598
+ "models"
599
+ ],
600
+ "additionalProperties": false
601
+ }
@@ -0,0 +1,45 @@
1
+ import { matchesAnyGlob, matchesGlob } from './glob'
2
+ import type { CheckConfig } from './schema'
3
+
4
+ /** `--untracked-files=all` lists a new directory's files one by one; the default folds it into `dir/`, which names no package root. */
5
+ export const STATUS_COMMAND = ['git', 'status', '--porcelain', '--untracked-files=all'] as const
6
+
7
+ export type ChangedFile = { path: string; staged: boolean }
8
+
9
+ const unquote = (path: string): string =>
10
+ path.startsWith('"') && path.endsWith('"') ? path.slice(1, -1).replace(/\\"/g, '"') : path
11
+
12
+ /**
13
+ * `git status --porcelain` rather than `git diff`, because a diff against HEAD lists no untracked
14
+ * files, so a brand new module and its test would be invisible to the whole check.
15
+ */
16
+ export const parsePorcelain = (output: string): ChangedFile[] =>
17
+ output
18
+ .split('\n')
19
+ .filter((line) => line.length > 3)
20
+ // Position 3 is always a space in porcelain v1. If it is not, something trimmed the status
21
+ // column off the front of the line, and reading it as-is would eat the path's first character.
22
+ .map((line) => (line[2] === ' ' ? line : ` ${line}`))
23
+ .flatMap((line) => {
24
+ const index = line[0]
25
+ const rest = line.slice(3)
26
+ // A rename reads `R old -> new`; the new path is the one that exists now.
27
+ const path = unquote(rest.includes(' -> ') ? (rest.split(' -> ').at(-1) as string) : rest)
28
+ if (index === 'D' || line[1] === 'D') return []
29
+ return [{ path, staged: index !== ' ' && index !== '?' }]
30
+ })
31
+
32
+ export const stagedBuildArtifacts = (
33
+ files: readonly ChangedFile[],
34
+ artifactGlobs: CheckConfig['buildArtifacts'],
35
+ ): string[] => files.filter((file) => file.staged && matchesAnyGlob(file.path, artifactGlobs)).map((file) => file.path)
36
+
37
+ /** Files a generator owns: a hand edit is lost on the next run, so the commit has to come from the generator. */
38
+ export const generatorOwnedFiles = (
39
+ paths: readonly string[],
40
+ owners: CheckConfig['generatorOwned'],
41
+ ): { path: string; generator: string }[] =>
42
+ paths.flatMap((path) => {
43
+ const owner = owners.find(({ glob }) => matchesGlob(path, glob))
44
+ return owner ? [{ path, generator: owner.generator }] : []
45
+ })
@@ -0,0 +1,12 @@
1
+ const TOKEN = /(?:"[^"]*"|'[^']*'|\S)+/g
2
+ const QUOTED = /"([^"]*)"|'([^']*)'/g
3
+
4
+ /**
5
+ * Splits a configured command into arguments without a shell: whitespace separates, single and
6
+ * double quotes group. No expansion, no pipes; a command that needs them belongs in a script.
7
+ */
8
+ export const tokenize = (command: string): string[] =>
9
+ (command.match(TOKEN) ?? []).map((token) => {
10
+ if (/["']/.test(token.replace(QUOTED, ''))) throw new Error(`Unterminated quote in command: ${command}`)
11
+ return token.replace(QUOTED, '$1$2')
12
+ })