@tdk-landscape/tdk-cli-core 1.3.53 → 1.3.54

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 (388) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/cli/dist/generator/extension-fetch.js +16 -9
  3. package/cli/package.json +1 -1
  4. package/package.json +16 -1
  5. package/.claude/skills/layer-autoresearch/SKILL.md +0 -48
  6. package/.claude/skills/tdk-troubleshoot/SKILL.md +0 -222
  7. package/.github/ISSUE_TEMPLATE/bug_report.yml +0 -40
  8. package/.github/ISSUE_TEMPLATE/config.yml +0 -11
  9. package/.github/ISSUE_TEMPLATE/feature_request.yml +0 -18
  10. package/.github/ISSUE_TEMPLATE/premium_license.yml +0 -43
  11. package/.github/dependabot.yml +0 -33
  12. package/.github/pull_request_template.md +0 -5
  13. package/.github/workflows/ci.yml +0 -200
  14. package/.github/workflows/release-binaries.yml +0 -139
  15. package/.github/zizmor.yml +0 -9
  16. package/.pre-commit-config.yaml +0 -57
  17. package/CODE_OF_CONDUCT.md +0 -9
  18. package/CONTRIBUTING.md +0 -42
  19. package/Makefile +0 -92
  20. package/SECURITY.md +0 -17
  21. package/benchmarks/results/container-scale-2026-09-25T20-54-49-736Z.json +0 -45
  22. package/benchmarks/results/container-scale-2026-09-25T21-01-20-540Z.json +0 -150
  23. package/benchmarks/results/container-scale-2026-09-25T21-15-01-441Z.json +0 -73
  24. package/benchmarks/results/container-scale-2026-09-25T22-09-01-630Z.json +0 -77
  25. package/benchmarks/results/container-scale-2026-09-25T22-18-28-371Z.json +0 -202
  26. package/cli/AGENTS.md +0 -390
  27. package/cli/DESIGN.md +0 -735
  28. package/cli/README.md +0 -292
  29. package/cli/biome.json +0 -40
  30. package/cli/dependency-graph.svg +0 -1135
  31. package/cli/dist/cli.d.ts +0 -3
  32. package/cli/dist/cli.d.ts.map +0 -1
  33. package/cli/dist/cli.js.map +0 -1
  34. package/cli/dist/commands/completion.d.ts +0 -3
  35. package/cli/dist/commands/completion.d.ts.map +0 -1
  36. package/cli/dist/commands/completion.js.map +0 -1
  37. package/cli/dist/commands/config.d.ts +0 -3
  38. package/cli/dist/commands/config.d.ts.map +0 -1
  39. package/cli/dist/commands/config.js.map +0 -1
  40. package/cli/dist/commands/doctor.d.ts +0 -19
  41. package/cli/dist/commands/doctor.d.ts.map +0 -1
  42. package/cli/dist/commands/doctor.js.map +0 -1
  43. package/cli/dist/commands/down.d.ts +0 -3
  44. package/cli/dist/commands/down.d.ts.map +0 -1
  45. package/cli/dist/commands/down.js.map +0 -1
  46. package/cli/dist/commands/help.d.ts +0 -2
  47. package/cli/dist/commands/help.d.ts.map +0 -1
  48. package/cli/dist/commands/help.js.map +0 -1
  49. package/cli/dist/commands/networks.d.ts +0 -3
  50. package/cli/dist/commands/networks.d.ts.map +0 -1
  51. package/cli/dist/commands/networks.js.map +0 -1
  52. package/cli/dist/commands/project.d.ts +0 -9
  53. package/cli/dist/commands/project.d.ts.map +0 -1
  54. package/cli/dist/commands/project.js.map +0 -1
  55. package/cli/dist/commands/projects.d.ts +0 -3
  56. package/cli/dist/commands/projects.d.ts.map +0 -1
  57. package/cli/dist/commands/projects.js.map +0 -1
  58. package/cli/dist/commands/resource.d.ts +0 -69
  59. package/cli/dist/commands/resource.d.ts.map +0 -1
  60. package/cli/dist/commands/resource.js.map +0 -1
  61. package/cli/dist/commands/resources.d.ts +0 -3
  62. package/cli/dist/commands/resources.d.ts.map +0 -1
  63. package/cli/dist/commands/resources.js.map +0 -1
  64. package/cli/dist/commands/stack.d.ts +0 -3
  65. package/cli/dist/commands/stack.d.ts.map +0 -1
  66. package/cli/dist/commands/stack.js.map +0 -1
  67. package/cli/dist/commands/stacks.d.ts +0 -3
  68. package/cli/dist/commands/stacks.d.ts.map +0 -1
  69. package/cli/dist/commands/stacks.js.map +0 -1
  70. package/cli/dist/commands/status.d.ts +0 -3
  71. package/cli/dist/commands/status.d.ts.map +0 -1
  72. package/cli/dist/commands/status.js.map +0 -1
  73. package/cli/dist/commands/ui.d.ts +0 -3
  74. package/cli/dist/commands/ui.d.ts.map +0 -1
  75. package/cli/dist/commands/ui.js.map +0 -1
  76. package/cli/dist/commands/up.d.ts +0 -3
  77. package/cli/dist/commands/up.d.ts.map +0 -1
  78. package/cli/dist/commands/up.js.map +0 -1
  79. package/cli/dist/commands/upgrade.d.ts +0 -14
  80. package/cli/dist/commands/upgrade.d.ts.map +0 -1
  81. package/cli/dist/commands/upgrade.js.map +0 -1
  82. package/cli/dist/commands/version.d.ts +0 -3
  83. package/cli/dist/commands/version.d.ts.map +0 -1
  84. package/cli/dist/commands/version.js.map +0 -1
  85. package/cli/dist/components/Accessible.d.ts +0 -8
  86. package/cli/dist/components/Accessible.d.ts.map +0 -1
  87. package/cli/dist/components/Accessible.js.map +0 -1
  88. package/cli/dist/components/BaseTooltip.d.ts +0 -4
  89. package/cli/dist/components/BaseTooltip.d.ts.map +0 -1
  90. package/cli/dist/components/BaseTooltip.js.map +0 -1
  91. package/cli/dist/components/DetailPanel.d.ts +0 -4
  92. package/cli/dist/components/DetailPanel.d.ts.map +0 -1
  93. package/cli/dist/components/DetailPanel.js.map +0 -1
  94. package/cli/dist/components/FileTree.d.ts +0 -4
  95. package/cli/dist/components/FileTree.d.ts.map +0 -1
  96. package/cli/dist/components/FileTree.js.map +0 -1
  97. package/cli/dist/components/ResourceSelectInput.d.ts +0 -4
  98. package/cli/dist/components/ResourceSelectInput.d.ts.map +0 -1
  99. package/cli/dist/components/ResourceSelectInput.js.map +0 -1
  100. package/cli/dist/components/ResourceTable.d.ts +0 -4
  101. package/cli/dist/components/ResourceTable.d.ts.map +0 -1
  102. package/cli/dist/components/ResourceTable.js.map +0 -1
  103. package/cli/dist/components/TabBar.d.ts +0 -4
  104. package/cli/dist/components/TabBar.d.ts.map +0 -1
  105. package/cli/dist/components/TabBar.js.map +0 -1
  106. package/cli/dist/components/Tooltip.d.ts +0 -12
  107. package/cli/dist/components/Tooltip.d.ts.map +0 -1
  108. package/cli/dist/components/Tooltip.js.map +0 -1
  109. package/cli/dist/components/index.d.ts +0 -8
  110. package/cli/dist/components/index.d.ts.map +0 -1
  111. package/cli/dist/components/index.js.map +0 -1
  112. package/cli/dist/config/platform-standards.d.ts +0 -159
  113. package/cli/dist/config/platform-standards.d.ts.map +0 -1
  114. package/cli/dist/config/platform-standards.js.map +0 -1
  115. package/cli/dist/generator/extension-fetch.d.ts +0 -25
  116. package/cli/dist/generator/extension-fetch.d.ts.map +0 -1
  117. package/cli/dist/generator/extension-fetch.js.map +0 -1
  118. package/cli/dist/generator/template-engine.d.ts +0 -62
  119. package/cli/dist/generator/template-engine.d.ts.map +0 -1
  120. package/cli/dist/generator/template-engine.js.map +0 -1
  121. package/cli/dist/index.d.ts +0 -11
  122. package/cli/dist/index.d.ts.map +0 -1
  123. package/cli/dist/index.js.map +0 -1
  124. package/cli/dist/types/index.d.ts +0 -257
  125. package/cli/dist/types/index.d.ts.map +0 -1
  126. package/cli/dist/types/index.js.map +0 -1
  127. package/cli/dist/utils/cache.d.ts +0 -19
  128. package/cli/dist/utils/cache.d.ts.map +0 -1
  129. package/cli/dist/utils/cache.js.map +0 -1
  130. package/cli/dist/utils/command-helpers.d.ts +0 -17
  131. package/cli/dist/utils/command-helpers.d.ts.map +0 -1
  132. package/cli/dist/utils/command-helpers.js.map +0 -1
  133. package/cli/dist/utils/constants.d.ts +0 -53
  134. package/cli/dist/utils/constants.d.ts.map +0 -1
  135. package/cli/dist/utils/constants.js.map +0 -1
  136. package/cli/dist/utils/discovery-context.d.ts +0 -4
  137. package/cli/dist/utils/discovery-context.d.ts.map +0 -1
  138. package/cli/dist/utils/discovery-context.js.map +0 -1
  139. package/cli/dist/utils/docker.d.ts +0 -4
  140. package/cli/dist/utils/docker.d.ts.map +0 -1
  141. package/cli/dist/utils/docker.js.map +0 -1
  142. package/cli/dist/utils/doctor-runtime.d.ts +0 -81
  143. package/cli/dist/utils/doctor-runtime.d.ts.map +0 -1
  144. package/cli/dist/utils/doctor-runtime.js.map +0 -1
  145. package/cli/dist/utils/env-validator.d.ts +0 -15
  146. package/cli/dist/utils/env-validator.d.ts.map +0 -1
  147. package/cli/dist/utils/env-validator.js.map +0 -1
  148. package/cli/dist/utils/errors.d.ts +0 -31
  149. package/cli/dist/utils/errors.d.ts.map +0 -1
  150. package/cli/dist/utils/errors.js.map +0 -1
  151. package/cli/dist/utils/file-helpers.d.ts +0 -14
  152. package/cli/dist/utils/file-helpers.d.ts.map +0 -1
  153. package/cli/dist/utils/file-helpers.js.map +0 -1
  154. package/cli/dist/utils/formatting.d.ts +0 -30
  155. package/cli/dist/utils/formatting.d.ts.map +0 -1
  156. package/cli/dist/utils/formatting.js.map +0 -1
  157. package/cli/dist/utils/paths.d.ts +0 -3
  158. package/cli/dist/utils/paths.d.ts.map +0 -1
  159. package/cli/dist/utils/paths.js.map +0 -1
  160. package/cli/dist/utils/port-assignment.d.ts +0 -6
  161. package/cli/dist/utils/port-assignment.d.ts.map +0 -1
  162. package/cli/dist/utils/port-assignment.js.map +0 -1
  163. package/cli/dist/utils/project-features.d.ts +0 -23
  164. package/cli/dist/utils/project-features.d.ts.map +0 -1
  165. package/cli/dist/utils/project-features.js.map +0 -1
  166. package/cli/dist/utils/project-templates.d.ts +0 -7
  167. package/cli/dist/utils/project-templates.d.ts.map +0 -1
  168. package/cli/dist/utils/project-templates.js.map +0 -1
  169. package/cli/dist/utils/prompt.d.ts +0 -28
  170. package/cli/dist/utils/prompt.d.ts.map +0 -1
  171. package/cli/dist/utils/prompt.js.map +0 -1
  172. package/cli/dist/utils/resource-features.d.ts +0 -29
  173. package/cli/dist/utils/resource-features.d.ts.map +0 -1
  174. package/cli/dist/utils/resource-features.js.map +0 -1
  175. package/cli/dist/utils/service-urls.d.ts +0 -30
  176. package/cli/dist/utils/service-urls.d.ts.map +0 -1
  177. package/cli/dist/utils/service-urls.js.map +0 -1
  178. package/cli/dist/utils/services.d.ts +0 -18
  179. package/cli/dist/utils/services.d.ts.map +0 -1
  180. package/cli/dist/utils/services.js.map +0 -1
  181. package/cli/dist/utils/stack-features.d.ts +0 -22
  182. package/cli/dist/utils/stack-features.d.ts.map +0 -1
  183. package/cli/dist/utils/stack-features.js.map +0 -1
  184. package/cli/dist/utils/tar.d.ts +0 -7
  185. package/cli/dist/utils/tar.d.ts.map +0 -1
  186. package/cli/dist/utils/tar.js.map +0 -1
  187. package/cli/dist/utils/tilt.d.ts +0 -20
  188. package/cli/dist/utils/tilt.d.ts.map +0 -1
  189. package/cli/dist/utils/tilt.js.map +0 -1
  190. package/cli/dist/utils/validation.d.ts +0 -16
  191. package/cli/dist/utils/validation.d.ts.map +0 -1
  192. package/cli/dist/utils/validation.js.map +0 -1
  193. package/cli/knip.json +0 -6
  194. package/cli/pnpm-lock.yaml +0 -2305
  195. package/cli/pnpm-workspace.yaml +0 -2
  196. package/cli/src/cli.ts +0 -72
  197. package/cli/src/commands/__tests__/always-enabled-infra.test.ts +0 -109
  198. package/cli/src/commands/__tests__/config.test.ts +0 -146
  199. package/cli/src/commands/__tests__/doctor.test.ts +0 -730
  200. package/cli/src/commands/__tests__/error-handling.test.ts +0 -78
  201. package/cli/src/commands/__tests__/phases-model.test.ts +0 -161
  202. package/cli/src/commands/__tests__/project-resource-features-e2e.test.ts +0 -187
  203. package/cli/src/commands/__tests__/project.test.ts +0 -68
  204. package/cli/src/commands/__tests__/resource.test.ts +0 -226
  205. package/cli/src/commands/__tests__/saas-starter-integration.test.ts +0 -194
  206. package/cli/src/commands/__tests__/stack-features-e2e.test.ts +0 -135
  207. package/cli/src/commands/__tests__/upgrade.test.ts +0 -198
  208. package/cli/src/commands/completion.ts +0 -300
  209. package/cli/src/commands/config.ts +0 -299
  210. package/cli/src/commands/doctor.ts +0 -926
  211. package/cli/src/commands/down.ts +0 -37
  212. package/cli/src/commands/help.ts +0 -143
  213. package/cli/src/commands/networks-design.md +0 -80
  214. package/cli/src/commands/networks.ts +0 -332
  215. package/cli/src/commands/project.ts +0 -456
  216. package/cli/src/commands/projects.ts +0 -82
  217. package/cli/src/commands/resource.ts +0 -652
  218. package/cli/src/commands/resources.ts +0 -95
  219. package/cli/src/commands/stack.ts +0 -128
  220. package/cli/src/commands/stacks.ts +0 -52
  221. package/cli/src/commands/status.ts +0 -88
  222. package/cli/src/commands/ui.tsx +0 -843
  223. package/cli/src/commands/up.ts +0 -169
  224. package/cli/src/commands/upgrade.ts +0 -628
  225. package/cli/src/commands/version.ts +0 -9
  226. package/cli/src/components/Accessible.tsx +0 -21
  227. package/cli/src/components/BaseTooltip.tsx +0 -66
  228. package/cli/src/components/DetailPanel.tsx +0 -146
  229. package/cli/src/components/FileTree.tsx +0 -89
  230. package/cli/src/components/ResourceSelectInput.tsx +0 -30
  231. package/cli/src/components/ResourceTable.tsx +0 -78
  232. package/cli/src/components/TabBar.tsx +0 -53
  233. package/cli/src/components/Tooltip.tsx +0 -11
  234. package/cli/src/components/index.ts +0 -7
  235. package/cli/src/config/platform-standards.test.ts +0 -11
  236. package/cli/src/config/platform-standards.ts +0 -196
  237. package/cli/src/generator/__tests__/extension-fetch.test.ts +0 -242
  238. package/cli/src/generator/__tests__/template-engine.test.ts +0 -70
  239. package/cli/src/generator/extension-fetch.ts +0 -286
  240. package/cli/src/generator/template-engine.ts +0 -752
  241. package/cli/src/index.ts +0 -86
  242. package/cli/src/templates.d.ts +0 -4
  243. package/cli/src/types/index.ts +0 -353
  244. package/cli/src/utils/__tests__/cache.test.ts +0 -98
  245. package/cli/src/utils/__tests__/formatting.test.ts +0 -170
  246. package/cli/src/utils/__tests__/paths.test.ts +0 -180
  247. package/cli/src/utils/__tests__/port-assignment.test.ts +0 -121
  248. package/cli/src/utils/__tests__/service-urls.test.ts +0 -174
  249. package/cli/src/utils/__tests__/services.test.ts +0 -531
  250. package/cli/src/utils/__tests__/tilt.test.ts +0 -172
  251. package/cli/src/utils/__tests__/validation.test.ts +0 -148
  252. package/cli/src/utils/cache.ts +0 -76
  253. package/cli/src/utils/command-helpers.ts +0 -54
  254. package/cli/src/utils/constants.ts +0 -130
  255. package/cli/src/utils/discovery-context.ts +0 -49
  256. package/cli/src/utils/docker.ts +0 -20
  257. package/cli/src/utils/doctor-runtime.ts +0 -644
  258. package/cli/src/utils/env-validator.ts +0 -139
  259. package/cli/src/utils/errors.ts +0 -168
  260. package/cli/src/utils/file-helpers.ts +0 -62
  261. package/cli/src/utils/formatting.ts +0 -215
  262. package/cli/src/utils/paths.ts +0 -53
  263. package/cli/src/utils/port-assignment.ts +0 -106
  264. package/cli/src/utils/project-features.ts +0 -118
  265. package/cli/src/utils/project-templates.ts +0 -29
  266. package/cli/src/utils/prompt.ts +0 -128
  267. package/cli/src/utils/resource-features.ts +0 -215
  268. package/cli/src/utils/service-urls.ts +0 -124
  269. package/cli/src/utils/services.ts +0 -364
  270. package/cli/src/utils/stack-features.ts +0 -30
  271. package/cli/src/utils/tar.ts +0 -24
  272. package/cli/src/utils/tilt.ts +0 -133
  273. package/cli/src/utils/validation.ts +0 -67
  274. package/cli/tsconfig.json +0 -25
  275. package/cli/tsconfig.typecheck.json +0 -8
  276. package/docs/FEATURES.md +0 -281
  277. package/docs/demo.svg +0 -217
  278. package/engine/docs/AUTODISCOVERY_TEST.md +0 -182
  279. package/engine/docs/C4-ARCHITECTURE-operations.md +0 -396
  280. package/engine/docs/C4-ARCHITECTURE-overview.md +0 -284
  281. package/engine/docs/C4-ARCHITECTURE.md +0 -17
  282. package/engine/docs/GOLDEN_IMAGE_INTEGRATION.md +0 -349
  283. package/engine/docs/MANIFEST_DRIVEN_ARCHITECTURE.md +0 -357
  284. package/engine/docs/README.md +0 -284
  285. package/install.sh +0 -19
  286. package/knip.json +0 -10
  287. package/openspec/changes/add-vscode-tdk-troubleshooter-plugin/.openspec.yaml +0 -2
  288. package/openspec/changes/add-vscode-tdk-troubleshooter-plugin/design.md +0 -102
  289. package/openspec/changes/add-vscode-tdk-troubleshooter-plugin/proposal.md +0 -31
  290. package/openspec/changes/add-vscode-tdk-troubleshooter-plugin/specs/vscode-tdk-notifications/spec.md +0 -48
  291. package/openspec/changes/add-vscode-tdk-troubleshooter-plugin/specs/vscode-tdk-orchestration/spec.md +0 -63
  292. package/openspec/changes/add-vscode-tdk-troubleshooter-plugin/specs/vscode-tdk-troubleshooting/spec.md +0 -56
  293. package/openspec/changes/add-vscode-tdk-troubleshooter-plugin/tasks.md +0 -61
  294. package/openspec/changes/archive/2026-04-28-rename-domain-to-stack-service-to-resource/.openspec.yaml +0 -2
  295. package/openspec/changes/archive/2026-04-28-rename-domain-to-stack-service-to-resource/design.md +0 -114
  296. package/openspec/changes/archive/2026-04-28-rename-domain-to-stack-service-to-resource/proposal.md +0 -32
  297. package/openspec/changes/archive/2026-04-28-rename-domain-to-stack-service-to-resource/specs/manifest-field-migration/spec.md +0 -20
  298. package/openspec/changes/archive/2026-04-28-rename-domain-to-stack-service-to-resource/specs/resource-terminology-standard/spec.md +0 -20
  299. package/openspec/changes/archive/2026-04-28-rename-domain-to-stack-service-to-resource/specs/stack-terminology-standard/spec.md +0 -20
  300. package/openspec/changes/archive/2026-04-28-rename-domain-to-stack-service-to-resource/tasks.md +0 -194
  301. package/openspec/changes/archive/2026-04-28-star-files-parameter-fixes/.openspec.yaml +0 -2
  302. package/openspec/changes/archive/2026-04-28-star-files-parameter-fixes/design.md +0 -111
  303. package/openspec/changes/archive/2026-04-28-star-files-parameter-fixes/proposal.md +0 -33
  304. package/openspec/changes/archive/2026-04-28-star-files-parameter-fixes/specs/function-naming-alignment/spec.md +0 -12
  305. package/openspec/changes/archive/2026-04-28-star-files-parameter-fixes/specs/optional-parameter-patterns/spec.md +0 -18
  306. package/openspec/changes/archive/2026-04-28-star-files-parameter-fixes/specs/parameter-documentation/spec.md +0 -16
  307. package/openspec/changes/archive/2026-04-28-star-files-parameter-fixes/specs/parameter-naming-consistency/spec.md +0 -12
  308. package/openspec/changes/archive/2026-04-28-star-files-parameter-fixes/specs/parameter-ordering-standard/spec.md +0 -12
  309. package/openspec/changes/archive/2026-04-28-star-files-parameter-fixes/tasks.md +0 -194
  310. package/openspec/changes/archive/2026-04-29-scan-repo-gaps-fix/.openspec.yaml +0 -2
  311. package/openspec/changes/archive/2026-04-29-scan-repo-gaps-fix/design.md +0 -84
  312. package/openspec/changes/archive/2026-04-29-scan-repo-gaps-fix/proposal.md +0 -31
  313. package/openspec/changes/archive/2026-04-29-scan-repo-gaps-fix/specs/codebase-audit/spec.md +0 -27
  314. package/openspec/changes/archive/2026-04-29-scan-repo-gaps-fix/specs/dead-code-cleanup/spec.md +0 -27
  315. package/openspec/changes/archive/2026-04-29-scan-repo-gaps-fix/specs/test-gap-fill/spec.md +0 -23
  316. package/openspec/changes/archive/2026-04-29-scan-repo-gaps-fix/specs/todo-resolution/spec.md +0 -27
  317. package/openspec/changes/archive/2026-04-29-scan-repo-gaps-fix/tasks.md +0 -39
  318. package/openspec/changes/archive/2026-06-25-landscape-consolidation/.openspec.yaml +0 -2
  319. package/openspec/changes/archive/2026-06-25-landscape-consolidation/design.md +0 -80
  320. package/openspec/changes/archive/2026-06-25-landscape-consolidation/proposal.md +0 -40
  321. package/openspec/changes/archive/2026-06-25-landscape-consolidation/spec.md +0 -52
  322. package/openspec/changes/archive/2026-06-25-landscape-consolidation/tasks.md +0 -51
  323. package/openspec/changes/archive/2026-09-17-fix-generated-stack-boot/.openspec.yaml +0 -2
  324. package/openspec/changes/archive/2026-09-17-fix-generated-stack-boot/design.md +0 -43
  325. package/openspec/changes/archive/2026-09-17-fix-generated-stack-boot/proposal.md +0 -29
  326. package/openspec/changes/archive/2026-09-17-fix-generated-stack-boot/specs/self-contained-generated-projects/spec.md +0 -67
  327. package/openspec/changes/archive/2026-09-17-fix-generated-stack-boot/tasks.md +0 -27
  328. package/openspec/changes/optimize-runtime-docker-layers/.openspec.yaml +0 -3
  329. package/openspec/changes/optimize-runtime-docker-layers/design.md +0 -81
  330. package/openspec/changes/optimize-runtime-docker-layers/proposal.md +0 -44
  331. package/openspec/changes/optimize-runtime-docker-layers/specs/runtime-container-footprint/spec.md +0 -79
  332. package/openspec/changes/optimize-runtime-docker-layers/tasks.md +0 -36
  333. package/openspec/changes/prioritized-cold-start/.openspec.yaml +0 -4
  334. package/openspec/changes/prioritized-cold-start/design.md +0 -137
  335. package/openspec/changes/prioritized-cold-start/proposal.md +0 -41
  336. package/openspec/changes/prioritized-cold-start/specs/on-demand-resource-startup/spec.md +0 -98
  337. package/openspec/changes/prioritized-cold-start/tasks.md +0 -69
  338. package/openspec/config.yaml +0 -1
  339. package/openspec/specs/manifest-field-migration/spec.md +0 -24
  340. package/openspec/specs/resource-terminology-standard/spec.md +0 -24
  341. package/openspec/specs/self-contained-generated-projects/spec.md +0 -67
  342. package/openspec/specs/stack-terminology-standard/spec.md +0 -24
  343. package/platform/services/platform/proxy/service.yaml +0 -14
  344. package/scripts/audit-codebase.sh +0 -213
  345. package/scripts/autoresearch/layer-eval.sh +0 -65
  346. package/scripts/benchmark/README.md +0 -25
  347. package/scripts/benchmark/container-scale.ts +0 -503
  348. package/scripts/benchmark/pre-release-gate.sh +0 -9
  349. package/scripts/install-git-hooks.sh +0 -14
  350. package/scripts/measure-idle-footprint.sh +0 -58
  351. package/scripts/record-demo.sh +0 -43
  352. package/scripts/release-binaries.sh +0 -97
  353. package/scripts/setup-pre-commit.sh +0 -33
  354. package/scripts/stage-npm-engine.sh +0 -36
  355. package/tests/tilt-engine/__init__.py +0 -5
  356. package/tests/tilt-engine/conftest.py +0 -182
  357. package/tests/tilt-engine/fixtures/appointment-frontend-service.json +0 -11
  358. package/tests/tilt-engine/fixtures/identity-backend-service.json +0 -12
  359. package/tests/tilt-engine/fixtures/invalid-service.json +0 -4
  360. package/tests/tilt-engine/test_agents_md_generator.py +0 -341
  361. package/tests/tilt-engine/test_agents_md_integration.py +0 -378
  362. package/tests/tilt-engine/test_cache_operations.py +0 -181
  363. package/tests/tilt-engine/test_cache_persistence.py +0 -142
  364. package/tests/tilt-engine/test_code_executor.py +0 -152
  365. package/tests/tilt-engine/test_code_viewer.py +0 -127
  366. package/tests/tilt-engine/test_compose_port_anchors.py +0 -310
  367. package/tests/tilt-engine/test_config_inspector.py +0 -162
  368. package/tests/tilt-engine/test_daemon_focus_mode.py +0 -89
  369. package/tests/tilt-engine/test_daemon_polling.py +0 -122
  370. package/tests/tilt-engine/test_daemon_registration.py +0 -115
  371. package/tests/tilt-engine/test_daemon_validation.py +0 -107
  372. package/tests/tilt-engine/test_docker_generator_bugs.py +0 -493
  373. package/tests/tilt-engine/test_docker_prune.py +0 -119
  374. package/tests/tilt-engine/test_dockerignore_path_bug.py +0 -82
  375. package/tests/tilt-engine/test_file_browser.py +0 -193
  376. package/tests/tilt-engine/test_frontend_basepath_manifest.py +0 -27
  377. package/tests/tilt-engine/test_health_dependencies.py +0 -130
  378. package/tests/tilt-engine/test_health_endpoints.py +0 -118
  379. package/tests/tilt-engine/test_health_tilt_ui.py +0 -85
  380. package/tests/tilt-engine/test_runtime_container_footprint.py +0 -162
  381. package/tests/tilt-engine/test_sablier_defer_start.py +0 -237
  382. package/tests/tilt-engine/test_safety_aliases.py +0 -84
  383. package/tests/tilt-engine/test_snapshot_diff.py +0 -136
  384. package/tests/tilt-engine/test_snapshot_persistence.py +0 -163
  385. package/tests/tilt-engine/test_snapshot_scanning.py +0 -123
  386. package/tests/tilt-engine/test_standalone_project_boot.py +0 -61
  387. package/tests/tilt-engine/test_standalone_traefik.py +0 -160
  388. package/tests/tilt-engine/test_traefik_static_wake_route.py +0 -187
