@topogram/cli 0.3.63 → 0.3.65

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 (344) hide show
  1. package/package.json +1 -1
  2. package/src/adoption/plan/index.js +703 -0
  3. package/src/adoption/plan.d.ts +6 -0
  4. package/src/adoption/plan.js +12 -703
  5. package/src/adoption/reporting.d.ts +10 -0
  6. package/src/adoption/review-groups.d.ts +6 -0
  7. package/src/agent-brief.d.ts +3 -0
  8. package/src/agent-brief.js +495 -0
  9. package/src/agent-ops/query-builders/auth.js +375 -0
  10. package/src/agent-ops/query-builders/change-risk/change-plan.js +123 -0
  11. package/src/agent-ops/query-builders/change-risk/import-plan.js +49 -0
  12. package/src/agent-ops/query-builders/change-risk/maintained.js +286 -0
  13. package/src/agent-ops/query-builders/change-risk/review-packets.js +123 -0
  14. package/src/agent-ops/query-builders/change-risk/risk.js +189 -0
  15. package/src/agent-ops/query-builders/change-risk.js +25 -0
  16. package/src/agent-ops/query-builders/common.js +149 -0
  17. package/src/agent-ops/query-builders/maintained-risk.js +539 -0
  18. package/src/agent-ops/query-builders/maintained-shared.js +120 -0
  19. package/src/agent-ops/query-builders/multi-agent.js +547 -0
  20. package/src/agent-ops/query-builders/projection-impacts.js +514 -0
  21. package/src/agent-ops/query-builders/work-packets.js +417 -0
  22. package/src/agent-ops/query-builders/workflow-context-shared.js +300 -0
  23. package/src/agent-ops/query-builders/workflow-context.js +398 -0
  24. package/src/agent-ops/query-builders/workflow-presets-core.js +676 -0
  25. package/src/agent-ops/query-builders/workflow-presets.js +341 -0
  26. package/src/agent-ops/query-builders.d.ts +26 -0
  27. package/src/agent-ops/query-builders.js +42 -5021
  28. package/src/archive/archive.d.ts +2 -0
  29. package/src/archive/compact.d.ts +1 -0
  30. package/src/archive/unarchive.d.ts +1 -0
  31. package/src/catalog/constants.js +10 -0
  32. package/src/catalog/copy.js +60 -0
  33. package/src/catalog/diagnostics.js +15 -0
  34. package/src/catalog/entries.js +42 -0
  35. package/src/catalog/files.js +67 -0
  36. package/src/catalog/provenance.js +122 -0
  37. package/src/catalog/source.js +150 -0
  38. package/src/catalog/validation.js +252 -0
  39. package/src/catalog.d.ts +12 -0
  40. package/src/catalog.js +18 -750
  41. package/src/cli/catalog-alias.d.ts +1 -0
  42. package/src/cli/command-parser.js +38 -0
  43. package/src/cli/command-parsers/core.js +102 -0
  44. package/src/cli/command-parsers/generator.js +39 -0
  45. package/src/cli/command-parsers/import.js +44 -0
  46. package/src/cli/command-parsers/legacy-workflow.js +21 -0
  47. package/src/cli/command-parsers/project.js +47 -0
  48. package/src/cli/command-parsers/sdlc.js +47 -0
  49. package/src/cli/command-parsers/shared.js +51 -0
  50. package/src/cli/command-parsers/template.js +48 -0
  51. package/src/cli/commands/agent.js +47 -0
  52. package/src/cli/commands/catalog/check.js +31 -0
  53. package/src/cli/commands/catalog/copy.js +59 -0
  54. package/src/cli/commands/catalog/doctor.js +248 -0
  55. package/src/cli/commands/catalog/help.js +21 -0
  56. package/src/cli/commands/catalog/list.js +52 -0
  57. package/src/cli/commands/catalog/runner.js +92 -0
  58. package/src/cli/commands/catalog/shared.js +17 -0
  59. package/src/cli/commands/catalog/show.js +134 -0
  60. package/src/cli/commands/catalog.js +32 -0
  61. package/src/cli/commands/check.js +268 -0
  62. package/src/cli/commands/doctor.js +268 -0
  63. package/src/cli/commands/emit.js +149 -0
  64. package/src/cli/commands/generate.js +96 -0
  65. package/src/cli/commands/generator-policy/package-info.js +162 -0
  66. package/src/cli/commands/generator-policy/payloads.js +372 -0
  67. package/src/cli/commands/generator-policy/printers.js +159 -0
  68. package/src/cli/commands/generator-policy/runner.js +81 -0
  69. package/src/cli/commands/generator-policy/shared.js +39 -0
  70. package/src/cli/commands/generator-policy.js +17 -0
  71. package/src/cli/commands/generator.js +443 -0
  72. package/src/cli/commands/import/adopt.js +170 -0
  73. package/src/cli/commands/import/check.js +91 -0
  74. package/src/cli/commands/import/diff.js +84 -0
  75. package/src/cli/commands/import/help.js +47 -0
  76. package/src/cli/commands/import/paths.js +277 -0
  77. package/src/cli/commands/import/plan.js +284 -0
  78. package/src/cli/commands/import/refresh.js +470 -0
  79. package/src/cli/commands/import/status-history.js +196 -0
  80. package/src/cli/commands/import/workspace.js +230 -0
  81. package/src/cli/commands/import-runner.js +157 -0
  82. package/src/cli/commands/import.js +35 -0
  83. package/src/cli/commands/inspect.js +55 -0
  84. package/src/cli/commands/new.js +94 -0
  85. package/src/cli/commands/package/constants.js +17 -0
  86. package/src/cli/commands/package/doctor.js +240 -0
  87. package/src/cli/commands/package/help.js +27 -0
  88. package/src/cli/commands/package/lockfile.js +135 -0
  89. package/src/cli/commands/package/npm.js +97 -0
  90. package/src/cli/commands/package/reporting.js +35 -0
  91. package/src/cli/commands/package/runner.js +33 -0
  92. package/src/cli/commands/package/shared.js +9 -0
  93. package/src/cli/commands/package/update-cli.js +252 -0
  94. package/src/cli/commands/package/versions.js +35 -0
  95. package/src/cli/commands/package.js +31 -0
  96. package/src/cli/commands/query/change-plan.js +68 -0
  97. package/src/cli/commands/query/definitions.js +202 -0
  98. package/src/cli/commands/query/import-adopt.js +121 -0
  99. package/src/cli/commands/query/runner/artifacts.js +102 -0
  100. package/src/cli/commands/query/runner/boundaries.js +211 -0
  101. package/src/cli/commands/query/runner/change.js +182 -0
  102. package/src/cli/commands/query/runner/import-adopt.js +111 -0
  103. package/src/cli/commands/query/runner/index.js +31 -0
  104. package/src/cli/commands/query/runner/output.js +12 -0
  105. package/src/cli/commands/query/runner/workflow.js +241 -0
  106. package/src/cli/commands/query/runner.js +3 -0
  107. package/src/cli/commands/query/workflow-context.js +5 -0
  108. package/src/cli/commands/query/workspace.js +274 -0
  109. package/src/cli/commands/query.js +11 -0
  110. package/src/cli/commands/release-rollout.js +257 -0
  111. package/src/cli/commands/release-shared.js +528 -0
  112. package/src/cli/commands/release-status.js +429 -0
  113. package/src/cli/commands/release.js +107 -0
  114. package/src/cli/commands/sdlc.js +168 -0
  115. package/src/cli/commands/setup.js +76 -0
  116. package/src/cli/commands/source.js +291 -0
  117. package/src/cli/commands/template/baseline.js +100 -0
  118. package/src/cli/commands/template/check.js +466 -0
  119. package/src/cli/commands/template/constants.js +8 -0
  120. package/src/cli/commands/template/diagnostics.js +26 -0
  121. package/src/cli/commands/template/help.js +28 -0
  122. package/src/cli/commands/template/lifecycle.js +404 -0
  123. package/src/cli/commands/template/list-show.js +287 -0
  124. package/src/cli/commands/template/policy.js +422 -0
  125. package/src/cli/commands/template/shared.js +127 -0
  126. package/src/cli/commands/template/updates.js +352 -0
  127. package/src/cli/commands/template-runner.js +198 -0
  128. package/src/cli/commands/template.js +43 -0
  129. package/src/cli/commands/trust.js +219 -0
  130. package/src/cli/commands/version.js +40 -0
  131. package/src/cli/commands/widget.js +168 -0
  132. package/src/cli/commands/workflow.js +63 -0
  133. package/src/cli/dispatcher.js +392 -0
  134. package/src/cli/help-dispatch.js +188 -0
  135. package/src/cli/help.js +296 -0
  136. package/src/cli/migration-guidance.js +59 -0
  137. package/src/cli/options.js +96 -0
  138. package/src/cli/output-safety.js +107 -0
  139. package/src/cli/path-normalization.js +29 -0
  140. package/src/cli.js +47 -11711
  141. package/src/example-implementation.d.ts +2 -0
  142. package/src/format.d.ts +1 -0
  143. package/src/generator/api/contracts.js +497 -0
  144. package/src/generator/api/metadata.js +221 -0
  145. package/src/generator/api/openapi.js +559 -0
  146. package/src/generator/api/schema.js +124 -0
  147. package/src/generator/api/types.d.ts +98 -0
  148. package/src/generator/api.js +3 -1195
  149. package/src/generator/check.d.ts +1 -0
  150. package/src/generator/context/bundle.d.ts +1 -0
  151. package/src/generator/context/shared/domain-sdlc.js +282 -0
  152. package/src/generator/context/shared/maintained-boundary.js +665 -0
  153. package/src/generator/context/shared/metrics.js +85 -0
  154. package/src/generator/context/shared/primitives.js +64 -0
  155. package/src/generator/context/shared/relationships.js +453 -0
  156. package/src/generator/context/shared/summaries.js +263 -0
  157. package/src/generator/context/shared/types.d.ts +207 -0
  158. package/src/generator/context/shared.d.ts +44 -0
  159. package/src/generator/context/shared.js +80 -1390
  160. package/src/generator/context/slice/core.js +397 -0
  161. package/src/generator/context/slice/sdlc.js +417 -0
  162. package/src/generator/context/slice/ui-packets.js +183 -0
  163. package/src/generator/context/slice.js +2 -859
  164. package/src/generator/native/parity-bundle.js +2 -1
  165. package/src/generator/registry/index.js +507 -0
  166. package/src/generator/registry.js +18 -504
  167. package/src/generator/runtime/environment/index.js +666 -0
  168. package/src/generator/runtime/environment.js +4 -666
  169. package/src/generator/runtime/runtime-check/index.js +554 -0
  170. package/src/generator/runtime/runtime-check.js +4 -554
  171. package/src/generator/runtime/shared/index.js +572 -0
  172. package/src/generator/runtime/shared.js +19 -570
  173. package/src/generator/shared.d.ts +2 -0
  174. package/src/generator/surfaces/shared.d.ts +3 -0
  175. package/src/generator/surfaces/web/html-escape.js +22 -0
  176. package/src/generator/surfaces/web/react.js +10 -8
  177. package/src/generator/surfaces/web/sveltekit.js +7 -5
  178. package/src/generator/surfaces/web/vanilla.js +8 -4
  179. package/src/generator/widget-conformance/behavior-report.js +258 -0
  180. package/src/generator/widget-conformance/checks.js +371 -0
  181. package/src/generator/widget-conformance/projection-context.js +200 -0
  182. package/src/generator/widget-conformance/report.js +166 -0
  183. package/src/generator/widget-conformance/types.d.ts +121 -0
  184. package/src/generator/widget-conformance.js +3 -824
  185. package/src/generator.d.ts +2 -0
  186. package/src/github-client.js +520 -0
  187. package/src/import/core/context.d.ts +3 -0
  188. package/src/import/core/contracts.d.ts +1 -0
  189. package/src/import/core/registry.d.ts +4 -0
  190. package/src/import/core/runner/candidates.js +217 -0
  191. package/src/import/core/runner/options.js +22 -0
  192. package/src/import/core/runner/reports.js +50 -0
  193. package/src/import/core/runner/run.js +79 -0
  194. package/src/import/core/runner/tracks.js +150 -0
  195. package/src/import/core/runner/ui-drafts.js +337 -0
  196. package/src/import/core/runner.js +3 -698
  197. package/src/import/core/shared/api-routes.js +221 -0
  198. package/src/import/core/shared/candidates.js +97 -0
  199. package/src/import/core/shared/files.js +177 -0
  200. package/src/import/core/shared/next-app.js +389 -0
  201. package/src/import/core/shared/types.d.ts +51 -0
  202. package/src/import/core/shared/ui-routes.js +230 -0
  203. package/src/import/core/shared.js +67 -910
  204. package/src/import/extractors/api/flutter-dio.js +4 -8
  205. package/src/import/extractors/api/react-native-repository.js +4 -8
  206. package/src/import/index.d.ts +4 -0
  207. package/src/import/provenance.d.ts +4 -0
  208. package/src/new-project/constants.js +128 -0
  209. package/src/new-project/create.js +83 -0
  210. package/src/new-project/json.js +28 -0
  211. package/src/new-project/metadata.js +96 -0
  212. package/src/new-project/package-spec.js +161 -0
  213. package/src/new-project/project-files.js +348 -0
  214. package/src/new-project/template-policy.js +269 -0
  215. package/src/new-project/template-resolution.js +368 -0
  216. package/src/new-project/template-snapshots.js +430 -0
  217. package/src/new-project/template-updates.js +512 -0
  218. package/src/new-project/types.d.ts +83 -0
  219. package/src/new-project.js +6 -2188
  220. package/src/npm-safety.js +79 -0
  221. package/src/parser.d.ts +87 -0
  222. package/src/parser.js +118 -0
  223. package/src/path-helpers.d.ts +1 -0
  224. package/src/path-helpers.js +20 -0
  225. package/src/policy/review-boundaries.d.ts +15 -0
  226. package/src/project-config/index.js +564 -0
  227. package/src/project-config.js +19 -560
  228. package/src/reconcile/docs.d.ts +8 -0
  229. package/src/reconcile/journeys.d.ts +1 -0
  230. package/src/resolver/enrich/acceptance-criterion.js +2 -0
  231. package/src/resolver/enrich/bug.js +2 -0
  232. package/src/resolver/enrich/pitch.js +2 -0
  233. package/src/resolver/enrich/requirement.js +2 -0
  234. package/src/resolver/enrich/task.js +2 -0
  235. package/src/resolver/index.js +19 -2089
  236. package/src/resolver/normalize.js +384 -1
  237. package/src/resolver/plans.js +168 -0
  238. package/src/resolver/projections-api.js +494 -0
  239. package/src/resolver/projections-db.js +133 -0
  240. package/src/resolver/projections-ui.js +317 -0
  241. package/src/resolver/shapes.js +251 -0
  242. package/src/resolver/shared.js +278 -0
  243. package/src/resolver/widgets.js +132 -0
  244. package/src/resolver.d.ts +1 -0
  245. package/src/runtime-support.js +29 -0
  246. package/src/sdlc/adopt.d.ts +1 -0
  247. package/src/sdlc/check.d.ts +1 -0
  248. package/src/sdlc/explain.d.ts +1 -0
  249. package/src/sdlc/release.d.ts +1 -0
  250. package/src/sdlc/scaffold.d.ts +1 -0
  251. package/src/sdlc/transition.d.ts +1 -0
  252. package/src/template-trust/constants.js +62 -0
  253. package/src/template-trust/content.js +258 -0
  254. package/src/template-trust/diff.js +92 -0
  255. package/src/template-trust/policy.js +61 -0
  256. package/src/template-trust/record.js +90 -0
  257. package/src/template-trust/status.js +182 -0
  258. package/src/template-trust.js +24 -687
  259. package/src/text-helpers.d.ts +7 -0
  260. package/src/text-helpers.js +245 -0
  261. package/src/topogram-config.js +306 -0
  262. package/src/topogram-types.d.ts +69 -0
  263. package/src/validator/common.js +488 -0
  264. package/src/validator/data-model.js +237 -0
  265. package/src/validator/docs.js +167 -0
  266. package/src/validator/expressions.js +146 -1
  267. package/src/validator/index.d.ts +23 -0
  268. package/src/validator/index.js +32 -3585
  269. package/src/validator/kinds.d.ts +41 -0
  270. package/src/validator/kinds.js +2 -0
  271. package/src/validator/model-helpers.js +46 -0
  272. package/src/validator/per-kind/acceptance-criterion.js +5 -0
  273. package/src/validator/per-kind/bug.js +6 -0
  274. package/src/validator/per-kind/domain.js +15 -2
  275. package/src/validator/per-kind/pitch.js +7 -0
  276. package/src/validator/per-kind/requirement.js +5 -0
  277. package/src/validator/per-kind/task.js +7 -0
  278. package/src/validator/per-kind/widget.js +14 -0
  279. package/src/validator/projections/api-http-async.js +410 -0
  280. package/src/validator/projections/api-http-authz.js +88 -0
  281. package/src/validator/projections/api-http-core.js +205 -0
  282. package/src/validator/projections/api-http-policies.js +339 -0
  283. package/src/validator/projections/api-http-responses.js +233 -0
  284. package/src/validator/projections/api-http.js +44 -0
  285. package/src/validator/projections/db.js +353 -0
  286. package/src/validator/projections/generator-defaults.js +45 -0
  287. package/src/validator/projections/helpers.js +87 -0
  288. package/src/validator/projections/ui-helpers.js +214 -0
  289. package/src/validator/projections/ui-navigation.js +344 -0
  290. package/src/validator/projections/ui-structure.js +364 -0
  291. package/src/validator/projections/ui-widgets.js +493 -0
  292. package/src/validator/projections/ui.js +46 -0
  293. package/src/validator/registry.js +48 -1
  294. package/src/validator/utils.d.ts +20 -0
  295. package/src/validator/utils.js +115 -12
  296. package/src/validator.d.ts +2 -0
  297. package/src/widget-behavior.d.ts +1 -0
  298. package/src/workflows/adoption/index.js +26 -0
  299. package/src/workflows/docs-generate.js +262 -0
  300. package/src/workflows/docs-scan.js +703 -0
  301. package/src/workflows/docs.js +15 -0
  302. package/src/workflows/import-app/api/collect.js +221 -0
  303. package/src/workflows/import-app/api/openapi.js +257 -0
  304. package/src/workflows/import-app/api/routes.js +327 -0
  305. package/src/workflows/import-app/api/sources.js +22 -0
  306. package/src/workflows/import-app/api.js +4 -0
  307. package/src/workflows/import-app/db.js +538 -0
  308. package/src/workflows/import-app/index.js +30 -0
  309. package/src/workflows/import-app/shared.js +218 -0
  310. package/src/workflows/import-app/ui.js +443 -0
  311. package/src/workflows/import-app/workflow.js +159 -0
  312. package/src/workflows/reconcile/adoption-plan/build.js +208 -0
  313. package/src/workflows/reconcile/adoption-plan/dependencies.js +75 -0
  314. package/src/workflows/reconcile/adoption-plan/outputs.js +143 -0
  315. package/src/workflows/reconcile/adoption-plan/paths.js +58 -0
  316. package/src/workflows/reconcile/adoption-plan/projection-patches.js +177 -0
  317. package/src/workflows/reconcile/adoption-plan/reasons.js +107 -0
  318. package/src/workflows/reconcile/adoption-plan.js +32 -0
  319. package/src/workflows/reconcile/auth/closures.js +115 -0
  320. package/src/workflows/reconcile/auth/formatters.js +142 -0
  321. package/src/workflows/reconcile/auth/inference.js +330 -0
  322. package/src/workflows/reconcile/auth/roles.js +122 -0
  323. package/src/workflows/reconcile/auth.js +37 -0
  324. package/src/workflows/reconcile/bundle-core/index.js +600 -0
  325. package/src/workflows/reconcile/bundle-core.js +14 -0
  326. package/src/workflows/reconcile/bundle-shared.js +75 -0
  327. package/src/workflows/reconcile/candidate-model.js +477 -0
  328. package/src/workflows/reconcile/canonical-surface.js +264 -0
  329. package/src/workflows/reconcile/gap-report.js +333 -0
  330. package/src/workflows/reconcile/ids.js +6 -0
  331. package/src/workflows/reconcile/impacts/adoption-plan.js +192 -0
  332. package/src/workflows/reconcile/impacts/indexes.js +101 -0
  333. package/src/workflows/reconcile/impacts/patches.js +252 -0
  334. package/src/workflows/reconcile/impacts/reports.js +80 -0
  335. package/src/workflows/reconcile/impacts.js +16 -0
  336. package/src/workflows/reconcile/index.js +7 -0
  337. package/src/workflows/reconcile/renderers.js +461 -0
  338. package/src/workflows/reconcile/summary.js +90 -0
  339. package/src/workflows/reconcile/workflow.js +309 -0
  340. package/src/workflows/shared.js +189 -0
  341. package/src/workflows/types.d.ts +93 -0
  342. package/src/workflows.d.ts +1 -0
  343. package/src/workflows.js +10 -7652
  344. package/src/workspace-docs.d.ts +29 -0
