@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,230 @@
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
+ collectImportSourceFileRecords,
9
+ TOPOGRAM_IMPORT_FILE,
10
+ writeTopogramImportRecord
11
+ } from "../../../import/provenance.js";
12
+ import { runWorkflow } from "../../../workflows.js";
13
+ import { shellCommandArg } from "../catalog.js";
14
+
15
+ /**
16
+ * @typedef {Record<string, any>} AnyRecord
17
+ */
18
+
19
+ /**
20
+ * @param {string} targetPath
21
+ * @returns {void}
22
+ */
23
+ export function ensureEmptyImportTarget(targetPath) {
24
+ if (!fs.existsSync(targetPath)) {
25
+ fs.mkdirSync(targetPath, { recursive: true });
26
+ return;
27
+ }
28
+ if (!fs.statSync(targetPath).isDirectory()) {
29
+ throw new Error(`Cannot import into non-directory path '${targetPath}'.`);
30
+ }
31
+ const entries = fs.readdirSync(targetPath).filter((/** @type {string} */ entry) => entry !== ".DS_Store");
32
+ if (entries.length > 0) {
33
+ throw new Error(`Refusing to import into non-empty directory '${targetPath}'.`);
34
+ }
35
+ }
36
+
37
+ /**
38
+ * @param {string} outDir
39
+ * @param {Record<string, any>} files
40
+ * @returns {string[]}
41
+ */
42
+ export function writeRelativeFiles(outDir, files) {
43
+ const written = [];
44
+ for (const [relativePath, contents] of Object.entries(files || {})) {
45
+ const normalizedRelativePath = relativePath.replaceAll(path.sep, "/");
46
+ const destination = path.join(outDir, normalizedRelativePath);
47
+ fs.mkdirSync(path.dirname(destination), { recursive: true });
48
+ fs.writeFileSync(destination, typeof contents === "string" ? contents : `${stableStringify(contents)}\n`, "utf8");
49
+ written.push(normalizedRelativePath);
50
+ }
51
+ return written.sort((a, b) => a.localeCompare(b));
52
+ }
53
+
54
+ /**
55
+ * @returns {Record<string, any>}
56
+ */
57
+ function importedProjectConfig() {
58
+ return {
59
+ version: "0.1",
60
+ outputs: {
61
+ maintained_app: {
62
+ path: "./app",
63
+ ownership: "maintained"
64
+ }
65
+ },
66
+ topology: {
67
+ runtimes: []
68
+ }
69
+ };
70
+ }
71
+
72
+ /**
73
+ * @param {string} sourceRoot
74
+ * @param {string} targetRoot
75
+ * @param {ReturnType<typeof runWorkflow>["summary"]} importSummary
76
+ * @returns {string}
77
+ */
78
+ function importedWorkspaceReadme(sourceRoot, targetRoot, importSummary) {
79
+ return [
80
+ "# Imported Topogram Workspace",
81
+ "",
82
+ "This workspace was created from a brownfield app import.",
83
+ "",
84
+ `- Imported source: \`${sourceRoot}\``,
85
+ `- Target workspace: \`${targetRoot}\``,
86
+ `- Tracks: ${(importSummary.tracks || []).join(", ") || "none"}`,
87
+ `- Provenance: \`${TOPOGRAM_IMPORT_FILE}\``,
88
+ "",
89
+ "Imported Topogram artifacts are project-owned after creation. Edit them directly, promote candidates deliberately, and run `topogram check` before generation or maintained-app work.",
90
+ "",
91
+ "Useful commands:",
92
+ "",
93
+ "```sh",
94
+ "topogram import check",
95
+ "topogram check",
96
+ "topogram query import-plan ./topogram",
97
+ "```",
98
+ ""
99
+ ].join("\n");
100
+ }
101
+
102
+ /**
103
+ * @param {Record<string, any>} summary
104
+ * @returns {Record<string, number>}
105
+ */
106
+ export function importCandidateCounts(summary) {
107
+ const candidates = summary.candidates || {};
108
+ return {
109
+ dbEntities: candidates.db?.entities?.length || 0,
110
+ dbEnums: candidates.db?.enums?.length || 0,
111
+ apiCapabilities: candidates.api?.capabilities?.length || 0,
112
+ apiRoutes: candidates.api?.routes?.length || 0,
113
+ uiScreens: candidates.ui?.screens?.length || 0,
114
+ uiRoutes: candidates.ui?.routes?.length || 0,
115
+ uiWidgets: candidates.ui?.widgets?.length || candidates.ui?.components?.length || 0,
116
+ workflows: candidates.workflows?.workflows?.length || 0,
117
+ verifications: candidates.verification?.verifications?.length || 0
118
+ };
119
+ }
120
+
121
+ /**
122
+ * @param {string} rootPath
123
+ * @returns {number}
124
+ */
125
+ export function countFilesRecursive(rootPath) {
126
+ if (!fs.existsSync(rootPath)) {
127
+ return 0;
128
+ }
129
+ let count = 0;
130
+ for (const entry of fs.readdirSync(rootPath, { withFileTypes: true })) {
131
+ const childPath = path.join(rootPath, entry.name);
132
+ if (entry.isDirectory()) {
133
+ count += countFilesRecursive(childPath);
134
+ } else if (entry.isFile()) {
135
+ count += 1;
136
+ }
137
+ }
138
+ return count;
139
+ }
140
+
141
+ /**
142
+ * @param {string} sourcePath
143
+ * @param {string} targetPath
144
+ * @param {{ from?: string|null }} [options]
145
+ * @returns {{ ok: boolean, sourcePath: string, targetPath: string, topogramRoot: string, projectConfigPath: string, provenancePath: string, tracks: string[], sourceFiles: number, rawCandidateFiles: number, reconcileFiles: number, writtenFiles: string[], candidateCounts: Record<string, number>, nextCommands: string[] }}
146
+ */
147
+ export function buildBrownfieldImportWorkspacePayload(sourcePath, targetPath, options = {}) {
148
+ const sourceRoot = path.resolve(sourcePath);
149
+ const targetRoot = path.resolve(targetPath);
150
+ if (!fs.existsSync(sourceRoot) || !fs.statSync(sourceRoot).isDirectory()) {
151
+ throw new Error(`Cannot import missing app directory '${sourcePath}'.`);
152
+ }
153
+ if (sourceRoot === targetRoot) {
154
+ throw new Error("Refusing to import into the same directory as the brownfield app.");
155
+ }
156
+ ensureEmptyImportTarget(targetRoot);
157
+
158
+ const topogramRoot = path.join(targetRoot, "topogram");
159
+ fs.mkdirSync(topogramRoot, { recursive: true });
160
+ const sourceFiles = collectImportSourceFileRecords(sourceRoot, { excludeRoots: [targetRoot] });
161
+ const importResult = runWorkflow("import-app", sourceRoot, { from: options.from || null });
162
+ const rawCandidateFiles = writeRelativeFiles(topogramRoot, importResult.files || {});
163
+
164
+ const projectConfigPath = path.join(targetRoot, "topogram.project.json");
165
+ fs.writeFileSync(projectConfigPath, `${stableStringify(importedProjectConfig())}\n`, "utf8");
166
+ fs.writeFileSync(path.join(targetRoot, "README.md"), importedWorkspaceReadme(sourceRoot, targetRoot, importResult.summary), "utf8");
167
+
168
+ const reconcileResult = runWorkflow("reconcile", targetRoot, {});
169
+ const reconcileFiles = writeRelativeFiles(topogramRoot, reconcileResult.files || {});
170
+ const candidateCounts = importCandidateCounts(importResult.summary);
171
+ const provenance = writeTopogramImportRecord(targetRoot, {
172
+ sourceRoot,
173
+ ignoredRoots: [targetRoot],
174
+ tracks: importResult.summary.tracks || [],
175
+ findingsCount: importResult.summary.findings_count || 0,
176
+ candidateCounts,
177
+ files: sourceFiles
178
+ });
179
+ const writtenFiles = [
180
+ "README.md",
181
+ "topogram.project.json",
182
+ TOPOGRAM_IMPORT_FILE,
183
+ ...rawCandidateFiles.map((filePath) => `topogram/${filePath}`),
184
+ ...reconcileFiles.map((filePath) => `topogram/${filePath}`)
185
+ ].sort((a, b) => a.localeCompare(b));
186
+ return {
187
+ ok: true,
188
+ sourcePath: sourceRoot,
189
+ targetPath: targetRoot,
190
+ topogramRoot,
191
+ projectConfigPath,
192
+ provenancePath: provenance.path,
193
+ tracks: importResult.summary.tracks || [],
194
+ sourceFiles: sourceFiles.length,
195
+ rawCandidateFiles: rawCandidateFiles.length,
196
+ reconcileFiles: reconcileFiles.length,
197
+ writtenFiles,
198
+ candidateCounts,
199
+ nextCommands: [
200
+ "topogram import check",
201
+ "topogram import plan",
202
+ "topogram import adopt bundle:task --dry-run",
203
+ "topogram import status",
204
+ "topogram check",
205
+ "topogram query import-plan ./topogram"
206
+ ]
207
+ };
208
+ }
209
+
210
+ /**
211
+ * @param {ReturnType<typeof buildBrownfieldImportWorkspacePayload>} payload
212
+ * @returns {void}
213
+ */
214
+ export function printBrownfieldImportWorkspace(payload) {
215
+ console.log(`Imported brownfield app to ${payload.targetPath}.`);
216
+ console.log(`Source: ${payload.sourcePath}`);
217
+ console.log(`Topogram: ${payload.topogramRoot}`);
218
+ console.log(`Project config: ${payload.projectConfigPath}`);
219
+ console.log(`Import provenance: ${payload.provenancePath}`);
220
+ console.log(`Tracked source files: ${payload.sourceFiles}`);
221
+ console.log(`Raw candidate files: ${payload.rawCandidateFiles}`);
222
+ console.log(`Reconcile proposal files: ${payload.reconcileFiles}`);
223
+ console.log("Imported Topogram artifacts are project-owned after creation; source hashes record the app evidence trusted at import time.");
224
+ console.log("");
225
+ console.log("Next steps:");
226
+ console.log(` cd ${shellCommandArg(path.relative(process.cwd(), payload.targetPath) || ".")}`);
227
+ for (const command of payload.nextCommands) {
228
+ console.log(` ${command}`);
229
+ }
230
+ }
@@ -0,0 +1,157 @@
1
+ // @ts-check
2
+
3
+ import { stableStringify } from "../../format.js";
4
+ import {
5
+ buildBrownfieldImportAdoptListPayload,
6
+ buildBrownfieldImportAdoptPayload,
7
+ buildBrownfieldImportCheckPayload,
8
+ buildBrownfieldImportDiffPayload,
9
+ buildBrownfieldImportHistoryPayload,
10
+ buildBrownfieldImportPlanPayload,
11
+ buildBrownfieldImportRefreshPayload,
12
+ buildBrownfieldImportStatusPayload,
13
+ buildBrownfieldImportWorkspacePayload,
14
+ printBrownfieldImportAdopt,
15
+ printBrownfieldImportAdoptList,
16
+ printBrownfieldImportCheck,
17
+ printBrownfieldImportDiff,
18
+ printBrownfieldImportHistory,
19
+ printBrownfieldImportPlan,
20
+ printBrownfieldImportRefresh,
21
+ printBrownfieldImportStatus,
22
+ printBrownfieldImportWorkspace,
23
+ printImportHelp
24
+ } from "./import.js";
25
+
26
+ /**
27
+ * @param {{ commandArgs: Record<string, any>, inputPath: string|null|undefined, outPath?: string|null, fromValue?: string|null, reasonValue?: string|null, refreshAdopted?: boolean, dryRun?: boolean, write?: boolean, force?: boolean, json?: boolean }} context
28
+ * @returns {number}
29
+ */
30
+ export function runImportCommand(context) {
31
+ const {
32
+ commandArgs,
33
+ inputPath,
34
+ outPath = null,
35
+ fromValue = null,
36
+ reasonValue = null,
37
+ refreshAdopted = false,
38
+ dryRun = false,
39
+ write = false,
40
+ force = false,
41
+ json = false
42
+ } = context;
43
+ const command = commandArgs.importCommand;
44
+
45
+ if (command === "workspace") {
46
+ if (!outPath) {
47
+ console.error("Missing required --out <target>.");
48
+ printImportHelp();
49
+ return 1;
50
+ }
51
+ const payload = buildBrownfieldImportWorkspacePayload(inputPath || "", outPath, { from: fromValue });
52
+ if (json) {
53
+ console.log(stableStringify(payload));
54
+ } else {
55
+ printBrownfieldImportWorkspace(payload);
56
+ }
57
+ return 0;
58
+ }
59
+
60
+ if (command === "diff") {
61
+ const payload = buildBrownfieldImportDiffPayload(inputPath || ".", { sourcePath: fromValue });
62
+ if (json) {
63
+ console.log(stableStringify(payload));
64
+ } else {
65
+ printBrownfieldImportDiff(payload);
66
+ }
67
+ return 0;
68
+ }
69
+
70
+ if (command === "refresh") {
71
+ const payload = buildBrownfieldImportRefreshPayload(inputPath || ".", { sourcePath: fromValue, dryRun });
72
+ if (json) {
73
+ console.log(stableStringify(payload));
74
+ } else {
75
+ printBrownfieldImportRefresh(payload);
76
+ }
77
+ return payload.ok ? 0 : 1;
78
+ }
79
+
80
+ if (command === "check") {
81
+ const payload = buildBrownfieldImportCheckPayload(inputPath || ".");
82
+ if (json) {
83
+ console.log(stableStringify(payload));
84
+ } else {
85
+ printBrownfieldImportCheck(payload);
86
+ }
87
+ return payload.ok ? 0 : 1;
88
+ }
89
+
90
+ if (command === "plan") {
91
+ const payload = buildBrownfieldImportPlanPayload(inputPath || ".");
92
+ if (json) {
93
+ console.log(stableStringify(payload));
94
+ } else {
95
+ printBrownfieldImportPlan(payload);
96
+ }
97
+ return 0;
98
+ }
99
+
100
+ if (command === "adopt-list") {
101
+ const payload = buildBrownfieldImportAdoptListPayload(inputPath || ".");
102
+ if (json) {
103
+ console.log(stableStringify(payload));
104
+ } else {
105
+ printBrownfieldImportAdoptList(payload);
106
+ }
107
+ return 0;
108
+ }
109
+
110
+ if (command === "adopt") {
111
+ if (!commandArgs.importAdoptSelector || commandArgs.importAdoptSelector.startsWith("-")) {
112
+ console.error("Missing required <selector>.");
113
+ printImportHelp();
114
+ return 1;
115
+ }
116
+ if (write && dryRun) {
117
+ console.error("Use either --dry-run or --write, not both.");
118
+ printImportHelp();
119
+ return 1;
120
+ }
121
+ const payload = buildBrownfieldImportAdoptPayload(commandArgs.importAdoptSelector, inputPath || ".", {
122
+ dryRun,
123
+ write,
124
+ force,
125
+ reason: reasonValue,
126
+ refreshAdopted
127
+ });
128
+ if (json) {
129
+ console.log(stableStringify(payload));
130
+ } else {
131
+ printBrownfieldImportAdopt(payload);
132
+ }
133
+ return payload.ok ? 0 : 1;
134
+ }
135
+
136
+ if (command === "status") {
137
+ const payload = buildBrownfieldImportStatusPayload(inputPath || ".");
138
+ if (json) {
139
+ console.log(stableStringify(payload));
140
+ } else {
141
+ printBrownfieldImportStatus(payload);
142
+ }
143
+ return payload.ok ? 0 : 1;
144
+ }
145
+
146
+ if (command === "history") {
147
+ const payload = buildBrownfieldImportHistoryPayload(inputPath || ".", { verify: commandArgs.verify });
148
+ if (json) {
149
+ console.log(stableStringify(payload));
150
+ } else {
151
+ printBrownfieldImportHistory(payload);
152
+ }
153
+ return payload.ok ? 0 : 1;
154
+ }
155
+
156
+ throw new Error(`Unknown import command '${command}'`);
157
+ }
@@ -0,0 +1,35 @@
1
+ // @ts-check
2
+
3
+ export { printImportHelp } from "./import/help.js";
4
+ export {
5
+ buildBrownfieldImportWorkspacePayload,
6
+ printBrownfieldImportWorkspace
7
+ } from "./import/workspace.js";
8
+ export {
9
+ buildBrownfieldImportRefreshPayload,
10
+ printBrownfieldImportRefresh
11
+ } from "./import/refresh.js";
12
+ export {
13
+ buildBrownfieldImportDiffPayload,
14
+ printBrownfieldImportDiff
15
+ } from "./import/diff.js";
16
+ export {
17
+ buildBrownfieldImportCheckPayload,
18
+ printBrownfieldImportCheck
19
+ } from "./import/check.js";
20
+ export {
21
+ buildBrownfieldImportPlanPayload,
22
+ printBrownfieldImportPlan,
23
+ buildBrownfieldImportAdoptListPayload,
24
+ printBrownfieldImportAdoptList
25
+ } from "./import/plan.js";
26
+ export {
27
+ buildBrownfieldImportAdoptPayload,
28
+ printBrownfieldImportAdopt
29
+ } from "./import/adopt.js";
30
+ export {
31
+ buildBrownfieldImportStatusPayload,
32
+ printBrownfieldImportStatus,
33
+ buildBrownfieldImportHistoryPayload,
34
+ printBrownfieldImportHistory
35
+ } from "./import/status-history.js";
@@ -0,0 +1,55 @@
1
+ // @ts-check
2
+
3
+ import { stableStringify } from "../../format.js";
4
+ import { parsePath } from "../../parser.js";
5
+ import { resolveWorkspace } from "../../resolver.js";
6
+ import { formatValidationErrors } from "../../validator.js";
7
+
8
+ /**
9
+ * @param {Record<string, any>} workspaceAst
10
+ * @returns {void}
11
+ */
12
+ function summarize(workspaceAst) {
13
+ const statements = workspaceAst.files.flatMap((/** @type {{ statements: any[] }} */ file) => file.statements);
14
+ const byKind = new Map();
15
+
16
+ for (const statement of statements) {
17
+ byKind.set(statement.kind, (byKind.get(statement.kind) || 0) + 1);
18
+ }
19
+
20
+ console.log(`Parsed ${workspaceAst.files.length} file(s) and ${statements.length} statement(s).`);
21
+ for (const [kind, count] of [...byKind.entries()].sort((a, b) => a[0].localeCompare(b[0]))) {
22
+ console.log(`- ${kind}: ${count}`);
23
+ }
24
+ }
25
+
26
+ /**
27
+ * @param {string|null|undefined} inputPath
28
+ * @returns {number}
29
+ */
30
+ export function runResolveCommand(inputPath) {
31
+ const ast = parsePath(inputPath || ".");
32
+ const result = resolveWorkspace(ast);
33
+ if (!result.ok) {
34
+ console.error(formatValidationErrors(result.validation));
35
+ return 1;
36
+ }
37
+
38
+ console.log(JSON.stringify(result.graph, null, 2));
39
+ return 0;
40
+ }
41
+
42
+ /**
43
+ * @param {string|null|undefined} inputPath
44
+ * @param {{ json?: boolean }} [options]
45
+ * @returns {number}
46
+ */
47
+ export function runParseCommand(inputPath, options = {}) {
48
+ const ast = parsePath(inputPath || ".");
49
+ if (options.json) {
50
+ console.log(stableStringify(ast));
51
+ } else {
52
+ summarize(ast);
53
+ }
54
+ return 0;
55
+ }
@@ -0,0 +1,94 @@
1
+ // @ts-check
2
+
3
+ import path from "node:path";
4
+
5
+ import { resolveCatalogTemplateAlias } from "../catalog-alias.js";
6
+ import { GENERATOR_POLICY_FILE } from "../../generator-policy.js";
7
+ import { createNewProject } from "../../new-project.js";
8
+
9
+ const ENGINE_ROOT = path.resolve(decodeURIComponent(new URL("../../../", import.meta.url).pathname));
10
+ const TEMPLATES_ROOT = path.join(ENGINE_ROOT, "templates");
11
+
12
+ /**
13
+ * @param {ReturnType<typeof createNewProject>} result
14
+ * @param {string} cwd
15
+ * @returns {string}
16
+ */
17
+ function displayProjectRootForNewProject(result, cwd) {
18
+ const relativeProjectRoot = path.relative(cwd, result.projectRoot);
19
+ return !relativeProjectRoot || relativeProjectRoot.startsWith("..")
20
+ ? result.projectRoot
21
+ : relativeProjectRoot;
22
+ }
23
+
24
+ /**
25
+ * @param {ReturnType<typeof createNewProject>} result
26
+ * @param {string} cwd
27
+ * @returns {void}
28
+ */
29
+ export function printNewProjectResult(result, cwd) {
30
+ const template = result.template || {};
31
+ console.log(`Created Topogram project at ${result.projectRoot}.`);
32
+ console.log(`Template: ${result.templateName}`);
33
+ console.log(`Source: ${template.source || "unknown"}`);
34
+ if (template.sourceSpec) {
35
+ console.log(`Source spec: ${template.sourceSpec}`);
36
+ }
37
+ if (template.catalog) {
38
+ console.log(`Catalog: ${template.catalog.id} from ${template.catalog.source}`);
39
+ console.log(`Package: ${template.catalog.packageSpec}`);
40
+ }
41
+ console.log(`Executable implementation: ${template.includesExecutableImplementation ? "yes" : "no"}`);
42
+ console.log("Policy: topogram.template-policy.json");
43
+ console.log(`Generator policy: ${GENERATOR_POLICY_FILE}`);
44
+ console.log("Template files: .topogram-template-files.json");
45
+ if (template.includesExecutableImplementation) {
46
+ console.log("Trust: .topogram-template-trust.json");
47
+ }
48
+ for (const warning of result.warnings) {
49
+ console.warn(`Warning: ${warning}`);
50
+ }
51
+ console.log("");
52
+ console.log("Next steps:");
53
+ console.log(` cd ${displayProjectRootForNewProject(result, cwd)}`);
54
+ console.log(" npm install");
55
+ console.log(" npm run agent:brief");
56
+ console.log(" npm run doctor");
57
+ console.log(" npm run source:status");
58
+ console.log(" npm run template:explain");
59
+ console.log(" npm run check");
60
+ console.log(" npm run generator:policy:status");
61
+ console.log(" npm run generator:policy:check");
62
+ if (template.includesExecutableImplementation) {
63
+ console.log(" npm run template:policy:explain");
64
+ console.log(" npm run trust:status");
65
+ }
66
+ console.log(" npm run generate");
67
+ console.log(" npm run verify");
68
+ }
69
+
70
+ /**
71
+ * @param {string} inputPath
72
+ * @param {{ templateName: string, catalogSource?: string|null, cwd?: string }} options
73
+ * @returns {number}
74
+ */
75
+ export function runNewProjectCommand(inputPath, options) {
76
+ const cwd = options.cwd || process.cwd();
77
+ const projectRoot = path.resolve(inputPath);
78
+ const relativeToEngine = path.relative(ENGINE_ROOT, projectRoot);
79
+ if (relativeToEngine === "" || (!relativeToEngine.startsWith("..") && !path.isAbsolute(relativeToEngine))) {
80
+ throw new Error(
81
+ `Refusing to create a generated project inside the engine directory. Use a path outside engine, for example '../${path.basename(projectRoot)}'.`
82
+ );
83
+ }
84
+ const resolvedTemplate = resolveCatalogTemplateAlias(options.templateName, options.catalogSource || null);
85
+ const result = createNewProject({
86
+ targetPath: inputPath,
87
+ templateName: resolvedTemplate.templateName,
88
+ templateProvenance: resolvedTemplate.provenance,
89
+ engineRoot: ENGINE_ROOT,
90
+ templatesRoot: TEMPLATES_ROOT
91
+ });
92
+ printNewProjectResult(result, cwd);
93
+ return 0;
94
+ }
@@ -0,0 +1,17 @@
1
+ // @ts-check
2
+
3
+ export const CLI_PACKAGE_NAME = "@topogram/cli";
4
+ export const NPMJS_REGISTRY = "https://registry.npmjs.org";
5
+
6
+ export const PACKAGE_UPDATE_CLI_CHECK_SCRIPTS = [
7
+ "cli:surface",
8
+ "doctor",
9
+ "catalog:show",
10
+ "catalog:template-show",
11
+ "check",
12
+ "pack:check",
13
+ "verify"
14
+ ];
15
+ export const PACKAGE_UPDATE_CLI_INFO_SCRIPTS = ["cli:surface", "doctor", "catalog:show", "catalog:template-show"];
16
+ export const PACKAGE_UPDATE_CLI_VERIFICATION_SCRIPTS = ["verify", "pack:check", "check"];
17
+ export const ENGINE_ROOT = decodeURIComponent(new URL("../../../../", import.meta.url).pathname);