@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
@@ -0,0 +1,348 @@
1
+ // @ts-check
2
+
3
+ import fs from "node:fs";
4
+ import path from "node:path";
5
+
6
+ import { githubRepoSlug } from "../topogram-config.js";
7
+ import { cliDependencyForProject, generatorDependenciesForTemplate, isSameOrInside, packageNameFromPath, writeProjectNpmConfig } from "./package-spec.js";
8
+
9
+ /** @typedef {import("./types.js").CreateNewProjectOptions} CreateNewProjectOptions */
10
+ /** @typedef {import("./types.js").TemplateUpdatePlanOptions} TemplateUpdatePlanOptions */
11
+ /** @typedef {import("./types.js").TemplateUpdateFileActionOptions} TemplateUpdateFileActionOptions */
12
+ /** @typedef {import("./types.js").TemplateOwnedFileRecord} TemplateOwnedFileRecord */
13
+ /** @typedef {import("./types.js").TemplateManifest} TemplateManifest */
14
+ /** @typedef {import("./types.js").TemplateTopologySummary} TemplateTopologySummary */
15
+ /** @typedef {import("./types.js").TemplatePolicy} TemplatePolicy */
16
+ /** @typedef {import("./types.js").TemplatePolicyInfo} TemplatePolicyInfo */
17
+ /** @typedef {import("./types.js").TemplateUpdateDiagnostic} TemplateUpdateDiagnostic */
18
+ /** @typedef {import("./types.js").ResolvedTemplate} ResolvedTemplate */
19
+ /** @typedef {import("./types.js").CatalogTemplateProvenance} CatalogTemplateProvenance */
20
+
21
+ /**
22
+ * @param {string} projectRoot
23
+ * @param {string} engineRoot
24
+ * @returns {void}
25
+ */
26
+ export function assertProjectOutsideEngine(projectRoot, engineRoot) {
27
+ if (isSameOrInside(path.resolve(engineRoot), path.resolve(projectRoot))) {
28
+ throw new Error(
29
+ `Refusing to create a generated project inside the engine directory. Use a path outside engine, for example '../${path.basename(projectRoot)}'.`
30
+ );
31
+ }
32
+ }
33
+
34
+ /**
35
+ * @param {string} projectRoot
36
+ * @returns {void}
37
+ */
38
+ export function ensureCreatableProjectRoot(projectRoot) {
39
+ if (!fs.existsSync(projectRoot)) {
40
+ fs.mkdirSync(projectRoot, { recursive: true });
41
+ return;
42
+ }
43
+ if (!fs.statSync(projectRoot).isDirectory()) {
44
+ throw new Error(`Cannot create project at '${projectRoot}' because it is not a directory.`);
45
+ }
46
+ /** @type {string[]} */
47
+ const dirEntries = fs.readdirSync(projectRoot);
48
+ const entries = dirEntries.filter((entry) => entry !== ".DS_Store");
49
+ if (entries.length > 0) {
50
+ throw new Error(`Refusing to create a Topogram project in non-empty directory '${projectRoot}'.`);
51
+ }
52
+ }
53
+
54
+ /**
55
+ * @param {string} templateRoot
56
+ * @param {string} projectRoot
57
+ * @returns {void}
58
+ */
59
+ export function copyTopogramWorkspace(templateRoot, projectRoot) {
60
+ const topogramRoot = path.join(projectRoot, "topogram");
61
+ fs.cpSync(path.join(templateRoot, "topogram"), topogramRoot, { recursive: true });
62
+
63
+ fs.cpSync(
64
+ path.join(templateRoot, "topogram.project.json"),
65
+ path.join(projectRoot, "topogram.project.json")
66
+ );
67
+ const implementationRoot = path.join(templateRoot, "implementation");
68
+ if (fs.existsSync(implementationRoot)) {
69
+ fs.cpSync(
70
+ implementationRoot,
71
+ path.join(projectRoot, "implementation"),
72
+ { recursive: true }
73
+ );
74
+ }
75
+ }
76
+
77
+ /**
78
+ * @param {string} projectRoot
79
+ * @param {string} engineRoot
80
+ * @param {ResolvedTemplate} template
81
+ * @returns {void}
82
+ */
83
+ export function writeProjectPackage(projectRoot, engineRoot, template) {
84
+ const cliDependency = cliDependencyForProject(projectRoot, engineRoot);
85
+ const generatorDependencies = generatorDependenciesForTemplate(template.root);
86
+ const starterScripts = template.manifest.starterScripts || {};
87
+ const pkg = {
88
+ name: packageNameFromPath(projectRoot),
89
+ private: true,
90
+ type: "module",
91
+ scripts: {
92
+ explain: "node ./scripts/explain.mjs",
93
+ doctor: "topogram doctor",
94
+ "agent:brief": "topogram agent brief --json",
95
+ "source:status": "topogram source status --local",
96
+ "source:status:remote": "topogram source status --remote",
97
+ check: "topogram check",
98
+ "check:json": "topogram check --json",
99
+ "query:list": "topogram query list --json",
100
+ "query:show": "topogram query show",
101
+ generate: "topogram generate",
102
+ "template:explain": "topogram template explain",
103
+ "template:status": "topogram template status",
104
+ "template:detach": "topogram template detach",
105
+ "template:detach:dry-run": "topogram template detach --dry-run",
106
+ "template:policy:check": "topogram template policy check",
107
+ "template:policy:explain": "topogram template policy explain",
108
+ "generator:policy:status": "topogram generator policy status",
109
+ "generator:policy:check": "topogram generator policy check",
110
+ "generator:policy:explain": "topogram generator policy explain",
111
+ "template:update:status": "topogram template update --status",
112
+ "template:update:recommend": "topogram template update --recommend",
113
+ "template:update:plan": "topogram template update --plan",
114
+ "template:update:check": "topogram template update --check",
115
+ "template:update:apply": "topogram template update --apply",
116
+ "trust:status": "topogram trust status",
117
+ "trust:diff": "topogram trust diff",
118
+ verify: "npm run app:compile",
119
+ bootstrap: "npm run app:bootstrap",
120
+ dev: "npm run app:dev",
121
+ "app:bootstrap": "npm --prefix ./app run bootstrap",
122
+ "app:dev": "npm --prefix ./app run dev",
123
+ "app:compile": "npm --prefix ./app run compile",
124
+ "app:smoke": "npm --prefix ./app run smoke",
125
+ "app:runtime-check": "npm --prefix ./app run runtime-check",
126
+ "app:check": "npm run app:compile",
127
+ "app:probe": "npm run app:smoke && npm run app:runtime-check",
128
+ "app:runtime": "npm --prefix ./app run runtime",
129
+ ...starterScripts
130
+ },
131
+ devDependencies: {
132
+ [cliDependency.name]: cliDependency.spec,
133
+ ...generatorDependencies
134
+ }
135
+ };
136
+ fs.writeFileSync(path.join(projectRoot, "package.json"), `${JSON.stringify(pkg, null, 2)}\n`, "utf8");
137
+ writeProjectNpmConfig(projectRoot, cliDependency);
138
+ }
139
+
140
+ /**
141
+ * @param {string} projectRoot
142
+ * @returns {void}
143
+ */
144
+ export function writeExplainScript(projectRoot) {
145
+ const scriptDir = path.join(projectRoot, "scripts");
146
+ fs.mkdirSync(scriptDir, { recursive: true });
147
+ const script = `const message = \`
148
+ Topogram app workflow
149
+
150
+ 1. Edit:
151
+ topogram/
152
+ topogram.project.json
153
+
154
+ 2. Start with project guidance:
155
+ npm run agent:brief
156
+
157
+ 3. Validate:
158
+ npm run doctor
159
+ npm run source:status
160
+ npm run template:explain
161
+ npm run check
162
+
163
+ 4. Regenerate:
164
+ npm run generate
165
+
166
+ 5. Verify generated app:
167
+ npm run verify
168
+
169
+ 6. Run locally:
170
+ npm run bootstrap
171
+ npm run dev
172
+
173
+ 7. Probe the running app from another terminal:
174
+ npm run app:probe
175
+
176
+ Or run self-contained local runtime verification:
177
+ npm run app:runtime
178
+
179
+ Useful inspection:
180
+ npm run agent:brief
181
+ npm run check:json
182
+ topogram emit ui-widget-contract ./topogram --json
183
+ topogram emit widget-conformance-report ./topogram --json
184
+ npm run doctor
185
+ npm run source:status
186
+ npm run source:status:remote
187
+ npm run template:explain
188
+ npm run template:status
189
+ npm run template:detach:dry-run
190
+ npm run template:policy:check
191
+ npm run template:policy:explain
192
+ npm run generator:policy:status
193
+ npm run generator:policy:check
194
+ npm run generator:policy:explain
195
+ npm run template:update:status
196
+ npm run template:update:recommend
197
+ npm run template:update:plan
198
+ npm run template:update:check
199
+ npm run template:update:apply
200
+ npm run trust:status
201
+ npm run trust:diff
202
+ \`;
203
+
204
+ console.log(message.trimEnd());
205
+ `;
206
+ fs.writeFileSync(path.join(scriptDir, "explain.mjs"), script, "utf8");
207
+ }
208
+
209
+ /**
210
+ * @param {string} projectRoot
211
+ * @param {Record<string, any>} projectConfig
212
+ * @returns {void}
213
+ */
214
+ export function writeProjectReadme(projectRoot, projectConfig) {
215
+ const template = projectConfig.template || {};
216
+ const templateName = template.id || "unknown";
217
+ const workflowCommands = [
218
+ "npm install",
219
+ "npm run explain",
220
+ "npm run agent:brief",
221
+ "npm run doctor",
222
+ "npm run source:status",
223
+ "npm run template:explain",
224
+ "npm run check",
225
+ "npm run template:policy:check",
226
+ "npm run generator:policy:status",
227
+ "npm run generator:policy:check",
228
+ ...(template.includesExecutableImplementation ? [
229
+ "npm run template:policy:explain",
230
+ "npm run trust:status"
231
+ ] : []),
232
+ "npm run generate",
233
+ "npm run verify"
234
+ ];
235
+ const provenanceLines = [];
236
+ provenanceLines.push(`- Template: \`${templateName}@${template.version || "unknown"}\``);
237
+ provenanceLines.push(`- Source: \`${template.source || "unknown"}\``);
238
+ if (template.sourceSpec) {
239
+ provenanceLines.push(`- Source spec: \`${template.sourceSpec}\``);
240
+ }
241
+ if (template.catalog) {
242
+ provenanceLines.push(`- Catalog: \`${template.catalog.id}\` from \`${template.catalog.source}\``);
243
+ provenanceLines.push(`- Package: \`${template.catalog.packageSpec}\``);
244
+ }
245
+ provenanceLines.push(`- Executable implementation: \`${template.includesExecutableImplementation ? "yes" : "no"}\``);
246
+ const readme = `# ${packageNameFromPath(projectRoot)}
247
+
248
+ Generated by \`topogram new\`.
249
+
250
+ ## Template
251
+
252
+ ${provenanceLines.join("\n")}
253
+
254
+ ## Workflow
255
+
256
+ \`\`\`bash
257
+ ${workflowCommands.join("\n")}
258
+ \`\`\`
259
+
260
+ Edit \`topogram/\` and \`topogram.project.json\`, then regenerate with \`npm run generate\`.
261
+ Generated app code is written to \`app/\`.
262
+ Use \`topogram emit <target>\` to inspect contracts, reports, snapshots, and other artifacts without regenerating the app.
263
+ Agents should start with \`AGENTS.md\` and \`npm run agent:brief\`. The direct \`topogram agent brief --json\` command is the canonical machine-readable first-run guidance.
264
+ ${template.includesExecutableImplementation ? "\nThis template copied `implementation/` code. `topogram new` did not execute it; review `implementation/`, `topogram.template-policy.json`, and `.topogram-template-trust.json` before regenerating after edits.\n" : ""}
265
+ `;
266
+ fs.writeFileSync(path.join(projectRoot, "README.md"), readme, "utf8");
267
+ }
268
+
269
+ /**
270
+ * @param {string} projectRoot
271
+ * @param {Record<string, any>} projectConfig
272
+ * @returns {void}
273
+ */
274
+ export function writeAgentsGuide(projectRoot, projectConfig) {
275
+ const template = projectConfig.template || {};
276
+ const hasImplementation = Boolean(projectConfig.implementation || template.includesExecutableImplementation);
277
+ const guide = `# Agent Guide
278
+
279
+ Start here before editing this Topogram project.
280
+
281
+ ## First Read
282
+
283
+ 1. \`AGENTS.md\`
284
+ 2. \`README.md\`
285
+ 3. \`topogram.project.json\`
286
+ 4. \`topogram.template-policy.json\`
287
+ 5. \`topogram.generator-policy.json\`
288
+ ${hasImplementation ? "6. `.topogram-template-trust.json`\n7. `implementation/`\n8. Focused `topogram query ...` output\n" : "6. Focused `topogram query ...` output\n"}
289
+ Machine-readable source:
290
+
291
+ \`\`\`bash
292
+ topogram agent brief --json
293
+ \`\`\`
294
+
295
+ Local shortcut:
296
+
297
+ \`\`\`bash
298
+ npm run agent:brief
299
+ \`\`\`
300
+
301
+ Reference: https://github.com/${githubRepoSlug(null)}/blob/main/docs/agent-first-run.md
302
+
303
+ ## First Commands
304
+
305
+ \`\`\`bash
306
+ npm run agent:brief
307
+ npm run doctor
308
+ npm run source:status
309
+ npm run template:explain
310
+ npm run generator:policy:check
311
+ ${hasImplementation ? "npm run trust:status\n" : ""}npm run check
312
+ npm run query:list
313
+ npm run query:show -- widget-behavior
314
+ \`\`\`
315
+
316
+ ## Edit Rules
317
+
318
+ - Edit \`topogram/**\` and \`topogram.project.json\` first.
319
+ - Review policy files before editing \`topogram.template-policy.json\` or \`topogram.generator-policy.json\`.
320
+ - Do not make lasting edits under generated-owned \`app/**\`; use \`npm run generate\` to replace generated output.
321
+ - If an output is changed to maintained ownership, agents may edit that app code directly after reading focused query packets.
322
+
323
+ ## UI And Widgets
324
+
325
+ - \`ui_contract\` owns screens, regions, widget bindings, behavior, visibility, and semantic design tokens.
326
+ - Web/iOS/Android surfaces realize the shared UI contract; they do not own widget placement.
327
+ - Use \`topogram widget check --json\`, \`topogram widget behavior --json\`, and focused \`topogram query ...\` packets after UI edits.
328
+
329
+ ## Template And Trust
330
+
331
+ - Local edits to template-derived Topogram files are project-owned.
332
+ - Use \`npm run source:status\` and \`npm run template:update:recommend\` before applying template updates.
333
+ ${hasImplementation ? "- This project has executable `implementation/` code. `topogram new` did not execute it. Do not refresh trust until the implementation has been reviewed.\n" : "- This template does not declare executable implementation code.\n"}
334
+ ## Import And Adoption
335
+
336
+ - If \`.topogram-import.json\` exists, run \`topogram import check .\`, \`topogram import plan .\`, \`topogram import adopt --list .\`, and \`topogram import history . --verify\`.
337
+ - Imported Topogram files are project-owned after adoption; source hashes record trusted import evidence at the time of import.
338
+
339
+ ## Verification Gates
340
+
341
+ \`\`\`bash
342
+ npm run check
343
+ npm run generate
344
+ npm run verify
345
+ \`\`\`
346
+ `;
347
+ fs.writeFileSync(path.join(projectRoot, "AGENTS.md"), guide, "utf8");
348
+ }
@@ -0,0 +1,269 @@
1
+ // @ts-check
2
+
3
+ import fs from "node:fs";
4
+ import path from "node:path";
5
+
6
+ import { TEMPLATE_POLICY_FILE } from "./constants.js";
7
+ import { stableJsonStringify } from "./json.js";
8
+ import { currentTemplateMetadata } from "./metadata.js";
9
+ import { packageScopeFromSpec } from "./package-spec.js";
10
+
11
+ /** @typedef {import("./types.js").CreateNewProjectOptions} CreateNewProjectOptions */
12
+ /** @typedef {import("./types.js").TemplateUpdatePlanOptions} TemplateUpdatePlanOptions */
13
+ /** @typedef {import("./types.js").TemplateUpdateFileActionOptions} TemplateUpdateFileActionOptions */
14
+ /** @typedef {import("./types.js").TemplateOwnedFileRecord} TemplateOwnedFileRecord */
15
+ /** @typedef {import("./types.js").TemplateManifest} TemplateManifest */
16
+ /** @typedef {import("./types.js").TemplateTopologySummary} TemplateTopologySummary */
17
+ /** @typedef {import("./types.js").TemplatePolicy} TemplatePolicy */
18
+ /** @typedef {import("./types.js").TemplatePolicyInfo} TemplatePolicyInfo */
19
+ /** @typedef {import("./types.js").TemplateUpdateDiagnostic} TemplateUpdateDiagnostic */
20
+ /** @typedef {import("./types.js").ResolvedTemplate} ResolvedTemplate */
21
+ /** @typedef {import("./types.js").CatalogTemplateProvenance} CatalogTemplateProvenance */
22
+
23
+ /**
24
+ * @param {Record<string, any>} input
25
+ * @returns {TemplateUpdateDiagnostic}
26
+ */
27
+ export function templateUpdateDiagnostic(input) {
28
+ return {
29
+ code: String(input.code || "template_update_failed"),
30
+ severity: input.severity === "warning" ? "warning" : "error",
31
+ message: String(input.message || "Template update failed."),
32
+ path: typeof input.path === "string" ? input.path : null,
33
+ suggestedFix: typeof input.suggestedFix === "string" ? input.suggestedFix : null,
34
+ step: typeof input.step === "string" ? input.step : null
35
+ };
36
+ }
37
+
38
+ /**
39
+ * @param {unknown} value
40
+ * @param {string} policyPath
41
+ * @returns {TemplatePolicy}
42
+ */
43
+ function validateTemplatePolicy(value, policyPath) {
44
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
45
+ throw new Error(`${TEMPLATE_POLICY_FILE} must contain a JSON object.`);
46
+ }
47
+ const policy = /** @type {Record<string, unknown>} */ (value);
48
+ const version = typeof policy.version === "string" && policy.version ? policy.version : "0.1";
49
+ const allowedSources = Array.isArray(policy.allowedSources) ? policy.allowedSources : ["local", "package"];
50
+ const invalidSource = allowedSources.find((source) => !["local", "package"].includes(String(source)));
51
+ if (invalidSource) {
52
+ throw new Error(`${policyPath} has invalid allowedSources value '${String(invalidSource)}'.`);
53
+ }
54
+ const allowedTemplateIds = Array.isArray(policy.allowedTemplateIds)
55
+ ? policy.allowedTemplateIds.map(String).filter(Boolean)
56
+ : [];
57
+ const allowedPackageScopes = Array.isArray(policy.allowedPackageScopes)
58
+ ? policy.allowedPackageScopes.map(String).filter(Boolean)
59
+ : [];
60
+ const executableImplementation = policy.executableImplementation === "deny" || policy.executableImplementation === "warn"
61
+ ? policy.executableImplementation
62
+ : "allow";
63
+ const pinnedVersions = policy.pinnedVersions && typeof policy.pinnedVersions === "object" && !Array.isArray(policy.pinnedVersions)
64
+ ? Object.fromEntries(Object.entries(policy.pinnedVersions).filter(([, pin]) => typeof pin === "string"))
65
+ : {};
66
+ return {
67
+ version,
68
+ allowedSources: /** @type {Array<"local"|"package">} */ (allowedSources),
69
+ allowedTemplateIds,
70
+ allowedPackageScopes,
71
+ executableImplementation,
72
+ pinnedVersions
73
+ };
74
+ }
75
+
76
+ /**
77
+ * @param {string} projectRoot
78
+ * @returns {TemplatePolicyInfo}
79
+ */
80
+ export function loadTemplatePolicy(projectRoot) {
81
+ const policyPath = path.join(projectRoot, TEMPLATE_POLICY_FILE);
82
+ if (!fs.existsSync(policyPath)) {
83
+ return {
84
+ path: policyPath,
85
+ policy: null,
86
+ exists: false,
87
+ diagnostics: []
88
+ };
89
+ }
90
+ try {
91
+ return {
92
+ path: policyPath,
93
+ policy: validateTemplatePolicy(JSON.parse(fs.readFileSync(policyPath, "utf8")), policyPath),
94
+ exists: true,
95
+ diagnostics: []
96
+ };
97
+ } catch (error) {
98
+ return {
99
+ path: policyPath,
100
+ policy: null,
101
+ exists: true,
102
+ diagnostics: [templateUpdateDiagnostic({
103
+ code: "template_policy_invalid",
104
+ message: error instanceof Error ? error.message : String(error),
105
+ path: policyPath,
106
+ suggestedFix: "Fix topogram.template-policy.json or regenerate it with `topogram template policy init`.",
107
+ step: "policy"
108
+ })]
109
+ };
110
+ }
111
+ }
112
+
113
+ /**
114
+ * @param {ResolvedTemplate} template
115
+ * @returns {TemplatePolicy}
116
+ */
117
+ export function defaultTemplatePolicyForTemplate(template) {
118
+ const allowedPackageScopes = [];
119
+ const idScope = template.source === "package"
120
+ ? packageScopeFromSpec(template.packageSpec || template.requested)
121
+ : null;
122
+ if (template.source === "package" && idScope) {
123
+ allowedPackageScopes.push(idScope);
124
+ }
125
+ return {
126
+ version: "0.1",
127
+ allowedSources: ["local", "package"],
128
+ allowedTemplateIds: [template.manifest.id],
129
+ allowedPackageScopes,
130
+ executableImplementation: "allow",
131
+ pinnedVersions: {}
132
+ };
133
+ }
134
+
135
+ /**
136
+ * @param {string} projectRoot
137
+ * @param {TemplatePolicy} policy
138
+ * @returns {TemplatePolicy}
139
+ */
140
+ export function writeTemplatePolicy(projectRoot, policy) {
141
+ fs.writeFileSync(path.join(projectRoot, TEMPLATE_POLICY_FILE), `${stableJsonStringify(policy)}\n`, "utf8");
142
+ return policy;
143
+ }
144
+
145
+ /**
146
+ * @param {string} projectRoot
147
+ * @param {Record<string, any>} projectConfig
148
+ * @returns {TemplatePolicy}
149
+ */
150
+ export function writeTemplatePolicyForProject(projectRoot, projectConfig) {
151
+ const current = currentTemplateMetadata(projectConfig);
152
+ /** @type {string[]} */
153
+ const allowedPackageScopes = [];
154
+ if (current.source === "package") {
155
+ const currentScope = packageScopeFromSpec(current.sourceSpec) ||
156
+ (current.id?.startsWith("@") ? current.id.split("/")[0] : null);
157
+ if (currentScope) {
158
+ allowedPackageScopes.push(currentScope);
159
+ }
160
+ }
161
+ return writeTemplatePolicy(projectRoot, {
162
+ version: "0.1",
163
+ allowedSources: ["local", "package"],
164
+ allowedTemplateIds: current.id ? [current.id] : [],
165
+ allowedPackageScopes,
166
+ executableImplementation: "allow",
167
+ pinnedVersions: {}
168
+ });
169
+ }
170
+
171
+ /**
172
+ * @param {TemplatePolicyInfo} policyInfo
173
+ * @param {ResolvedTemplate} template
174
+ * @param {string} step
175
+ * @returns {TemplateUpdateDiagnostic[]}
176
+ */
177
+ export function templatePolicyDiagnosticsForTemplate(policyInfo, template, step) {
178
+ if (policyInfo.diagnostics.length > 0) {
179
+ return policyInfo.diagnostics;
180
+ }
181
+ if (!policyInfo.policy) {
182
+ return [];
183
+ }
184
+ const policy = policyInfo.policy;
185
+ /** @type {TemplateUpdateDiagnostic[]} */
186
+ const diagnostics = [];
187
+ if (policy.allowedSources.length > 0 && !policy.allowedSources.includes(template.source)) {
188
+ diagnostics.push(templateUpdateDiagnostic({
189
+ code: "template_source_denied",
190
+ message: `Template source '${template.source}' is not allowed by ${TEMPLATE_POLICY_FILE}.`,
191
+ path: policyInfo.path,
192
+ suggestedFix: `Run \`topogram template policy init\` to reset from the current project, or add '${template.source}' to allowedSources after review.`,
193
+ step
194
+ }));
195
+ }
196
+ if (policy.allowedTemplateIds.length > 0 && !policy.allowedTemplateIds.includes(template.manifest.id)) {
197
+ diagnostics.push(templateUpdateDiagnostic({
198
+ code: "template_id_denied",
199
+ message: `Template '${template.manifest.id}' is not allowed by ${TEMPLATE_POLICY_FILE}.`,
200
+ path: policyInfo.path,
201
+ suggestedFix: `Run \`topogram template policy pin ${template.manifest.id}@${template.manifest.version}\` after review, or choose an allowed template.`,
202
+ step
203
+ }));
204
+ }
205
+ if (template.source === "package" && policy.allowedPackageScopes && policy.allowedPackageScopes.length > 0) {
206
+ const scope = packageScopeFromSpec(template.packageSpec || template.requested) ||
207
+ (template.manifest.id.startsWith("@") ? template.manifest.id.split("/")[0] : null);
208
+ if (!scope || !policy.allowedPackageScopes.includes(scope)) {
209
+ diagnostics.push(templateUpdateDiagnostic({
210
+ code: "template_package_scope_denied",
211
+ message: `Template package scope '${scope || "(unscoped)"}' is not allowed by ${TEMPLATE_POLICY_FILE}.`,
212
+ path: policyInfo.path,
213
+ suggestedFix: `Add '${scope || "(unscoped)"}' to allowedPackageScopes after review, or choose a package from an allowed scope.`,
214
+ step
215
+ }));
216
+ }
217
+ }
218
+ const pinnedVersion = policy.pinnedVersions?.[template.manifest.id];
219
+ if (pinnedVersion && pinnedVersion !== template.manifest.version) {
220
+ diagnostics.push(templateUpdateDiagnostic({
221
+ code: "template_version_mismatch",
222
+ message: `Template '${template.manifest.id}' is pinned to version '${pinnedVersion}', but candidate version is '${template.manifest.version}'.`,
223
+ path: policyInfo.path,
224
+ suggestedFix: `Run \`topogram template policy pin ${template.manifest.id}@${template.manifest.version}\` after review, or use version '${pinnedVersion}'.`,
225
+ step
226
+ }));
227
+ }
228
+ if (template.manifest.includesExecutableImplementation) {
229
+ if (policy.executableImplementation === "deny") {
230
+ diagnostics.push(templateUpdateDiagnostic({
231
+ code: "template_executable_denied",
232
+ message: `Template '${template.manifest.id}' includes executable implementation code, which is denied by ${TEMPLATE_POLICY_FILE}.`,
233
+ path: policyInfo.path,
234
+ suggestedFix: "Use a non-executable template, or set executableImplementation to 'allow' after reviewing implementation/.",
235
+ step
236
+ }));
237
+ } else if (policy.executableImplementation === "warn") {
238
+ diagnostics.push(templateUpdateDiagnostic({
239
+ code: "template_executable_warning",
240
+ severity: "warning",
241
+ message: `Template '${template.manifest.id}' includes executable implementation code.`,
242
+ path: policyInfo.path,
243
+ suggestedFix: "Review implementation/ before running topogram generate.",
244
+ step
245
+ }));
246
+ }
247
+ }
248
+ return diagnostics;
249
+ }
250
+
251
+ /**
252
+ * @param {string} projectRoot
253
+ * @param {ResolvedTemplate} template
254
+ * @param {string} step
255
+ * @returns {TemplateUpdateDiagnostic[]}
256
+ */
257
+ export function templatePolicyDiagnosticsForProject(projectRoot, template, step) {
258
+ return templatePolicyDiagnosticsForTemplate(loadTemplatePolicy(projectRoot), template, step);
259
+ }
260
+
261
+ /**
262
+ * @param {TemplateUpdateDiagnostic[]} diagnostics
263
+ * @returns {string[]}
264
+ */
265
+ export function issueMessagesFromDiagnostics(diagnostics) {
266
+ return diagnostics
267
+ .filter((diagnostic) => diagnostic.severity === "error")
268
+ .map((diagnostic) => diagnostic.message);
269
+ }