@@ -1,242 +0,0 @@
1
- // Covers the exact three scenarios demonstrated manually on the real CLI:
2
- // 1. no TDK_LICENSE_KEY set -> free tier, zero network calls
3
- // 2. TDK_LICENSE_KEY set but invalid -> "no premium resources unlocked", free tier
4
- // 3. TDK_LICENSE_KEY set and valid -> premium files applied over the stubs
5
- //
6
- // Only the network boundary (fetch) is mocked - tar extraction, the file
7
- // overlay, and the on-disk cache all run for real against temp directories,
8
- // so this exercises the same code path `tdk project` actually runs.
9
-
10
- import { execFileSync } from "node:child_process";
11
- import {
12
- existsSync,
13
- mkdirSync,
14
- mkdtempSync,
15
- readFileSync,
16
- rmSync,
17
- utimesSync,
18
- writeFileSync,
19
- } from "node:fs";
20
- import { tmpdir } from "node:os";
21
- import { join } from "node:path";
22
- import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
23
-
24
- let projectRoot: string;
25
- let destDir: string;
26
- let fakeHome: string;
27
- let fixtureTarball: Buffer;
28
-
29
- function buildFixtureTarball(): Buffer {
30
- const src = mkdtempSync(join(tmpdir(), "tdk-premium-fixture-"));
31
- mkdirSync(join(src, "typescript"), { recursive: true });
32
- writeFileSync(
33
- join(src, "typescript", "playwright_config.star"),
34
- "# REAL premium playwright config\ndef generate_playwright_config(): pass\n",
35
- );
36
- writeFileSync(join(src, "c4_diagram.star"), "# REAL premium c4 diagram generator\n");
37
-
38
- // Match exactly how the real premium.tar.gz is built (tar -C dir .), so
39
- // entries get a "./" prefix - extractTarball's --strip-components=1
40
- // expects that dummy leading component, not a real directory name.
41
- const tarPath = join(src, "..", "premium-fixture.tar.gz");
42
- execFileSync("tar", ["-czf", tarPath, "-C", src, "."]);
43
- const buf = readFileSync(tarPath);
44
- rmSync(src, { recursive: true, force: true });
45
- rmSync(tarPath, { force: true });
46
- return buf;
47
- }
48
-
49
- beforeEach(() => {
50
- projectRoot = mkdtempSync(join(tmpdir(), "tdk-project-"));
51
- destDir = mkdtempSync(join(tmpdir(), "tdk-dest-"));
52
- fakeHome = mkdtempSync(join(tmpdir(), "tdk-home-"));
53
-
54
- // Seed destDir with the free-tier stub, same as vendorTdkExtension does
55
- // before ever calling applyPremiumOverlay - so we can assert it gets
56
- // overwritten only when a premium fetch actually succeeds.
57
- mkdirSync(join(destDir, "engine/topologies/tilt/generators/typescript"), { recursive: true });
58
- writeFileSync(
59
- join(destDir, "engine/topologies/tilt/generators/typescript/playwright_config.star"),
60
- "# unlicensed stub\n",
61
- );
62
-
63
- process.env.HOME = fakeHome;
64
- delete process.env.TDK_LICENSE_KEY;
65
- delete process.env.TDK_PREMIUM_ENDPOINT;
66
- vi.restoreAllMocks();
67
- });
68
-
69
- afterEach(() => {
70
- rmSync(projectRoot, { recursive: true, force: true });
71
- rmSync(destDir, { recursive: true, force: true });
72
- rmSync(fakeHome, { recursive: true, force: true });
73
- vi.unstubAllGlobals();
74
- });
75
-
76
- describe("applyPremiumOverlay", () => {
77
- it("scenario 1: no license key -> returns false, never calls fetch", async () => {
78
- const fetchSpy = vi.fn();
79
- vi.stubGlobal("fetch", fetchSpy);
80
-
81
- const { applyPremiumOverlay } = await import("../extension-fetch.js");
82
- const applied = await applyPremiumOverlay(projectRoot, destDir);
83
-
84
- expect(applied).toBe(false);
85
- expect(fetchSpy).not.toHaveBeenCalled();
86
- // Stub must be left untouched - zero side effects for free users.
87
- expect(
88
- readFileSync(
89
- join(destDir, "engine/topologies/tilt/generators/typescript/playwright_config.star"),
90
- "utf-8",
91
- ),
92
- ).toBe("# unlicensed stub\n");
93
- });
94
-
95
- it("scenario 2: invalid/ungranted key -> tries every known resource, then falls back to free tier", async () => {
96
- process.env.TDK_LICENSE_KEY = "tdk-fa411b"; // the mistyped key from the real session
97
-
98
- const fetchSpy = vi
99
- .fn()
100
- .mockResolvedValue(new Response("key does not grant resource", { status: 403 }));
101
- vi.stubGlobal("fetch", fetchSpy);
102
-
103
- const { applyPremiumOverlay } = await import("../extension-fetch.js");
104
- const applied = await applyPremiumOverlay(projectRoot, destDir);
105
-
106
- expect(applied).toBe(false);
107
- // Every known resource name gets a shot before giving up.
108
- expect(fetchSpy).toHaveBeenCalledTimes(6);
109
- for (const call of fetchSpy.mock.calls) {
110
- const url = call[0] as string;
111
- expect(url).toContain("key=tdk-fa411b");
112
- }
113
- expect(
114
- readFileSync(
115
- join(destDir, "engine/topologies/tilt/generators/typescript/playwright_config.star"),
116
- "utf-8",
117
- ),
118
- ).toBe("# unlicensed stub\n");
119
- });
120
-
121
- it("scenario 3: valid key granting the first resource -> real files overlay the stubs", async () => {
122
- process.env.TDK_LICENSE_KEY = "tdk-fa411a"; // the real key from the session, grants playwright
123
- fixtureTarball ??= buildFixtureTarball();
124
-
125
- const fetchSpy = vi.fn().mockImplementation((url: string) => {
126
- if (url.includes("resource=playwright")) {
127
- return Promise.resolve(new Response(new Uint8Array(fixtureTarball), { status: 200 }));
128
- }
129
- return Promise.resolve(new Response("not granted", { status: 403 }));
130
- });
131
- vi.stubGlobal("fetch", fetchSpy);
132
-
133
- const { applyPremiumOverlay } = await import("../extension-fetch.js");
134
- const applied = await applyPremiumOverlay(projectRoot, destDir);
135
-
136
- expect(applied).toBe(true);
137
- // Stops at the first granted resource - doesn't keep trying c4-diagram/logging.
138
- expect(fetchSpy).toHaveBeenCalledTimes(1);
139
-
140
- const playwrightOut = readFileSync(
141
- join(destDir, "engine/topologies/tilt/generators/typescript/playwright_config.star"),
142
- "utf-8",
143
- );
144
- expect(playwrightOut).toContain("REAL premium playwright config");
145
- expect(playwrightOut).not.toContain("unlicensed stub");
146
-
147
- const c4Out = readFileSync(
148
- join(destDir, "engine/topologies/tilt/generators/c4_diagram.star"),
149
- "utf-8",
150
- );
151
- expect(c4Out).toContain("REAL premium c4 diagram generator");
152
- });
153
-
154
- it("sends the per-project id and reuses it across calls instead of generating a new one each time", async () => {
155
- process.env.TDK_LICENSE_KEY = "tdk-fa411b";
156
- const seenProjectIds: string[] = [];
157
- const fetchSpy = vi.fn().mockImplementation((url: string) => {
158
- seenProjectIds.push(new URL(url).searchParams.get("projectId") ?? "");
159
- return Promise.resolve(new Response("not granted", { status: 403 }));
160
- });
161
- vi.stubGlobal("fetch", fetchSpy);
162
-
163
- const { applyPremiumOverlay } = await import("../extension-fetch.js");
164
- await applyPremiumOverlay(projectRoot, destDir);
165
- const idFile = join(projectRoot, ".tdk", ".project-id");
166
- expect(existsSync(idFile)).toBe(true);
167
- const persistedId = readFileSync(idFile, "utf-8").trim();
168
-
169
- expect(new Set(seenProjectIds).size).toBe(1);
170
- expect(seenProjectIds[0]).toBe(persistedId);
171
- });
172
-
173
- it("caches a successful fetch and does not re-fetch within the TTL", async () => {
174
- process.env.TDK_LICENSE_KEY = "tdk-fa411a";
175
- fixtureTarball ??= buildFixtureTarball();
176
-
177
- const fetchSpy = vi
178
- .fn()
179
- .mockResolvedValue(new Response(new Uint8Array(fixtureTarball), { status: 200 }));
180
- vi.stubGlobal("fetch", fetchSpy);
181
-
182
- const { applyPremiumOverlay } = await import("../extension-fetch.js");
183
- await applyPremiumOverlay(projectRoot, destDir);
184
- await applyPremiumOverlay(projectRoot, destDir);
185
-
186
- expect(fetchSpy).toHaveBeenCalledTimes(1);
187
- });
188
-
189
- it("re-fetches once the cached bundle is older than the TTL", async () => {
190
- process.env.TDK_LICENSE_KEY = "tdk-fa411a";
191
- fixtureTarball ??= buildFixtureTarball();
192
-
193
- // A Response body can only be read once - mockResolvedValue would
194
- // reuse the same instance across both calls in this test, so build a
195
- // fresh Response per invocation instead.
196
- const fetchSpy = vi
197
- .fn()
198
- .mockImplementation(() =>
199
- Promise.resolve(new Response(new Uint8Array(fixtureTarball), { status: 200 })),
200
- );
201
- vi.stubGlobal("fetch", fetchSpy);
202
-
203
- const { applyPremiumOverlay } = await import("../extension-fetch.js");
204
- await applyPremiumOverlay(projectRoot, destDir);
205
-
206
- const cachedPath = join(fakeHome, ".tdk", "cache", "premium-tdk-fa411a", "premium.tar.gz");
207
- expect(existsSync(cachedPath)).toBe(true);
208
- const longAgo = new Date(Date.now() - 13 * 60 * 60 * 1000); // TTL is 12h
209
- utimesSync(cachedPath, longAgo, longAgo);
210
-
211
- await applyPremiumOverlay(projectRoot, destDir);
212
- expect(fetchSpy).toHaveBeenCalledTimes(2);
213
- });
214
-
215
- it("switching keys uses a separate cache instead of serving the other key's bundle", async () => {
216
- fixtureTarball ??= buildFixtureTarball();
217
-
218
- process.env.TDK_LICENSE_KEY = "tdk-fa411a";
219
- vi.stubGlobal(
220
- "fetch",
221
- vi.fn().mockResolvedValue(new Response(new Uint8Array(fixtureTarball), { status: 200 })),
222
- );
223
- const { applyPremiumOverlay } = await import("../extension-fetch.js");
224
- await applyPremiumOverlay(projectRoot, destDir);
225
-
226
- process.env.TDK_LICENSE_KEY = "tdk-fa411b";
227
- const secondFetch = vi.fn().mockResolvedValue(new Response("not granted", { status: 403 }));
228
- vi.stubGlobal("fetch", secondFetch);
229
- const applied = await applyPremiumOverlay(projectRoot, destDir);
230
-
231
- expect(applied).toBe(false);
232
- expect(secondFetch).toHaveBeenCalled();
233
- });
234
-
235
- it("a network error is caught, never throws, and falls back to the free tier", async () => {
236
- process.env.TDK_LICENSE_KEY = "tdk-fa411a";
237
- vi.stubGlobal("fetch", vi.fn().mockRejectedValue(new Error("network unreachable")));
238
-
239
- const { applyPremiumOverlay } = await import("../extension-fetch.js");
240
- await expect(applyPremiumOverlay(projectRoot, destDir)).resolves.toBe(false);
241
- });
242
- });
@@ -1,70 +0,0 @@
1
- import * as fs from "node:fs";
2
- import * as os from "node:os";
3
- import * as path from "node:path";
4
- import { afterEach, beforeEach, describe, expect, it } from "vitest";
5
- import { loadTemplate } from "../template-engine.js";
6
-
7
- // Real template files, keyed by a substring that only appears in that specific
8
- // file - regression coverage for the bug where loadTemplate joined a candidate
9
- // *directory* (not the file) and silently fell through every candidate.
10
- const REAL_TEMPLATES: Record<string, string> = {
11
- "TILT_RESOURCE_DEFAULTS.star.hbs": "get_resource_defaults",
12
- "TILT_TECH_STACK.star.hbs": "get_tech_stack",
13
- "Tiltfile.hbs": "Tiltfile",
14
- ".tiltignore.hbs": "TILT IGNORE FILE",
15
- "spec.master.hbs": "spec.master",
16
- };
17
-
18
- describe("template-engine", () => {
19
- describe("loadTemplate", () => {
20
- for (const [filename, marker] of Object.entries(REAL_TEMPLATES)) {
21
- it(`should load ${filename} and return its own content`, () => {
22
- const content = loadTemplate(filename);
23
- expect(typeof content).toBe("string");
24
- expect(content.length).toBeGreaterThan(0);
25
- expect(content).toContain(marker);
26
- });
27
- }
28
-
29
- it("should return distinct content for each template (not the same file/dir every time)", () => {
30
- const contents = Object.keys(REAL_TEMPLATES).map((filename) => loadTemplate(filename));
31
- expect(new Set(contents).size).toBe(contents.length);
32
- });
33
-
34
- it("should throw (not silently return directory bytes) for non-existent template", () => {
35
- expect(() => loadTemplate("non-existent.hbs")).toThrow("Failed to load template");
36
- });
37
-
38
- describe("executable-relative fallback (compiled binary layout)", () => {
39
- let fakeExecDir: string;
40
- let originalExecPath: string;
41
-
42
- beforeEach(() => {
43
- // Mirrors what scripts/release-binaries.sh bundles next to the
44
- // compiled binary: <exeDir>/tdk-cli/cli/templates/<filename>.
45
- fakeExecDir = fs.mkdtempSync(path.join(os.tmpdir(), "tdk-exec-"));
46
- const bundledTemplatesDir = path.join(fakeExecDir, "tdk-cli", "cli", "templates");
47
- fs.mkdirSync(bundledTemplatesDir, { recursive: true });
48
- fs.writeFileSync(path.join(bundledTemplatesDir, "only-in-bundle.hbs"), "bundled-marker");
49
-
50
- originalExecPath = process.execPath;
51
- Object.defineProperty(process, "execPath", {
52
- value: path.join(fakeExecDir, "tdk"),
53
- configurable: true,
54
- });
55
- });
56
-
57
- afterEach(() => {
58
- Object.defineProperty(process, "execPath", {
59
- value: originalExecPath,
60
- configurable: true,
61
- });
62
- fs.rmSync(fakeExecDir, { recursive: true, force: true });
63
- });
64
-
65
- it("finds a template that only exists next to the executable", () => {
66
- expect(loadTemplate("only-in-bundle.hbs")).toBe("bundled-marker");
67
- });
68
- });
69
- });
70
- });
@@ -1,286 +0,0 @@
1
- // Fetches the paid-tier "premium" resource bundle (playwright, c4-diagram,
2
- // logging, agents-md, sablier, verdaccio, and a few other extras - see
3
- // tdk-cli-extensions/premium/) from the gated distribution worker, when a
4
- // license key is configured. The free engine never needs this for its own
5
- // resources - docker-compose, npm, bun, etc. are already public in this
6
- // repo, no key required.
7
- //
8
- // DDD (domain-driven-design scaffolding) is the one paid feature that is
9
- // NOT a file overlay: it's gated separately by hasDddLicense() below, via
10
- // the shared hasLiveResourceLicense() helper, since its code stays in this
11
- // public repo and is turned on/off by a runtime check rather than swapped
12
- // in - see that helper's own comment for why it can't just be added to
13
- // KNOWN_RESOURCES. hasVerdaccioLicense()/hasSablierLicense() also use that
14
- // same helper, but only to print a "this needs a license" warning in
15
- // template-engine.ts - Verdaccio and Sablier's real gate is the file
16
- // overlay above (their public files are disabled stubs, not gated code).
17
- //
18
- // The worker (tdk-extension-dist) is the real access-control boundary: it
19
- // checks the key against BUNDLES_REPO/keys/*.json - existence, activation/
20
- // expiry dates, granted resources, and a per-key project limit - before
21
- // serving anything. This client just asks and, if granted, unpacks the
22
- // result over the vendored stub files so the generator pipeline picks up
23
- // the real implementations transparently. See
24
- // tdk-extension-dist/src/index.ts for the server-side enforcement and
25
- // tdk-extension-dist/src/project-limit.ts for the project-limit logic.
26
-
27
- import { randomUUID } from "node:crypto";
28
- import { existsSync, mkdirSync, readFileSync, statSync, writeFileSync } from "node:fs";
29
- import { homedir } from "node:os";
30
- import { join } from "node:path";
31
- import { extractTarball } from "../utils/tar.js";
32
-
33
- const DEFAULT_ENDPOINT =
34
- "https://tdk-extension-dist.oranguman.workers.dev/v1/premium/bundle.tar.gz";
35
-
36
- // Tried in order until one is granted - the worker unlocks the whole
37
- // bundle on the first resource name a key is found to grant, since
38
- // premium.tar.gz ships all paid resources together. Keep in sync with
39
- // what issue-key.yml/update-key.yml accept as `resources` entries.
40
- const KNOWN_RESOURCES = [
41
- "playwright",
42
- "c4-diagram",
43
- "logging",
44
- "agents-md",
45
- "sablier",
46
- "verdaccio",
47
- ];
48
-
49
- // Re-check the license periodically rather than trusting a local cache
50
- // forever - an expired or revoked key shouldn't keep unlocking premium
51
- // content indefinitely just because it worked once.
52
- const CACHE_TTL_MS = 12 * 60 * 60 * 1000;
53
-
54
- // Maps each file's path inside premium.tar.gz to where it belongs in the
55
- // vendored engine output, so the generator pipeline finds it in the same
56
- // place the free stub (or, for the never-wired items, nothing at all)
57
- // used to be.
58
- const PREMIUM_PATH_MAP: Record<string, string> = {
59
- "typescript/playwright_config.star":
60
- "engine/topologies/tilt/generators/typescript/playwright_config.star",
61
- "generators/agents_md.star": "engine/topologies/tilt/generators/agents_md.star",
62
- "c4_diagram.star": "engine/topologies/tilt/generators/c4_diagram.star",
63
- "observability/logging.star": "engine/topologies/platform/observability/logging.star",
64
- "generators/database_provisioner.star":
65
- "engine/topologies/tilt/generators/database_provisioner.star",
66
- "generators/dependency_manifest.star":
67
- "engine/topologies/tilt/generators/dependency_manifest.star",
68
- "generators/fixed_frontend_tsconfig.star":
69
- "engine/topologies/tilt/generators/typescript/fixed_frontend_tsconfig.star",
70
- "synthetic_monitor.star": "engine/resources/synthetic_monitor.star",
71
- "synthetic-monitor-topology.star": "engine/topologies/platform/services/synthetic-monitor.star",
72
- "database-management-service.yaml": "platform/services/platform/database-management/service.yaml",
73
- "networking/sablier_container_cycle.star":
74
- "engine/topologies/platform/docker/networking/sablier_container_cycle.star",
75
- "registries/verdaccio_loader.star": "engine/topologies/platform/registries/verdaccio_loader.star",
76
- };
77
-
78
- function getLicenseKey(): string | null {
79
- return process.env.TDK_LICENSE_KEY?.trim() || null;
80
- }
81
-
82
- function getEndpoint(): string {
83
- return process.env.TDK_PREMIUM_ENDPOINT?.trim() || DEFAULT_ENDPOINT;
84
- }
85
-
86
- // A stable per-project id for the worker's project-limit tracking - not a
87
- // device or user id. Generated once and persisted alongside the rest of
88
- // the project's .tdk/ state.
89
- function getOrCreateProjectId(projectRoot: string): string {
90
- const idPath = join(projectRoot, ".tdk", ".project-id");
91
- if (existsSync(idPath)) {
92
- return readFileSync(idPath, "utf-8").trim();
93
- }
94
- const id = randomUUID();
95
- mkdirSync(join(projectRoot, ".tdk"), { recursive: true });
96
- writeFileSync(idPath, `${id}\n`);
97
- return id;
98
- }
99
-
100
- function cacheTarballPath(key: string): string {
101
- // Cache is per-key (not shared across different keys on the same
102
- // machine) so switching license keys doesn't serve a stale bundle
103
- // fetched under a different plan.
104
- const safeName = key.replace(/[^a-zA-Z0-9_-]/g, "_");
105
- return join(homedir(), ".tdk", "cache", `premium-${safeName}`, "premium.tar.gz");
106
- }
107
-
108
- function isCacheFresh(path: string): boolean {
109
- if (!existsSync(path)) return false;
110
- return Date.now() - statSync(path).mtimeMs < CACHE_TTL_MS;
111
- }
112
-
113
- async function fetchPremiumBundle(key: string, projectId: string): Promise<Buffer | null> {
114
- const endpoint = getEndpoint();
115
- for (const resource of KNOWN_RESOURCES) {
116
- const url =
117
- `${endpoint}?key=${encodeURIComponent(key)}` +
118
- `&resource=${encodeURIComponent(resource)}` +
119
- `&projectId=${encodeURIComponent(projectId)}`;
120
-
121
- let res: Response;
122
- try {
123
- res = await fetch(url);
124
- } catch (err) {
125
- console.warn(`⚠️ Premium fetch failed (network error): ${(err as Error).message}`);
126
- return null;
127
- }
128
-
129
- if (res.ok) {
130
- return Buffer.from(await res.arrayBuffer());
131
- }
132
- if (res.status === 401 || res.status === 403) {
133
- // Not granted for this specific resource name - try the next one
134
- // before concluding the key has nothing to offer.
135
- continue;
136
- }
137
- // Anything else (404 missing bundle release, 502 upstream failure,
138
- // etc.) won't be fixed by trying a different resource name.
139
- console.warn(`⚠️ Premium fetch failed: HTTP ${res.status}`);
140
- return null;
141
- }
142
- return null;
143
- }
144
-
145
- /**
146
- * Fetches (with a local, time-limited cache) the premium bundle for the
147
- * configured license key and overlays its files onto the already-vendored
148
- * free engine at destDir. Best-effort: returns false (never throws) if
149
- * there's no key configured, the key doesn't grant anything, or the fetch
150
- * fails - the caller should keep going with the free engine either way.
151
- */
152
- export async function applyPremiumOverlay(projectRoot: string, destDir: string): Promise<boolean> {
153
- const key = getLicenseKey();
154
- if (!key) return false;
155
-
156
- const tarballPath = cacheTarballPath(key);
157
-
158
- if (!isCacheFresh(tarballPath)) {
159
- const projectId = getOrCreateProjectId(projectRoot);
160
- const bundle = await fetchPremiumBundle(key, projectId);
161
- if (!bundle) {
162
- console.warn("⚠️ No premium resources unlocked for this key - using free tier only.");
163
- return false;
164
- }
165
- mkdirSync(join(tarballPath, ".."), { recursive: true });
166
- writeFileSync(tarballPath, bundle);
167
- }
168
-
169
- try {
170
- const extractDir = join(tarballPath, "..", "extracted");
171
- mkdirSync(extractDir, { recursive: true });
172
- extractTarball(readFileSync(tarballPath), extractDir);
173
-
174
- let applied = 0;
175
- for (const [src, dest] of Object.entries(PREMIUM_PATH_MAP)) {
176
- const from = join(extractDir, src);
177
- if (!existsSync(from)) continue;
178
- const to = join(destDir, dest);
179
- mkdirSync(join(to, ".."), { recursive: true });
180
- writeFileSync(to, readFileSync(from));
181
- applied++;
182
- }
183
-
184
- if (applied > 0) {
185
- console.log(`✓ Premium resources unlocked (${applied} file${applied === 1 ? "" : "s"})`);
186
- return true;
187
- }
188
- return false;
189
- } catch (err) {
190
- console.warn(`⚠️ Failed to apply premium overlay: ${(err as Error).message}`);
191
- return false;
192
- }
193
- }
194
-
195
- function liveResourceAccessCachePath(key: string, resource: string): string {
196
- const safeName = key.replace(/[^a-zA-Z0-9_-]/g, "_");
197
- return join(homedir(), ".tdk", "cache", `premium-${safeName}`, `${resource}-access.json`);
198
- }
199
-
200
- /**
201
- * Checks whether the configured license key grants a given "live" premium
202
- * resource. Originally added for resources with nothing to swap on disk
203
- * (ddd is still exactly that: gated code baked into the free engine, no
204
- * file overlay). verdaccio and sablier also use this - not because they
205
- * lack a PREMIUM_PATH_MAP entry (they have one now), but because their
206
- * public files are already disabled stubs regardless of license, so this
207
- * check only ever drives a "you need a license for this" warning in
208
- * template-engine.ts, never an actual enable/disable decision. Can't reuse
209
- * KNOWN_RESOURCES/fetchPremiumBundle for that warning either: that loop
210
- * stops at the FIRST resource the key grants and would report false for a
211
- * key that grants this resource but not, say, playwright (or vice versa).
212
- *
213
- * Best-effort: returns false (never throws) if there's no key, the fetch
214
- * fails, or the worker denies the resource - the caller decides what "not
215
- * licensed" means. Caches the grant/deny outcome (not the bundle itself,
216
- * which we never need here) for CACHE_TTL_MS so repeated checks don't
217
- * re-download the full premium.tar.gz just to read a status code.
218
- */
219
- async function hasLiveResourceLicense(projectRoot: string, resource: string): Promise<boolean> {
220
- const key = getLicenseKey();
221
- if (!key) return false;
222
-
223
- const cachePath = liveResourceAccessCachePath(key, resource);
224
- if (isCacheFresh(cachePath)) {
225
- try {
226
- const cached = JSON.parse(readFileSync(cachePath, "utf-8")) as { granted: boolean };
227
- return cached.granted === true;
228
- } catch {
229
- // Corrupt/unreadable cache - fall through and re-check live.
230
- }
231
- }
232
-
233
- const projectId = getOrCreateProjectId(projectRoot);
234
- const endpoint = getEndpoint();
235
- const url =
236
- `${endpoint}?key=${encodeURIComponent(key)}` +
237
- `&resource=${encodeURIComponent(resource)}&projectId=${encodeURIComponent(projectId)}`;
238
-
239
- let granted = false;
240
- try {
241
- const res = await fetch(url);
242
- granted = res.ok;
243
- // Drain the body (a full premium.tar.gz on success) so we don't leave
244
- // it dangling - we only need the status, not the content.
245
- if (res.body) {
246
- await res.arrayBuffer().catch(() => undefined);
247
- }
248
- } catch (err) {
249
- console.warn(`⚠️ ${resource} license check failed (network error): ${(err as Error).message}`);
250
- return false;
251
- }
252
-
253
- try {
254
- mkdirSync(join(cachePath, ".."), { recursive: true });
255
- writeFileSync(cachePath, JSON.stringify({ granted, checked: new Date().toISOString() }));
256
- } catch {
257
- // Best-effort cache; a write failure just means we re-check next time.
258
- }
259
-
260
- return granted;
261
- }
262
-
263
- /** Checks whether the configured license key grants the "verdaccio" resource. */
264
- export async function hasVerdaccioLicense(projectRoot: string): Promise<boolean> {
265
- return hasLiveResourceLicense(projectRoot, "verdaccio");
266
- }
267
-
268
- /**
269
- * Checks whether the configured license key grants the "ddd" resource
270
- * (domain-driven-design folder structure + path aliases for backend
271
- * resources - see generate_backend_path_aliases() in
272
- * engine/topologies/tilt/generators/vite/helpers.star).
273
- */
274
- export async function hasDddLicense(projectRoot: string): Promise<boolean> {
275
- return hasLiveResourceLicense(projectRoot, "ddd");
276
- }
277
-
278
- /**
279
- * Checks whether the configured license key grants the "sablier" resource
280
- * (on-demand start/stop for idle resources via a `sablier: {enable: true}`
281
- * manifest block - see sablier_container_cycle.star in
282
- * engine/topologies/platform/docker/networking/).
283
- */
284
- export async function hasSablierLicense(projectRoot: string): Promise<boolean> {
285
- return hasLiveResourceLicense(projectRoot, "sablier");
286
- }