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 @@
1
+ {"version":3,"file":"check.js","sourceRoot":"","sources":["../../src/config/check.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,177 @@
1
+ /**
2
+ * Loading and saving `harness.config.json` — the only place the CLI reads or writes that file.
3
+ *
4
+ * Two properties this module exists to hold:
5
+ *
6
+ * 1. **A read reports; it does not throw.** {@link loadConfig} answers with a list of problems —
7
+ * file absent, unparsable, or structurally wrong — so `doctor` can name everything wrong with a
8
+ * repository in one pass instead of stopping at the first fault. A caller that needs a usable
9
+ * config asks for one explicitly with {@link requireConfig}.
10
+ * 2. **A write is guarded.** Nothing here writes a config that `config/check.ts` reports an `error`
11
+ * on. `init` generating one and `config set` editing one both go through that guard, so the CLI
12
+ * cannot be the thing that leaves an adopter with a config the schema gate then rejects.
13
+ *
14
+ * Every write is enqueued on the caller's {@link WritePlan} rather than performed here, so
15
+ * `--dry-run` and `--force` keep meaning what the write engine says they mean and this module has
16
+ * no filesystem-mutating call of its own.
17
+ */
18
+ import { existsSync } from 'node:fs';
19
+ import { join } from 'node:path';
20
+ import { HarnessError } from '../core/errors.js';
21
+ import { readJsonFile } from '../core/json.js';
22
+ import { checkConfigShape, formatProblem, hasErrors } from './check.js';
23
+ import { CONFIG_FILENAME } from './model.js';
24
+ /** Absolute path of `harness.config.json` for a repository. */
25
+ export function configPath(repoRoot) {
26
+ return join(repoRoot, CONFIG_FILENAME);
27
+ }
28
+ /**
29
+ * Is there a config file here at all?
30
+ *
31
+ * Deliberately existence and nothing more — it does not parse, so a repository whose config has a
32
+ * syntax error answers `true` and is reported by {@link loadConfig} rather than being treated as
33
+ * unwired and generated over.
34
+ */
35
+ export function configExists(repoRoot) {
36
+ return existsSync(configPath(repoRoot));
37
+ }
38
+ /**
39
+ * Read, parse and structurally check the repository's config.
40
+ *
41
+ * Absence and unparsable JSON are reported as problems rather than thrown, for the reason in the
42
+ * module header. Unparsable is kept distinct from absent in the message, because the two have
43
+ * opposite fixes: one is "run `init`", the other is "your file has a syntax error and `init` will
44
+ * not overwrite it".
45
+ */
46
+ export function loadConfig(repoRoot) {
47
+ const path = configPath(repoRoot);
48
+ let parsed;
49
+ try {
50
+ parsed = readJsonFile(path);
51
+ }
52
+ catch (error) {
53
+ const detail = error instanceof Error ? error.message : String(error);
54
+ return { config: undefined, problems: [{ path: '', message: detail, severity: 'error' }], path };
55
+ }
56
+ if (parsed === undefined) {
57
+ return {
58
+ config: undefined,
59
+ problems: [
60
+ {
61
+ path: '',
62
+ message: `${CONFIG_FILENAME} not found at ${path}: this repository is not wired yet — run \`npx autonomous-sdlc-harness init\``,
63
+ severity: 'error',
64
+ },
65
+ ],
66
+ path,
67
+ };
68
+ }
69
+ const problems = checkConfigShape(parsed);
70
+ const usable = typeof parsed === 'object' && parsed !== null && !Array.isArray(parsed);
71
+ return { config: usable ? parsed : undefined, problems, path };
72
+ }
73
+ /**
74
+ * The parsed config and its problems, or a refusal when **nothing parsed** — `config list`'s read.
75
+ *
76
+ * A shape error is returned rather than refused, because the configurations most in need of being
77
+ * printed are the ones carrying one. Absent, unparsable or not a JSON object is still a refusal:
78
+ * there is no file "as it stands" to show.
79
+ */
80
+ export function readParsedConfig(repoRoot) {
81
+ const loaded = loadConfig(repoRoot);
82
+ if (loaded.config === undefined) {
83
+ throw new HarnessError(refusal(`cannot read ${CONFIG_FILENAME}`, loaded.problems));
84
+ }
85
+ return { ...loaded, config: loaded.config };
86
+ }
87
+ /**
88
+ * The config, or a refusal naming every problem at once.
89
+ *
90
+ * For the commands that cannot do their job without a **valid** config — `config get`, `daemon`.
91
+ * The refusal is input-side: a file already carrying an `error` problem is refused before the
92
+ * caller sees a value. `doctor` deliberately does **not** use this: reporting is its job, so it
93
+ * reads {@link loadConfig} and prints what it found, and `config list` reads
94
+ * {@link readParsedConfig} for the same reason.
95
+ */
96
+ export function requireConfig(repoRoot) {
97
+ const loaded = readParsedConfig(repoRoot);
98
+ if (hasErrors(loaded.problems)) {
99
+ throw new HarnessError(refusal(`cannot read ${CONFIG_FILENAME}`, loaded.problems));
100
+ }
101
+ return loaded.config;
102
+ }
103
+ /**
104
+ * Enqueue the write of a freshly generated config — `init`'s writer.
105
+ *
106
+ * `create-if-absent`: the adopter owns and edits this file after `init`, and there is no private
107
+ * second copy to fall back on, so a re-run must never rewrite it (`docs/config.md` §1, and the
108
+ * per-artifact table in `core/writer.ts`). `options.forceOverride` fixes the enqueued request's
109
+ * overwrite decision whatever the run's `--force` says, which is how this one artifact stands
110
+ * outside that flag: `'never'` for an ordinary `init`, so a `--force` run keeps the adopter's
111
+ * config, and `'always'` for `init --reset-config`, so the start-over path rebuilds it after a
112
+ * `.bak` on a run with no `--force`. Both are `generators/harnessConfig.ts`'s to set — it is the
113
+ * sole caller — and omitting the option leaves the run's flag deciding, exactly as it did before
114
+ * this parameter existed.
115
+ *
116
+ * The guard refuses on an `error` problem only — a `warning` is expected here, since a generated
117
+ * config legitimately carries an undetected command's placeholder for the adopter to replace.
118
+ */
119
+ export function saveConfig(repoRoot, config, plan, options) {
120
+ const problems = checkConfigShape(config);
121
+ if (hasErrors(problems)) {
122
+ throw new HarnessError(refusal(`refusing to write a malformed ${CONFIG_FILENAME}`, problems));
123
+ }
124
+ const path = configPath(repoRoot);
125
+ plan.add({
126
+ path,
127
+ policy: 'create-if-absent',
128
+ content: asJson(config),
129
+ label: CONFIG_FILENAME,
130
+ ...(options?.forceOverride === undefined ? {} : { forceOverride: options.forceOverride }),
131
+ });
132
+ return path;
133
+ }
134
+ /**
135
+ * Re-read the config, apply an edit, re-check the result and enqueue the write — `config set`.
136
+ *
137
+ * Re-reading rather than taking a caller-held object is the point: the file on disk is the truth,
138
+ * and an edit computed against a stale copy would silently discard whatever changed since. The
139
+ * mutator is handed a **private deep copy**, so a refused update leaves nothing half-applied.
140
+ *
141
+ * The write is enqueued as `create-if-absent`, which is the engine's only content-replacing
142
+ * policy; `config set` is therefore the one command that applies its plan with `force: true`, and
143
+ * the engine writes a `.bak` sibling before replacing the file. That is deliberate for the single
144
+ * command whose job is to change a file the adopter owns — the previous values stay one file away.
145
+ */
146
+ export function updateConfig(repoRoot, mutate, plan) {
147
+ const loaded = loadConfig(repoRoot);
148
+ if (loaded.config === undefined || hasErrors(loaded.problems)) {
149
+ throw new HarnessError(refusal(`cannot update ${CONFIG_FILENAME}`, loaded.problems));
150
+ }
151
+ const updated = structuredClone(loaded.config);
152
+ mutate(updated);
153
+ const problems = checkConfigShape(updated);
154
+ if (hasErrors(problems)) {
155
+ throw new HarnessError(refusal(`refusing to write ${CONFIG_FILENAME}: the edit would make it invalid`, problems));
156
+ }
157
+ plan.add({ path: loaded.path, policy: 'create-if-absent', content: asJson(updated), label: CONFIG_FILENAME });
158
+ return { config: updated, problems, path: loaded.path };
159
+ }
160
+ /**
161
+ * The config as the JSON the write engine serializes.
162
+ *
163
+ * A cast rather than a conversion: `JSON.stringify` drops a key whose value is `undefined`, so an
164
+ * optional key left unset is absent from the file rather than written as `null`. Key order is the
165
+ * object's own — the generator that builds the config owns that order, and an edited config keeps
166
+ * whatever order the adopter's file had, so `config set` produces a one-line diff rather than a
167
+ * reordered file.
168
+ */
169
+ function asJson(config) {
170
+ return config;
171
+ }
172
+ /** `<headline>: <problem>; <problem>` — one message naming every problem, for a refusal. */
173
+ function refusal(headline, problems) {
174
+ const lines = problems.map(formatProblem);
175
+ return lines.length === 0 ? headline : `${headline}: ${lines.join('; ')}`;
176
+ }
177
+ //# sourceMappingURL=io.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"io.js","sourceRoot":"","sources":["../../src/config/io.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,406 @@
1
+ /**
2
+ * The typed in-memory model of `harness.config.json`, and the schema's own declared defaults.
3
+ *
4
+ * **The rule this module exists to enforce: this file mirrors `schemas/harness.config.schema.json`
5
+ * key for key and invents nothing.** The schema is authoritative — it is what
6
+ * `npm run validate:config` checks an adopter's file against — so a key here that is not there is
7
+ * a key no config may legally carry, and a default here that disagrees with the schema's `default`
8
+ * makes `init` generate a file whose values contradict its own documentation. Every field below
9
+ * carries the schema's description condensed to one line, so the type is readable without opening
10
+ * the schema, and every optional field is optional in the type for the same reason it is optional
11
+ * there.
12
+ *
13
+ * **Edit this file in the same change as any schema edit**, together with `config/check.ts` and
14
+ * `docs/config.md` §5's key reference — those four are one contract in four places.
15
+ *
16
+ * Paths: every string path in this model is **repo-relative** (`docs/config.md` §5), except
17
+ * `$schema`, which resolves relative to the config file's own location, and
18
+ * `parity.referenceImplPath`, which may be absolute. Both say so in their own doc comment.
19
+ */
20
+ /** The config file's name, at the adopting repository's root. */
21
+ export const CONFIG_FILENAME = 'harness.config.json';
22
+ /** The only format version this release recognises — the schema's `version` const. */
23
+ export const CONFIG_VERSION = 1;
24
+ /**
25
+ * The schema's declared defaults, mirrored so a generator seeds a config from one place.
26
+ *
27
+ * Every key the schema gives a `default` appears here, plus `version`, which it fixes as a const.
28
+ * A key with no default (`projectName`, `forge`, `agentEffort`, `pushEnvPath`, everything under
29
+ * `detection` — measured per repository rather than defaulted — everything under
30
+ * `qa` but `driver` and `portSeed`, `design.source`) is absent because the schema has no opinion
31
+ * about it, and inventing one here would be inventing configuration. `forge`, `design.source` and
32
+ * `agentEffort` are the deliberate cases rather than the incidental ones: the schema withholds
33
+ * `forge`'s default so an absent value reads as "not yet decided" rather than as a silent
34
+ * assumption of one platform, withholds `design.source`'s for that same reason
35
+ * ({@link DESIGN_SOURCES}), and withholds `agentEffort`'s because an absent value there is already
36
+ * resolved ({@link AGENT_EFFORT_LEVELS}). In every case a value here would be a value no generator
37
+ * writes.
38
+ *
39
+ * `as const` makes these literals, so a caller copies rather than aliases them —
40
+ * `[...DEFAULTS.protectedBranches]`, `{ ...DEFAULTS.phases }` — and no generator can mutate the
41
+ * defaults out from under the next one.
42
+ */
43
+ export const DEFAULTS = {
44
+ version: CONFIG_VERSION,
45
+ defaultBranch: 'main',
46
+ protectedBranches: ['main'],
47
+ stateDir: 'sdlc-harness/',
48
+ appDir: '.',
49
+ scriptsDir: 'scripts',
50
+ githooksDir: 'githooks',
51
+ agentModel: 'opus',
52
+ clientEnvPrefix: null,
53
+ phases: { qa: false, docs: false, parity: false },
54
+ qa: { driver: 'web-playwright', portSeed: 3001 },
55
+ };
56
+ /**
57
+ * The schema's `forge` `enum`, mirrored verbatim: the code-hosting platforms the flow knows.
58
+ *
59
+ * `none` is a value rather than the absence of one — it says work stays on branches and no pull
60
+ * request is opened, which is a decision. An **omitted** `forge` says the decision has not been
61
+ * made; that is why the schema gives this key no `default` and {@link DEFAULTS} carries none.
62
+ *
63
+ * Exported so the check that validates the key imports the set rather than restating it: a list
64
+ * spelled twice is a list that can disagree with the schema in one of its two copies.
65
+ */
66
+ export const FORGE_KINDS = ['github', 'gitlab', 'none'];
67
+ /**
68
+ * The schema's `agentEffort` `enum`, mirrored verbatim: the reasoning-effort levels the launch flag
69
+ * accepts.
70
+ *
71
+ * The schema gives this key no `default` and {@link DEFAULTS} carries none, for a different reason
72
+ * than {@link FORGE_KINDS}: an absent value is a *resolved* state rather than an undecided one — no
73
+ * effort flag reaches the launch line at all, so the runtime applies its own per-model default.
74
+ *
75
+ * Exported for the same reason as {@link FORGE_KINDS}: one list, imported, not restated.
76
+ */
77
+ export const AGENT_EFFORT_LEVELS = ['low', 'medium', 'high', 'xhigh', 'max'];
78
+ /**
79
+ * The schema's `stateDir` character-class `pattern`, mirrored verbatim.
80
+ *
81
+ * It is **not** sufficient on its own: the class admits `.` and `/` after position 0, so this
82
+ * alone accepts `sdlc/../.claude`, which resolves to a dot-directory at runtime. It is always
83
+ * checked together with {@link STATE_DIR_DOT_PATTERN} — the schema states the two as separate
84
+ * clauses for exactly this reason, and so does the check.
85
+ */
86
+ export const STATE_DIR_PATTERN = /^[A-Za-z0-9_][A-Za-z0-9._/-]*\/?$/;
87
+ /**
88
+ * The schema's `not` clause on `stateDir`, mirrored verbatim: a dot at the start of **any**
89
+ * segment, which covers `../`, `/./` and `/.hidden/` as well as a leading dot.
90
+ *
91
+ * A match is a rejection. The prohibition exists because the run-artifact tree has to be writable
92
+ * by an unattended run, and a dot-path is where a host reserves directories an unattended run may
93
+ * not write to — so a dot-named state directory does not fail loudly, it silently loses every
94
+ * artifact the run produced (`docs/config.md` §3).
95
+ */
96
+ export const STATE_DIR_DOT_PATTERN = /(^|\/)\./;
97
+ /**
98
+ * The schema's `detection.preset` `enum`, mirrored verbatim: the layer presets, in signal-table
99
+ * order.
100
+ *
101
+ * **This module owns the list**, and `detect/signals.ts`'s `PRESET_NAMES` re-exports it rather than
102
+ * declaring a second copy, so the schema's enum and the set `--preset` is validated against cannot
103
+ * disagree. Adding a preset means adding it here, to the schema's `detection.preset` enum, to
104
+ * `SIGNALS` in `detect/signals.ts` and to `presetLayers` in `detect/presets.ts`.
105
+ *
106
+ * A preset is a **layer profile**, not a build tool, which is why `jvm` is one name for both Maven
107
+ * and Gradle: the two share the `src/main/<java|kotlin>` source root and differ only in the runner,
108
+ * so a second preset would buy a second name and the same profile. The runner is chosen by the
109
+ * command family instead, which is selected independently of the preset.
110
+ *
111
+ * `dotnet` is one name for a .NET **backend and frontend** on the same argument taken one step
112
+ * further: the two share the build tool, the `*.sln` / `*.csproj` manifests and the `src/` source
113
+ * root, so the layer profile is identical. What would distinguish them is the optional-phase set —
114
+ * and phases come from `init`'s own flags (`generators/harnessConfig.ts`, `buildConfig`), not from
115
+ * the preset, so a split name would carry no behaviour at all.
116
+ *
117
+ * `apple-native` is one name for **iOS and macOS**, and for a SwiftPM package and an Xcode project
118
+ * alike, on that same argument: nothing a file-existence test can ask separates the platforms — the
119
+ * manifests, the `Sources/` root and the toolchain are the same — so a per-platform name would buy a
120
+ * second name and the same profile. Which of `swift` and `xcodebuild` answers is the command
121
+ * family's question, as it is for `jvm`.
122
+ *
123
+ * `rust-cargo` names the build tool because in Rust the two are the same thing: `Cargo.toml` is the
124
+ * only manifest, `cargo` the only toolchain, and `src/` the only source root, so there is no second
125
+ * runner for the preset to stay neutral about.
126
+ *
127
+ * `ruby-bundler` names its dependency tool on that same argument: `Gemfile` is the only manifest and
128
+ * `bundle` the only resolver, so there is no second runner to stay neutral about. Its profile is a
129
+ * source root — `app/` or `lib/`, whichever exists — rather than a Rails layer list, because
130
+ * naming a Rails application's `app/` sub-directories as layers would decide its architecture, and
131
+ * that is `/harness-analyze`'s. A Rails-shaped repository does not reach this preset at all: it
132
+ * matches `api-service:route-directory` on its `app/controllers`, keeps that profile, and gains
133
+ * the Bundler commands through the command family, which is selected independently of the preset.
134
+ * A repository whose root `package.json` declares a script the npm commands are derived from does
135
+ * not reach it either: a React Native tree's root `Gemfile` pins CocoaPods and fastlane rather than
136
+ * declaring a Ruby stack, so the row declines it and it keeps its npm lines.
137
+ *
138
+ * `php-composer` names its dependency tool for `ruby-bundler`'s reason: `composer.json` is the only
139
+ * manifest and `composer` the only resolver. Its profile is a source root — Laravel's `app/` or
140
+ * PSR-4's `src/`, whichever exists — and a Laravel-shaped repository does not reach it, matching
141
+ * `api-service:route-directory` on its `routes/` and gaining the Composer commands through the
142
+ * family.
143
+ *
144
+ * `cmake-cpp` names the build system for `rust-cargo`'s reason inverted: C++ has no single
145
+ * toolchain to name — the compiler, the test runner and the dependency source all vary — and
146
+ * `CMakeLists.txt` is the one file the ecosystem agrees on, so the build system is the only fixed
147
+ * thing about a C++ repository to name it after. Its profile is the `src/` source root where one
148
+ * exists, and **not** a second layer for `include/`: headers and sources are one implementation
149
+ * concern rather than two routing targets, so a second layer would buy a name no orchestrator
150
+ * would route work to differently. Its row is the **last** before the fallback, because a
151
+ * `CMakeLists.txt` is the manifest most likely to describe a sub-component of a repository whose
152
+ * own stack is something else — a native extension in a Python distribution, a `node-gyp` addon,
153
+ * a Rust FFI shim. Order settles the Python and Rust cases; the Node one is settled by a guard on
154
+ * the row itself, since Node has no row of its own to be caught by — a repository whose root
155
+ * `package.json` declares a script the npm commands are derived from is declined here.
156
+ *
157
+ * Exported for the same reason as {@link FORGE_KINDS}: one list, imported, not restated.
158
+ */
159
+ export const DETECTION_PRESET_NAMES = [
160
+ 'monorepo',
161
+ 'layered-clean-arch',
162
+ 'python-package',
163
+ 'api-service',
164
+ 'flutter',
165
+ 'android-gradle',
166
+ 'jvm',
167
+ 'dotnet',
168
+ 'apple-native',
169
+ 'rust-cargo',
170
+ 'ruby-bundler',
171
+ 'php-composer',
172
+ 'cmake-cpp',
173
+ 'flat',
174
+ ];
175
+ /**
176
+ * The preset the detection table's unconditional last row selects — the unrecognised-layout
177
+ * fallback, not a layout that was recognised as flat.
178
+ *
179
+ * Two readers: this module's enum mirror above, and `doctor`'s `layer-profile` check, which grades
180
+ * a recorded `detection.preset` of this value as a profile nobody has reviewed rather than as a
181
+ * decision. Named here so neither spells the string at the point of use.
182
+ */
183
+ export const FALLBACK_PRESET = 'flat';
184
+ /**
185
+ * The schema's `detection.review.verdict` `enum`, mirrored verbatim: what a layer-profile review
186
+ * concluded.
187
+ *
188
+ * All three clear `doctor`'s `layer-profile` check, because what that check grades is an
189
+ * **unreviewed** profile: `considered-no-change` is the target's own considered-and-declined and
190
+ * `proposed-and-refused` is the operator's, and a decline that leaves a trace is the point of
191
+ * recording it.
192
+ *
193
+ * Exported for the same reason as {@link FORGE_KINDS}: one list, imported, not restated.
194
+ */
195
+ export const LAYER_REVIEW_VERDICTS = ['applied', 'considered-no-change', 'proposed-and-refused'];
196
+ /**
197
+ * The schema's `layers.contains` `const`, mirrored verbatim: the `path` of the catch-all layer.
198
+ *
199
+ * The catch-all is the layer work matching no other layer's `path` is routed to. The schema
200
+ * requires **at least one** row carrying it — never exactly one, because draft-07 has no
201
+ * `maxContains`, so an upper bound is not expressible and none is claimed — and the routing table
202
+ * escalates its absence as a configuration gap mid-run, which is the expensive moment to find a
203
+ * one-line config mistake. The constraint is on `path`, not on a layer name.
204
+ *
205
+ * Named here so the check that enforces the clause compares against this constant instead of
206
+ * spelling the string at the point of use, where a bare `'.'` is indistinguishable from the other
207
+ * meanings that character carries in this model — `appDir`'s default, or a relative-path segment.
208
+ */
209
+ export const LAYER_CATCH_ALL_PATH = '.';
210
+ /** The schema's `layers[].name` pattern, mirrored verbatim. */
211
+ export const LAYER_NAME_PATTERN = /^[a-z][a-z0-9-]*$/;
212
+ /**
213
+ * The schema's `qa.driver` `enum`, mirrored verbatim: which variant of the interactive test agent
214
+ * the QA phase runs, and so how that agent reaches the application.
215
+ *
216
+ * `web-playwright` drives a browser directly; the two mobile values drive an installed app through
217
+ * a device runner. The browser variant is the schema's `default` and so the value in
218
+ * {@link DEFAULTS}, which means a project whose application is a mobile app has to set this key:
219
+ * leaving it out selects a driver that cannot reach the application at all.
220
+ *
221
+ * Exported for the same reason as {@link FORGE_KINDS}: one list, imported, not restated.
222
+ */
223
+ export const QA_DRIVERS = ['web-playwright', 'mobile-maestro', 'mobile-mcp'];
224
+ /**
225
+ * Which of {@link QA_DRIVERS} this release actually implements.
226
+ *
227
+ * **Not a schema key**: the schema declares the enum, this declares the release's own state, and it
228
+ * is the single owner of that state for the surfaces that **render the value list** — the three
229
+ * {@link qaDriverChoices} feeds. A `Record` keyed by the type rather than a list of the implemented
230
+ * values, so adding an enum value fails the build until its status is declared.
231
+ *
232
+ * **Implementing a driver is not one edit here.** Flipping a `false` to `true` re-renders those
233
+ * three surfaces and nothing else; every other statement of the fact is its own text and has to be
234
+ * swept in the same change. Derive that set by grepping
235
+ * `declared-not-implemented|declared but not implemented|not implemented in this release` over
236
+ * `docs README.md ARCHITECTURE.md cli plugin schemas examples`. Load-bearing rather than prose among
237
+ * its hits: the schema's `qa.driver` `description` and `config/check.ts`'s explanation of the same
238
+ * key, that driver's `plugin/agents/qa-tester-mobile-*.md` stub and the driver gate in
239
+ * `plugin/agents/qa-tester.md` that routes to it, the browser-wiring gates in
240
+ * `generators/repoRoot.ts` and `generators/permissionProfile.ts`, `doctor`'s mobile-driver pass text
241
+ * in `doctor/checks.ts`, `settleQaDriver`'s warning in `generators/harnessConfig.ts`, `docs/cli.md`
242
+ * §2 and §6, `ARCHITECTURE.md` §10, and the generated-file preambles in
243
+ * `templates/claude/settings.autonomous.qa.json` and `templates/repo/README.md`.
244
+ */
245
+ export const QA_DRIVER_IMPLEMENTED = {
246
+ 'web-playwright': true,
247
+ 'mobile-maestro': false,
248
+ 'mobile-mcp': false,
249
+ };
250
+ /**
251
+ * The enum rendered for a reader **choosing** a value: schema order, each unimplemented driver
252
+ * suffixed ` [not implemented]`, joined with `, `.
253
+ *
254
+ * Its readers are the three places a value is offered or rejected rather than already chosen —
255
+ * `init`'s driver question, the `--qa-driver` refusal (both in `commands/init.ts`) and
256
+ * `resolveQaDriver`'s fallback warning — so none of them can disagree with the others about which
257
+ * values work. Data and a join, per this module's no-import rule.
258
+ */
259
+ export function qaDriverChoices() {
260
+ const choices = QA_DRIVERS.map((driver) => QA_DRIVER_IMPLEMENTED[driver] ? driver : `${driver} [not implemented]`);
261
+ return choices.join(', ');
262
+ }
263
+ /**
264
+ * The schema's `design.source` `enum`, mirrored verbatim: the design tools that can hold a
265
+ * project's design source of truth.
266
+ *
267
+ * `none` is a value rather than the absence of one — it says the project has no design source of
268
+ * truth at all, which is a decision. An **omitted** `design.source` says the decision has not been
269
+ * made; that is why the schema gives this key no `default` and {@link DEFAULTS} carries none.
270
+ *
271
+ * Exported for the same reason as {@link FORGE_KINDS}: one list, imported, not restated. Its one
272
+ * consumer is the `checkEnum` call that validates the key in `config/check.ts`.
273
+ */
274
+ export const DESIGN_SOURCES = ['figma', 'penpot', 'none'];
275
+ /**
276
+ * The one lookup from a typed-in string to a {@link HarnessQaDriver}: `--qa-driver`'s parse-time
277
+ * check and the config generator's check of an answer given at a prompt both go through it, so a
278
+ * value is judged on the same terms wherever it was typed.
279
+ *
280
+ * **Total rather than throwing**, unlike the flag parsers elsewhere in the CLI. This module mirrors
281
+ * the schema and imports nothing — no error vocabulary, no exit codes — and the two callers want
282
+ * different outcomes from the same rejection anyway: a refusal at the flag, and a fall back to the
283
+ * default at the prompt.
284
+ */
285
+ export function asQaDriver(value) {
286
+ return QA_DRIVERS.find((driver) => driver === value);
287
+ }
288
+ /**
289
+ * Does this config call for the browser wiring — the repository's `.mcp.json` block and the
290
+ * permission profile's interactive-test fragment?
291
+ *
292
+ * **Declared once, here, because the two generators that read it enforce each other.** The profile
293
+ * fragment names the servers a run starts and `.mcp.json` declares them; a copy of this predicate
294
+ * in one generator that drifted from the other would leave `enabledMcpjsonServers` starting a server
295
+ * nothing declares, and an un-loaded tool stalls an unattended run rather than failing it. Their
296
+ * *templates* are checked against each other at generation time (`generators/repoRoot.ts`); nothing
297
+ * checks two spellings of the *config* question, so there is only ever one.
298
+ *
299
+ * Both conditions are needed. The phase must be on — an adopter who never runs it should pay neither
300
+ * the browser tool schemas in every session's context nor a launched browser process — and the driver
301
+ * must be the browser one: the two mobile variants of the interactive test agent ship
302
+ * declared-not-implemented with built-ins-only tool allowlists, so for them a declared server is
303
+ * wiring nothing can ever start.
304
+ *
305
+ * The `?? DEFAULTS.qa.driver` is load-bearing rather than defensive: a hand-edited config may carry
306
+ * `phases.qa` with no `qa.driver`, and the schema's default for that key is the browser driver.
307
+ */
308
+ export function browserWiringApplies(config) {
309
+ if (config.phases?.qa !== true)
310
+ return false;
311
+ return (config.qa?.driver ?? DEFAULTS.qa.driver) === 'web-playwright';
312
+ }
313
+ /** The schema's `qa.portSeed` bounds, mirrored verbatim. */
314
+ export const PORT_SEED_MIN = 1024;
315
+ export const PORT_SEED_MAX = 65535;
316
+ /**
317
+ * The marker `init` embeds in a `commands.*` value that stack detection could not fill in.
318
+ *
319
+ * It is defined here, next to the model, because several sides must agree on one string: the
320
+ * generator that writes it, and everything that later asks whether an adopter has replaced it —
321
+ * `config/check.ts`'s warning, the wrapper generator's "write no wrapper for this key", the
322
+ * permission profile's "allow-list no wrapper that was not written". None of them formats or
323
+ * matches the string itself: they go through {@link placeholderCommand} and {@link isPlaceholder},
324
+ * which are the constant's only writer and its only reader.
325
+ */
326
+ export const COMMAND_PLACEHOLDER_MARKER = 'configure this';
327
+ /**
328
+ * The placeholder value written for a command the detector could not determine — a legal non-empty
329
+ * string, so the generated file still passes the schema, that is obviously unfinished to a reader
330
+ * and detectable by {@link isPlaceholder}.
331
+ */
332
+ export function placeholderCommand(key) {
333
+ return `<${COMMAND_PLACEHOLDER_MARKER}: set commands.${key}>`;
334
+ }
335
+ /**
336
+ * Is this configured command line still the marker `init` wrote for a command it could not detect?
337
+ *
338
+ * The one reader of {@link COMMAND_PLACEHOLDER_MARKER}, paired with {@link placeholderCommand} as
339
+ * its one writer. It is a **containment** test rather than a comparison against
340
+ * {@link placeholderCommand}'s exact output, so a value an adopter half-edited — the key changed,
341
+ * the marker left in place — still reads as unfinished rather than as a real command line that
342
+ * would be written into a wrapper and run.
343
+ */
344
+ export function isPlaceholder(value) {
345
+ return value.includes(COMMAND_PLACEHOLDER_MARKER);
346
+ }
347
+ /**
348
+ * The literal an adopter writes into `commands.typecheck` to say **this repository has no type
349
+ * check** — an answer, not an unanswered key (`docs/typecheck-key-decision.md` §7, option (b)).
350
+ *
351
+ * Beside {@link COMMAND_PLACEHOLDER_MARKER} because the module's two marker strings are the same
352
+ * kind of thing: one string several sides must agree on, spelled here and nowhere else. It is
353
+ * **published** — the schema's `description`, {@link HarnessCommands}'s field comment and
354
+ * `docs/config.md` §5's key reference all carry it — because an adopter has to type it exactly.
355
+ *
356
+ * It has no writer. `init` never writes it (§5 dimension 5: `init` must not assert on the adopter's
357
+ * behalf a claim detection did not establish), so a `noneCommand()` helper would exist only to
358
+ * invite one.
359
+ */
360
+ export const COMMAND_NONE_SENTINEL = '<none>';
361
+ /**
362
+ * Is this configured command line the {@link COMMAND_NONE_SENTINEL}?
363
+ *
364
+ * **Exact, case-sensitive, on the trimmed value whole** — deliberately not
365
+ * {@link isPlaceholder}'s containment test. A real command line that happened to contain the
366
+ * sentinel's text would read as *answered: none* under containment and silently disable the key;
367
+ * the placeholder can afford containment because its marker is a phrase no command line carries,
368
+ * and because a half-edited placeholder should still read as unfinished.
369
+ *
370
+ * The sides that must agree on this answer: `config/check.ts`'s grading of the key, the wrapper
371
+ * generator's "write no wrapper for this key", `doctor`'s two command checks and `init`'s command
372
+ * report.
373
+ *
374
+ * **Value shape only.** Every consumer outside `config/check.ts` calls {@link answersNone} instead,
375
+ * which adds the key gate.
376
+ */
377
+ export function isNoneSentinel(value) {
378
+ return value.trim() === COMMAND_NONE_SENTINEL;
379
+ }
380
+ /**
381
+ * The one command key {@link COMMAND_NONE_SENTINEL} is recognised on.
382
+ *
383
+ * The ratified decision widens the meaning of `commands.typecheck`; it assesses nothing about the
384
+ * other command keys, and reading the sentinel on `commands.test` would silently turn off the test
385
+ * gate.
386
+ */
387
+ export const NONE_SENTINEL_KEY = 'typecheck';
388
+ /**
389
+ * Does this key hold the answered-`none` state — the **key-gated reader every consumer uses**?
390
+ *
391
+ * `key` is the **bare** command key (`typecheck`, `test`, `devServer`, `build`, `depInstall`),
392
+ * never a `commands.`-prefixed key path: every call site walks the command keys and already holds
393
+ * the bare name.
394
+ *
395
+ * The gate lives here so the "recognised on `commands.typecheck` only" rule has one statement
396
+ * rather than one per consumer. A value-shape-only check at a consumer would recognise the sentinel
397
+ * on `commands.test` too and silently withdraw the test gate's wrapper, its permission entry and
398
+ * its mismatch report — contradicting the warning `config/check.ts` prints on that same key.
399
+ *
400
+ * `config/check.ts` is the deliberate sole caller of the ungated {@link isNoneSentinel}, because
401
+ * its job is precisely to say something different on the other keys.
402
+ */
403
+ export function answersNone(key, value) {
404
+ return key === NONE_SENTINEL_KEY && typeof value === 'string' && isNoneSentinel(value);
405
+ }
406
+ //# sourceMappingURL=model.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model.js","sourceRoot":"","sources":["../../src/config/model.ts"],"names":[],"mappings":"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"}