@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,2 @@
1
+ export function buildOutputFiles(result: any, options?: any): any;
2
+ export function generateWorkspace(ast: any, options?: any): any;
@@ -0,0 +1,520 @@
1
+ // @ts-check
2
+
3
+ import childProcess from "node:child_process";
4
+
5
+ const DEFAULT_GITHUB_API_BASE_URL = "https://api.github.com";
6
+ const GITHUB_REST_SCRIPT = `
7
+ const request = JSON.parse(process.argv[1]);
8
+ const base = String(request.baseUrl || "https://api.github.com").replace(/\\/+$/, "") + "/";
9
+ const path = String(request.path || "").replace(/^\\/+/, "");
10
+ const url = new URL(path, base);
11
+ for (const [key, value] of Object.entries(request.query || {})) {
12
+ if (value === null || value === undefined || value === "") continue;
13
+ url.searchParams.set(key, String(value));
14
+ }
15
+ function canAttachToken(urlValue) {
16
+ const hostname = new URL(urlValue).hostname.toLowerCase();
17
+ return hostname === "api.github.com" || hostname.endsWith(".github.com");
18
+ }
19
+ const headers = {
20
+ accept: "application/vnd.github+json",
21
+ "user-agent": "topogram-cli",
22
+ "x-github-api-version": "2022-11-28"
23
+ };
24
+ if (request.token && canAttachToken(url)) {
25
+ headers.authorization = "Bearer " + request.token;
26
+ }
27
+ if (process.env.TOPOGRAM_GITHUB_API_FIXTURE_ROOT) {
28
+ const fs = await import("node:fs");
29
+ const pathModule = await import("node:path");
30
+ const segments = path.split("/").filter(Boolean);
31
+ if (segments.some((segment) => segment === ".." || segment.includes("\\\\") || segment.includes("\\0"))) {
32
+ process.stderr.write("Unsafe GitHub API fixture path.");
33
+ process.exit(1);
34
+ }
35
+ if (process.env.TOPOGRAM_GITHUB_API_FIXTURE_LOG) {
36
+ fs.appendFileSync(process.env.TOPOGRAM_GITHUB_API_FIXTURE_LOG, JSON.stringify({
37
+ path,
38
+ search: url.search,
39
+ tokenPresent: Boolean(request.token),
40
+ tokenWouldAttach: Boolean(request.token && canAttachToken(url))
41
+ }) + "\\n", "utf8");
42
+ }
43
+ const fixturePath = pathModule.join(process.env.TOPOGRAM_GITHUB_API_FIXTURE_ROOT, ...segments) + ".json";
44
+ if (!fs.existsSync(fixturePath)) {
45
+ process.stderr.write(JSON.stringify({
46
+ status: 404,
47
+ statusText: "Not Found",
48
+ body: JSON.stringify({ message: "Fixture Not Found", path }),
49
+ url: url.toString()
50
+ }));
51
+ process.exit(2);
52
+ }
53
+ process.stdout.write(JSON.stringify({
54
+ status: 200,
55
+ body: fs.readFileSync(fixturePath, "utf8"),
56
+ url: url.toString()
57
+ }));
58
+ process.exit(0);
59
+ }
60
+ try {
61
+ const response = await fetch(url, { headers });
62
+ const text = await response.text();
63
+ if (!response.ok) {
64
+ process.stderr.write(JSON.stringify({
65
+ status: response.status,
66
+ statusText: response.statusText,
67
+ body: text,
68
+ url: url.toString()
69
+ }));
70
+ process.exit(2);
71
+ }
72
+ process.stdout.write(JSON.stringify({
73
+ status: response.status,
74
+ body: text,
75
+ url: url.toString()
76
+ }));
77
+ } catch (error) {
78
+ process.stderr.write(error instanceof Error ? error.message : String(error));
79
+ process.exit(1);
80
+ }
81
+ `;
82
+
83
+ /**
84
+ * @typedef {Object} GitHubCliStatus
85
+ * @property {boolean} checked
86
+ * @property {boolean} available
87
+ * @property {boolean} authenticated
88
+ * @property {string|null} reason
89
+ */
90
+
91
+ /**
92
+ * @typedef {Object} GitHubRun
93
+ * @property {number|string|undefined} [databaseId]
94
+ * @property {string|undefined} [workflowName]
95
+ * @property {string|undefined} [status]
96
+ * @property {string|undefined} [conclusion]
97
+ * @property {string|undefined} [headSha]
98
+ * @property {string|undefined} [url]
99
+ */
100
+
101
+ /**
102
+ * @typedef {Object} GitHubJob
103
+ * @property {number|string|undefined} [databaseId]
104
+ * @property {string|undefined} [name]
105
+ * @property {string|undefined} [status]
106
+ * @property {string|undefined} [conclusion]
107
+ * @property {string|undefined} [url]
108
+ */
109
+
110
+ export class GitHubClientError extends Error {
111
+ /**
112
+ * @param {string} message
113
+ * @param {{ status?: number|null, statusText?: string|null, body?: string|null, url?: string|null, command?: string|null }} [details]
114
+ */
115
+ constructor(message, details = {}) {
116
+ super(message);
117
+ this.name = "GitHubClientError";
118
+ this.status = details.status ?? null;
119
+ this.statusText = details.statusText ?? null;
120
+ this.body = details.body ?? null;
121
+ this.url = details.url ?? null;
122
+ this.command = details.command ?? null;
123
+ }
124
+ }
125
+
126
+ /**
127
+ * @returns {string|null}
128
+ */
129
+ export function githubTokenFromEnv() {
130
+ return process.env.GITHUB_TOKEN || process.env.GH_TOKEN || null;
131
+ }
132
+
133
+ /**
134
+ * @returns {string}
135
+ */
136
+ export function githubApiBaseUrl() {
137
+ return process.env.TOPOGRAM_GITHUB_API_BASE_URL || DEFAULT_GITHUB_API_BASE_URL;
138
+ }
139
+
140
+ /**
141
+ * @returns {boolean}
142
+ */
143
+ function shouldUseRestApi() {
144
+ return Boolean(githubTokenFromEnv());
145
+ }
146
+
147
+ /**
148
+ * @param {string} path
149
+ * @param {{ query?: Record<string, string|number|boolean|null|undefined> }} [options]
150
+ * @returns {any}
151
+ */
152
+ function githubRequestJson(path, options = {}) {
153
+ const result = childProcess.spawnSync(process.execPath, [
154
+ "--input-type=module",
155
+ "-e",
156
+ GITHUB_REST_SCRIPT,
157
+ JSON.stringify({
158
+ baseUrl: githubApiBaseUrl(),
159
+ path,
160
+ query: options.query || {},
161
+ token: githubTokenFromEnv() || ""
162
+ })
163
+ ], {
164
+ encoding: "utf8",
165
+ env: {
166
+ ...process.env,
167
+ PATH: process.env.PATH || ""
168
+ }
169
+ });
170
+ if (result.status !== 0) {
171
+ const error = parseRestError(result);
172
+ throw new GitHubClientError(formatRestErrorMessage(error), error);
173
+ }
174
+ /** @type {any} */
175
+ let payload = {};
176
+ try {
177
+ payload = JSON.parse(String(result.stdout || "{}"));
178
+ } catch (error) {
179
+ throw new GitHubClientError(`GitHub REST response was not valid JSON: ${messageFromError(error)}`);
180
+ }
181
+ const body = typeof payload.body === "string" ? payload.body : "";
182
+ try {
183
+ return body ? JSON.parse(body) : null;
184
+ } catch (error) {
185
+ throw new GitHubClientError(`GitHub REST body was not valid JSON: ${messageFromError(error)}`, {
186
+ body,
187
+ url: typeof payload.url === "string" ? payload.url : null
188
+ });
189
+ }
190
+ }
191
+
192
+ /**
193
+ * @param {ReturnType<typeof childProcess.spawnSync>} result
194
+ * @returns {{ status: number|null, statusText: string|null, body: string|null, url: string|null }}
195
+ */
196
+ function parseRestError(result) {
197
+ if (result.status === 2) {
198
+ try {
199
+ const payload = JSON.parse(String(result.stderr || "{}"));
200
+ return {
201
+ status: Number.isFinite(payload.status) ? payload.status : null,
202
+ statusText: typeof payload.statusText === "string" ? payload.statusText : null,
203
+ body: typeof payload.body === "string" ? payload.body : null,
204
+ url: typeof payload.url === "string" ? payload.url : null
205
+ };
206
+ } catch {
207
+ // Fall through to the generic shape below.
208
+ }
209
+ }
210
+ return {
211
+ status: null,
212
+ statusText: null,
213
+ body: [result.error?.message, result.stderr, result.stdout].filter(Boolean).join("\n").trim() || null,
214
+ url: null
215
+ };
216
+ }
217
+
218
+ /**
219
+ * @param {{ status: number|null, statusText: string|null, body: string|null, url: string|null }} error
220
+ * @returns {string}
221
+ */
222
+ function formatRestErrorMessage(error) {
223
+ const status = error.status ? `${error.status}${error.statusText ? ` ${error.statusText}` : ""}` : "failed";
224
+ const body = String(error.body || "").trim();
225
+ return [`GitHub REST request ${status}.`, body.slice(0, 800)].filter(Boolean).join("\n");
226
+ }
227
+
228
+ /**
229
+ * @param {unknown} error
230
+ * @returns {string}
231
+ */
232
+ function messageFromError(error) {
233
+ return error instanceof Error ? error.message : String(error);
234
+ }
235
+
236
+ /**
237
+ * @param {string} source
238
+ * @returns {{ owner: string, repo: string, filePath: string, ref: string|null }}
239
+ */
240
+ export function parseGithubCatalogSource(source) {
241
+ const spec = source.slice("github:".length);
242
+ const [pathPart, ref] = spec.split("?ref=");
243
+ const segments = pathPart.split("/").filter(Boolean);
244
+ if (segments.length < 3) {
245
+ throw new Error(`Invalid GitHub catalog source '${source}'. Expected github:owner/repo/path/to/catalog.json.`);
246
+ }
247
+ const [owner, repo, ...fileSegments] = segments;
248
+ return {
249
+ owner,
250
+ repo,
251
+ filePath: fileSegments.join("/"),
252
+ ref: ref || null
253
+ };
254
+ }
255
+
256
+ /**
257
+ * @param {string} source
258
+ * @returns {string}
259
+ */
260
+ export function readGithubCatalogSourceText(source) {
261
+ const parsed = parseGithubCatalogSource(source);
262
+ if (shouldUseRestApi()) {
263
+ try {
264
+ const payload = githubRequestJson(`repos/${parsed.owner}/${parsed.repo}/contents/${parsed.filePath}`, {
265
+ query: parsed.ref ? { ref: parsed.ref } : {}
266
+ });
267
+ const content = typeof payload?.content === "string" ? payload.content : "";
268
+ return Buffer.from(content.replace(/\s+/g, ""), "base64").toString("utf8");
269
+ } catch (error) {
270
+ throw new Error(formatGithubCatalogError(source, error, "rest"));
271
+ }
272
+ }
273
+ const result = runGh(githubCatalogGhArgs(parsed));
274
+ if (result.status !== 0) {
275
+ throw new Error(formatGithubCatalogError(source, result, "gh"));
276
+ }
277
+ return Buffer.from(String(result.stdout || "").replace(/\s+/g, ""), "base64").toString("utf8");
278
+ }
279
+
280
+ /**
281
+ * @param {{ owner: string, repo: string, filePath: string, ref: string|null }} parsed
282
+ * @returns {string[]}
283
+ */
284
+ function githubCatalogGhArgs(parsed) {
285
+ const args = ["api", `repos/${parsed.owner}/${parsed.repo}/contents/${parsed.filePath}`, "--jq", ".content"];
286
+ if (parsed.ref) {
287
+ args.splice(2, 0, "-f", `ref=${parsed.ref}`);
288
+ }
289
+ return args;
290
+ }
291
+
292
+ /**
293
+ * @param {string} source
294
+ * @param {unknown} error
295
+ * @param {"rest"|"gh"} mode
296
+ * @returns {string}
297
+ */
298
+ function formatGithubCatalogError(source, error, mode) {
299
+ const output = githubErrorOutput(error);
300
+ const normalized = output.toLowerCase();
301
+ const commandError = error && typeof error === "object" && "error" in error
302
+ ? /** @type {{ error?: { code?: string } }} */ (error)
303
+ : null;
304
+ if (mode === "gh" && commandError?.error?.code === "ENOENT") {
305
+ return [
306
+ `GitHub CLI (gh) is required to read catalog '${source}' without GITHUB_TOKEN or GH_TOKEN.`,
307
+ "Install gh, set GITHUB_TOKEN or GH_TOKEN, or set TOPOGRAM_CATALOG_SOURCE to a local topograms.catalog.json file."
308
+ ].join("\n");
309
+ }
310
+ if (/\b(401|403)\b/.test(normalized) || normalized.includes("authentication") || normalized.includes("not logged in") || normalized.includes("forbidden")) {
311
+ return [
312
+ `Authentication is required to read private catalog '${source}'.`,
313
+ "Set GITHUB_TOKEN or GH_TOKEN with repository read access, or run gh auth login as a local fallback.",
314
+ output
315
+ ].filter(Boolean).join("\n");
316
+ }
317
+ if (/\b404\b/.test(normalized) || normalized.includes("not found")) {
318
+ return [
319
+ `Catalog source '${source}' was not found, or the current token does not have repository access.`,
320
+ "Check the github:owner/repo/path source and grant repository read access to the token or GitHub Actions workflow.",
321
+ output
322
+ ].filter(Boolean).join("\n");
323
+ }
324
+ return [
325
+ `Failed to read catalog '${source}' with ${mode === "rest" ? "GitHub REST API" : "gh api"}.`,
326
+ "Set GITHUB_TOKEN or GH_TOKEN, or run gh auth login as a local fallback.",
327
+ output || "unknown error"
328
+ ].join("\n");
329
+ }
330
+
331
+ /**
332
+ * @param {unknown} error
333
+ * @returns {string}
334
+ */
335
+ function githubErrorOutput(error) {
336
+ if (error instanceof GitHubClientError) {
337
+ return [error.message, error.body].filter(Boolean).join("\n").trim();
338
+ }
339
+ if (error && typeof error === "object" && ("stdout" in error || "stderr" in error || "error" in error)) {
340
+ const result = /** @type {{ stdout?: string, stderr?: string, error?: Error }} */ (error);
341
+ return [result.error?.message, result.stderr, result.stdout].filter(Boolean).join("\n").trim();
342
+ }
343
+ return messageFromError(error);
344
+ }
345
+
346
+ /**
347
+ * @param {{ repoSlug: string, branch?: string, workflowName: string, cwd?: string|null }} input
348
+ * @returns {GitHubRun|null}
349
+ */
350
+ export function latestWorkflowRun(input) {
351
+ if (shouldUseRestApi()) {
352
+ const payload = githubRequestJson(`repos/${input.repoSlug}/actions/runs`, {
353
+ query: {
354
+ branch: input.branch || "main",
355
+ per_page: 50
356
+ }
357
+ });
358
+ const runs = /** @type {any[]} */ (Array.isArray(payload?.workflow_runs) ? payload.workflow_runs : []);
359
+ const run = runs.find((candidate) => workflowRunName(candidate) === input.workflowName) || null;
360
+ return run ? normalizeWorkflowRun(run, input.workflowName) : null;
361
+ }
362
+ const result = runGh([
363
+ "run",
364
+ "list",
365
+ "--repo",
366
+ input.repoSlug,
367
+ "--branch",
368
+ input.branch || "main",
369
+ "--workflow",
370
+ input.workflowName,
371
+ "--limit",
372
+ "1",
373
+ "--json",
374
+ "databaseId,workflowName,status,conclusion,headSha,url"
375
+ ], input.cwd || undefined);
376
+ if (result.status !== 0) {
377
+ throw new GitHubClientError("GitHub CLI workflow run lookup failed.", {
378
+ body: githubErrorOutput(result),
379
+ command: "gh run list"
380
+ });
381
+ }
382
+ /** @type {any[]} */
383
+ let runs = [];
384
+ try {
385
+ runs = JSON.parse(String(result.stdout || "[]"));
386
+ } catch (error) {
387
+ throw new GitHubClientError(`GitHub CLI workflow run output was not valid JSON: ${messageFromError(error)}`, {
388
+ body: String(result.stdout || "")
389
+ });
390
+ }
391
+ return Array.isArray(runs) && runs.length > 0 ? normalizeWorkflowRun(runs[0], input.workflowName) : null;
392
+ }
393
+
394
+ /**
395
+ * @param {any} run
396
+ * @returns {string|null}
397
+ */
398
+ function workflowRunName(run) {
399
+ return typeof run?.workflowName === "string"
400
+ ? run.workflowName
401
+ : typeof run?.name === "string"
402
+ ? run.name
403
+ : null;
404
+ }
405
+
406
+ /**
407
+ * @param {any} run
408
+ * @param {string} fallbackWorkflowName
409
+ * @returns {GitHubRun}
410
+ */
411
+ function normalizeWorkflowRun(run, fallbackWorkflowName) {
412
+ return {
413
+ databaseId: run.databaseId ?? run.id,
414
+ workflowName: run.workflowName || run.name || fallbackWorkflowName,
415
+ status: run.status,
416
+ conclusion: run.conclusion,
417
+ headSha: run.headSha || run.head_sha,
418
+ url: run.html_url || run.url
419
+ };
420
+ }
421
+
422
+ /**
423
+ * @param {{ repoSlug: string, runId: number|string, cwd?: string|null }} input
424
+ * @returns {GitHubJob[]}
425
+ */
426
+ export function workflowRunJobs(input) {
427
+ if (shouldUseRestApi()) {
428
+ const payload = githubRequestJson(`repos/${input.repoSlug}/actions/runs/${input.runId}/jobs`, {
429
+ query: { per_page: 100 }
430
+ });
431
+ const jobs = /** @type {any[]} */ (Array.isArray(payload?.jobs) ? payload.jobs : []);
432
+ return jobs.map(normalizeWorkflowJob);
433
+ }
434
+ const result = runGh([
435
+ "run",
436
+ "view",
437
+ String(input.runId),
438
+ "--repo",
439
+ input.repoSlug,
440
+ "--json",
441
+ "jobs"
442
+ ], input.cwd || undefined);
443
+ if (result.status !== 0) {
444
+ throw new GitHubClientError("GitHub CLI workflow job lookup failed.", {
445
+ body: githubErrorOutput(result),
446
+ command: "gh run view"
447
+ });
448
+ }
449
+ /** @type {any} */
450
+ let payload = {};
451
+ try {
452
+ payload = JSON.parse(String(result.stdout || "{}"));
453
+ } catch (error) {
454
+ throw new GitHubClientError(`GitHub CLI workflow job output was not valid JSON: ${messageFromError(error)}`, {
455
+ body: String(result.stdout || "")
456
+ });
457
+ }
458
+ const jobs = Array.isArray(payload.jobs) ? payload.jobs : [];
459
+ return jobs.map(normalizeWorkflowJob);
460
+ }
461
+
462
+ /**
463
+ * @param {any} job
464
+ * @returns {GitHubJob}
465
+ */
466
+ function normalizeWorkflowJob(job) {
467
+ return {
468
+ databaseId: job.databaseId ?? job.id,
469
+ name: job.name,
470
+ status: job.status,
471
+ conclusion: job.conclusion,
472
+ url: job.html_url || job.url
473
+ };
474
+ }
475
+
476
+ /**
477
+ * @param {string[]} args
478
+ * @param {string} [cwd]
479
+ * @returns {ReturnType<typeof childProcess.spawnSync>}
480
+ */
481
+ function runGh(args, cwd = process.cwd()) {
482
+ return childProcess.spawnSync("gh", args, {
483
+ cwd,
484
+ encoding: "utf8",
485
+ env: {
486
+ ...process.env,
487
+ GH_TOKEN: process.env.GH_TOKEN || process.env.GITHUB_TOKEN || "",
488
+ PATH: process.env.PATH || ""
489
+ }
490
+ });
491
+ }
492
+
493
+ /**
494
+ * @param {{ checkGh?: boolean }} [options]
495
+ * @returns {{ githubTokenEnv: boolean, ghTokenEnv: boolean, ghCli: GitHubCliStatus }}
496
+ */
497
+ export function githubAuthStatus(options = {}) {
498
+ /** @type {GitHubCliStatus} */
499
+ const ghCli = {
500
+ checked: Boolean(options.checkGh),
501
+ available: false,
502
+ authenticated: false,
503
+ reason: null
504
+ };
505
+ if (options.checkGh) {
506
+ const result = runGh(["auth", "token"]);
507
+ ghCli.available = result.error?.code !== "ENOENT";
508
+ ghCli.authenticated = result.status === 0 && Boolean(String(result.stdout || "").trim());
509
+ if (!ghCli.available) {
510
+ ghCli.reason = "GitHub CLI (gh) is not installed or not on PATH.";
511
+ } else if (!ghCli.authenticated) {
512
+ ghCli.reason = (result.stderr || result.stdout || result.error?.message || "gh auth token failed.").trim();
513
+ }
514
+ }
515
+ return {
516
+ githubTokenEnv: Boolean(process.env.GITHUB_TOKEN),
517
+ ghTokenEnv: Boolean(process.env.GH_TOKEN),
518
+ ghCli
519
+ };
520
+ }
@@ -0,0 +1,3 @@
1
+ export function createImportContext(...args: any[]): any;
2
+ export function findNearestGitRoot(...args: any[]): any;
3
+ export function normalizeWorkspacePaths(...args: any[]): any;
@@ -0,0 +1 @@
1
+ export const IMPORT_TRACKS: Set<string>;
@@ -0,0 +1,4 @@
1
+ export const extractorRegistry: Record<string, any[]>;
2
+ export const enricherRegistry: Record<string, any[]>;
3
+ export function getExtractorsForTrack(...args: any[]): any[];
4
+ export function getEnrichersForTrack(...args: any[]): any[];