@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,76 @@
1
+ // @ts-check
2
+
3
+ /**
4
+ * @returns {void}
5
+ */
6
+ export function printSetupHelp() {
7
+ console.log("Usage: topogram setup package-auth|catalog-auth");
8
+ console.log("");
9
+ console.log("Prints setup guidance for public Topogram packages, private package auth, and catalog access. This command does not write credentials.");
10
+ console.log("");
11
+ console.log("Commands:");
12
+ console.log(" topogram setup package-auth");
13
+ console.log(" topogram setup catalog-auth");
14
+ }
15
+
16
+ /**
17
+ * @returns {void}
18
+ */
19
+ export function printPackageAuthSetup() {
20
+ console.log("Topogram package auth setup");
21
+ console.log("");
22
+ console.log("Public Topogram CLI, generator, template, and starter packages are published to npmjs.");
23
+ console.log("");
24
+ console.log("Local public-package setup:");
25
+ console.log(" npm install --save-dev @topogram/cli");
26
+ console.log("");
27
+ console.log("Private template or generator packages may still require registry-specific npm auth.");
28
+ console.log("Run `topogram doctor` after setup.");
29
+ }
30
+
31
+ /**
32
+ * @returns {void}
33
+ */
34
+ export function printCatalogAuthSetup() {
35
+ console.log("Topogram catalog auth setup");
36
+ console.log("");
37
+ console.log("The default Topogram catalog is public and does not require GitHub auth.");
38
+ console.log("Restricted GitHub catalog reads prefer GITHUB_TOKEN or GH_TOKEN. Local `gh auth login` is a fallback when no token env var is set.");
39
+ console.log("");
40
+ console.log("Restricted catalog local setup:");
41
+ console.log(" export GITHUB_TOKEN=<token-with-repo-read>");
42
+ console.log(" topogram catalog list");
43
+ console.log("");
44
+ console.log("Local fallback without token env:");
45
+ console.log(" gh auth login");
46
+ console.log(" topogram catalog list");
47
+ console.log("");
48
+ console.log("Restricted catalog GitHub Actions setup:");
49
+ console.log(" permissions:");
50
+ console.log(" contents: read");
51
+ console.log(" env:");
52
+ console.log(" GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}");
53
+ console.log("");
54
+ console.log("For restricted catalog repositories, grant the workflow token or PAT read access.");
55
+ console.log("Run `topogram catalog doctor` after setup.");
56
+ }
57
+
58
+ /**
59
+ * @param {string[]} args
60
+ * @returns {number|null}
61
+ */
62
+ export function handleSetupCommand(args) {
63
+ if (args[0] !== "setup") {
64
+ return null;
65
+ }
66
+ if (args[1] === "package-auth") {
67
+ printPackageAuthSetup();
68
+ return 0;
69
+ }
70
+ if (args[1] === "catalog-auth") {
71
+ printCatalogAuthSetup();
72
+ return 0;
73
+ }
74
+ printSetupHelp();
75
+ return args[1] ? 1 : 0;
76
+ }
@@ -0,0 +1,291 @@
1
+ // @ts-check
2
+
3
+ import fs from "node:fs";
4
+ import path from "node:path";
5
+
6
+ import { stableStringify } from "../../format.js";
7
+ import {
8
+ buildTopogramSourceStatus,
9
+ TOPOGRAM_SOURCE_FILE
10
+ } from "../../catalog.js";
11
+ import { loadProjectConfig } from "../../project-config.js";
12
+ import {
13
+ getTemplateTrustStatus,
14
+ TEMPLATE_TRUST_FILE
15
+ } from "../../template-trust.js";
16
+ import {
17
+ checkTemplatePackageStatus,
18
+ localTemplatePackageStatus
19
+ } from "./package.js";
20
+ import { buildTemplateOwnedBaselineStatus } from "./template.js";
21
+
22
+ /**
23
+ * @typedef {Record<string, any>} AnyRecord
24
+ */
25
+
26
+ /**
27
+ * @returns {void}
28
+ */
29
+ export function printSourceHelp() {
30
+ console.log("Usage: topogram source status [path] [--local|--remote] [--json]");
31
+ console.log("");
32
+ console.log("Reports source provenance, template attachment state, and whether local edits affect template-owned files.");
33
+ console.log("");
34
+ console.log("Examples:");
35
+ console.log(" topogram source status");
36
+ console.log(" topogram source status --local");
37
+ console.log(" topogram source status --remote");
38
+ console.log(" topogram source status --json");
39
+ }
40
+
41
+ /**
42
+ * @param {string} inputPath
43
+ * @returns {string}
44
+ */
45
+ function normalizeTopogramPath(inputPath) {
46
+ const absolute = path.resolve(inputPath);
47
+ if (path.basename(absolute) === "topogram") {
48
+ return absolute;
49
+ }
50
+ const candidate = path.join(absolute, "topogram");
51
+ return fs.existsSync(candidate) ? candidate : absolute;
52
+ }
53
+
54
+ /**
55
+ * @param {string} inputPath
56
+ * @returns {string}
57
+ */
58
+ export function normalizeProjectRoot(inputPath) {
59
+ const absolute = path.resolve(inputPath);
60
+ if (path.basename(absolute) === "topogram") {
61
+ return path.dirname(absolute);
62
+ }
63
+ return absolute;
64
+ }
65
+
66
+ /**
67
+ * @param {string} projectRoot
68
+ * @param {{ local?: boolean }} [options]
69
+ * @returns {ReturnType<typeof buildTopogramSourceStatus> & { project: AnyRecord }}
70
+ */
71
+ export function buildProjectSourceStatus(projectRoot, options = {}) {
72
+ const resolvedRoot = normalizeProjectRoot(projectRoot);
73
+ const sourceStatus = buildTopogramSourceStatus(resolvedRoot);
74
+ const projectConfigInfo = loadProjectConfig(normalizeTopogramPath(resolvedRoot));
75
+ const template = projectConfigInfo?.config?.template || null;
76
+ const baseline = buildTemplateOwnedBaselineStatus(resolvedRoot);
77
+ /** @type {AnyRecord} */
78
+ let trust = {
79
+ requiresTrust: false,
80
+ ok: true,
81
+ status: "not-required",
82
+ path: path.join(resolvedRoot, TEMPLATE_TRUST_FILE),
83
+ template: null,
84
+ implementation: null,
85
+ content: { trustedDigest: null, currentDigest: null, changed: [], added: [], removed: [] },
86
+ issues: []
87
+ };
88
+ if (projectConfigInfo?.config?.implementation) {
89
+ const trustStatus = getTemplateTrustStatus({
90
+ config: projectConfigInfo.config.implementation,
91
+ configPath: projectConfigInfo.configPath,
92
+ configDir: projectConfigInfo.configDir
93
+ }, projectConfigInfo.config);
94
+ trust = {
95
+ requiresTrust: trustStatus.requiresTrust,
96
+ ok: trustStatus.ok,
97
+ status: trustStatus.requiresTrust ? (trustStatus.ok ? "trusted" : "review-required") : "not-required",
98
+ path: trustStatus.trustPath,
99
+ template: trustStatus.template,
100
+ implementation: trustStatus.implementation,
101
+ content: trustStatus.content,
102
+ issues: trustStatus.issues
103
+ };
104
+ }
105
+ const packageStatus = template?.source === "package" && template.sourceSpec
106
+ ? (options.local ? localTemplatePackageStatus(template.sourceSpec) : checkTemplatePackageStatus(template.sourceSpec))
107
+ : null;
108
+ const projectDiagnostics = [];
109
+ if (!projectConfigInfo) {
110
+ projectDiagnostics.push({
111
+ code: "project_config_missing",
112
+ severity: "warning",
113
+ message: "topogram.project.json was not found.",
114
+ path: path.join(resolvedRoot, "topogram.project.json"),
115
+ suggestedFix: "Run `topogram check` from a Topogram project root."
116
+ });
117
+ }
118
+ return {
119
+ ...sourceStatus,
120
+ project: {
121
+ root: resolvedRoot,
122
+ config: projectConfigInfo
123
+ ? { exists: true, path: projectConfigInfo.configPath }
124
+ : { exists: false, path: path.join(resolvedRoot, "topogram.project.json") },
125
+ catalog: template?.catalog || sourceStatus.source?.catalog || null,
126
+ template: template
127
+ ? {
128
+ id: template.id || null,
129
+ version: template.version || null,
130
+ requested: template.requested || null,
131
+ source: template.source || null,
132
+ sourceSpec: template.sourceSpec || null,
133
+ includesExecutableImplementation: typeof template.includesExecutableImplementation === "boolean"
134
+ ? template.includesExecutableImplementation
135
+ : null
136
+ }
137
+ : null,
138
+ package: packageStatus,
139
+ packageChecks: {
140
+ mode: options.local ? "local" : "remote",
141
+ skipped: Boolean(options.local),
142
+ reason: options.local ? "Package registry checks were skipped because --local was used." : null
143
+ },
144
+ trust,
145
+ templateBaseline: baseline,
146
+ diagnostics: projectDiagnostics
147
+ },
148
+ diagnostics: [...sourceStatus.diagnostics, ...projectDiagnostics]
149
+ };
150
+ }
151
+
152
+ /**
153
+ * @param {ReturnType<typeof buildProjectSourceStatus>} payload
154
+ * @returns {void}
155
+ */
156
+ export function printTopogramSourceStatus(payload) {
157
+ if (payload.project?.package && payload.project?.packageChecks?.mode === "remote") {
158
+ console.log("Package checks: remote. Use --local to skip registry access.");
159
+ } else if (payload.project?.package && payload.project?.packageChecks?.mode === "local") {
160
+ console.log("Package checks: local. Registry access skipped.");
161
+ }
162
+ if (!payload.exists) {
163
+ console.log("Topogram source status: no provenance");
164
+ console.log(`Expected: ${payload.path}`);
165
+ console.log(`${TOPOGRAM_SOURCE_FILE} was not found. This workspace may not have been copied from a catalog topogram entry.`);
166
+ } else {
167
+ console.log(`Topogram source status: ${payload.status}`);
168
+ console.log(`File: ${payload.path}`);
169
+ if (payload.source?.catalog?.id) {
170
+ console.log(`Catalog: ${payload.source.catalog.id}${payload.source.catalog.source ? ` from ${payload.source.catalog.source}` : ""}`);
171
+ }
172
+ if (payload.source?.package?.spec) {
173
+ console.log(`Package: ${payload.source.package.spec}`);
174
+ }
175
+ }
176
+ if (payload.project?.config?.exists) {
177
+ console.log(`Project config: ${payload.project.config.path}`);
178
+ }
179
+ if (payload.project?.catalog?.id) {
180
+ console.log(`Project catalog: ${payload.project.catalog.id}${payload.project.catalog.source ? ` from ${payload.project.catalog.source}` : ""}`);
181
+ }
182
+ if (payload.project?.template?.id) {
183
+ console.log("Template attachment: attached");
184
+ console.log(`Template: ${payload.project.template.id}@${payload.project.template.version || "unknown"}`);
185
+ console.log(`Template source: ${payload.project.template.sourceSpec || payload.project.template.source || "unknown"}`);
186
+ console.log(`Executable implementation: ${payload.project.template.includesExecutableImplementation ? "yes" : "no"}`);
187
+ } else if (payload.project?.config?.exists) {
188
+ console.log("Template attachment: detached");
189
+ console.log("Template ownership: project-owned");
190
+ }
191
+ if (payload.project?.package?.package) {
192
+ const packageStatus = payload.project.package;
193
+ if (packageStatus.checked === false) {
194
+ console.log(`Template package: ${packageStatus.packageSpec} (not checked, local mode)`);
195
+ } else {
196
+ const currentLabel = packageStatus.current === null ? "unknown" : (packageStatus.current ? "current" : "update available");
197
+ console.log(`Template package: ${packageStatus.packageSpec} (${packageStatus.ok ? "reachable" : "unreachable"}, ${currentLabel})`);
198
+ if (packageStatus.latestVersion) {
199
+ console.log(`Latest template package version: ${packageStatus.latestVersion}`);
200
+ }
201
+ }
202
+ }
203
+ if (payload.project?.trust) {
204
+ console.log(`Implementation trust: ${payload.project.trust.status}`);
205
+ if (payload.project.trust.content.trustedDigest) {
206
+ console.log(`Trusted digest: ${payload.project.trust.content.trustedDigest}`);
207
+ }
208
+ if (payload.project.trust.content.currentDigest) {
209
+ console.log(`Current digest: ${payload.project.trust.content.currentDigest}`);
210
+ }
211
+ }
212
+ if (payload.project?.templateBaseline) {
213
+ const baseline = payload.project.templateBaseline;
214
+ const blockLabel = baseline.blocksCheck || baseline.blocksGenerate
215
+ ? "may block workflow"
216
+ : "does not block check/generate";
217
+ console.log(`Template baseline: ${baseline.state} (${baseline.trustedFiles} file(s), ${blockLabel})`);
218
+ console.log(`Template baseline meaning: ${baseline.meaning}`);
219
+ if (baseline.localOwnership) {
220
+ console.log("Template baseline ownership: local project owns these changes");
221
+ }
222
+ console.log(`Template baseline changed: ${baseline.content.changed.length}`);
223
+ console.log(`Template baseline removed: ${baseline.content.removed.length}`);
224
+ }
225
+ for (const kind of ["changed", "added", "removed"]) {
226
+ const files = payload.content[kind] || [];
227
+ console.log(`${kind[0].toUpperCase()}${kind.slice(1)}: ${files.length}`);
228
+ for (const file of files) {
229
+ console.log(`- ${file}`);
230
+ }
231
+ }
232
+ for (const diagnostic of payload.diagnostics) {
233
+ const label = diagnostic.severity === "warning" ? "Warning" : "Error";
234
+ console.log(`${label}: ${diagnostic.message}`);
235
+ }
236
+ if (payload.project?.package?.diagnostics?.length) {
237
+ for (const diagnostic of payload.project.package.diagnostics) {
238
+ const label = diagnostic.severity === "warning" ? "Warning" : "Error";
239
+ console.log(`${label}: ${diagnostic.message}`);
240
+ if (diagnostic.suggestedFix) {
241
+ console.log(`Fix: ${diagnostic.suggestedFix}`);
242
+ }
243
+ }
244
+ }
245
+ if (payload.project?.trust?.issues?.length) {
246
+ for (const issue of payload.project.trust.issues) {
247
+ console.log(`Issue: ${issue}`);
248
+ }
249
+ }
250
+ console.log("");
251
+ console.log(`${TOPOGRAM_SOURCE_FILE} records catalog-copy provenance only. Local edits are allowed.`);
252
+ console.log("Template attachment controls update tracking. Detaching makes the project fully owned by this workspace.");
253
+ console.log("Template baseline drift does not block `topogram check` or `topogram generate`.");
254
+ console.log("Implementation trust is separate and can block check/generate when review is required.");
255
+ if (payload.project?.trust?.status === "review-required") {
256
+ console.log("Next: review implementation changes, then run `topogram trust status` or `topogram trust template`.");
257
+ } else if (payload.exists && payload.status === "changed") {
258
+ console.log("Next: review the listed files, then run `topogram check` and `topogram generate` when ready.");
259
+ } else if (payload.project?.templateBaseline?.state === "diverged") {
260
+ console.log("Next: local template-derived changes are owned by this project. Run `topogram template update --check` only when reviewing upstream template changes.");
261
+ } else if (!payload.exists) {
262
+ console.log("Next: use `topogram catalog copy <id> <target>` for pure topogram provenance, or continue with template/project provenance above.");
263
+ } else {
264
+ console.log("Next: run `topogram check` or `topogram generate`.");
265
+ }
266
+ }
267
+
268
+ /**
269
+ * @param {{
270
+ * commandArgs: Record<string, any>,
271
+ * inputPath: string|null|undefined,
272
+ * args: string[],
273
+ * json: boolean
274
+ * }} context
275
+ * @returns {number}
276
+ */
277
+ export function runSourceCommand(context) {
278
+ if (context.commandArgs.sourceCommand !== "status") {
279
+ throw new Error(`Unknown source command '${context.commandArgs.sourceCommand}'`);
280
+ }
281
+ const sourceStatusRemote = context.args.includes("--remote");
282
+ const payload = buildProjectSourceStatus(normalizeProjectRoot(context.inputPath || "."), {
283
+ local: context.args.includes("--local") && !sourceStatusRemote
284
+ });
285
+ if (context.json) {
286
+ console.log(stableStringify(payload));
287
+ } else {
288
+ printTopogramSourceStatus(payload);
289
+ }
290
+ return 0;
291
+ }
@@ -0,0 +1,100 @@
1
+ // @ts-check
2
+
3
+ import crypto from "node:crypto";
4
+ import fs from "node:fs";
5
+ import path from "node:path";
6
+
7
+ import { stableStringify } from "../../../format.js";
8
+ import { TEMPLATE_FILES_MANIFEST } from "./constants.js";
9
+
10
+ /**
11
+ * @param {string} filePath
12
+ * @returns {{ sha256: string, size: number }}
13
+ */
14
+ function projectFileHash(filePath) {
15
+ const bytes = fs.readFileSync(filePath);
16
+ return {
17
+ sha256: crypto.createHash("sha256").update(bytes).digest("hex"),
18
+ size: bytes.length
19
+ };
20
+ }
21
+
22
+ /**
23
+ * @param {string} projectRoot
24
+ * @param {string} relativePath
25
+ * @returns {{ sha256: string, size: number }}
26
+ */
27
+ function templateBaselineFileHash(projectRoot, relativePath) {
28
+ const filePath = path.join(projectRoot, relativePath);
29
+ if (relativePath === "topogram.project.json") {
30
+ const content = `${stableStringify(JSON.parse(fs.readFileSync(filePath, "utf8")))}\n`;
31
+ return {
32
+ sha256: crypto.createHash("sha256").update(content).digest("hex"),
33
+ size: Buffer.byteLength(content)
34
+ };
35
+ }
36
+ return projectFileHash(filePath);
37
+ }
38
+
39
+ /**
40
+ * @param {string} projectRoot
41
+ * @returns {{ exists: boolean, path: string, status: "missing"|"clean"|"changed", state: "missing"|"matches-template"|"diverged", meaning: "no-template-baseline"|"matches-template-baseline"|"local-project-owns-changes", changedAllowed: boolean, localOwnership: boolean, blocksCheck: boolean, blocksGenerate: boolean, nextCommand: string|null, content: { changed: string[], added: string[], removed: string[] }, trustedFiles: number }}
42
+ */
43
+ export function buildTemplateOwnedBaselineStatus(projectRoot) {
44
+ const manifestPath = path.join(projectRoot, TEMPLATE_FILES_MANIFEST);
45
+ if (!fs.existsSync(manifestPath)) {
46
+ return {
47
+ exists: false,
48
+ path: manifestPath,
49
+ status: "missing",
50
+ state: "missing",
51
+ meaning: "no-template-baseline",
52
+ changedAllowed: true,
53
+ localOwnership: false,
54
+ blocksCheck: false,
55
+ blocksGenerate: false,
56
+ nextCommand: null,
57
+ content: { changed: [], added: [], removed: [] },
58
+ trustedFiles: 0
59
+ };
60
+ }
61
+ const manifest = JSON.parse(fs.readFileSync(manifestPath, "utf8"));
62
+ const trustedFiles = Array.isArray(manifest.files) ? manifest.files : [];
63
+ const changed = [];
64
+ const removed = [];
65
+ for (const file of trustedFiles) {
66
+ const relativePath = String(file.path || "");
67
+ if (!relativePath) {
68
+ continue;
69
+ }
70
+ const absolutePath = path.join(projectRoot, relativePath);
71
+ if (!fs.existsSync(absolutePath)) {
72
+ removed.push(relativePath);
73
+ continue;
74
+ }
75
+ const current = templateBaselineFileHash(projectRoot, relativePath);
76
+ if (current.sha256 !== file.sha256 || current.size !== file.size) {
77
+ changed.push(relativePath);
78
+ }
79
+ }
80
+ const status = changed.length || removed.length ? "changed" : "clean";
81
+ const diverged = status === "changed";
82
+ return {
83
+ exists: true,
84
+ path: manifestPath,
85
+ status,
86
+ state: diverged ? "diverged" : "matches-template",
87
+ meaning: diverged ? "local-project-owns-changes" : "matches-template-baseline",
88
+ changedAllowed: true,
89
+ localOwnership: diverged,
90
+ blocksCheck: false,
91
+ blocksGenerate: false,
92
+ nextCommand: diverged ? "topogram template update --check" : null,
93
+ content: {
94
+ changed: changed.sort((a, b) => a.localeCompare(b)),
95
+ added: [],
96
+ removed: removed.sort((a, b) => a.localeCompare(b))
97
+ },
98
+ trustedFiles: trustedFiles.length
99
+ };
100
+ }