@@ -1,563 +1,22 @@
1
1
  // @ts-check
2
2
 
3
- import fs from "node:fs";
4
- import path from "node:path";
5
-
6
- import {
7
- isGeneratorCompatible,
8
- resolveGeneratorManifestForBinding,
9
- validateGeneratorManifest
10
- } from "./generator/registry.js";
11
- import { validateProjectGeneratorPolicy } from "./generator-policy.js";
12
-
13
- /**
14
- * @typedef {Object} GeneratorBinding
15
- * @property {string} id
16
- * @property {string} version
17
- * @property {string} [package]
18
- */
19
-
20
- /**
21
- * @typedef {Object} RuntimeTopologyRuntime
22
- * @property {string} id
23
- * @property {"api_service"|"web_surface"|"ios_surface"|"android_surface"|"database"} kind
24
- * @property {string} projection
25
- * @property {GeneratorBinding} generator
26
- * @property {number|null} [port]
27
- * @property {string} [uses_api]
28
- * @property {string} [uses_database]
29
- * @property {Record<string, string>} [env]
30
- */
31
-
32
- /**
33
- * @typedef {Object} ProjectConfig
34
- * @property {string} version
35
- * @property {Record<string, { path: string, ownership: "generated"|"maintained" }>} outputs
36
- * @property {{ runtimes: RuntimeTopologyRuntime[] }} topology
37
- * @property {{ id?: string, module?: string, export?: string, implementation_module?: string, implementation_export?: string }} [implementation]
38
- */
39
-
40
- /**
41
- * @typedef {Object} ProjectConfigInfo
42
- * @property {ProjectConfig} config
43
- * @property {string|null} configPath
44
- * @property {string} configDir
45
- * @property {boolean} [compatibility]
46
- */
47
-
48
- /**
49
- * @typedef {Object} ValidationError
50
- * @property {string} message
51
- * @property {any} loc
52
- */
53
-
54
- const PROJECT_CONFIG_FILE = "topogram.project.json";
55
- const LEGACY_IMPLEMENTATION_FILE = "topogram.implementation.json";
56
- const GENERATED_OUTPUT_SENTINEL = ".topogram-generated.json";
57
- const IDENTIFIER_PATTERN = /^[a-z][a-z0-9_]*$/;
58
-
59
- /**
60
- * @param {string|null|undefined} root
61
- * @returns {string|null}
62
- */
63
- function normalizeSearchRoot(root) {
64
- if (!root) {
65
- return null;
66
- }
67
- const absolute = path.resolve(root);
68
- try {
69
- return fs.realpathSync(absolute);
70
- } catch {
71
- return absolute;
72
- }
73
- }
74
-
75
- /**
76
- * @param {string} root
77
- * @returns {string}
78
- */
79
- function normalizeRoot(root) {
80
- return String(root || "").replace(/\\/g, "/");
81
- }
82
-
83
- /**
84
- * @param {string} filePath
85
- * @returns {string}
86
- */
87
- function resolveComparablePath(filePath) {
88
- const absolute = path.resolve(filePath);
89
- try {
90
- return fs.existsSync(absolute)
91
- ? fs.realpathSync(absolute)
92
- : path.join(fs.realpathSync(path.dirname(absolute)), path.basename(absolute));
93
- } catch {
94
- return absolute;
95
- }
96
- }
97
-
98
- /**
99
- * @param {string} filePath
100
- * @returns {any}
101
- */
102
- function readJson(filePath) {
103
- return JSON.parse(fs.readFileSync(filePath, "utf8"));
104
- }
105
-
106
- /**
107
- * @param {string} oldName
108
- * @param {string} newName
109
- * @param {string} example
110
- * @returns {string}
111
- */
112
- function renameDiagnostic(oldName, newName, example) {
113
- return `${oldName} was renamed to ${newName}. Example fix: ${example}`;
114
- }
115
-
116
3
  /**
117
- * @param {string} root
118
- * @param {string} fileName
119
- * @returns {{ config: any, configPath: string, configDir: string }|null}
120
- */
121
- function findConfigFile(root, fileName) {
122
- let current = normalizeSearchRoot(root);
123
- while (current && current !== path.dirname(current)) {
124
- const candidate = path.join(current, fileName);
125
- if (fs.existsSync(candidate)) {
126
- return {
127
- config: readJson(candidate),
128
- configPath: candidate,
129
- configDir: path.dirname(candidate)
130
- };
131
- }
132
- current = path.dirname(current);
133
- }
134
- return null;
135
- }
136
-
137
- /**
138
- * @param {string} root
139
- * @returns {{ config: any, configPath: string, configDir: string }|null}
140
- */
141
- export function findProjectConfig(root) {
142
- return findConfigFile(root, PROJECT_CONFIG_FILE);
143
- }
144
-
145
- /**
146
- * @param {string} root
147
- * @returns {{ config: any, configPath: string, configDir: string }|null}
148
- */
149
- export function findLegacyImplementationConfig(root) {
150
- return findConfigFile(root, LEGACY_IMPLEMENTATION_FILE);
151
- }
152
-
153
- /**
154
- * @param {Record<string, any>} graph
155
- * @param {Record<string, any>|null} [implementation]
156
- * @returns {ProjectConfig}
157
- */
158
- export function defaultProjectConfigForGraph(graph, implementation = null) {
159
- const runtimeReference = implementation?.runtime?.reference || {};
160
- /** @type {Array<Record<string, any>>} */
161
- const projections = graph.byKind.projection || [];
162
- const apiProjection = projections.find((projection) => (projection.http || []).length > 0 || projection.type === "api_contract");
163
- const webProjection =
164
- projections.find((projection) => projection.id === "proj_web") ||
165
- projections.find((projection) => projection.type === "web_surface");
166
- const dbProjection =
167
- projections.find((projection) => projection.id === runtimeReference.localDbProjectionId) ||
168
- projections.find((projection) => projection.type === "db_contract");
169
- const ports = runtimeReference.ports || {};
170
- const dbProfile = (dbProjection?.generatorDefaults || []).find((/** @type {Record<string, any>} */ entry) => entry.key === "profile")?.value;
171
- const dbGenerator = dbProfile === "sqlite_sql" ? "topogram/sqlite" : "topogram/postgres";
172
- const dbRuntimeId = dbProfile === "sqlite_sql" ? "app_sqlite" : "app_postgres";
173
- /** @type {RuntimeTopologyRuntime[]} */
174
- const runtimes = [
175
- ...(apiProjection
176
- ? [{
177
- id: "app_api",
178
- kind: /** @type {"api_service"} */ ("api_service"),
179
- projection: apiProjection.id,
180
- generator: { id: "topogram/hono", version: "1" },
181
- port: ports.server || 3000,
182
- ...(dbProjection ? { uses_database: dbRuntimeId } : {})
183
- }]
184
- : []),
185
- ...(webProjection
186
- ? [{
187
- id: "app_sveltekit",
188
- kind: /** @type {"web_surface"} */ ("web_surface"),
189
- projection: webProjection.id,
190
- generator: { id: "topogram/sveltekit", version: "1" },
191
- port: ports.web || 5173,
192
- ...(apiProjection ? { uses_api: "app_api" } : {})
193
- }]
194
- : []),
195
- ...(dbProjection
196
- ? [{
197
- id: dbRuntimeId,
198
- kind: /** @type {"database"} */ ("database"),
199
- projection: dbProjection.id,
200
- generator: { id: dbGenerator, version: "1" },
201
- port: dbProfile === "sqlite_sql" ? null : 5432
202
- }]
203
- : [])
204
- ];
205
-
206
- return {
207
- version: "0.1",
208
- implementation: implementation?.exampleId
209
- ? {
210
- id: implementation.exampleId
211
- }
212
- : undefined,
213
- outputs: {
214
- app: {
215
- path: "./app",
216
- ownership: "generated"
217
- }
218
- },
219
- topology: {
220
- runtimes
221
- }
222
- };
223
- }
224
-
225
- /**
226
- * @param {string} root
227
- * @returns {ProjectConfigInfo|null}
228
- */
229
- export function loadProjectConfig(root) {
230
- const found = findProjectConfig(root);
231
- if (!found) {
232
- return null;
233
- }
234
- return {
235
- ...found,
236
- config: found.config,
237
- compatibility: false
238
- };
239
- }
240
-
241
- /**
242
- * @param {string} root
243
- * @param {Record<string, any>|null} [graph]
244
- * @param {Record<string, any>|null} [implementation]
245
- * @returns {ProjectConfigInfo|null}
246
- */
247
- export function projectConfigOrDefault(root, graph = null, implementation = null) {
248
- const found = loadProjectConfig(root);
249
- if (found) {
250
- return found;
251
- }
252
- if (!graph) {
253
- return null;
254
- }
255
- return {
256
- config: defaultProjectConfigForGraph(graph, implementation),
257
- configPath: null,
258
- configDir: path.dirname(path.resolve(root)),
259
- compatibility: true
260
- };
261
- }
262
-
263
- /**
264
- * @param {ValidationError[]} errors
265
- * @param {string} message
266
- * @param {any} [loc]
267
- * @returns {void}
268
- */
269
- function pushError(errors, message, loc = null) {
270
- errors.push({ message, loc });
271
- }
272
-
273
- /**
274
- * @param {Record<string, any>} graph
275
- * @returns {Map<string, Record<string, any>>}
276
- */
277
- function projectionById(graph) {
278
- /** @type {Array<Record<string, any>>} */
279
- const projections = graph?.byKind?.projection || [];
280
- return new Map(projections.map((projection) => [projection.id, projection]));
281
- }
282
-
283
- /**
284
- * @param {ValidationError[]} errors
285
- * @param {any} config
286
- * @returns {void}
287
- */
288
- function validateOutputConfig(errors, config) {
289
- if (!config.outputs || typeof config.outputs !== "object" || Array.isArray(config.outputs)) {
290
- pushError(errors, "topogram.project.json outputs must be an object");
291
- return;
292
- }
293
- for (const [name, output] of Object.entries(config.outputs)) {
294
- if (!output || typeof output !== "object" || Array.isArray(output)) {
295
- pushError(errors, `Output '${name}' must be an object`);
296
- continue;
297
- }
298
- if (!["generated", "maintained"].includes(output.ownership)) {
299
- pushError(errors, `Output '${name}' ownership must be generated or maintained`);
300
- }
301
- if (typeof output.path !== "string" || output.path.length === 0) {
302
- pushError(errors, `Output '${name}' path must be a non-empty string`);
303
- }
304
- }
305
- }
306
-
307
- /**
308
- * @param {any} runtime
309
- * @returns {string}
310
- */
311
- function runtimeLabel(runtime) {
312
- return runtime?.id ? `Runtime '${runtime.id}'` : "Topology runtime";
313
- }
314
-
315
- /**
316
- * @param {ValidationError[]} errors
317
- * @param {any} runtime
318
- * @param {Set<string>} seenIds
319
- * @returns {boolean}
320
- */
321
- function validateRuntimeShape(errors, runtime, seenIds) {
322
- if (!runtime || typeof runtime !== "object" || Array.isArray(runtime)) {
323
- pushError(errors, "Topology runtime must be an object");
324
- return false;
325
- }
326
- if (typeof runtime.id !== "string" || !IDENTIFIER_PATTERN.test(runtime.id)) {
327
- pushError(errors, `${runtimeLabel(runtime)} id must match ${IDENTIFIER_PATTERN}`);
328
- } else if (seenIds.has(runtime.id)) {
329
- pushError(errors, `Duplicate topology runtime id '${runtime.id}'`);
330
- } else {
331
- seenIds.add(runtime.id);
332
- }
333
- if (runtime.type != null) {
334
- pushError(errors, `${runtimeLabel(runtime)} ${renameDiagnostic("'type'", "'kind'", `"kind": "api_service"`)}`);
335
- }
336
- if (runtime.database != null) {
337
- pushError(errors, `${runtimeLabel(runtime)} ${renameDiagnostic("'database'", "'uses_database'", `"uses_database": "app_db"`)}`);
338
- }
339
- if (runtime.api != null) {
340
- pushError(errors, `${runtimeLabel(runtime)} ${renameDiagnostic("'api'", "'uses_api'", `"uses_api": "app_api"`)}`);
341
- }
342
- if (!["api_service", "web_surface", "ios_surface", "android_surface", "database"].includes(runtime.kind)) {
343
- pushError(errors, `${runtimeLabel(runtime)} kind must be api_service, web_surface, ios_surface, android_surface, or database`);
344
- }
345
- if (typeof runtime.projection !== "string" || runtime.projection.length === 0) {
346
- pushError(errors, `${runtimeLabel(runtime)} projection must be a non-empty string`);
347
- }
348
- if (!runtime.generator || typeof runtime.generator !== "object") {
349
- pushError(errors, `${runtimeLabel(runtime)} generator must be an object`);
350
- } else {
351
- if (typeof runtime.generator.id !== "string" || runtime.generator.id.length === 0) {
352
- pushError(errors, `${runtimeLabel(runtime)} generator.id must be a non-empty string`);
353
- }
354
- if (typeof runtime.generator.version !== "string" || runtime.generator.version.length === 0) {
355
- pushError(errors, `${runtimeLabel(runtime)} generator.version must be a non-empty string`);
356
- }
357
- if (runtime.generator.package != null && (typeof runtime.generator.package !== "string" || runtime.generator.package.length === 0)) {
358
- pushError(errors, `${runtimeLabel(runtime)} generator.package must be a non-empty string when provided`);
359
- }
360
- }
361
- if (runtime.port != null && (!Number.isInteger(runtime.port) || runtime.port <= 0 || runtime.port > 65535)) {
362
- pushError(errors, `${runtimeLabel(runtime)} port must be an integer from 1 to 65535`);
363
- }
364
- return true;
365
- }
366
-
367
- /**
368
- * @param {ValidationError[]} errors
369
- * @param {RuntimeTopologyRuntime} runtime
370
- * @param {Map<string, Record<string, any>>} projections
371
- * @param {{ configDir?: string|null, rootDir?: string|null }} [options]
372
- * @returns {void}
373
- */
374
- function validateRuntimeCompatibility(errors, runtime, projections, options = {}) {
375
- const projection = projections.get(runtime.projection);
376
- if (!projection) {
377
- pushError(errors, `${runtimeLabel(runtime)} references missing projection '${runtime.projection}'`);
378
- return;
379
- }
380
-
381
- const resolvedManifest = resolveGeneratorManifestForBinding(runtime.generator, options);
382
- const manifest = resolvedManifest.manifest;
383
- if (!manifest) {
384
- const details = resolvedManifest.errors.length > 0 ? `: ${resolvedManifest.errors.join("; ")}` : "";
385
- pushError(errors, `${runtimeLabel(runtime)} for projection '${projection.id}' uses unknown generator '${runtime.generator?.id}' version '${runtime.generator?.version || "unknown"}'${details}`);
386
- return;
387
- }
388
- const manifestValidation = validateGeneratorManifest(manifest);
389
- if (!manifestValidation.ok) {
390
- for (const message of manifestValidation.errors) {
391
- pushError(errors, `${runtimeLabel(runtime)} generator manifest invalid: ${message}`);
392
- }
393
- }
394
- if (manifest.planned) {
395
- pushError(errors, `${runtimeLabel(runtime)} for projection '${projection.id}' uses planned generator '${manifest.id}@${manifest.version}', which is not implemented yet`);
396
- }
397
- if (manifest.version !== runtime.generator.version) {
398
- pushError(errors, `${runtimeLabel(runtime)} for projection '${projection.id}' generator '${manifest.id}' version '${runtime.generator.version}' is unsupported; expected '${manifest.version}'`);
399
- }
400
- if (!isGeneratorCompatible(manifest, runtime.kind, projection)) {
401
- pushError(errors, `${runtimeLabel(runtime)} for projection '${projection.id}' generator '${manifest.id}@${manifest.version}' is incompatible with runtime kind '${runtime.kind}' and projection type '${projection.type || "api_contract"}'`);
402
- }
403
- }
404
-
405
- /**
406
- * @param {ValidationError[]} errors
407
- * @param {RuntimeTopologyRuntime[]} runtimes
408
- * @returns {void}
409
- */
410
- function validateTopologyReferences(errors, runtimes) {
411
- const byId = new Map(runtimes.map((runtime) => [runtime.id, runtime]));
412
- const usedPorts = new Map();
413
- for (const runtime of runtimes) {
414
- if (runtime.port != null) {
415
- const existing = usedPorts.get(runtime.port);
416
- if (existing) {
417
- pushError(errors, `Port ${runtime.port} is used by both '${existing}' and '${runtime.id}'`);
418
- } else {
419
- usedPorts.set(runtime.port, runtime.id);
420
- }
421
- }
422
- if (runtime.kind === "api_service") {
423
- if (runtime.uses_database && byId.get(runtime.uses_database)?.kind !== "database") {
424
- pushError(errors, `${runtimeLabel(runtime)} references missing database runtime '${runtime.uses_database}'`);
425
- }
426
- }
427
- if (["web_surface", "ios_surface", "android_surface"].includes(runtime.kind)) {
428
- if (runtime.uses_api && byId.get(runtime.uses_api)?.kind !== "api_service") {
429
- pushError(errors, `${runtimeLabel(runtime)} references missing api runtime '${runtime.uses_api}'`);
430
- }
431
- }
432
- }
433
- }
434
-
435
- /**
436
- * @param {any} config
437
- * @param {Record<string, any>|null} [graph]
438
- * @param {{ configDir?: string|null, rootDir?: string|null }} [options]
439
- * @returns {{ ok: boolean, errors: ValidationError[] }}
440
- */
441
- export function validateProjectConfig(config, graph = null, options = {}) {
442
- /** @type {ValidationError[]} */
443
- const errors = [];
444
- if (!config || typeof config !== "object" || Array.isArray(config)) {
445
- return { ok: false, errors: [{ message: "topogram.project.json must contain a JSON object", loc: null }] };
446
- }
447
- if (typeof config.version !== "string" || config.version.length === 0) {
448
- pushError(errors, "topogram.project.json version must be a non-empty string");
449
- }
450
- validateOutputConfig(errors, config);
451
- if (config.topology?.components != null) {
452
- pushError(errors, `topogram.project.json ${renameDiagnostic("'topology.components'", "'topology.runtimes'", `"topology": { "runtimes": [] }`)}`);
453
- }
454
- if (!config.topology || typeof config.topology !== "object" || !Array.isArray(config.topology.runtimes)) {
455
- pushError(errors, "topogram.project.json topology.runtimes must be an array");
456
- } else {
457
- const seenIds = new Set();
458
- for (const runtime of config.topology.runtimes) {
459
- validateRuntimeShape(errors, runtime, seenIds);
460
- }
461
- const generatorPolicy = validateProjectGeneratorPolicy(config, options);
462
- for (const error of generatorPolicy.errors) {
463
- pushError(errors, error.message, error.loc);
464
- }
465
- if (graph) {
466
- const projections = projectionById(graph);
467
- for (const runtime of config.topology.runtimes) {
468
- validateRuntimeCompatibility(errors, runtime, projections, options);
469
- }
470
- validateTopologyReferences(errors, config.topology.runtimes);
471
- }
472
- }
473
- return {
474
- ok: errors.length === 0,
475
- errors
476
- };
477
- }
478
-
479
- /**
480
- * @param {{ errors: ValidationError[] }} result
481
- * @param {string} [configPath]
482
- * @returns {string}
483
- */
484
- export function formatProjectConfigErrors(result, configPath = PROJECT_CONFIG_FILE) {
485
- return result.errors
486
- .map((error) => `${normalizeRoot(configPath)} ${error.message}`)
487
- .join("\n");
488
- }
489
-
490
- /**
491
- * @param {ProjectConfigInfo|null|undefined} configInfo
492
- * @param {string} outputName
493
- * @returns {string|null}
494
- */
495
- export function resolveOutputPath(configInfo, outputName) {
496
- const output = configInfo?.config?.outputs?.[outputName];
497
- if (!configInfo || !output?.path) {
498
- return null;
499
- }
500
- const baseDir = configInfo.configDir || process.cwd();
501
- return resolveComparablePath(path.resolve(baseDir, output.path));
502
- }
503
-
504
- /**
505
- * @param {ProjectConfigInfo|null|undefined} configInfo
506
- * @param {string} outDir
507
- * @returns {{ name: string, ownership: string, path: string }|null}
508
- */
509
- export function outputOwnershipForPath(configInfo, outDir) {
510
- if (!configInfo?.config?.outputs) {
511
- return null;
512
- }
513
- const resolvedOutDir = resolveComparablePath(outDir);
514
- for (const [name, output] of Object.entries(configInfo.config.outputs)) {
515
- if (!output?.path) {
516
- continue;
517
- }
518
- const resolvedOutput = resolveComparablePath(path.resolve(configInfo.configDir || process.cwd(), output.path));
519
- if (resolvedOutput === resolvedOutDir) {
520
- return {
521
- name,
522
- ownership: output.ownership,
523
- path: resolvedOutput
524
- };
525
- }
526
- }
527
- return null;
528
- }
529
-
530
- /**
531
- * @param {ProjectConfigInfo|null|undefined} configInfo
532
- * @returns {{ ok: boolean, errors: ValidationError[] }}
533
- */
534
- export function validateProjectOutputOwnership(configInfo) {
535
- /** @type {ValidationError[]} */
536
- const errors = [];
537
- if (!configInfo?.config?.outputs) {
538
- return { ok: true, errors };
539
- }
540
- for (const [name, output] of Object.entries(configInfo.config.outputs)) {
541
- if (!output?.path || !["generated", "maintained"].includes(output.ownership)) {
542
- continue;
543
- }
544
- const resolvedOutput = resolveComparablePath(path.resolve(configInfo.configDir || process.cwd(), output.path));
545
- const sentinelPath = path.join(resolvedOutput, GENERATED_OUTPUT_SENTINEL);
546
- if (output.ownership === "generated" && fs.existsSync(resolvedOutput) && !fs.existsSync(sentinelPath)) {
547
- pushError(
548
- errors,
549
- `Generated output '${name}' at '${normalizeRoot(resolvedOutput)}' is missing ${GENERATED_OUTPUT_SENTINEL}`
550
- );
551
- }
552
- if (output.ownership === "maintained" && fs.existsSync(sentinelPath)) {
553
- pushError(
554
- errors,
555
- `Maintained output '${name}' at '${normalizeRoot(resolvedOutput)}' contains ${GENERATED_OUTPUT_SENTINEL}`
556
- );
557
- }
558
- }
559
- return {
560
- ok: errors.length === 0,
561
- errors
562
- };
563
- }
4
+ * @typedef {import("./project-config/index.js").GeneratorBinding} GeneratorBinding
5
+ * @typedef {import("./project-config/index.js").RuntimeTopologyRuntime} RuntimeTopologyRuntime
6
+ * @typedef {import("./project-config/index.js").ProjectConfig} ProjectConfig
7
+ * @typedef {import("./project-config/index.js").ProjectConfigInfo} ProjectConfigInfo
8
+ * @typedef {import("./project-config/index.js").ValidationError} ValidationError
9
+ */
10
+
11
+ export {
12
+ defaultProjectConfigForGraph,
13
+ findLegacyImplementationConfig,
14
+ findProjectConfig,
15
+ formatProjectConfigErrors,
16
+ loadProjectConfig,
17
+ outputOwnershipForPath,
18
+ projectConfigOrDefault,
19
+ resolveOutputPath,
20
+ validateProjectConfig,
21
+ validateProjectOutputOwnership
22
+ } from "./project-config/index.js";
@@ -0,0 +1,8 @@
1
+ export function buildBundleDocDriftSummaries(...args: any[]): any[];
2
+ export function buildBundleDocMetadataPatches(...args: any[]): any[];
3
+ export function applyDocLinkPatchToMarkdown(...args: any[]): string;
4
+ export function applyDocMetadataPatchToMarkdown(...args: any[]): string;
5
+ export function buildDocDriftSummaries(...args: any[]): any[];
6
+ export function buildDocLinkSuggestions(...args: any[]): any[];
7
+ export function buildDocMetadataPatches(...args: any[]): any[];
8
+ export function extractDocMetadata(...args: any[]): any;
@@ -0,0 +1 @@
1
+ export function buildJourneyDrafts(graph: any): any;
@@ -1,3 +1,4 @@
1
+ // @ts-check
1
2
  // Resolver enrichment for acceptance criteria.
