autonomous-sdlc-harness 0.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.
Files changed (171) hide show
  1. package/LICENSE +201 -0
  2. package/NOTICE +7 -0
  3. package/README.md +24 -0
  4. package/dist/cli.js +194 -0
  5. package/dist/cli.js.map +1 -0
  6. package/dist/commands/config.js +561 -0
  7. package/dist/commands/config.js.map +1 -0
  8. package/dist/commands/daemon.js +791 -0
  9. package/dist/commands/daemon.js.map +1 -0
  10. package/dist/commands/doctor.js +336 -0
  11. package/dist/commands/doctor.js.map +1 -0
  12. package/dist/commands/init.js +2023 -0
  13. package/dist/commands/init.js.map +1 -0
  14. package/dist/commands/registry.js +42 -0
  15. package/dist/commands/registry.js.map +1 -0
  16. package/dist/config/check.js +505 -0
  17. package/dist/config/check.js.map +1 -0
  18. package/dist/config/io.js +177 -0
  19. package/dist/config/io.js.map +1 -0
  20. package/dist/config/model.js +406 -0
  21. package/dist/config/model.js.map +1 -0
  22. package/dist/core/errors.js +71 -0
  23. package/dist/core/errors.js.map +1 -0
  24. package/dist/core/git.js +537 -0
  25. package/dist/core/git.js.map +1 -0
  26. package/dist/core/json.js +125 -0
  27. package/dist/core/json.js.map +1 -0
  28. package/dist/core/layerCoverage.js +141 -0
  29. package/dist/core/layerCoverage.js.map +1 -0
  30. package/dist/core/layerGapRemedy.js +62 -0
  31. package/dist/core/layerGapRemedy.js.map +1 -0
  32. package/dist/core/nameList.js +23 -0
  33. package/dist/core/nameList.js.map +1 -0
  34. package/dist/core/paths.js +153 -0
  35. package/dist/core/paths.js.map +1 -0
  36. package/dist/core/prompt.js +206 -0
  37. package/dist/core/prompt.js.map +1 -0
  38. package/dist/core/repoPaths.js +55 -0
  39. package/dist/core/repoPaths.js.map +1 -0
  40. package/dist/core/report.js +150 -0
  41. package/dist/core/report.js.map +1 -0
  42. package/dist/core/templating.js +88 -0
  43. package/dist/core/templating.js.map +1 -0
  44. package/dist/core/writer.js +479 -0
  45. package/dist/core/writer.js.map +1 -0
  46. package/dist/daemon/backend.js +180 -0
  47. package/dist/daemon/backend.js.map +1 -0
  48. package/dist/daemon/units.js +380 -0
  49. package/dist/daemon/units.js.map +1 -0
  50. package/dist/detect/nestedApplication.js +79 -0
  51. package/dist/detect/nestedApplication.js.map +1 -0
  52. package/dist/detect/presets.js +2033 -0
  53. package/dist/detect/presets.js.map +1 -0
  54. package/dist/detect/signals.js +1368 -0
  55. package/dist/detect/signals.js.map +1 -0
  56. package/dist/doctor/checks.js +3530 -0
  57. package/dist/doctor/checks.js.map +1 -0
  58. package/dist/generators/claudeContext.js +588 -0
  59. package/dist/generators/claudeContext.js.map +1 -0
  60. package/dist/generators/githooks.js +446 -0
  61. package/dist/generators/githooks.js.map +1 -0
  62. package/dist/generators/harnessConfig.js +632 -0
  63. package/dist/generators/harnessConfig.js.map +1 -0
  64. package/dist/generators/notifications.js +191 -0
  65. package/dist/generators/notifications.js.map +1 -0
  66. package/dist/generators/outerLoopScripts.js +165 -0
  67. package/dist/generators/outerLoopScripts.js.map +1 -0
  68. package/dist/generators/permissionProfile.js +1172 -0
  69. package/dist/generators/permissionProfile.js.map +1 -0
  70. package/dist/generators/projectSettings.js +322 -0
  71. package/dist/generators/projectSettings.js.map +1 -0
  72. package/dist/generators/repoRoot.js +417 -0
  73. package/dist/generators/repoRoot.js.map +1 -0
  74. package/dist/generators/scripts.js +557 -0
  75. package/dist/generators/scripts.js.map +1 -0
  76. package/dist/generators/stateDir.js +221 -0
  77. package/dist/generators/stateDir.js.map +1 -0
  78. package/dist/machine/paths.js +111 -0
  79. package/dist/machine/paths.js.map +1 -0
  80. package/dist/machine/plugins.js +224 -0
  81. package/dist/machine/plugins.js.map +1 -0
  82. package/dist/machine/registry.js +330 -0
  83. package/dist/machine/registry.js.map +1 -0
  84. package/package.json +23 -0
  85. package/scripts/README.md +13 -0
  86. package/scripts/daemon/launchd.plist.template +59 -0
  87. package/scripts/daemon/systemd.service.template +58 -0
  88. package/templates/README.md +15 -0
  89. package/templates/claude/CLAUDE.md +54 -0
  90. package/templates/claude/README.md +5 -0
  91. package/templates/claude/context/api.md +29 -0
  92. package/templates/claude/context/conventions.md +23 -0
  93. package/templates/claude/context/data-layer.md +28 -0
  94. package/templates/claude/context/data-storage.md +29 -0
  95. package/templates/claude/context/docs-catalog.md +29 -0
  96. package/templates/claude/context/domain.md +28 -0
  97. package/templates/claude/context/layer.md +20 -0
  98. package/templates/claude/context/module.md +30 -0
  99. package/templates/claude/context/package.md +29 -0
  100. package/templates/claude/context/presentation.md +32 -0
  101. package/templates/claude/context/state-slices.md +28 -0
  102. package/templates/claude/context/tests.md +28 -0
  103. package/templates/claude/harness-task-offer.md +58 -0
  104. package/templates/claude/push-notify.env.example +21 -0
  105. package/templates/claude/qa-accounts.env.example +38 -0
  106. package/templates/claude/qa_test_scenarios.md +110 -0
  107. package/templates/claude/settings.autonomous.json +93 -0
  108. package/templates/claude/settings.autonomous.qa.json +36 -0
  109. package/templates/githooks/README.md +3 -0
  110. package/templates/githooks/pre-push +72 -0
  111. package/templates/repo/README.md +3 -0
  112. package/templates/repo/gitattributes +16 -0
  113. package/templates/repo/gitignore +61 -0
  114. package/templates/repo/gitignore.qa +25 -0
  115. package/templates/repo/mcp.json +17 -0
  116. package/templates/scripts/README.md +5 -0
  117. package/templates/scripts/autonomous-format-stream.sh +95 -0
  118. package/templates/scripts/autonomous-notify.sh +337 -0
  119. package/templates/scripts/autonomous-watcher.sh +3087 -0
  120. package/templates/scripts/cleanup-merged-worktrees.sh +327 -0
  121. package/templates/scripts/commit-on-branch.sh +288 -0
  122. package/templates/scripts/create-worktree.sh +360 -0
  123. package/templates/scripts/deploy.sh +47 -0
  124. package/templates/scripts/lib/harness-run-lib.sh +1481 -0
  125. package/templates/scripts/push-branch.sh +140 -0
  126. package/templates/scripts/refresh-branch.sh +244 -0
  127. package/templates/scripts/restart-watcher.sh +401 -0
  128. package/templates/scripts/scratch-run.sh +302 -0
  129. package/templates/scripts/setup-worktree.sh +262 -0
  130. package/templates/scripts/start-dev-server.sh +99 -0
  131. package/templates/scripts/test.sh +50 -0
  132. package/templates/scripts/typecheck.sh +50 -0
  133. package/templates/state-dir/README-root.md +13 -0
  134. package/templates/state-dir/README.md +9 -0
  135. package/templates/state-dir/architecture_branch_review_point_reviews/README.md +9 -0
  136. package/templates/state-dir/architecture_branch_reviews/README.md +9 -0
  137. package/templates/state-dir/architecture_reviews/README.md +9 -0
  138. package/templates/state-dir/architecture_user_review_reviews/README.md +9 -0
  139. package/templates/state-dir/autonomous_inbox/README.md +9 -0
  140. package/templates/state-dir/autonomous_logs/README.md +9 -0
  141. package/templates/state-dir/branch_statistics/README.md +9 -0
  142. package/templates/state-dir/business_parity_branch_review_point_reviews/README.md +9 -0
  143. package/templates/state-dir/business_parity_branch_reviews/README.md +9 -0
  144. package/templates/state-dir/business_parity_reviews/README.md +9 -0
  145. package/templates/state-dir/business_parity_user_review_reviews/README.md +9 -0
  146. package/templates/state-dir/clarification_digests/README.md +9 -0
  147. package/templates/state-dir/clarifications/README.md +9 -0
  148. package/templates/state-dir/code_reviews/README.md +9 -0
  149. package/templates/state-dir/dispatch_additions/README.md +19 -0
  150. package/templates/state-dir/docs_catalog/README.md +9 -0
  151. package/templates/state-dir/flow_progress/README.md +9 -0
  152. package/templates/state-dir/improvement_observations/README.md +19 -0
  153. package/templates/state-dir/improvement_suggestions.md +29 -0
  154. package/templates/state-dir/lessons.md +23 -0
  155. package/templates/state-dir/qa_review_point_reviews/README.md +9 -0
  156. package/templates/state-dir/qa_reviews/README.md +9 -0
  157. package/templates/state-dir/review_plan_point_reviews/README.md +9 -0
  158. package/templates/state-dir/review_plan_reviews/README.md +9 -0
  159. package/templates/state-dir/scratch/README.md +11 -0
  160. package/templates/state-dir/skeptic_review_plan_reviews/README.md +9 -0
  161. package/templates/state-dir/skeptic_review_point_reviews/README.md +9 -0
  162. package/templates/state-dir/skeptic_reviews/README.md +9 -0
  163. package/templates/state-dir/story_plans/README.md +9 -0
  164. package/templates/state-dir/task_plan_point_reviews/README.md +9 -0
  165. package/templates/state-dir/task_plan_reviews/README.md +9 -0
  166. package/templates/state-dir/task_plans/README.md +9 -0
  167. package/templates/state-dir/task_prompts/README.md +9 -0
  168. package/templates/state-dir/ui_test_plan_reviews/README.md +9 -0
  169. package/templates/state-dir/ui_test_plans/README.md +9 -0
  170. package/templates/state-dir/user_review_fix_plan_point_reviews/README.md +9 -0
  171. package/templates/state-dir/user_reviews/README.md +9 -0
