cohorte 2.10.1 → 3.0.0-dev.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 (211) hide show
  1. package/README.md +7 -0
  2. package/assets/manifest.json +193 -0
  3. package/assets/migrations/config/README.md +12 -0
  4. package/assets/migrations/state/0001_init.sql +154 -0
  5. package/assets/prompts/README.md +11 -0
  6. package/assets/prompts/agents/fixer.md +7 -0
  7. package/assets/prompts/agents/implementer.md +12 -0
  8. package/assets/prompts/agents/reviewer.md +8 -0
  9. package/assets/prompts/agents/security-reviewer.md +7 -0
  10. package/assets/prompts/phases/build.md +5 -0
  11. package/assets/prompts/phases/review.md +5 -0
  12. package/assets/prompts/phases/test.md +5 -0
  13. package/assets/prompts/system.md +11 -0
  14. package/assets/schemas/agent-output.schema.json +225 -0
  15. package/assets/schemas/auth-status.schema.json +87 -0
  16. package/assets/schemas/command-result.schema.json +192 -0
  17. package/assets/schemas/commands.schema.json +952 -0
  18. package/assets/schemas/config.schema.json +2259 -0
  19. package/assets/schemas/doctor-report.schema.json +104 -0
  20. package/assets/schemas/events.schema.json +8514 -0
  21. package/assets/schemas/fake-script.schema.json +549 -0
  22. package/assets/schemas/inspect.schema.json +3133 -0
  23. package/assets/schemas/manifest.schema.json +79 -0
  24. package/assets/schemas/ownership.schema.json +52 -0
  25. package/assets/schemas/policy-verdict.schema.json +282 -0
  26. package/assets/schemas/project-model.schema.json +783 -0
  27. package/assets/schemas/project-status.schema.json +217 -0
  28. package/assets/schemas/reconcile-plan.schema.json +155 -0
  29. package/assets/schemas/run-diff.schema.json +177 -0
  30. package/assets/schemas/run-snapshot-manifest.schema.json +2104 -0
  31. package/assets/schemas/run-state.schema.json +1755 -0
  32. package/assets/schemas/runtime-capabilities.schema.json +1545 -0
  33. package/assets/schemas/sandbox-capabilities.schema.json +116 -0
  34. package/assets/schemas/skill.schema.json +87 -0
  35. package/assets/schemas/spec.schema.json +202 -0
  36. package/assets/schemas/tool-catalogue.schema.json +655 -0
  37. package/assets/schemas/trust-record.schema.json +38 -0
  38. package/assets/skills/README.md +9 -0
  39. package/assets/skills/inspect-surface.md +4 -0
  40. package/dist/agent-host.mjs +50 -0
  41. package/dist/agent-host.mjs.map +1 -0
  42. package/dist/bundle-manifest.json +102 -0
  43. package/dist/chunks/__host-DgGPyco9.mjs +18 -0
  44. package/dist/chunks/__host-DgGPyco9.mjs.map +1 -0
  45. package/dist/chunks/approve-Cv135UqI.mjs +19 -0
  46. package/dist/chunks/approve-Cv135UqI.mjs.map +1 -0
  47. package/dist/chunks/auth-BT5oVp76.mjs +132 -0
  48. package/dist/chunks/auth-BT5oVp76.mjs.map +1 -0
  49. package/dist/chunks/auth-D8rCVY33.mjs +84 -0
  50. package/dist/chunks/auth-D8rCVY33.mjs.map +1 -0
  51. package/dist/chunks/brainstorm-CU10T1tm.mjs +7 -0
  52. package/dist/chunks/brainstorm-CU10T1tm.mjs.map +1 -0
  53. package/dist/chunks/cancel-KV_cpsqS.mjs +15 -0
  54. package/dist/chunks/cancel-KV_cpsqS.mjs.map +1 -0
  55. package/dist/chunks/canonical-C8UxeEmB.mjs +57 -0
  56. package/dist/chunks/canonical-C8UxeEmB.mjs.map +1 -0
  57. package/dist/chunks/catalogue-BvwSrM_j.mjs +1549 -0
  58. package/dist/chunks/catalogue-BvwSrM_j.mjs.map +1 -0
  59. package/dist/chunks/compose-Cr0hP0qm.mjs +7303 -0
  60. package/dist/chunks/compose-Cr0hP0qm.mjs.map +1 -0
  61. package/dist/chunks/config-DefHA2Lw.mjs +96 -0
  62. package/dist/chunks/config-DefHA2Lw.mjs.map +1 -0
  63. package/dist/chunks/contract-B0ra2-bm.mjs +295 -0
  64. package/dist/chunks/contract-B0ra2-bm.mjs.map +1 -0
  65. package/dist/chunks/contract-vYbwYr0Y.mjs +123 -0
  66. package/dist/chunks/contract-vYbwYr0Y.mjs.map +1 -0
  67. package/dist/chunks/deny-ClTxSvHJ.mjs +15 -0
  68. package/dist/chunks/deny-ClTxSvHJ.mjs.map +1 -0
  69. package/dist/chunks/diff-Qw0II0sj.mjs +101 -0
  70. package/dist/chunks/diff-Qw0II0sj.mjs.map +1 -0
  71. package/dist/chunks/discover-30Ciya_0.mjs +20 -0
  72. package/dist/chunks/discover-30Ciya_0.mjs.map +1 -0
  73. package/dist/chunks/doctor-DfCrKpfT.mjs +222 -0
  74. package/dist/chunks/doctor-DfCrKpfT.mjs.map +1 -0
  75. package/dist/chunks/fix-D4Tj8RVA.mjs +18 -0
  76. package/dist/chunks/fix-D4Tj8RVA.mjs.map +1 -0
  77. package/dist/chunks/gc-BBXlBF5w.mjs +161 -0
  78. package/dist/chunks/gc-BBXlBF5w.mjs.map +1 -0
  79. package/dist/chunks/init-Okz4mlhW.mjs +30 -0
  80. package/dist/chunks/init-Okz4mlhW.mjs.map +1 -0
  81. package/dist/chunks/inspect-Buby4cQD.mjs +22 -0
  82. package/dist/chunks/inspect-Buby4cQD.mjs.map +1 -0
  83. package/dist/chunks/logs-Giq5sUau.mjs +25 -0
  84. package/dist/chunks/logs-Giq5sUau.mjs.map +1 -0
  85. package/dist/chunks/migrate-DRoFUg53.mjs +19 -0
  86. package/dist/chunks/migrate-DRoFUg53.mjs.map +1 -0
  87. package/dist/chunks/models-Btp6X2YZ.mjs +24 -0
  88. package/dist/chunks/models-Btp6X2YZ.mjs.map +1 -0
  89. package/dist/chunks/pause-BASBfKLO.mjs +16 -0
  90. package/dist/chunks/pause-BASBfKLO.mjs.map +1 -0
  91. package/dist/chunks/policy-DUIgzF3W.mjs +139 -0
  92. package/dist/chunks/policy-DUIgzF3W.mjs.map +1 -0
  93. package/dist/chunks/providers-Dx78imKj.mjs +19 -0
  94. package/dist/chunks/providers-Dx78imKj.mjs.map +1 -0
  95. package/dist/chunks/reconcile-BfD785gd.mjs +26 -0
  96. package/dist/chunks/reconcile-BfD785gd.mjs.map +1 -0
  97. package/dist/chunks/render-DyZr5Lgi.mjs +53 -0
  98. package/dist/chunks/render-DyZr5Lgi.mjs.map +1 -0
  99. package/dist/chunks/resume-GJQRb2Eb.mjs +15 -0
  100. package/dist/chunks/resume-GJQRb2Eb.mjs.map +1 -0
  101. package/dist/chunks/retry-CLrUem1H.mjs +15 -0
  102. package/dist/chunks/retry-CLrUem1H.mjs.map +1 -0
  103. package/dist/chunks/review-BDdjb6kB.mjs +17 -0
  104. package/dist/chunks/review-BDdjb6kB.mjs.map +1 -0
  105. package/dist/chunks/run-CgTWYlcd.mjs +82 -0
  106. package/dist/chunks/run-CgTWYlcd.mjs.map +1 -0
  107. package/dist/chunks/run-tool-C3rAv4XF.mjs +26 -0
  108. package/dist/chunks/run-tool-C3rAv4XF.mjs.map +1 -0
  109. package/dist/chunks/schema-C9QbUW4H.mjs +578 -0
  110. package/dist/chunks/schema-C9QbUW4H.mjs.map +1 -0
  111. package/dist/chunks/send-BdnJ85Nz.mjs +19 -0
  112. package/dist/chunks/send-BdnJ85Nz.mjs.map +1 -0
  113. package/dist/chunks/ship-DTuLGoaJ.mjs +19 -0
  114. package/dist/chunks/ship-DTuLGoaJ.mjs.map +1 -0
  115. package/dist/chunks/shutdown-BM92Iyv2.mjs +15 -0
  116. package/dist/chunks/shutdown-BM92Iyv2.mjs.map +1 -0
  117. package/dist/chunks/skip-DZG5kpcH.mjs +18 -0
  118. package/dist/chunks/skip-DZG5kpcH.mjs.map +1 -0
  119. package/dist/chunks/spec-Bq0P3jVh.mjs +20 -0
  120. package/dist/chunks/spec-Bq0P3jVh.mjs.map +1 -0
  121. package/dist/chunks/src-CId6kMsY.mjs +1689 -0
  122. package/dist/chunks/src-CId6kMsY.mjs.map +1 -0
  123. package/dist/chunks/src-CfAOde7C.mjs +5403 -0
  124. package/dist/chunks/src-CfAOde7C.mjs.map +1 -0
  125. package/dist/chunks/src-Cu3TxNob.mjs +783 -0
  126. package/dist/chunks/src-Cu3TxNob.mjs.map +1 -0
  127. package/dist/chunks/src-DcU4IXMe.mjs +117 -0
  128. package/dist/chunks/src-DcU4IXMe.mjs.map +1 -0
  129. package/dist/chunks/src-JxawBQBn.mjs +446 -0
  130. package/dist/chunks/src-JxawBQBn.mjs.map +1 -0
  131. package/dist/chunks/src-s7YRvk0t.mjs +2116 -0
  132. package/dist/chunks/src-s7YRvk0t.mjs.map +1 -0
  133. package/dist/chunks/status-SMjiOMYy.mjs +29 -0
  134. package/dist/chunks/status-SMjiOMYy.mjs.map +1 -0
  135. package/dist/chunks/tail-BuhT-2PH.mjs +25 -0
  136. package/dist/chunks/tail-BuhT-2PH.mjs.map +1 -0
  137. package/dist/chunks/update-BXIppsbi.mjs +16 -0
  138. package/dist/chunks/update-BXIppsbi.mjs.map +1 -0
  139. package/dist/cli.mjs +175 -0
  140. package/dist/cli.mjs.map +1 -0
  141. package/package.json +17 -32
  142. package/CHANGELOG.md +0 -1461
  143. package/bin/cli.js +0 -817
  144. package/bin/report.js +0 -141
  145. package/core/adapter/render.js +0 -415
  146. package/core/agents/implementer.template.md +0 -142
  147. package/core/agents/profile-reader.md +0 -50
  148. package/core/agents/release.md +0 -58
  149. package/core/agents/review.md +0 -179
  150. package/core/commands/cohorte-align-ds.md +0 -33
  151. package/core/commands/cohorte-audit.md +0 -58
  152. package/core/commands/cohorte-brainstorm.md +0 -70
  153. package/core/commands/cohorte-build.md +0 -219
  154. package/core/commands/cohorte-doctor.md +0 -194
  155. package/core/commands/cohorte-fix.md +0 -80
  156. package/core/commands/cohorte-fleet.md +0 -103
  157. package/core/commands/cohorte-init-pipeline.md +0 -31
  158. package/core/commands/cohorte-intake.md +0 -92
  159. package/core/commands/cohorte-patch.md +0 -118
  160. package/core/commands/cohorte-refactor.md +0 -59
  161. package/core/commands/cohorte-retro.md +0 -85
  162. package/core/commands/cohorte-review.md +0 -270
  163. package/core/commands/cohorte-ship.md +0 -122
  164. package/core/commands/cohorte-spec.md +0 -101
  165. package/core/commands/cohorte-update-pipeline.md +0 -165
  166. package/core/hooks/gate.py +0 -588
  167. package/core/runtimes/claude.json +0 -74
  168. package/core/runtimes/codex.json +0 -85
  169. package/core/runtimes/cursor.json +0 -76
  170. package/core/runtimes/gemini.json +0 -76
  171. package/core/runtimes/opencode.json +0 -73
  172. package/core/templates/agent-handoff.md +0 -34
  173. package/core/templates/brainstorm-return.md +0 -36
  174. package/core/templates/decisions.template.md +0 -42
  175. package/core/templates/design-brief.md +0 -44
  176. package/core/templates/patch.template.md +0 -86
  177. package/core/templates/pr-body.md +0 -25
  178. package/core/templates/review-feedback.md +0 -38
  179. package/core/templates/spec.template.md +0 -87
  180. package/core/templates/steps/init-pipeline/01-detect-stack.md +0 -44
  181. package/core/templates/steps/init-pipeline/02-interview-gaps.md +0 -55
  182. package/core/templates/steps/init-pipeline/03-draft-profile.md +0 -10
  183. package/core/templates/steps/init-pipeline/04-write-render.md +0 -145
  184. package/core/templates/steps/init-pipeline/05-report.md +0 -12
  185. package/core/workflows/audit.js +0 -240
  186. package/core/workflows/loop.js +0 -641
  187. package/core/workflows/refactor.js +0 -276
  188. package/core/workflows/review.js +0 -456
  189. package/install.ps1 +0 -103
  190. package/install.sh +0 -114
  191. package/lib/doctor.js +0 -534
  192. package/lib/runtime.js +0 -139
  193. package/lib/versions.js +0 -149
  194. package/lib/yaml.js +0 -129
  195. package/profile/PIPELINE.template.md +0 -259
  196. package/profile/SCHEMA.md +0 -735
  197. package/profile/cohorte.config.template.yaml +0 -43
  198. package/scripts/assert-gate-hook.mjs +0 -75
  199. package/scripts/kanban-move.sh +0 -313
  200. package/scripts/metrics/collect.mjs +0 -531
  201. package/scripts/metrics/prices.json +0 -42
  202. package/scripts/new-feature.sh.template +0 -98
  203. package/scripts/preflight.sh +0 -124
  204. package/scripts/remove-feature.sh.template +0 -56
  205. package/scripts/test-adapter.mjs +0 -437
  206. package/scripts/test-gate.mjs +0 -443
  207. package/scripts/test-kanban.mjs +0 -304
  208. package/scripts/test-lib.mjs +0 -356
  209. package/scripts/test-metrics.mjs +0 -156
  210. package/scripts/test-workflows.mjs +0 -758
  211. package/scripts/validate-core.mjs +0 -325