2
3
  //
3
4
  // Back-link arrays:
@@ -5,6 +6,7 @@
5
6
  // verifications — verifications whose `acceptance_refs` includes this AC
6
7
  // supersededBy — ACs that supersede *this* one
7
8
 
9
+ /** @param {TopogramStatement} ac @param {ResolverBacklinkIndex} index */
8
10
  export function enrichAcceptanceCriterion(ac, index) {
9
11
  return {
10
12
  tasks: (index.tasksByAcceptanceRef.get(ac.id) || []).slice().sort(),
@@ -1,3 +1,4 @@
1
+ // @ts-check
1
2
  // Resolver enrichment for bugs.
2
3
  //
3
4
  // Back-link arrays:
@@ -5,6 +6,7 @@
5
6
  // (typically same set as bug.fixedInVerification, but the
6
7
  // author may set only one side; we surface both)
7
8
 
9
+ /** @param {TopogramStatement} bug @param {ResolverBacklinkIndex} index */
8
10
  export function enrichBug(bug, index) {
9
11
  return {
10
12
  verifiedBy: (index.verificationsFixingBug.get(bug.id) || []).slice().sort()
@@ -1,3 +1,4 @@
1
+ // @ts-check
1
2
  // Resolver enrichment for pitches.
2
3
  //
3
4
  // Builds back-link arrays so consumers can ask a pitch "who follows you?"
@@ -10,6 +11,7 @@
10
11
  //
11
12
  // Output is merged into the statement by `resolveWorkspace`.
12
13
 
14
+ /** @param {TopogramStatement} pitch @param {ResolverBacklinkIndex} index */
13
15
  export function enrichPitch(pitch, index) {
14
16
  return {
15
17
  requirements: (index.requirementsByPitch.get(pitch.id) || []).slice().sort(),
@@ -1,3 +1,4 @@
1
+ // @ts-check
1
2
  // Resolver enrichment for requirements.
2
3
  //
3
4
  // Back-link arrays:
@@ -8,6 +9,7 @@
8
9
  // documents — docs whose `satisfies` frontmatter points here
9
10
  // rules — rules whose `from_requirement` is this requirement
10
11
 
12
+ /** @param {TopogramStatement} requirement @param {ResolverBacklinkIndex} index */
11
13
  export function enrichRequirement(requirement, index) {
12
14
  return {
13
15
  acceptanceCriteria: (index.acsByRequirement.get(requirement.id) || []).slice().sort(),
@@ -1,3 +1,4 @@
1
+ // @ts-check
1
2
  // Resolver enrichment for tasks.
2
3
  //
3
4
  // Back-link arrays:
@@ -8,6 +9,7 @@
8
9
  // `blocked_by` are reciprocal, because authors only write one side. The
9
10
  // resolver bridges them.
10
11
 
12
+ /** @param {TopogramStatement} task @param {ResolverBacklinkIndex} index */
11
13
  export function enrichTask(task, index) {
12
14
  return {
13
15
  blockingMe: (index.tasksThatBlockTarget.get(task.id) || []).slice().sort(),