@@ -0,0 +1,557 @@
1
+ /**
2
+ * Generator: the project-command wrapper scripts `init` writes into the configured `scriptsDir`.
3
+ *
4
+ * **The rule this module exists to enforce: {@link WRAPPER_SCRIPTS} is the single source for the
5
+ * wrapper set, and {@link scriptInvocation} is the single producer of the string that names *any*
6
+ * script `init` writes into `scriptsDir`.** The generated config, the wrapper files and the
7
+ * generated permission profile are three views of one string; drift between them is invisible until
8
+ * an unattended run stalls on a command that matches neither `allow` nor `deny`, which in `-p` mode
9
+ * is a stall rather than a prompt. So the config generator and the profile generator import from
10
+ * here rather than formatting `bash …/….sh` themselves; {@link wrapperInvocation} is the typed
11
+ * wrapper-only spelling of the same producer, and `generators/outerLoopScripts.ts` — whose files
12
+ * land in the same directory and whose agent-invocable rows reach the same profile — calls
13
+ * {@link scriptInvocation} directly rather than becoming a second producer of the shape.
14
+ *
15
+ * ## Three non-obvious choices, and where each comes from
16
+ *
17
+ * 1. **`commands.*` holds the wrapper *invocation*; the wrapper file holds the *raw* command
18
+ * line.** The `commands` object of `examples/harness.config.json` is the worked shape:
19
+ * `"typecheck": "bash packages/storefront/scripts/typecheck.sh"` in the config, with the
20
+ * `npm run …` / `pytest` / `go vet …` line inside the script. `deploy.command` (that
21
+ * file's `deploy` object) takes the same wrapper form on its own object. The wrappers
22
+ * exist because an unattended run's permission profile can allow-list a literal script
23
+ * path far more safely than an arbitrary command line (`cli/templates/scripts/README.md`).
24
+ * 2. **`build` and `depInstall` are deliberately not wrapped**, and therefore never allow-listed:
25
+ * the same example config leaves both raw (`"npm run build --workspace …"`, `"npm ci"`),
26
+ * because they are orchestrator- or human-run rather than agent-run. That is the same reason
27
+ * the reference profile gates the package manager outright, which the generated profile's
28
+ * rationale block states. Wrapping them would hand an agent a script path it is allowed to
29
+ * run, which is exactly what those two must not have.
30
+ * 3. **Each script prints its own verdict line** — `PASS: <name>` / `FAIL: <name> (exit n)` —
31
+ * so a caller never appends `; echo $?` to it. That compound form is what stalls an
32
+ * unattended run on a permission prompt, and a wrapper that reports its own result removes
33
+ * the reason to write one.
34
+ *
35
+ * ## Scope
36
+ *
37
+ * This module is the **writer**, and the templates it renders now carry their finished bodies —
38
+ * self-anchoring to their own checkout, forwarding their arguments, and (for the dev server)
39
+ * detaching the process and reporting its pid and log path. What they never carry is the command
40
+ * line itself: that arrives from `commands.*` / `deploy.command` at render time. A wrapper this
41
+ * module selects is written with its body rather than left for later, because `commands.*` points
42
+ * at it and the permission profile allow-lists its literal path — writing a path the file does not
43
+ * back would generate a profile naming a file that does not exist.
44
+ *
45
+ * The one thing here that does not write is {@link wrapperCommandLine}, which reads a written
46
+ * wrapper's command line back out; it sits in this module rather than beside its caller for the
47
+ * reason its own doc gives.
48
+ */
49
+ import { join } from 'node:path';
50
+ import { answersNone, DEFAULTS, isPlaceholder } from '../config/model.js';
51
+ import { HarnessError } from '../core/errors.js';
52
+ import { readTemplate } from '../core/paths.js';
53
+ import { normalizeRepoDir } from '../core/repoPaths.js';
54
+ import { renderTemplate } from '../core/templating.js';
55
+ import { devServerPrestart } from '../detect/presets.js';
56
+ /**
57
+ * The whole wrapper set, in the order `init` writes it.
58
+ *
59
+ * **Declared once, here.** A `.sh` name that appears as a string literal anywhere else in the CLI
60
+ * is a second source for this table and will drift from it; the template path and the invocation
61
+ * string are both derived from a row rather than spelled out again.
62
+ */
63
+ export const WRAPPER_SCRIPTS = Object.freeze([
64
+ Object.freeze({ key: 'typecheck', file: 'typecheck.sh' }),
65
+ Object.freeze({ key: 'test', file: 'test.sh' }),
66
+ Object.freeze({ key: 'devServer', file: 'start-dev-server.sh' }),
67
+ Object.freeze({ key: 'deploy', file: 'deploy.sh' }),
68
+ ]);
69
+ /** The two wrappers written whatever the repository looks like: the flow's verification pair. */
70
+ const ALWAYS_SELECTED = Object.freeze(['typecheck', 'test']);
71
+ /** Executable, because `commands.*` invokes the file rather than sourcing it. */
72
+ const SCRIPT_MODE = 0o755;
73
+ /** The templates' subdirectory under `cli/templates/`, addressed as {@link readTemplate} wants it. */
74
+ const TEMPLATE_DIR = 'scripts';
75
+ /** `<dir>/<file>`, POSIX-style, with a `.`-valued directory meaning the repository root. */
76
+ function posixJoin(dir, file) {
77
+ const normalized = normalizeRepoDir(dir);
78
+ return normalized === '.' ? file : `${normalized}/${file}`;
79
+ }
80
+ /**
81
+ * The interpreter {@link scriptInvocation} prefixes every path with, and the one string
82
+ * {@link invokedPath} takes back off to name the file an invocation runs.
83
+ */
84
+ const INVOCATION_PREFIX = 'bash ';
85
+ /**
86
+ * The repo-relative path inside an invocation **this module produced** — never inside a configured
87
+ * value. It is the inverse of {@link scriptInvocation} over that one producer's own output, which is
88
+ * why it may slice a fixed prefix; a `commands.*` value may legitimately be a raw command line, and
89
+ * parsing one back into a path is how the three views drift apart (`docs/cli.md` §6).
90
+ */
91
+ function invokedPath(invocation) {
92
+ return invocation.slice(INVOCATION_PREFIX.length);
93
+ }
94
+ /** The `scriptsDir` every wrapper path is built from: the config's value or the schema default. */
95
+ function resolvedScriptsDir(config) {
96
+ return normalizeRepoDir(config.scriptsDir ?? DEFAULTS.scriptsDir);
97
+ }
98
+ /**
99
+ * **The one producer of `bash <scriptsDir>/<file>`**, for every script `init` writes into the
100
+ * configured `scriptsDir` — the wrappers here and the outer-loop scripts alike.
101
+ *
102
+ * Repo-relative, forward-slashed and unquoted, because commands are executed from the repository
103
+ * root and every path in the config file is repo-relative. The profile's allow entry (i) is this
104
+ * exact string; its repo-root-absolute and sibling-worktree twins are the profile's to derive and
105
+ * are deliberately not produced here.
106
+ *
107
+ * `file` is a path relative to `scriptsDir`, so a script in a subdirectory is named by passing
108
+ * `<subdir>/<file>` rather than by joining the pieces at the call site.
109
+ */
110
+ export function scriptInvocation(scriptsDir, file) {
111
+ return `${INVOCATION_PREFIX}${posixJoin(scriptsDir, file)}`;
112
+ }
113
+ /**
114
+ * The literal `commands.*` (or `deploy.command`) holds for one wrapper: {@link scriptInvocation}
115
+ * narrowed to {@link WrapperFile}.
116
+ *
117
+ * It delegates rather than formatting the string itself, so the wrapper set and the outer-loop set
118
+ * cannot come to be named in two subtly different ways, and the config, the profile and this
119
+ * generator keep reading one function's answer. The narrower parameter type is the point of keeping
120
+ * it: a caller that means "a wrapper" cannot pass an arbitrary name through it by mistake.
121
+ */
122
+ export function wrapperInvocation(scriptsDir, file) {
123
+ return scriptInvocation(scriptsDir, file);
124
+ }
125
+ /**
126
+ * One wrapper's repo-relative path, forward-slashed — {@link wrapperInvocation} without the
127
+ * interpreter, for a message that names the **file** rather than a line to run.
128
+ *
129
+ * Exported so a caller that has to speak about a wrapper on disk composes the path from this
130
+ * module's own `scriptsDir` and {@link WrapperFile} instead of restating the join or slicing it back
131
+ * out of an invocation ({@link invokedPath}'s standing prohibition).
132
+ */
133
+ export function wrapperPath(scriptsDir, file) {
134
+ return posixJoin(scriptsDir, file);
135
+ }
136
+ /**
137
+ * Where a wrapper's command line is configured, as a message should name it.
138
+ *
139
+ * Exported for the `doctor` check that reports on the same keys: `deploy`'s command lives on its own
140
+ * object, so a caller spelling the key family itself would name a `commands.deploy` no config has.
141
+ */
142
+ export function configKeyPath(key) {
143
+ return key === 'deploy' ? 'deploy.command' : `commands.${key}`;
144
+ }
145
+ /**
146
+ * The configured command line for one key, trimmed, or `undefined` when the key carries none.
147
+ *
148
+ * Exported for the caller that reports the lines this run put in effect, which covers the unwrapped
149
+ * `build` and `depInstall` too. `deploy` reads `deploy.command`, which is the same special case
150
+ * {@link configKeyPath} exists for — a second copy of it elsewhere is a second answer to "where is
151
+ * this key's line configured".
152
+ */
153
+ export function configuredCommand(config, key) {
154
+ const value = key === 'deploy' ? config.deploy?.command : config.commands[key];
155
+ if (value === undefined)
156
+ return undefined;
157
+ const trimmed = value.trim();
158
+ return trimmed === '' ? undefined : trimmed;
159
+ }
160
+ /**
161
+ * **The one owner of "a wrapped `commands.*` key holds a raw command line rather than its wrapper
162
+ * invocation".** `init` (through {@link resolveBody}), `doctor` and `config set` all ask this
163
+ * function rather than each restating the condition, so the three cannot come to disagree about what
164
+ * the defect is — the state a nested application's hand-fill path produces, where the permission
165
+ * profile allow-lists the wrapper and the configured string is refused.
166
+ *
167
+ * It compares **byte-equality against {@link wrapperInvocation}**, the single producer of the form,
168
+ * and never parses the configured value back into a path: that value may legitimately be a raw
169
+ * command line, and parsing it is how the three views drift apart (`docs/cli.md` §6).
170
+ *
171
+ * Four states are deliberately **not** this defect:
172
+ *
173
+ * - **unset or empty** — there is nothing to compare, and nothing was inlined into a wrapper;
174
+ * - **still the placeholder** — reported by the config check and by {@link writeWrapperScripts}, and
175
+ * no wrapper is written for it at all, so there is no allow-listed form for it to disagree with;
176
+ * - **`commands.typecheck` answered `none`** — the adopter's statement that this repository has no
177
+ * type check, for which no wrapper is written at all, so there is again no allow-listed form for it
178
+ * to disagree with. The exemption is made **here** rather than left to {@link selectWrapper}'s arm
179
+ * because `config set` — the supported route to writing that answer — calls this predicate
180
+ * directly, and would otherwise print {@link wrappedKeyMismatchMessage}, an instruction to undo the
181
+ * answer. The exemption is key-gated like the arm, so it holds on that key only: `commands.test`
182
+ * holding the same string keeps its wrapper and still gets its mismatch report;
183
+ * - **holding the invocation** — the normal state after a first `init`, and the state every correct
184
+ * adoption stays in.
185
+ */
186
+ export function wrappedKeyMismatch(config, key) {
187
+ const configured = configuredCommand(config, key);
188
+ if (configured === undefined || isPlaceholder(configured) || answersNone(key, configured))
189
+ return undefined;
190
+ // Read from the table rather than from a second `.sh` literal. A `WrapperKey` is that table's own
191
+ // union, so the lookup cannot miss; `undefined` there is the same answer this function gives for
192
+ // every other "nothing to report", which keeps a predicate from carrying an error path.
193
+ const script = WRAPPER_SCRIPTS.find((entry) => entry.key === key);
194
+ if (script === undefined)
195
+ return undefined;
196
+ const invocation = wrapperInvocation(resolvedScriptsDir(config), script.file);
197
+ return configured === invocation ? undefined : { configured, invocation, file: script.file };
198
+ }
199
+ /**
200
+ * The one sentence every consumer of {@link wrappedKeyMismatch} prints, so `init`, `doctor` and
201
+ * `config set` cannot state one defect three ways.
202
+ *
203
+ * {@link configKeyPath} is applied here rather than by the caller, which is what names the `deploy`
204
+ * row `deploy.command` instead of the `commands.deploy` that key does not have.
205
+ *
206
+ * **The re-run has a condition, and the sentence has to carry it.** Wrappers are written
207
+ * `create-if-absent` ({@link writeWrapperScripts}), so a re-run inlines this line **only** where the
208
+ * file is not there yet; over a wrapper already on disk the write engine keeps the file and the body
209
+ * {@link resolveBody} just computed is discarded, leaving a message that named a plain re-run
210
+ * prescribing a step that silently loses the adopter's line. Both arms are therefore named: the plain
211
+ * re-run for the absent file, and `init --force` — which backs the file up to a `.bak` first — or
212
+ * deleting it for the one that exists.
213
+ *
214
+ * **The two steps are ordered, and the sentence has to carry the order too** — because one of the
215
+ * three sites sees this state *before* the wrapper exists. `config set` is the hand-fill boundary a
216
+ * nested application reaches with the key still holding the placeholder, for which
217
+ * {@link writeWrapperScripts} wrote no wrapper at all; that file is created by the **next** `init`,
218
+ * from the raw line just stored, which is the absent arm. So the wrapper is named as the file that
219
+ * line goes into rather than as one that already runs it, and the corrective `set` is named after the
220
+ * write that has to precede it: performing it first leaves {@link resolveBody} nothing to inline —
221
+ * precedence 1 no longer sees a raw line, precedence 2 finds only the placeholder detection produced
222
+ * — and the wrapper is written to fail with the adopter's command line gone. That is the same
223
+ * sequence `init`'s own undetected-command warning prescribes (`detect/presets.ts`, arm 1), so the
224
+ * two read as one path.
225
+ */
226
+ export function wrappedKeyMismatchMessage(key, { configured, invocation }) {
227
+ const keyPath = configKeyPath(key);
228
+ const wrapperPath = invokedPath(invocation);
229
+ return (`${keyPath} holds a raw command line (${configured}) rather than the wrapper invocation; ` +
230
+ `${wrapperPath} is the wrapper that line belongs in, and the invocation is the form the permission ` +
231
+ `profile allow-lists. Wrappers are create-if-absent, so init writes ${wrapperPath} from this line ` +
232
+ `only while that file does not exist: re-run init where it is absent, and where it is already on ` +
233
+ `disk run init --force (which backs it up to ${wrapperPath}.bak first) or delete it and re-run. Then set ` +
234
+ `${keyPath} to ${invocation} — setting it before the wrapper holds the line discards the line. ` +
235
+ `An agent told to run the configured string as-is is refused on the raw line`);
236
+ }
237
+ /**
238
+ * **The wrapper-selection rule, and the only place it is written down.** Its two callers —
239
+ * {@link writeWrapperScripts}, which writes the files, and the permission profile's
240
+ * `selectWrapperScripts`, which decides what may be allow-listed — both run this function rather
241
+ * than each restating the rule:
242
+ *
243
+ * - `typecheck` and `test` always — the two commands the flow treats as "this change is done"
244
+ * (`config/check.ts`), so a repository always has both wrappers to point at;
245
+ * - `start-dev-server.sh` only when a dev-server command resolved: a project without one has no
246
+ * server to start, and writing the wrapper anyway would put a path in the permission profile that
247
+ * nothing runs;
248
+ * - `deploy.sh` only when the config carries `deploy.command`. `deploy` is an **adopter-added**
249
+ * section that `init` does not generate this release, so a fresh `init` selects no deploy wrapper;
250
+ * - **nothing at all for a key still holding the placeholder**, which is reported separately so the
251
+ * caller that writes files can warn about it while the caller that only lists them stays quiet;
252
+ * - **nothing at all for `commands.typecheck` answered `none`**, which is reported differently
253
+ * because the fix is not to fill it in — and only that key, because the same string on any other
254
+ * key is a command line this rule still writes a wrapper for.
255
+ *
256
+ * It is exported for exactly that second caller, which has to reach the same answer from a config
257
+ * alone and no write plan. A selection rule with two producers is precisely how a profile comes to
258
+ * allow-list a wrapper that was never written — an entry naming a file that does not exist — so the
259
+ * two answers are the same code rather than two statements of it.
260
+ */
261
+ export function selectWrapper(config, key) {
262
+ const configured = configuredCommand(config, key);
263
+ if (configured === undefined) {
264
+ return { selected: ALWAYS_SELECTED.includes(key), placeholder: false, answeredNone: false };
265
+ }
266
+ if (isPlaceholder(configured))
267
+ return { selected: false, placeholder: true, answeredNone: false, configured };
268
+ if (answersNone(key, configured))
269
+ return { selected: false, placeholder: false, answeredNone: true, configured };
270
+ return { selected: true, placeholder: false, answeredNone: false, configured };
271
+ }
272
+ /**
273
+ * What an adopter has to do for this wrapper to run something, as a message should say it.
274
+ *
275
+ * `deploy` gets its own sentence because the config key is never the missing piece there: the
276
+ * wrapper is selected only when `deploy.command` is already set, and no deploy command is ever
277
+ * detected, so naming `deploy.command` would name a key the adopter has set. The raw line goes in
278
+ * the wrapper.
279
+ */
280
+ function unresolvedFix(key, file) {
281
+ return key === 'deploy'
282
+ ? `put the deploy command line in ${file}`
283
+ : `set ${configKeyPath(key)} in harness.config.json`;
284
+ }
285
+ /**
286
+ * The body written when no command line resolved: it says what to fix and fails, rather than
287
+ * appearing to have run a check it never ran.
288
+ *
289
+ * This is the one body that exits before the template's verdict line, and deliberately: there is
290
+ * no verdict to report because nothing was verified, and the message is the diagnostic. Letting
291
+ * it fall through to `FAIL: <name>` would report a failed check where no check exists.
292
+ *
293
+ * It calls the template's own `harness_fail` rather than spelling out `echo … && exit 1`, and has
294
+ * to: every template appends `"$@"` to this line, so a compound would hand the caller's arguments
295
+ * to its last command — and `exit` given extra arguments refuses them, prints nothing but a shell
296
+ * error and does not exit, which is the fall-through this body exists to avoid. A single command
297
+ * that ignores the extra arguments is the shape that holds, and it is the shape the template's own
298
+ * comment above that line asks for.
299
+ */
300
+ function unresolvedBody(key, file) {
301
+ return `harness_fail "harness: ${unresolvedFix(key, file)}"`;
302
+ }
303
+ /**
304
+ * Render a wrapper template through {@link renderTemplate}.
305
+ *
306
+ * **`assertNoneSurvive` is deliberately left off here**, and this is the one generator for which
307
+ * that is true: the value substituted in is the adopter's own command line, which is allowed to
308
+ * contain `{{…}}`. The pre-substitution check that the shared renderer always performs is what
309
+ * covers the real fault — the template and this module disagreeing about the token set — without
310
+ * refusing a legal command.
311
+ */
312
+ function render(file, values) {
313
+ return renderTemplate(readTemplate(`${TEMPLATE_DIR}/${file}`), values, {
314
+ describe: `the wrapper template ${file}`,
315
+ });
316
+ }
317
+ /** The pre-start line for a wrapper with nothing to run before its command: a shell no-op. */
318
+ const NO_PRESTART = ':';
319
+ /**
320
+ * The `{{prestart}}` value for one wrapper — the line `start-dev-server.sh` runs to completion before
321
+ * it launches, or {@link NO_PRESTART} for every other wrapper and every dev server with nothing to
322
+ * build first.
323
+ *
324
+ * **It answers only for {@link resolveBody}'s second arm**, which the `body === rawCommands.devServer`
325
+ * test is: an adopter whose `commands.devServer` holds a raw line chose that line, and prefixing a
326
+ * build to somebody's own command is not this generator's call. Whether a *detected* line needs one is
327
+ * `detect/presets.ts`'s fact, asked through {@link devServerPrestart} rather than re-derived here.
328
+ *
329
+ * The line carries no `"$@"`, so {@link wrapperCommandLine} still reads the launch line back out as
330
+ * the wrapper's command — the property `doctor`'s `daemon-path` check depends on.
331
+ */
332
+ function prestartLine(file, body, rawCommands) {
333
+ if (file !== 'start-dev-server.sh' || body !== rawCommands.devServer)
334
+ return NO_PRESTART;
335
+ return devServerPrestart(rawCommands) ?? NO_PRESTART;
336
+ }
337
+ /**
338
+ * Resolve the command line a wrapper runs, in the one precedence that cannot produce a circular
339
+ * pair:
340
+ *
341
+ * 1. **A raw line already in the config wins** — an adopter who edited `commands.typecheck` to a
342
+ * real command line meant it, and that is the reading under which
343
+ * `templates/scripts/README.md`'s "command lines come from `commands.*`" holds. It wins and is
344
+ * **reported**: the profile allow-lists the wrapper this line was just inlined into, not the line
345
+ * itself, so the arm carries {@link wrappedKeyMismatchMessage} as its warning.
346
+ * 2. **Otherwise, when the configured value *is* this wrapper's own invocation** — the normal
347
+ * state after a first `init` — the body is stack detection's raw line. Inlining the
348
+ * self-reference instead would produce a script that runs itself forever, so
349
+ * {@link writeWrapperScripts} asserts against it explicitly rather than trusting this branch.
350
+ * 3. **When neither resolves**, the body says what to fix and exits non-zero — for `deploy`, which
351
+ * step 2 can never supply, that is the wrapper rather than the config key.
352
+ */
353
+ function resolveBody({ key, file }, configured, invocation, rawCommands) {
354
+ const detected = key === 'deploy' ? undefined : rawCommands[key];
355
+ // Precedence 1, and the moment Finding 65 describes: the raw line is inlined into the wrapper the
356
+ // profile allow-lists, so this is the one place that holds both halves. The warning is built from
357
+ // the strings this arm already has rather than by re-calling `wrappedKeyMismatch` — the same
358
+ // condition and the same two strings, read once, so the report cannot disagree with the body that
359
+ // was written. `deploy` reaches it too, and correctly: `deploy.command` takes the same wrapper
360
+ // form on its own object (`docs/cli.md` §5).
361
+ if (configured !== undefined && configured !== invocation) {
362
+ return { body: configured, warning: wrappedKeyMismatchMessage(key, { configured, invocation, file }) };
363
+ }
364
+ if (detected !== undefined && detected.trim() !== '' && !isPlaceholder(detected))
365
+ return { body: detected.trim() };
366
+ const fix = unresolvedFix(key, file);
367
+ return {
368
+ body: unresolvedBody(key, file),
369
+ unresolved: true,
370
+ warning: key === 'deploy'
371
+ ? `deploy.command holds ${file}'s own invocation and no deploy command is ever detected, so ${file} was written as a wrapper that fails with a message: ${fix}`
372
+ : `${configKeyPath(key)} could not be resolved to a command line, so ${key} was written as a wrapper that fails with a message: ${fix} and put the command line in the wrapper`,
373
+ };
374
+ }
375
+ /** Shell operators that end a command, so the token after one is a command name again. */
376
+ const COMMAND_SEPARATORS = new Set([';', '&&', '||', '|', '&', '(', '{', '!']);
377
+ /** Interpreters that run their first non-flag argument as a script file. */
378
+ const SCRIPT_INTERPRETERS = new Set(['bash', 'sh', 'zsh', 'dash', 'ksh']);
379
+ /** One shell word as a path: quotes and a `./` prefix name the same file, a trailing `;` does not. */
380
+ function pathToken(token) {
381
+ const bare = token.replace(/^['"]/, '').replace(/['"]$/, '').replace(/;+$/, '');
382
+ return bare.startsWith('./') ? bare.slice(2) : bare;
383
+ }
384
+ /**
385
+ * True when `body` **runs** the repo-relative `path` — as a bare command (`./deploy.sh`,
386
+ * `scripts/deploy.sh`) or as an interpreter's script argument (`bash scripts/deploy.sh`, `sh -x
387
+ * scripts/deploy.sh`) — and false when it merely mentions it, as an argument to something else.
388
+ *
389
+ * A substring test cannot tell the two apart, and gets the difference wrong in a supported
390
+ * configuration: with `scriptsDir: "."` the wrapper's path is its bare file name, so
391
+ * `bash scripts/typecheck.sh` — a *different* file — contains it. Only a token in command position
392
+ * counts.
393
+ */
394
+ function invokesScript(body, path) {
395
+ let position = 'command';
396
+ for (const raw of body.split(/\s+/)) {
397
+ if (raw === '')
398
+ continue;
399
+ const token = pathToken(raw);
400
+ if (COMMAND_SEPARATORS.has(token)) {
401
+ position = 'command';
402
+ continue;
403
+ }
404
+ if (position === 'argument')
405
+ continue;
406
+ if (position === 'interpreterArg' && token.startsWith('-'))
407
+ continue;
408
+ if (token === path)
409
+ return true;
410
+ position = position === 'command' && SCRIPT_INTERPRETERS.has(token) ? 'interpreterArg' : 'argument';
411
+ }
412
+ return false;
413
+ }
414
+ /**
415
+ * Enqueue the wrapper scripts for the configured `scriptsDir`: `ensure-dir` on the directory,
416
+ * then one `create-if-absent` write per wrapper {@link selectWrapper} selects — which is the rule,
417
+ * stated once there and applied identically by the permission profile's own fallback.
418
+ *
419
+ * Two unselected cases are the ones this caller handles differently, each warning rather than staying
420
+ * silent, and each in its own words:
421
+ *
422
+ * - **the placeholder** — the key stays visible in `commands.*`, where the config check and `doctor`
423
+ * both report it, and the command deliberately fails rather than running something that was never
424
+ * verified, so the warning says to fill the key in;
425
+ * - **`commands.typecheck` answered `none`** — an answer rather than an omission, so its warning
426
+ * states what was decided and what follows from it, and must not prescribe filling the key in,
427
+ * which would be an instruction to undo the answer. That branch is unreachable for any other key:
428
+ * {@link selectWrapper} never sets `answeredNone` for one.
429
+ *
430
+ * `create-if-absent` is the re-run contract for this artifact: the raw command line in each wrapper
431
+ * is the adopter's to correct, so a second `init` leaves an edited wrapper byte-identical — which
432
+ * also means a wrapper-body improvement shipped by this package reaches an already-wired repository
433
+ * only on an explicit `--force`. `--force` overwrites only after the write engine has taken a
434
+ * `.bak`.
435
+ */
436
+ export function writeWrapperScripts({ repoRoot, config, rawCommands, plan, }) {
437
+ const scriptsDir = resolvedScriptsDir(config);
438
+ const warnings = [];
439
+ const written = [];
440
+ plan.add({ path: join(repoRoot, scriptsDir), policy: 'ensure-dir', label: 'wrapper scripts directory' });
441
+ for (const script of WRAPPER_SCRIPTS) {
442
+ const { key, file } = script;
443
+ const { selected, placeholder, answeredNone, configured } = selectWrapper(config, key);
444
+ if (placeholder) {
445
+ warnings.push(`${configKeyPath(key)} still holds the placeholder init wrote, so no ${file} was written and none is allow-listed: set it in harness.config.json and re-run init`);
446
+ continue;
447
+ }
448
+ if (answeredNone) {
449
+ // What this run did, not what is on disk. An adopter who answers an already-filled key keeps
450
+ // the `${file}` an earlier run wrote — wrappers are `create-if-absent` and nothing here
451
+ // deletes — and its allow entries until a profile is regenerated, so a warning phrased as a
452
+ // state would assert the opposite of the record's stated residue.
453
+ warnings.push(`${configKeyPath(key)} states this repository has no such command, so this run wrote no ${file} and allow-listed none. A ${file} an earlier run wrote is left where it is, and the permission entries naming it are removed only by init --force, which regenerates the profile`);
454
+ continue;
455
+ }
456
+ if (!selected)
457
+ continue;
458
+ const invocation = wrapperInvocation(scriptsDir, file);
459
+ const { body, warning, unresolved } = resolveBody(script, configured, invocation, rawCommands);
460
+ // The assertion the precedence above exists to make impossible, stated anyway: a wrapper
461
+ // whose body runs the wrapper is an infinite recursion, and the failure mode of not catching
462
+ // it here is a run that hangs rather than one that reports anything. It is asked only of a
463
+ // body that runs something: the unresolved body runs nothing and quotes its own file name.
464
+ if (!unresolved && invokesScript(body, posixJoin(scriptsDir, file))) {
465
+ throw new HarnessError(`${configKeyPath(key)} resolved to a command line that runs ${file} itself (${body}), which would recurse forever: set it to the raw command line the wrapper should run`);
466
+ }
467
+ if (warning !== undefined)
468
+ warnings.push(warning);
469
+ plan.add({
470
+ path: join(repoRoot, scriptsDir, file),
471
+ policy: 'create-if-absent',
472
+ content: render(file, { command: body, name: key, prestart: prestartLine(file, body, rawCommands) }),
473
+ label: `wrapper script ${file}`,
474
+ mode: SCRIPT_MODE,
475
+ });
476
+ written.push({ key, file, invocation, command: body, unresolved: unresolved === true });
477
+ }
478
+ return { scriptsDir, written, warnings };
479
+ }
480
+ /** The argument forwarding every wrapper template appends to the command line it was given. */
481
+ const FORWARDED_ARGUMENTS = '"$@"';
482
+ /** The first token of {@link unresolvedBody}, and the whole of what identifies that body. */
483
+ const UNRESOLVED_HEAD = 'harness_fail';
484
+ /**
485
+ * The raw command line a wrapper runs, read back out of the file this module wrote.
486
+ *
487
+ * The rule keys on the templates' argument-forwarding convention — stated in `typecheck.sh`,
488
+ * `test.sh` and `deploy.sh`'s own comment (*"They attach to the *last* command of the line below, so
489
+ * keep that line one command rather than a compound"*) and followed by `start-dev-server.sh` — as the
490
+ * **last** line with no leading whitespace that does not start with `#` and carries
491
+ * {@link FORWARDED_ARGUMENTS}, truncated there and trimmed. Each exclusion buys one thing:
492
+ *
493
+ * - `#` drops the comment lines that quote `"$@"` while explaining the convention: every `"$@"` in the
494
+ * four wrapper templates other than the forwarding line is inside a comment;
495
+ * - **last** rather than first keeps a preamble an adopter added above the command line from being
496
+ * read as the command;
497
+ * - the indentation test is **defensive rather than template-driven**: no wrapper template renders an
498
+ * indented forwarding line, so it buys nothing today and exists so that an adopter-edited wrapper
499
+ * that forwards from inside a conditional or a function is reported `unrecognised` rather than
500
+ * mis-read.
501
+ *
502
+ * {@link unresolvedBody} is substituted into `{{command}}` like any other body, so that wrapper's
503
+ * rendered line *is* a line this rule matches. It is classified by its first token rather than
504
+ * excluded, because the distinction the caller needs is that it runs no command.
505
+ *
506
+ * **It lives beside the render it inverts**, for the reason `daemon/units.ts` gives for keeping
507
+ * `unitEnvValue` beside `environmentStanza`: a change to the templates and a change to this parse are
508
+ * then one edit in one file, and the round trip — the property this parse claims and cannot show on
509
+ * its own — has both sides in one module.
510
+ *
511
+ * The wrapper is the **adopter's** file from `init` on ({@link writeWrapperScripts}: *"the raw command
512
+ * line in each wrapper is the adopter's to correct"*), which is why an unreadable body is a reported
513
+ * state rather than a fallback. Its one caller is `doctor`'s `daemon-path` check, which must treat
514
+ * neither `unresolved` nor `unrecognised` as a binary the run needs.
515
+ */
516
+ export function wrapperCommandLine(text) {
517
+ // Reversed rather than indexed backwards, because `for…of` over the copy yields a `string` where
518
+ // an index into it yields `string | undefined` under `noUncheckedIndexedAccess`.
519
+ for (const line of text.split('\n').reverse()) {
520
+ if (/^\s/.test(line) || line.startsWith('#'))
521
+ continue;
522
+ const forwarded = line.indexOf(FORWARDED_ARGUMENTS);
523
+ if (forwarded === -1)
524
+ continue;
525
+ const command = line.slice(0, forwarded).trim();
526
+ return command.split(/\s+/)[0] === UNRESOLVED_HEAD ? { kind: 'unresolved' } : { kind: 'command', command };
527
+ }
528
+ return { kind: 'unrecognised' };
529
+ }
530
+ /**
531
+ * The wrapper file `key`'s configured value invokes, or `undefined` when that value is not this
532
+ * wrapper's invocation — unset, empty, still the placeholder, or a raw command line alike.
533
+ *
534
+ * The path is **composed** from {@link WRAPPER_SCRIPTS} and {@link wrapperInvocation} and the
535
+ * configured value compared to it byte-for-byte, never parsed back into a path: that is
536
+ * {@link invokedPath}'s standing prohibition, and on a key holding a command line this predicate is
537
+ * the exact complement of {@link wrappedKeyMismatch} — one answers *"the value is the wrapper"*, the
538
+ * other *"the value is a raw line"*, off the same comparison, so the two cannot come to disagree about
539
+ * what the wrapper form is.
540
+ *
541
+ * `path` is repo-relative and forward-slashed like every path in the config; joining it to a
542
+ * repository root is the caller's. Its one caller is `doctor`'s `daemon-path` check, which reads the
543
+ * file it names through {@link wrapperCommandLine}.
544
+ */
545
+ export function configuredWrapperFile(config, key) {
546
+ // Read from the table rather than from a second `.sh` literal. A `WrapperKey` is that table's own
547
+ // union, so the lookup cannot miss; `undefined` there is the same answer this function gives for
548
+ // "the value is not this wrapper's invocation", which keeps a predicate from carrying an error path.
549
+ const script = WRAPPER_SCRIPTS.find((entry) => entry.key === key);
550
+ if (script === undefined)
551
+ return undefined;
552
+ const scriptsDir = resolvedScriptsDir(config);
553
+ return configuredCommand(config, key) === wrapperInvocation(scriptsDir, script.file)
554
+ ? { file: script.file, path: wrapperPath(scriptsDir, script.file) }
555
+ : undefined;
556
+ }
557
+ //# sourceMappingURL=scripts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scripts.js","sourceRoot":"","sources":["../../src/generators/scripts.ts"],"names":[],"mappings":"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"}