@@ -0,0 +1,446 @@
1
+ import { n as sha256Hex, t as canonicalJson } from "./canonical-C8UxeEmB.mjs";
2
+ import "./src-Cu3TxNob.mjs";
3
+ import "./contract-vYbwYr0Y.mjs";
4
+ import { s as DEFAULT_CONFIG } from "./schema-C9QbUW4H.mjs";
5
+ import { mkdir, readFile, readdir, writeFile } from "node:fs/promises";
6
+ import { join, relative } from "node:path";
7
+ import { parse, stringify } from "yaml";
8
+ //#region ../../packages/project-model/src/desired/index.ts
9
+ function deriveDesiredState(input) {
10
+ const modelYaml = stringify(input.model);
11
+ const builtin = {
12
+ "manifest.yaml": stringify({
13
+ schemaVersion: 1,
14
+ cohorteVersion: input.cohorteVersion,
15
+ createdWith: input.cohorteVersion,
16
+ protocol: {
17
+ min: "3.0",
18
+ max: "3.x"
19
+ },
20
+ stateSchemaVersion: 1,
21
+ generated: [
22
+ {
23
+ path: "project.yaml",
24
+ templateId: "project-model/v1",
25
+ templateSha256: sha256Hex(modelYaml),
26
+ renderedSha256: sha256Hex(modelYaml)
27
+ },
28
+ {
29
+ path: ".gitignore",
30
+ templateId: "cohorte/gitignore/v1",
31
+ templateSha256: sha256Hex("state/\nruns/\n"),
32
+ renderedSha256: sha256Hex("state/\nruns/\n")
33
+ },
34
+ {
35
+ path: "generated/.gitkeep",
36
+ templateId: "cohorte/generated-dir/v1",
37
+ templateSha256: sha256Hex(""),
38
+ renderedSha256: sha256Hex("")
39
+ }
40
+ ]
41
+ }),
42
+ "project.yaml": modelYaml,
43
+ "config.yaml": "schemaVersion: 1\n",
44
+ "ownership.yaml": "surfaces: {}\n",
45
+ ".gitignore": "state/\nruns/\n",
46
+ "generated/.gitkeep": ""
47
+ };
48
+ const files = new Set(Object.keys(builtin));
49
+ for (const path of input.model.generatedArtifacts.value) files.add(path.replace(/^\.cohorte\//u, ""));
50
+ const stateFiles = [...files].sort().map((path) => ({
51
+ path,
52
+ class: path === "config.yaml" || path === "ownership.yaml" ? "human" : "generated",
53
+ sha256: sha256Hex(builtin[path] ?? canonicalJson({
54
+ path,
55
+ model: input.model,
56
+ config: input.config,
57
+ skills: input.skills
58
+ })),
59
+ ...input.skills[path] === void 0 ? {} : { templateId: path }
60
+ }));
61
+ return {
62
+ cohorteVersion: input.cohorteVersion,
63
+ files: stateFiles
64
+ };
65
+ }
66
+ //#endregion
67
+ //#region ../../packages/project-model/src/drift/index.ts
68
+ async function readActualState(root) {
69
+ const stateRoot = join(root, ".cohorte");
70
+ let manifest = null;
71
+ try {
72
+ manifest = parse(await readFile(join(stateRoot, "manifest.yaml"), "utf8"));
73
+ } catch {
74
+ return {
75
+ manifest: null,
76
+ files: []
77
+ };
78
+ }
79
+ const files = [];
80
+ const visit = async (dir) => {
81
+ try {
82
+ const entries = await readdir(dir, { withFileTypes: true });
83
+ for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {
84
+ if (entry.name === "state" || entry.name === "runs") continue;
85
+ const path = join(dir, entry.name);
86
+ if (entry.isDirectory()) await visit(path);
87
+ else if (entry.isFile()) {
88
+ const bytes = await readFile(path);
89
+ const relativePath = relative(stateRoot, path).split("\\").join("/");
90
+ const generated = relativePath === "manifest.yaml" ? {
91
+ path: relativePath,
92
+ templateId: "cohorte/manifest/v1",
93
+ renderedSha256: sha256Hex(bytes)
94
+ } : manifest?.generated.find((item) => item.path === relativePath);
95
+ files.push({
96
+ path: relativePath,
97
+ class: generated ? "generated" : "human",
98
+ sha256: sha256Hex(bytes),
99
+ ...generated?.templateId ? { templateId: generated.templateId } : {}
100
+ });
101
+ }
102
+ }
103
+ } catch {
104
+ return;
105
+ }
106
+ };
107
+ await visit(stateRoot);
108
+ return {
109
+ manifest,
110
+ files
111
+ };
112
+ }
113
+ function diffStates(desired, actual, clock) {
114
+ const desiredByPath = new Map(desired.files.map((file) => [file.path, file]));
115
+ const actualByPath = new Map(actual.files.map((file) => [file.path, file]));
116
+ const recorded = new Map((actual.manifest?.generated ?? []).map((file) => [file.path, file.renderedSha256]));
117
+ const entries = [.../* @__PURE__ */ new Set([...desiredByPath.keys(), ...actualByPath.keys()])].sort().flatMap((path) => {
118
+ const expected = desiredByPath.get(path);
119
+ const found = actualByPath.get(path);
120
+ const recordedSha256 = recorded.get(path);
121
+ if (!found && expected) return [{
122
+ target: path,
123
+ class: expected.class,
124
+ diff: "absent",
125
+ desiredSha256: expected.sha256,
126
+ ...recordedSha256 ? { recordedSha256 } : {},
127
+ detail: "desired file is absent"
128
+ }];
129
+ if (found && !expected) return [{
130
+ target: path,
131
+ class: found.class,
132
+ diff: found.class === "generated" ? "potential-deletion" : "unknown",
133
+ actualSha256: found.sha256,
134
+ ...recordedSha256 ? { recordedSha256 } : {},
135
+ detail: "file exists but is not desired"
136
+ }];
137
+ if (!found || !expected) throw new Error("unreachable drift entry");
138
+ if (found.sha256 === expected.sha256) return [];
139
+ if (found.class === "human") return [{
140
+ target: path,
141
+ class: found.class,
142
+ diff: "human-change",
143
+ desiredSha256: expected.sha256,
144
+ actualSha256: found.sha256,
145
+ ...recordedSha256 ? { recordedSha256 } : {},
146
+ detail: "content changed in a human-owned file"
147
+ }];
148
+ if (recordedSha256 === void 0 || found.sha256 === recordedSha256) return [{
149
+ target: path,
150
+ class: expected.class,
151
+ diff: "expected-change",
152
+ desiredSha256: expected.sha256,
153
+ actualSha256: found.sha256,
154
+ ...recordedSha256 ? { recordedSha256 } : {},
155
+ detail: "generated content differs from the previous render"
156
+ }];
157
+ return [{
158
+ target: path,
159
+ class: found.class,
160
+ diff: "conflict",
161
+ desiredSha256: expected.sha256,
162
+ actualSha256: found.sha256,
163
+ recordedSha256,
164
+ detail: "content changed since the recorded render"
165
+ }];
166
+ });
167
+ return {
168
+ schemaVersion: 1,
169
+ generatedAt: clock.now(),
170
+ entries
171
+ };
172
+ }
173
+ //#endregion
174
+ //#region ../../packages/project-model/src/init/index.ts
175
+ async function planInit(options) {
176
+ if (options.semantic) throw new Error("configuration/phase-not-available: semantic init is not available in V3.0");
177
+ const root = options.root;
178
+ const files = [
179
+ {
180
+ path: "project.yaml",
181
+ class: "generated",
182
+ content: stringify(options.model),
183
+ templateId: "project-model/v1"
184
+ },
185
+ {
186
+ path: "config.yaml",
187
+ class: "human",
188
+ content: "schemaVersion: 1\n"
189
+ },
190
+ {
191
+ path: "ownership.yaml",
192
+ class: "human",
193
+ content: "surfaces: {}\n"
194
+ },
195
+ {
196
+ path: ".gitignore",
197
+ class: "generated",
198
+ content: "state/\nruns/\n",
199
+ templateId: "cohorte/gitignore/v1"
200
+ },
201
+ {
202
+ path: "generated/.gitkeep",
203
+ class: "generated",
204
+ content: "",
205
+ templateId: "cohorte/generated-dir/v1"
206
+ }
207
+ ];
208
+ const initFiles = [];
209
+ for (const file of files) {
210
+ let exists = false;
211
+ try {
212
+ await readFile(join(root, ".cohorte", file.path));
213
+ exists = true;
214
+ } catch {}
215
+ const renderedSha256 = sha256Hex(file.content);
216
+ initFiles.push({
217
+ path: file.path,
218
+ action: exists ? "keep-existing" : "create",
219
+ class: file.class,
220
+ content: file.content,
221
+ ...file.templateId === void 0 ? {} : { templateId: file.templateId },
222
+ ...file.class === "generated" ? {
223
+ templateSha256: renderedSha256,
224
+ renderedSha256
225
+ } : {}
226
+ });
227
+ }
228
+ const generated = initFiles.filter((file) => file.class === "generated").map((file) => ({
229
+ path: file.path,
230
+ templateId: file.templateId ?? "builtin",
231
+ templateSha256: file.templateSha256 ?? sha256Hex(file.content),
232
+ renderedSha256: file.renderedSha256 ?? sha256Hex(file.content)
233
+ }));
234
+ return {
235
+ projectRoot: root,
236
+ model: options.model,
237
+ files: initFiles,
238
+ manifest: {
239
+ schemaVersion: 1,
240
+ cohorteVersion: options.cohorteVersion,
241
+ createdWith: options.cohorteVersion,
242
+ protocol: {
243
+ min: "3.0",
244
+ max: "3.x"
245
+ },
246
+ stateSchemaVersion: 1,
247
+ generated
248
+ },
249
+ warnings: []
250
+ };
251
+ }
252
+ async function applyInit(plan) {
253
+ await mkdir(join(plan.projectRoot, ".cohorte"), {
254
+ recursive: true,
255
+ mode: 448
256
+ });
257
+ const written = [];
258
+ const kept = [];
259
+ for (const file of plan.files) {
260
+ const target = join(plan.projectRoot, ".cohorte", file.path);
261
+ if (file.action === "keep-existing") {
262
+ kept.push(file.path);
263
+ continue;
264
+ }
265
+ await mkdir(join(target, ".."), {
266
+ recursive: true,
267
+ mode: 448
268
+ });
269
+ await writeFile(target, file.content, { mode: 384 });
270
+ written.push(file.path);
271
+ }
272
+ const manifestPath = join(plan.projectRoot, ".cohorte", "manifest.yaml");
273
+ try {
274
+ await readFile(manifestPath);
275
+ kept.push("manifest.yaml");
276
+ } catch {
277
+ await writeFile(manifestPath, stringify(plan.manifest), { mode: 384 });
278
+ written.push("manifest.yaml");
279
+ }
280
+ return {
281
+ written,
282
+ kept
283
+ };
284
+ }
285
+ //#endregion
286
+ //#region ../../packages/project-model/src/reconcile/index.ts
287
+ /** READ-ONLY. */
288
+ async function planReconcile(options) {
289
+ const model = await options.scan(options.root);
290
+ let stableModel = model;
291
+ try {
292
+ const generatedAt = parse(await readFile(join(options.root, ".cohorte", "project.yaml"), "utf8")).provenance?.generatedAt;
293
+ const stableGeneratedAt = generatedAt instanceof Date ? generatedAt.toISOString() : typeof generatedAt === "string" ? generatedAt : void 0;
294
+ if (stableGeneratedAt !== void 0) stableModel = {
295
+ ...model,
296
+ provenance: {
297
+ ...model.provenance,
298
+ generatedAt: stableGeneratedAt
299
+ }
300
+ };
301
+ } catch {}
302
+ const drift = diffStates(deriveDesiredState({
303
+ model: stableModel,
304
+ config: DEFAULT_CONFIG,
305
+ cohorteVersion: options.cohorteVersion,
306
+ skills: {}
307
+ }), await readActualState(options.root), options.clock);
308
+ const operations = drift.entries.map((entry) => {
309
+ return {
310
+ op: entry.diff === "absent" ? "create" : entry.diff === "expected-change" ? "replace" : entry.diff === "potential-deletion" ? "delete" : entry.diff === "unknown" ? "keep" : "ask",
311
+ target: entry.target,
312
+ diff: entry.diff,
313
+ reason: entry.detail
314
+ };
315
+ });
316
+ return {
317
+ schemaVersion: 1,
318
+ cohorteVersion: options.cohorteVersion,
319
+ generatedAt: drift.generatedAt,
320
+ drift,
321
+ operations,
322
+ conflicts: drift.entries.filter((entry) => entry.diff === "conflict").map((entry) => entry.target),
323
+ applyAvailable: false
324
+ };
325
+ }
326
+ //#endregion
327
+ //#region ../../packages/project-model/src/scan/index.ts
328
+ async function filesUnder(root) {
329
+ const found = [];
330
+ const visit = async (dir) => {
331
+ try {
332
+ const entries = await readdir(dir, { withFileTypes: true });
333
+ for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {
334
+ if (entry.name === ".git" || entry.name === "node_modules" || entry.name === ".cohorte" || entry.name === ".pi" || entry.name === ".build" || entry.name === "dist" || entry.name === "coverage") continue;
335
+ const path = join(dir, entry.name);
336
+ if (entry.isDirectory()) await visit(path);
337
+ else if (entry.isFile()) found.push(relative(root, path).split("\\").join("/"));
338
+ }
339
+ } catch {
340
+ return;
341
+ }
342
+ };
343
+ await visit(root);
344
+ return found.sort();
345
+ }
346
+ function field(value, detector, sources, className = "observed") {
347
+ return {
348
+ value,
349
+ class: className,
350
+ provenance: {
351
+ detector,
352
+ sources
353
+ }
354
+ };
355
+ }
356
+ async function scanRepository(root, options) {
357
+ const files = await filesUnder(root);
358
+ const packagePath = join(root, "package.json");
359
+ let pkg = {};
360
+ try {
361
+ pkg = JSON.parse(await readFile(packagePath, "utf8"));
362
+ } catch {}
363
+ const ext = /* @__PURE__ */ new Map([
364
+ [".ts", "typescript"],
365
+ [".tsx", "typescript"],
366
+ [".js", "javascript"],
367
+ [".jsx", "javascript"],
368
+ [".py", "python"],
369
+ [".go", "go"],
370
+ [".rs", "rust"],
371
+ [".java", "java"]
372
+ ]);
373
+ const languages = [...new Set(files.map((file) => ext.get(file.slice(file.lastIndexOf(".")))).filter((value) => value !== void 0))].sort();
374
+ const supportedLocks = [
375
+ "pnpm-lock.yaml",
376
+ "package-lock.json",
377
+ "yarn.lock",
378
+ "bun.lockb"
379
+ ];
380
+ const locks = files.filter((file) => supportedLocks.includes(file));
381
+ const lock = locks.length === 1 ? locks[0] : void 0;
382
+ const packageManager = lock === void 0 ? pkg.packageManager?.split("@")[0] ?? null : lock === "pnpm-lock.yaml" ? "pnpm" : lock === "package-lock.json" ? "npm" : lock === "yarn.lock" ? "yarn" : "bun";
383
+ const deps = {
384
+ ...pkg.dependencies ?? {},
385
+ ...pkg.devDependencies ?? {}
386
+ };
387
+ const frameworks = Object.keys(deps).filter((name) => /^(react|vue|angular|svelte|next|nuxt|express|nestjs|fastify|vite|vitest|jest|playwright)/i.test(name)).sort();
388
+ const scripts = pkg.scripts ?? {};
389
+ const commands = {};
390
+ for (const name of Object.keys(scripts).sort()) {
391
+ const command = scripts[name];
392
+ if (command !== void 0) commands[name] = field(command.split(/\s+/u), "package-json", ["package.json"]);
393
+ }
394
+ const testLocations = files.filter((file) => /(^|\/)(test|tests|__tests__)(\/|$)|\.(test|spec)\./u.test(file));
395
+ const surfaces = {};
396
+ const topLevel = [...new Set(files.map((file) => file.split("/")[0]).filter((name) => Boolean(name && !name.startsWith("."))))];
397
+ for (const name of topLevel.sort()) {
398
+ const paths = files.filter((file) => file === name || file.startsWith(`${name}/`));
399
+ if (paths.length) surfaces[name.replace(/[^A-Za-z0-9_.-]/g, "_")] = { paths: field([`${name}/**`], "workspace-layout", paths) };
400
+ }
401
+ const id = pkg.name?.replace(/^@[^/]+\//u, "") ?? (relative(process.cwd(), root).replace(/[^A-Za-z0-9_.-]/g, "_") || "project");
402
+ const unknowns = locks.length > 1 ? [{
403
+ id: "package-manager",
404
+ question: "more than one supported lockfile was detected; which package manager is authoritative?",
405
+ candidates: [...locks].sort(),
406
+ sources: [...locks].sort()
407
+ }] : [];
408
+ return {
409
+ schemaVersion: 1,
410
+ project: {
411
+ id: field(id, "package-json", ["package.json"], "human"),
412
+ root: field(root, "filesystem", [])
413
+ },
414
+ stack: {
415
+ languages: field(languages, "file-extensions", files),
416
+ packageManager: field(packageManager, "lockfile", lock ? [lock] : []),
417
+ frameworks: field(frameworks, "package-json", ["package.json"])
418
+ },
419
+ surfaces,
420
+ commands,
421
+ testStrategy: field({
422
+ runner: scripts.test ? scripts.test.split(/\s+/u)[0] ?? null : null,
423
+ locations: testLocations
424
+ }, "package-json", ["package.json"]),
425
+ deploymentHints: field(files.filter((file) => /(^|\/)(Dockerfile|Procfile|vercel\.json|fly\.toml)$/u.test(file)), "file-presence", files),
426
+ ownership: field({ codeowners: files.includes(".github/CODEOWNERS") ? ".github/CODEOWNERS" : null }, "file-presence", [".github/CODEOWNERS"]),
427
+ risks: packageManager === null ? [{
428
+ id: "missing-lockfile",
429
+ severity: "medium",
430
+ message: "no supported lockfile was detected",
431
+ sources: []
432
+ }] : [],
433
+ conventions: field(files.filter((file) => /(^|\/)(CONTRIBUTING|conventions)\.(md|yaml)$/iu.test(file)), "file-presence", files),
434
+ generatedArtifacts: field(["manifest.yaml", "project.yaml"], "manifest", [".cohorte/manifest.yaml"]),
435
+ unknowns,
436
+ provenance: {
437
+ generatedAt: options.clock.now(),
438
+ toolVersion: options.toolVersion,
439
+ analysis: "deterministic"
440
+ }
441
+ };
442
+ }
443
+ //#endregion
444
+ export { planInit as i, planReconcile as n, applyInit as r, scanRepository as t };
445
+
446
+ //# sourceMappingURL=src-JxawBQBn.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"src-JxawBQBn.mjs","names":[],"sources":["../../../../packages/project-model/src/desired/index.ts","../../../../packages/project-model/src/drift/index.ts","../../../../packages/project-model/src/init/index.ts","../../../../packages/project-model/src/reconcile/index.ts","../../../../packages/project-model/src/scan/index.ts"],"sourcesContent":["import { canonicalJson, type JsonValue, sha256Hex } from '@cohorte/base';\nimport type { CohorteConfig } from '@cohorte/config/schema';\nimport { stringify } from 'yaml';\nimport type { DesiredState, ProjectModel } from '../contract.ts';\n\nexport interface DesiredStateInput {\n model: ProjectModel;\n config: CohorteConfig;\n cohorteVersion: string;\n /** skill id -> version */\n skills: Readonly<Record<string, string>>;\n}\n\nexport function deriveDesiredState(input: DesiredStateInput): DesiredState {\n const modelYaml = stringify(input.model);\n const builtin: Record<string, string> = {\n 'manifest.yaml': stringify({\n schemaVersion: 1,\n cohorteVersion: input.cohorteVersion,\n createdWith: input.cohorteVersion,\n protocol: { min: '3.0', max: '3.x' },\n stateSchemaVersion: 1,\n generated: [\n {\n path: 'project.yaml',\n templateId: 'project-model/v1',\n templateSha256: sha256Hex(modelYaml),\n renderedSha256: sha256Hex(modelYaml),\n },\n {\n path: '.gitignore',\n templateId: 'cohorte/gitignore/v1',\n templateSha256: sha256Hex('state/\\nruns/\\n'),\n renderedSha256: sha256Hex('state/\\nruns/\\n'),\n },\n {\n path: 'generated/.gitkeep',\n templateId: 'cohorte/generated-dir/v1',\n templateSha256: sha256Hex(''),\n renderedSha256: sha256Hex(''),\n },\n ],\n }),\n 'project.yaml': modelYaml,\n 'config.yaml': 'schemaVersion: 1\\n',\n 'ownership.yaml': 'surfaces: {}\\n',\n '.gitignore': 'state/\\nruns/\\n',\n 'generated/.gitkeep': '',\n };\n const files = new Set(Object.keys(builtin));\n for (const path of input.model.generatedArtifacts.value) files.add(path.replace(/^\\.cohorte\\//u, ''));\n const stateFiles = [...files].sort().map((path) => ({\n path,\n class: path === 'config.yaml' || path === 'ownership.yaml' ? ('human' as const) : ('generated' as const),\n sha256: sha256Hex(\n builtin[path] ??\n canonicalJson({ path, model: input.model, config: input.config, skills: input.skills } as unknown as JsonValue),\n ),\n ...(input.skills[path] === undefined ? {} : { templateId: path }),\n }));\n return { cohorteVersion: input.cohorteVersion, files: stateFiles };\n}\n","import { readdir, readFile } from 'node:fs/promises';\nimport { join, relative } from 'node:path';\nimport { type Clock, sha256Hex } from '@cohorte/base';\nimport { parse } from 'yaml';\nimport type { ActualState, DesiredState, DriftEntry, DriftReport } from '../contract.ts';\n\nexport async function readActualState(root: string): Promise<ActualState> {\n const stateRoot = join(root, '.cohorte');\n let manifest = null;\n try {\n manifest = parse(await readFile(join(stateRoot, 'manifest.yaml'), 'utf8')) as ActualState['manifest'];\n } catch {\n return { manifest: null, files: [] };\n }\n const files: ActualState['files'] = [];\n const visit = async (dir: string): Promise<void> => {\n try {\n const entries = await readdir(dir, { withFileTypes: true });\n for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {\n if (entry.name === 'state' || entry.name === 'runs') continue;\n const path = join(dir, entry.name);\n if (entry.isDirectory()) await visit(path);\n else if (entry.isFile()) {\n const bytes = await readFile(path);\n const relativePath = relative(stateRoot, path).split('\\\\').join('/');\n const generated =\n relativePath === 'manifest.yaml'\n ? { path: relativePath, templateId: 'cohorte/manifest/v1', renderedSha256: sha256Hex(bytes) }\n : manifest?.generated.find((item) => item.path === relativePath);\n files.push({\n path: relativePath,\n class: generated ? 'generated' : 'human',\n sha256: sha256Hex(bytes),\n ...(generated?.templateId ? { templateId: generated.templateId } : {}),\n });\n }\n }\n } catch {\n return;\n }\n };\n await visit(stateRoot);\n return { manifest, files };\n}\n\nexport function diffStates(desired: DesiredState, actual: ActualState, clock: Clock): DriftReport {\n const desiredByPath = new Map(desired.files.map((file) => [file.path, file]));\n const actualByPath = new Map(actual.files.map((file) => [file.path, file]));\n const recorded = new Map((actual.manifest?.generated ?? []).map((file) => [file.path, file.renderedSha256]));\n const paths = [...new Set([...desiredByPath.keys(), ...actualByPath.keys()])].sort();\n const entries = paths.flatMap((path): DriftEntry[] => {\n const expected = desiredByPath.get(path);\n const found = actualByPath.get(path);\n const recordedSha256 = recorded.get(path);\n if (!found && expected)\n return [\n {\n target: path,\n class: expected.class,\n diff: 'absent' as const,\n desiredSha256: expected.sha256,\n ...(recordedSha256 ? { recordedSha256 } : {}),\n detail: 'desired file is absent',\n },\n ];\n if (found && !expected)\n return [\n {\n target: path,\n class: found.class,\n diff: found.class === 'generated' ? ('potential-deletion' as const) : ('unknown' as const),\n actualSha256: found.sha256,\n ...(recordedSha256 ? { recordedSha256 } : {}),\n detail: 'file exists but is not desired',\n },\n ];\n if (!found || !expected) throw new Error('unreachable drift entry');\n if (found.sha256 === expected.sha256) return [];\n if (found.class === 'human')\n return [\n {\n target: path,\n class: found.class,\n diff: 'human-change' as const,\n desiredSha256: expected.sha256,\n actualSha256: found.sha256,\n ...(recordedSha256 ? { recordedSha256 } : {}),\n detail: 'content changed in a human-owned file',\n },\n ];\n if (recordedSha256 === undefined || found.sha256 === recordedSha256)\n return [\n {\n target: path,\n class: expected.class,\n diff: 'expected-change' as const,\n desiredSha256: expected.sha256,\n actualSha256: found.sha256,\n ...(recordedSha256 ? { recordedSha256 } : {}),\n detail: 'generated content differs from the previous render',\n },\n ];\n return [\n {\n target: path,\n class: found.class,\n diff: 'conflict' as const,\n desiredSha256: expected.sha256,\n actualSha256: found.sha256,\n recordedSha256,\n detail: 'content changed since the recorded render',\n },\n ];\n });\n return { schemaVersion: 1, generatedAt: clock.now(), entries };\n}\n","import { mkdir, readFile, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { sha256Hex } from '@cohorte/base';\nimport { stringify } from 'yaml';\nimport type { InitPlan, ProjectModel } from '../contract.ts';\n\nexport interface PlanInitOptions {\n root: string;\n model: ProjectModel;\n cohorteVersion: string;\n /** refused in V3.0: `configuration/phase-not-available` */\n semantic?: boolean;\n}\n\nexport async function planInit(options: PlanInitOptions): Promise<InitPlan> {\n if (options.semantic) throw new Error('configuration/phase-not-available: semantic init is not available in V3.0');\n const root = options.root;\n const modelYaml = stringify(options.model);\n const files = [\n { path: 'project.yaml', class: 'generated' as const, content: modelYaml, templateId: 'project-model/v1' },\n { path: 'config.yaml', class: 'human' as const, content: 'schemaVersion: 1\\n' },\n { path: 'ownership.yaml', class: 'human' as const, content: 'surfaces: {}\\n' },\n {\n path: '.gitignore',\n class: 'generated' as const,\n content: 'state/\\nruns/\\n',\n templateId: 'cohorte/gitignore/v1',\n },\n {\n path: 'generated/.gitkeep',\n class: 'generated' as const,\n content: '',\n templateId: 'cohorte/generated-dir/v1',\n },\n ];\n const initFiles: InitPlan['files'] = [];\n for (const file of files) {\n let exists = false;\n try {\n await readFile(join(root, '.cohorte', file.path));\n exists = true;\n } catch {\n /* create */\n }\n const renderedSha256 = sha256Hex(file.content);\n initFiles.push({\n path: file.path,\n action: exists ? 'keep-existing' : 'create',\n class: file.class,\n content: file.content,\n ...(file.templateId === undefined ? {} : { templateId: file.templateId }),\n ...(file.class === 'generated' ? { templateSha256: renderedSha256, renderedSha256 } : {}),\n });\n }\n const generated = initFiles\n .filter((file) => file.class === 'generated')\n .map((file) => ({\n path: file.path,\n templateId: file.templateId ?? 'builtin',\n templateSha256: file.templateSha256 ?? sha256Hex(file.content),\n renderedSha256: file.renderedSha256 ?? sha256Hex(file.content),\n }));\n return {\n projectRoot: root,\n model: options.model,\n files: initFiles,\n manifest: {\n schemaVersion: 1,\n cohorteVersion: options.cohorteVersion,\n createdWith: options.cohorteVersion,\n protocol: { min: '3.0', max: '3.x' },\n stateSchemaVersion: 1,\n generated,\n },\n warnings: [],\n };\n}\n\nexport async function applyInit(plan: InitPlan): Promise<{ written: string[]; kept: string[] }> {\n await mkdir(join(plan.projectRoot, '.cohorte'), { recursive: true, mode: 0o700 });\n const written: string[] = [];\n const kept: string[] = [];\n for (const file of plan.files) {\n const target = join(plan.projectRoot, '.cohorte', file.path);\n if (file.action === 'keep-existing') {\n kept.push(file.path);\n continue;\n }\n await mkdir(join(target, '..'), { recursive: true, mode: 0o700 });\n await writeFile(target, file.content, { mode: 0o600 });\n written.push(file.path);\n }\n const manifestPath = join(plan.projectRoot, '.cohorte', 'manifest.yaml');\n try {\n await readFile(manifestPath);\n kept.push('manifest.yaml');\n } catch {\n await writeFile(manifestPath, stringify(plan.manifest), { mode: 0o600 });\n written.push('manifest.yaml');\n }\n return { written, kept };\n}\n","import { readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport type { Clock } from '@cohorte/base';\nimport { DEFAULT_CONFIG } from '@cohorte/config/schema';\nimport { parse } from 'yaml';\nimport type { ReconcilePlan, RepositoryScanner } from '../contract.ts';\nimport { deriveDesiredState } from '../desired/index.ts';\nimport { diffStates, readActualState } from '../drift/index.ts';\n\nexport interface PlanReconcileOptions {\n root: string;\n /** injected: this area never imports the scan area */\n scan: RepositoryScanner;\n cohorteVersion: string;\n clock: Clock;\n}\n\n/** READ-ONLY. */\nexport async function planReconcile(options: PlanReconcileOptions): Promise<ReconcilePlan> {\n const model = await options.scan(options.root);\n // `provenance.generatedAt` is metadata, not project content. Reuse the\n // previous generated timestamp so a read-only reconcile is stable; changed\n // model fields still alter the rendered project and manifest hashes.\n let stableModel = model;\n try {\n const actual = parse(await readFile(join(options.root, '.cohorte', 'project.yaml'), 'utf8')) as {\n provenance?: { generatedAt?: unknown };\n };\n const generatedAt = actual.provenance?.generatedAt;\n const stableGeneratedAt =\n generatedAt instanceof Date\n ? generatedAt.toISOString()\n : typeof generatedAt === 'string'\n ? generatedAt\n : undefined;\n if (stableGeneratedAt !== undefined) {\n stableModel = {\n ...model,\n provenance: {\n ...model.provenance,\n generatedAt: stableGeneratedAt as typeof model.provenance.generatedAt,\n },\n };\n }\n } catch {\n /* an uninitialised or malformed project is represented by the normal drift entries */\n }\n const desired = deriveDesiredState({\n model: stableModel,\n config: DEFAULT_CONFIG,\n cohorteVersion: options.cohorteVersion,\n skills: {},\n });\n const actual = await readActualState(options.root);\n const drift = diffStates(desired, actual, options.clock);\n const operations = drift.entries.map((entry) => {\n const op =\n entry.diff === 'absent'\n ? 'create'\n : entry.diff === 'expected-change'\n ? 'replace'\n : entry.diff === 'potential-deletion'\n ? 'delete'\n : entry.diff === 'unknown'\n ? 'keep'\n : 'ask';\n return { op, target: entry.target, diff: entry.diff, reason: entry.detail } as const;\n });\n return {\n schemaVersion: 1,\n cohorteVersion: options.cohorteVersion,\n generatedAt: drift.generatedAt,\n drift,\n operations,\n conflicts: drift.entries.filter((entry) => entry.diff === 'conflict').map((entry) => entry.target),\n applyAvailable: false,\n };\n}\n","// Deterministic repository scan: bounded filesystem observations, never guessed semantics.\n\nimport { readdir, readFile } from 'node:fs/promises';\nimport { join, relative } from 'node:path';\nimport type { Clock } from '@cohorte/base';\nimport type { ProjectModel } from '../contract.ts';\n\nexport interface ScanOptions {\n clock: Clock;\n /** stamped into `provenance.toolVersion` */\n toolVersion: string;\n}\n\nasync function filesUnder(root: string): Promise<string[]> {\n const found: string[] = [];\n const visit = async (dir: string): Promise<void> => {\n try {\n const entries = await readdir(dir, { withFileTypes: true });\n for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {\n if (\n entry.name === '.git' ||\n entry.name === 'node_modules' ||\n entry.name === '.cohorte' ||\n entry.name === '.pi' ||\n entry.name === '.build' ||\n entry.name === 'dist' ||\n entry.name === 'coverage'\n )\n continue;\n const path = join(dir, entry.name);\n if (entry.isDirectory()) await visit(path);\n else if (entry.isFile()) found.push(relative(root, path).split('\\\\').join('/'));\n }\n } catch {\n return;\n }\n };\n await visit(root);\n return found.sort();\n}\n\nfunction field<T>(\n value: T,\n detector: string,\n sources: string[],\n className: ProjectModel['project']['id']['class'] = 'observed',\n) {\n return { value, class: className, provenance: { detector, sources } };\n}\n\nexport async function scanRepository(root: string, options: ScanOptions): Promise<ProjectModel> {\n const files = await filesUnder(root);\n const packagePath = join(root, 'package.json');\n let pkg: {\n name?: string;\n packageManager?: string;\n scripts?: Record<string, string>;\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n } = {};\n try {\n pkg = JSON.parse(await readFile(packagePath, 'utf8')) as typeof pkg;\n } catch {\n /* absent or invalid package.json is an observation */\n }\n const ext = new Map<string, string>([\n ['.ts', 'typescript'],\n ['.tsx', 'typescript'],\n ['.js', 'javascript'],\n ['.jsx', 'javascript'],\n ['.py', 'python'],\n ['.go', 'go'],\n ['.rs', 'rust'],\n ['.java', 'java'],\n ]);\n const languages = [\n ...new Set(\n files\n .map((file) => ext.get(file.slice(file.lastIndexOf('.'))))\n .filter((value): value is string => value !== undefined),\n ),\n ].sort();\n const supportedLocks = ['pnpm-lock.yaml', 'package-lock.json', 'yarn.lock', 'bun.lockb'];\n const locks = files.filter((file) => supportedLocks.includes(file));\n const lock = locks.length === 1 ? locks[0] : undefined;\n const packageManager =\n lock === undefined\n ? (pkg.packageManager?.split('@')[0] ?? null)\n : lock === 'pnpm-lock.yaml'\n ? 'pnpm'\n : lock === 'package-lock.json'\n ? 'npm'\n : lock === 'yarn.lock'\n ? 'yarn'\n : 'bun';\n const deps = { ...(pkg.dependencies ?? {}), ...(pkg.devDependencies ?? {}) };\n const frameworks = Object.keys(deps)\n .filter((name) =>\n /^(react|vue|angular|svelte|next|nuxt|express|nestjs|fastify|vite|vitest|jest|playwright)/i.test(name),\n )\n .sort();\n const scripts = pkg.scripts ?? {};\n const commands: Record<string, ReturnType<typeof field<string[]>>> = {};\n for (const name of Object.keys(scripts).sort()) {\n const command = scripts[name];\n if (command !== undefined) commands[name] = field(command.split(/\\s+/u), 'package-json', ['package.json']);\n }\n const testLocations = files.filter((file) => /(^|\\/)(test|tests|__tests__)(\\/|$)|\\.(test|spec)\\./u.test(file));\n const surfaces: ProjectModel['surfaces'] = {};\n const topLevel: string[] = [\n ...new Set(\n files.map((file) => file.split('/')[0]).filter((name): name is string => Boolean(name && !name.startsWith('.'))),\n ),\n ];\n for (const name of topLevel.sort()) {\n const paths = files.filter((file) => file === name || file.startsWith(`${name}/`));\n if (paths.length)\n surfaces[name.replace(/[^A-Za-z0-9_.-]/g, '_')] = { paths: field([`${name}/**`], 'workspace-layout', paths) };\n }\n const id =\n pkg.name?.replace(/^@[^/]+\\//u, '') ??\n (relative(process.cwd(), root).replace(/[^A-Za-z0-9_.-]/g, '_') || 'project');\n const unknowns =\n locks.length > 1\n ? [\n {\n id: 'package-manager',\n question: 'more than one supported lockfile was detected; which package manager is authoritative?',\n candidates: [...locks].sort(),\n sources: [...locks].sort(),\n },\n ]\n : [];\n return {\n schemaVersion: 1,\n project: { id: field(id, 'package-json', ['package.json'], 'human'), root: field(root, 'filesystem', []) },\n stack: {\n languages: field(languages, 'file-extensions', files),\n packageManager: field(packageManager, 'lockfile', lock ? [lock] : []),\n frameworks: field(frameworks, 'package-json', ['package.json']),\n },\n surfaces,\n commands,\n testStrategy: field(\n { runner: scripts.test ? (scripts.test.split(/\\s+/u)[0] ?? null) : null, locations: testLocations },\n 'package-json',\n ['package.json'],\n ),\n deploymentHints: field(\n files.filter((file) => /(^|\\/)(Dockerfile|Procfile|vercel\\.json|fly\\.toml)$/u.test(file)),\n 'file-presence',\n files,\n ),\n ownership: field(\n { codeowners: files.includes('.github/CODEOWNERS') ? '.github/CODEOWNERS' : null },\n 'file-presence',\n ['.github/CODEOWNERS'],\n ),\n risks:\n packageManager === null\n ? [{ id: 'missing-lockfile', severity: 'medium', message: 'no supported lockfile was detected', sources: [] }]\n : [],\n conventions: field(\n files.filter((file) => /(^|\\/)(CONTRIBUTING|conventions)\\.(md|yaml)$/iu.test(file)),\n 'file-presence',\n files,\n ),\n generatedArtifacts: field(['manifest.yaml', 'project.yaml'], 'manifest', ['.cohorte/manifest.yaml']),\n unknowns,\n provenance: { generatedAt: options.clock.now(), toolVersion: options.toolVersion, analysis: 'deterministic' },\n };\n}\n"],"mappings":"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"}