@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,466 @@
1
+ // @ts-check
2
+
3
+ import fs from "node:fs";
4
+ import os from "node:os";
5
+ import path from "node:path";
6
+
7
+ import { parsePath } from "../../../parser.js";
8
+ import { resolveWorkspace } from "../../../resolver.js";
9
+ import {
10
+ loadProjectConfig,
11
+ validateProjectConfig,
12
+ validateProjectOutputOwnership
13
+ } from "../../../project-config.js";
14
+ import {
15
+ buildTemplateUpdatePlan,
16
+ createNewProject,
17
+ loadTemplatePolicy,
18
+ resolveTemplate,
19
+ templatePolicyDiagnosticsForTemplate
20
+ } from "../../../new-project.js";
21
+ import {
22
+ getTemplateTrustStatus,
23
+ implementationRequiresTrust,
24
+ TEMPLATE_TRUST_FILE,
25
+ templateTrustRecoveryGuidance,
26
+ validateProjectImplementationTrust
27
+ } from "../../../template-trust.js";
28
+ import { runNpmForPackageUpdate } from "../package.js";
29
+ import { ENGINE_ROOT, TEMPLATES_ROOT } from "./constants.js";
30
+ import { combineProjectValidationResults, messageFromError } from "./shared.js";
31
+ import { templateCheckDiagnostic } from "./diagnostics.js";
32
+
33
+ /**
34
+ * @typedef {Object} TemplateCheckDiagnostic
35
+ * @property {string} code
36
+ * @property {"error"|"warning"} severity
37
+ * @property {string} message
38
+ * @property {string|null} path
39
+ * @property {string|null} suggestedFix
40
+ * @property {string|null} step
41
+ */
42
+
43
+ /**
44
+ * @param {string} templateSpec
45
+ * @param {string} relativePath
46
+ * @returns {string|null}
47
+ */
48
+ function localTemplatePath(templateSpec, relativePath) {
49
+ if (
50
+ templateSpec === "." ||
51
+ templateSpec.startsWith("./") ||
52
+ templateSpec.startsWith("../") ||
53
+ path.isAbsolute(templateSpec)
54
+ ) {
55
+ return path.join(path.resolve(templateSpec), relativePath);
56
+ }
57
+ return null;
58
+ }
59
+
60
+ /**
61
+ * @param {string} message
62
+ * @param {string} templateSpec
63
+ * @param {string} step
64
+ * @returns {TemplateCheckDiagnostic}
65
+ */
66
+ function diagnosticForTemplateCreateFailure(message, templateSpec, step) {
67
+ if (message.includes("is missing topogram-template.json")) {
68
+ return templateCheckDiagnostic({
69
+ code: "template_manifest_missing",
70
+ message,
71
+ path: localTemplatePath(templateSpec, "topogram-template.json"),
72
+ suggestedFix: "Add topogram-template.json with id, version, kind, and topogramVersion.",
73
+ step
74
+ });
75
+ }
76
+ if (message.includes("contains implementation/") && message.includes("includesExecutableImplementation: true")) {
77
+ return templateCheckDiagnostic({
78
+ code: "template_implementation_undeclared",
79
+ message,
80
+ path: localTemplatePath(templateSpec, "topogram-template.json"),
81
+ suggestedFix: "Set includesExecutableImplementation to true after reviewing implementation/, or remove implementation/.",
82
+ step
83
+ });
84
+ }
85
+ if (message.includes("is missing required string field") || message.includes("topogram-template.json")) {
86
+ return templateCheckDiagnostic({
87
+ code: "template_manifest_invalid",
88
+ message,
89
+ path: localTemplatePath(templateSpec, "topogram-template.json"),
90
+ suggestedFix: "Fix topogram-template.json so it matches the template manifest schema.",
91
+ step
92
+ });
93
+ }
94
+ if (message.includes("is missing topogram/")) {
95
+ return templateCheckDiagnostic({
96
+ code: "template_topogram_missing",
97
+ message,
98
+ path: localTemplatePath(templateSpec, "topogram"),
99
+ suggestedFix: "Add a topogram/ directory with the reusable Topogram source files.",
100
+ step
101
+ });
102
+ }
103
+ if (message.includes("is missing topogram.project.json")) {
104
+ return templateCheckDiagnostic({
105
+ code: "template_project_config_missing",
106
+ message,
107
+ path: localTemplatePath(templateSpec, "topogram.project.json"),
108
+ suggestedFix: "Add topogram.project.json beside topogram/ with outputs and topology.runtimes.",
109
+ step
110
+ });
111
+ }
112
+ if (message.includes("is missing implementation/")) {
113
+ return templateCheckDiagnostic({
114
+ code: "template_implementation_missing",
115
+ message,
116
+ path: localTemplatePath(templateSpec, "implementation"),
117
+ suggestedFix: "Add implementation/ or set includesExecutableImplementation to false.",
118
+ step
119
+ });
120
+ }
121
+ if (message.includes("unsupported symlink")) {
122
+ return templateCheckDiagnostic({
123
+ code: "template_symlink_unsupported",
124
+ message,
125
+ path: path.isAbsolute(templateSpec) ? templateSpec : null,
126
+ suggestedFix: "Replace template symlinks with real files or directories, then rerun `topogram new` or `topogram template check`.",
127
+ step
128
+ });
129
+ }
130
+ return templateCheckDiagnostic({
131
+ code: "template_create_failed",
132
+ message,
133
+ path: path.isAbsolute(templateSpec) ? templateSpec : null,
134
+ suggestedFix: "Fix the template pack so topogram new can create a starter from it.",
135
+ step
136
+ });
137
+ }
138
+
139
+ /**
140
+ * @param {{ message: string, loc?: any }} error
141
+ * @param {string} step
142
+ * @param {string|null} configPath
143
+ * @returns {TemplateCheckDiagnostic}
144
+ */
145
+ function diagnosticForStarterCheckFailure(error, step, configPath) {
146
+ const locFile = typeof error?.loc?.file === "string" ? error.loc.file : null;
147
+ const isTrust = error.message.includes(TEMPLATE_TRUST_FILE) ||
148
+ error.message.includes("unsupported symlink") ||
149
+ error.message.includes("must be under implementation/");
150
+ return templateCheckDiagnostic({
151
+ code: isTrust ? "template_trust_invalid" : "starter_check_failed",
152
+ message: error.message,
153
+ path: locFile || configPath,
154
+ suggestedFix: isTrust
155
+ ? templateTrustRecoveryGuidance(error.message)
156
+ : "Fix the generated Topogram source or topogram.project.json so topogram check passes.",
157
+ step
158
+ });
159
+ }
160
+
161
+ /**
162
+ * @param {string} name
163
+ * @param {boolean} ok
164
+ * @param {Record<string, any>} [details]
165
+ * @param {TemplateCheckDiagnostic[]} [diagnostics]
166
+ * @returns {{ name: string, ok: boolean, details: Record<string, any>, diagnostics: TemplateCheckDiagnostic[] }}
167
+ */
168
+ function templateCheckStep(name, ok, details = {}, diagnostics = []) {
169
+ return { name, ok, details, diagnostics };
170
+ }
171
+
172
+ /**
173
+ * @param {string} projectRoot
174
+ * @returns {string[]}
175
+ */
176
+ function templateCheckGeneratorDependencies(projectRoot) {
177
+ const packagePath = path.join(projectRoot, "package.json");
178
+ if (!fs.existsSync(packagePath)) {
179
+ return [];
180
+ }
181
+ const pkg = JSON.parse(fs.readFileSync(packagePath, "utf8"));
182
+ const dependencies = {
183
+ ...(pkg.dependencies || {}),
184
+ ...(pkg.devDependencies || {})
185
+ };
186
+ return Object.keys(dependencies).filter((name) =>
187
+ name.includes("topogram-generator") || name.startsWith("@topogram/generator-")
188
+ ).sort();
189
+ }
190
+
191
+ /**
192
+ * @param {string} projectRoot
193
+ * @param {string[]} dependencies
194
+ * @returns {TemplateCheckDiagnostic|null}
195
+ */
196
+ function installTemplateCheckGeneratorDependencies(projectRoot, dependencies) {
197
+ if (dependencies.length === 0) {
198
+ return null;
199
+ }
200
+ const result = runNpmForPackageUpdate(["install", "--ignore-scripts"], projectRoot);
201
+ if (result.status === 0) {
202
+ return null;
203
+ }
204
+ const output = `${result.stdout || ""}\n${result.stderr || ""}`.trim();
205
+ return templateCheckDiagnostic({
206
+ code: "template_generator_dependencies_install_failed",
207
+ message: `Failed to install package-backed generator dependencies: ${dependencies.join(", ")}.`,
208
+ path: path.join(projectRoot, "package.json"),
209
+ suggestedFix: `Run npm install before checking this package-backed generator template.${output ? ` ${output.split(/\r?\n/).slice(-3).join(" ")}` : ""}`,
210
+ step: "generator-dependencies"
211
+ });
212
+ }
213
+
214
+ /**
215
+ * @param {string} templateSpec
216
+ * @returns {{ ok: boolean, templateSpec: string, projectRoot: string|null, steps: Array<{ name: string, ok: boolean, details: Record<string, any>, diagnostics: TemplateCheckDiagnostic[] }>, diagnostics: TemplateCheckDiagnostic[], errors: string[] }}
217
+ */
218
+ export function buildTemplateCheckPayload(templateSpec) {
219
+ if (!templateSpec) {
220
+ throw new Error("topogram template check requires <template-spec-or-path>.");
221
+ }
222
+ const runRoot = fs.mkdtempSync(path.join(os.tmpdir(), "topogram-template-check-"));
223
+ const projectRoot = path.join(runRoot, "starter");
224
+ /** @type {Array<{ name: string, ok: boolean, details: Record<string, any>, diagnostics: TemplateCheckDiagnostic[] }>} */
225
+ const steps = [];
226
+ /** @type {TemplateCheckDiagnostic[]} */
227
+ const diagnostics = [];
228
+ try {
229
+ const callerPolicyInfo = loadTemplatePolicy(process.cwd());
230
+ if (callerPolicyInfo.exists) {
231
+ const resolvedTemplate = resolveTemplate(templateSpec, TEMPLATES_ROOT);
232
+ const policyDiagnostics = templatePolicyDiagnosticsForTemplate(callerPolicyInfo, resolvedTemplate, "template-check-policy");
233
+ if (policyDiagnostics.some((diagnostic) => diagnostic.severity === "error")) {
234
+ const stepDiagnostics = policyDiagnostics.map((diagnostic) => templateCheckDiagnostic(diagnostic));
235
+ diagnostics.push(...stepDiagnostics);
236
+ steps.push(templateCheckStep("template-policy", false, {
237
+ path: callerPolicyInfo.path
238
+ }, stepDiagnostics));
239
+ return {
240
+ ok: false,
241
+ templateSpec,
242
+ projectRoot: null,
243
+ steps,
244
+ diagnostics,
245
+ errors: diagnostics.map((diagnostic) => diagnostic.message)
246
+ };
247
+ }
248
+ }
249
+ const created = createNewProject({
250
+ targetPath: projectRoot,
251
+ templateName: templateSpec,
252
+ engineRoot: ENGINE_ROOT,
253
+ templatesRoot: TEMPLATES_ROOT
254
+ });
255
+ steps.push(templateCheckStep("create-starter", true, {
256
+ template: created.templateName,
257
+ warnings: created.warnings.length
258
+ }));
259
+ const generatorDependencies = templateCheckGeneratorDependencies(projectRoot);
260
+ const installDiagnostic = installTemplateCheckGeneratorDependencies(projectRoot, generatorDependencies);
261
+ if (installDiagnostic) {
262
+ diagnostics.push(installDiagnostic);
263
+ steps.push(templateCheckStep("generator-dependencies", false, {
264
+ dependencies: generatorDependencies
265
+ }, [installDiagnostic]));
266
+ return {
267
+ ok: false,
268
+ templateSpec,
269
+ projectRoot,
270
+ steps,
271
+ diagnostics,
272
+ errors: diagnostics.map((diagnostic) => diagnostic.message)
273
+ };
274
+ }
275
+ if (generatorDependencies.length > 0) {
276
+ steps.push(templateCheckStep("generator-dependencies", true, {
277
+ dependencies: generatorDependencies
278
+ }));
279
+ }
280
+ } catch (error) {
281
+ const stepDiagnostics = [
282
+ diagnosticForTemplateCreateFailure(messageFromError(error), templateSpec, "create-starter")
283
+ ];
284
+ diagnostics.push(...stepDiagnostics);
285
+ steps.push(templateCheckStep("create-starter", false, {}, stepDiagnostics));
286
+ return {
287
+ ok: false,
288
+ templateSpec,
289
+ projectRoot: null,
290
+ steps,
291
+ diagnostics,
292
+ errors: diagnostics.map((diagnostic) => diagnostic.message)
293
+ };
294
+ }
295
+
296
+ const projectConfigInfo = loadProjectConfig(projectRoot);
297
+ if (!projectConfigInfo) {
298
+ const stepDiagnostics = [
299
+ templateCheckDiagnostic({
300
+ code: "starter_project_config_missing",
301
+ message: "Generated starter is missing topogram.project.json.",
302
+ path: path.join(projectRoot, "topogram.project.json"),
303
+ suggestedFix: "Ensure the template includes topogram.project.json at its root.",
304
+ step: "project-config"
305
+ })
306
+ ];
307
+ diagnostics.push(...stepDiagnostics);
308
+ steps.push(templateCheckStep("project-config", false, {}, stepDiagnostics));
309
+ return {
310
+ ok: false,
311
+ templateSpec,
312
+ projectRoot,
313
+ steps,
314
+ diagnostics,
315
+ errors: diagnostics.map((diagnostic) => diagnostic.message)
316
+ };
317
+ }
318
+ steps.push(templateCheckStep("project-config", true, {
319
+ path: projectConfigInfo.configPath,
320
+ template: projectConfigInfo.config.template?.id || null
321
+ }));
322
+
323
+ const ast = parsePath(path.join(projectRoot, "topogram"));
324
+ const resolved = resolveWorkspace(ast);
325
+ const projectValidation = combineProjectValidationResults(
326
+ validateProjectConfig(projectConfigInfo.config, resolved.ok ? resolved.graph : null, { configDir: projectConfigInfo.configDir }),
327
+ validateProjectOutputOwnership(projectConfigInfo),
328
+ validateProjectImplementationTrust(projectConfigInfo)
329
+ );
330
+ const starterCheckOk = resolved.ok && projectValidation.ok;
331
+ const starterDiagnostics = [
332
+ ...(resolved.ok ? [] : resolved.validation.errors),
333
+ ...projectValidation.errors
334
+ ].map((error) => diagnosticForStarterCheckFailure(error, "starter-check", projectConfigInfo.configPath));
335
+ steps.push(templateCheckStep("starter-check", starterCheckOk, {
336
+ files: ast.files.length,
337
+ statements: ast.files.flatMap((/** @type {{ statements: any[] }} */ file) => file.statements).length
338
+ }, starterDiagnostics));
339
+ if (!starterCheckOk) {
340
+ diagnostics.push(...starterDiagnostics);
341
+ }
342
+
343
+ const implementationInfo = projectConfigInfo.config.implementation
344
+ ? {
345
+ config: projectConfigInfo.config.implementation,
346
+ configPath: projectConfigInfo.configPath,
347
+ configDir: projectConfigInfo.configDir
348
+ }
349
+ : null;
350
+ if (implementationInfo && implementationRequiresTrust(implementationInfo, projectConfigInfo.config)) {
351
+ const trustStatus = getTemplateTrustStatus(implementationInfo, projectConfigInfo.config);
352
+ const trustDiagnostics = trustStatus.issues.map((issue) => templateCheckDiagnostic({
353
+ code: "template_trust_invalid",
354
+ message: issue,
355
+ path: trustStatus.trustPath,
356
+ suggestedFix: templateTrustRecoveryGuidance(issue),
357
+ step: "executable-implementation-trust"
358
+ }));
359
+ steps.push(templateCheckStep("executable-implementation-trust", trustStatus.ok, {
360
+ requiresTrust: true,
361
+ trustPath: trustStatus.trustPath,
362
+ trustedFiles: trustStatus.trustRecord?.content?.files?.length || 0
363
+ }, trustDiagnostics));
364
+ if (!trustStatus.ok) {
365
+ diagnostics.push(...trustDiagnostics);
366
+ }
367
+ } else {
368
+ steps.push(templateCheckStep("executable-implementation-trust", true, {
369
+ requiresTrust: false
370
+ }));
371
+ }
372
+
373
+ try {
374
+ const updatePlan = buildTemplateUpdatePlan({
375
+ projectRoot,
376
+ projectConfig: projectConfigInfo.config,
377
+ templateName: null,
378
+ templatesRoot: TEMPLATES_ROOT
379
+ });
380
+ steps.push(templateCheckStep("template-update-plan", updatePlan.ok, {
381
+ writes: updatePlan.writes,
382
+ added: updatePlan.summary.added,
383
+ changed: updatePlan.summary.changed,
384
+ currentOnly: updatePlan.summary.currentOnly
385
+ }));
386
+ if (!updatePlan.ok) {
387
+ const stepDiagnostics = updatePlan.issues.map((issue) => templateCheckDiagnostic({
388
+ code: "template_update_plan_failed",
389
+ message: issue,
390
+ path: projectConfigInfo.configPath,
391
+ suggestedFix: "Fix template metadata so a no-write update plan can be produced.",
392
+ step: "template-update-plan"
393
+ }));
394
+ steps[steps.length - 1].diagnostics.push(...stepDiagnostics);
395
+ diagnostics.push(...stepDiagnostics);
396
+ }
397
+ } catch (error) {
398
+ const stepDiagnostics = [
399
+ templateCheckDiagnostic({
400
+ code: "template_update_plan_failed",
401
+ message: messageFromError(error),
402
+ path: projectConfigInfo.configPath,
403
+ suggestedFix: "Fix template metadata so a no-write update plan can be produced.",
404
+ step: "template-update-plan"
405
+ })
406
+ ];
407
+ diagnostics.push(...stepDiagnostics);
408
+ steps.push(templateCheckStep("template-update-plan", false, {}, stepDiagnostics));
409
+ }
410
+
411
+ return {
412
+ ok: steps.every((step) => step.ok),
413
+ templateSpec,
414
+ projectRoot,
415
+ steps,
416
+ diagnostics,
417
+ errors: diagnostics.map((diagnostic) => diagnostic.message)
418
+ };
419
+ }
420
+
421
+ /**
422
+ * @param {Record<string, any>} details
423
+ * @returns {string[]}
424
+ */
425
+ function formatTemplateCheckDetails(details) {
426
+ return Object.entries(details)
427
+ .filter(([, value]) => value !== undefined && value !== null)
428
+ .map(([key, value]) => ` ${key}: ${typeof value === "object" ? JSON.stringify(value) : String(value)}`);
429
+ }
430
+
431
+ /**
432
+ * @param {ReturnType<typeof buildTemplateCheckPayload>} payload
433
+ * @returns {void}
434
+ */
435
+ export function printTemplateCheckPayload(payload) {
436
+ console.log(payload.ok ? "Template check passed" : "Template check failed");
437
+ console.log(`Template spec: ${payload.templateSpec}`);
438
+ if (payload.projectRoot) {
439
+ console.log(`Temp starter: ${payload.projectRoot}`);
440
+ }
441
+ for (const step of payload.steps) {
442
+ console.log(`${step.ok ? "PASS" : "FAIL"} ${step.name}`);
443
+ for (const detail of formatTemplateCheckDetails(step.details)) {
444
+ console.log(detail);
445
+ }
446
+ for (const diagnostic of step.diagnostics) {
447
+ console.log(` [${diagnostic.severity}] ${diagnostic.code}: ${diagnostic.message}`);
448
+ if (diagnostic.path) {
449
+ console.log(` path: ${diagnostic.path}`);
450
+ }
451
+ if (diagnostic.suggestedFix) {
452
+ console.log(` fix: ${diagnostic.suggestedFix}`);
453
+ }
454
+ }
455
+ }
456
+ const stepDiagnostics = new Set(payload.steps.flatMap((step) => step.diagnostics));
457
+ for (const diagnostic of payload.diagnostics.filter((item) => !stepDiagnostics.has(item))) {
458
+ console.log(`[${diagnostic.severity}] ${diagnostic.code}: ${diagnostic.message}`);
459
+ if (diagnostic.path) {
460
+ console.log(` path: ${diagnostic.path}`);
461
+ }
462
+ if (diagnostic.suggestedFix) {
463
+ console.log(` fix: ${diagnostic.suggestedFix}`);
464
+ }
465
+ }
466
+ }
@@ -0,0 +1,8 @@
1
+ // @ts-check
2
+
3
+ import path from "node:path";
4
+
5
+ export const TEMPLATE_FILES_MANIFEST = ".topogram-template-files.json";
6
+ export const TEMPLATE_POLICY_FILE = "topogram.template-policy.json";
7
+ export const ENGINE_ROOT = decodeURIComponent(new URL("../../../../", import.meta.url).pathname);
8
+ export const TEMPLATES_ROOT = path.join(ENGINE_ROOT, "templates");
@@ -0,0 +1,26 @@
1
+ // @ts-check
2
+
3
+ /**
4
+ * @typedef {Object} TemplateCheckDiagnostic
5
+ * @property {string} code
6
+ * @property {"error"|"warning"} severity
7
+ * @property {string} message
8
+ * @property {string|null} path
9
+ * @property {string|null} suggestedFix
10
+ * @property {string|null} step
11
+ */
12
+
13
+ /**
14
+ * @param {Record<string, any>} input
15
+ * @returns {TemplateCheckDiagnostic}
16
+ */
17
+ export function templateCheckDiagnostic(input) {
18
+ return {
19
+ code: String(input.code || "template_check_failed"),
20
+ severity: input.severity === "warning" ? "warning" : "error",
21
+ message: String(input.message || "Template check failed."),
22
+ path: typeof input.path === "string" ? input.path : null,
23
+ suggestedFix: typeof input.suggestedFix === "string" ? input.suggestedFix : null,
24
+ step: typeof input.step === "string" ? input.step : null
25
+ };
26
+ }
@@ -0,0 +1,28 @@
1
+ // @ts-check
2
+
3
+ /**
4
+ * @returns {void}
5
+ */
6
+ export function printTemplateHelp() {
7
+ console.log("Usage: topogram template list [--json] [--catalog <path-or-source>]");
8
+ console.log(" or: topogram template explain [path] [--json]");
9
+ console.log(" or: topogram template status [path] [--latest] [--json]");
10
+ console.log(" or: topogram template detach [path] [--dry-run] [--remove-policy] [--json]");
11
+ console.log(" or: topogram template check <template-spec-or-path> [--json]");
12
+ console.log(" or: topogram template policy init [path] [--json]");
13
+ console.log(" or: topogram template policy check [path] [--json]");
14
+ console.log(" or: topogram template policy explain [path] [--json]");
15
+ console.log(" or: topogram template policy pin <template-id@version> [path] [--json]");
16
+ console.log(" or: topogram template update [path] --status|--recommend|--plan|--check|--apply [--template <spec>|--latest] [--json] [--out <path>]");
17
+ console.log("");
18
+ console.log("Template commands inspect catalog-backed starters, project provenance, trust policy, and update plans.");
19
+ console.log("");
20
+ console.log("Examples:");
21
+ console.log(" topogram template list");
22
+ console.log(" topogram template explain");
23
+ console.log(" topogram template status");
24
+ console.log(" topogram template status --latest");
25
+ console.log(" topogram template policy check");
26
+ console.log(" topogram template check ./local-template");
27
+ console.log(" topogram template update --recommend");
28
+ }