hammerkit 1.5.1 → 1.6.0-alpha.1

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 (480) hide show
  1. package/.agents/FEEDBACK.md +74 -0
  2. package/.agents/skills/before-commit/SKILL.md +101 -0
  3. package/.agents/skills/do-the-work/SKILL.md +64 -0
  4. package/.agents/skills/fix-ci/SKILL.md +98 -0
  5. package/.agents/skills/speckit-git-commit/SKILL.md +53 -0
  6. package/.agents/skills/speckit-git-feature/SKILL.md +72 -0
  7. package/.agents/skills/speckit-git-initialize/SKILL.md +54 -0
  8. package/.agents/skills/speckit-git-remote/SKILL.md +50 -0
  9. package/.agents/skills/speckit-git-validate/SKILL.md +54 -0
  10. package/.gitbook.yaml +5 -0
  11. package/.specify/extensions/.registry +37 -0
  12. package/.specify/extensions/git/README.md +100 -0
  13. package/.specify/extensions/git/commands/speckit.git.commit.md +48 -0
  14. package/.specify/extensions/git/commands/speckit.git.feature.md +67 -0
  15. package/.specify/extensions/git/commands/speckit.git.initialize.md +49 -0
  16. package/.specify/extensions/git/commands/speckit.git.remote.md +45 -0
  17. package/.specify/extensions/git/commands/speckit.git.validate.md +49 -0
  18. package/.specify/extensions/git/config-template.yml +62 -0
  19. package/.specify/extensions/git/extension.yml +140 -0
  20. package/.specify/extensions/git/git-config.yml +62 -0
  21. package/.specify/extensions.yml +149 -0
  22. package/.specify/feature.json +3 -0
  23. package/.specify/init-options.json +10 -0
  24. package/.specify/integration.json +15 -0
  25. package/.specify/integrations/claude.manifest.json +16 -0
  26. package/.specify/integrations/speckit.manifest.json +17 -0
  27. package/.specify/memory/constitution.md +162 -0
  28. package/.specify/templates/checklist-template.md +40 -0
  29. package/.specify/templates/constitution-template.md +50 -0
  30. package/.specify/templates/plan-template.md +113 -0
  31. package/.specify/templates/spec-template.md +131 -0
  32. package/.specify/templates/tasks-template.md +252 -0
  33. package/.specify/workflows/speckit/workflow.yml +77 -0
  34. package/.specify/workflows/workflow-registry.json +13 -0
  35. package/AGENTS.md +94 -0
  36. package/Dockerfile +3 -3
  37. package/FOLLOWUPS.md +34 -0
  38. package/README.md +9 -7
  39. package/SUMMARY.md +30 -5
  40. package/VALUES.md +53 -0
  41. package/build.schema.json +542 -408
  42. package/dist/cache/auto-pull.spec.js +123 -0
  43. package/dist/cache/backends/local-cache-backend.js +56 -0
  44. package/dist/cache/backends/local-cache-backend.spec.js +72 -0
  45. package/dist/cache/backends/s3-cache-backend.js +124 -0
  46. package/dist/cache/backends/s3-cache-backend.spec.js +118 -0
  47. package/dist/cache/cache-backend-registry.js +21 -0
  48. package/dist/cache/cache-backend-registry.spec.js +22 -0
  49. package/dist/cache/cache-backend.js +3 -0
  50. package/dist/cache/resolve-cache.js +60 -0
  51. package/dist/cache/resolve-cache.spec.js +52 -0
  52. package/dist/cli.js +112 -82
  53. package/dist/cli.spec.js +20 -2
  54. package/dist/console/get-logger.spec.js +23 -0
  55. package/dist/docker/get-default-platform.spec.js +29 -0
  56. package/dist/docker/longest-common-prefix.spec.js +26 -0
  57. package/dist/docker/package.js +283 -0
  58. package/dist/docker/package.spec.js +145 -0
  59. package/dist/docker/pull.js +4 -4
  60. package/dist/docker/remove-container.spec.js +32 -0
  61. package/dist/docker/stream.js +3 -3
  62. package/dist/docker/using-container.js +29 -11
  63. package/dist/docker/using-container.spec.js +90 -0
  64. package/dist/environment/merge-environment-variables.js +21 -0
  65. package/dist/environment/merge-environment-variables.spec.js +24 -0
  66. package/dist/environment/replace-env-variables.js +43 -10
  67. package/dist/environment/replace-env-variables.spec.js +47 -0
  68. package/dist/executer/abort.spec.js +18 -0
  69. package/dist/executer/await-completed-dependencies.js +56 -0
  70. package/dist/executer/cache-metadata.js +11 -0
  71. package/dist/executer/check-readiness.js +1 -1
  72. package/dist/{planner/work-node-port.js → executer/container-bind.js} +1 -1
  73. package/dist/executer/docker-service.js +110 -86
  74. package/dist/executer/docker-task.js +132 -0
  75. package/dist/executer/environment-mock.js +3 -4
  76. package/dist/executer/environment-mock.spec.js +22 -0
  77. package/dist/executer/event-cache.js +60 -127
  78. package/dist/executer/execute-command.js +4 -3
  79. package/dist/executer/execute-docker.js +32 -14
  80. package/dist/executer/execute-work-service.js +61 -0
  81. package/dist/executer/execute-work-task.js +107 -0
  82. package/dist/executer/execute-work-tree.js +27 -0
  83. package/dist/executer/execute.spec.js +14 -10
  84. package/dist/executer/execution-steps.js +47 -31
  85. package/dist/executer/get-container-binds.js +19 -0
  86. package/dist/executer/get-docker-executor.js +12 -12
  87. package/dist/executer/get-scheduler-down-result.js +12 -0
  88. package/dist/executer/get-scheduler-execute-result.js +28 -0
  89. package/dist/executer/get-scheduler-up-result.js +12 -0
  90. package/dist/executer/get-service-containers.js +14 -0
  91. package/dist/executer/get-service-containers.spec.js +59 -0
  92. package/dist/executer/get-service-env-hints.js +35 -0
  93. package/dist/executer/get-service-env-hints.spec.js +65 -0
  94. package/dist/executer/kubernetes-service.js +116 -48
  95. package/dist/executer/label-values.js +29 -46
  96. package/dist/executer/label-values.spec.js +61 -0
  97. package/dist/executer/lazy-resolver.js +16 -0
  98. package/dist/executer/lazy-resolver.spec.js +20 -0
  99. package/dist/executer/local-task.js +44 -0
  100. package/dist/executer/process-manager.js +16 -70
  101. package/dist/executer/process-manager.spec.js +39 -76
  102. package/dist/executer/reset-work-tree.js +30 -0
  103. package/dist/executer/scheduler/check-for-loop.js +17 -7
  104. package/dist/executer/scheduler/{scheduler-state.js → dependency-state.js} +1 -1
  105. package/dist/executer/scheduler/enqueue-next.js +83 -19
  106. package/dist/executer/scheduler/enqueue-next.spec.js +136 -0
  107. package/dist/executer/scheduler/{node-state.js → need-state.js} +1 -1
  108. package/dist/{parser/build-file.js → executer/scheduler/task-state.js} +1 -1
  109. package/dist/executer/set-user-permission.js +1 -1
  110. package/dist/executer/state-resolver.js +61 -0
  111. package/dist/executer/state-resolver.spec.js +37 -0
  112. package/dist/executer/state.js +37 -31
  113. package/dist/executer/state.spec.js +66 -0
  114. package/dist/executer/states.spec.js +14 -0
  115. package/dist/executer/watch-loop.js +68 -0
  116. package/dist/executer/watch-state-key.js +44 -0
  117. package/dist/executer/work-scope.js +1 -5
  118. package/dist/file/get-file-context.js +24 -3
  119. package/dist/file/get-file-context.spec.js +178 -0
  120. package/dist/file/move-files.js +2 -2
  121. package/dist/file/move-files.spec.js +48 -0
  122. package/dist/index.js +7 -8
  123. package/dist/json-schema.js +12 -0
  124. package/dist/kubernetes/apply.js +34 -0
  125. package/dist/kubernetes/await-running-state.js +71 -0
  126. package/dist/kubernetes/ensure-http-route.js +53 -0
  127. package/dist/kubernetes/ensure-http-route.spec.js +70 -0
  128. package/dist/kubernetes/ensure-ingress.js +54 -0
  129. package/dist/kubernetes/ensure-kubernetes-deployment-exists.js +105 -0
  130. package/dist/kubernetes/ensure-kubernetes-persistent-volume-claim-exists.js +40 -0
  131. package/dist/kubernetes/ensure-kubernetes-service-exists.js +36 -0
  132. package/dist/kubernetes/ensure-namespace.js +43 -0
  133. package/dist/kubernetes/ensure-namespace.spec.js +39 -0
  134. package/dist/kubernetes/ensure-persistent-data.js +158 -0
  135. package/dist/kubernetes/get-service-ip.js +11 -0
  136. package/dist/kubernetes/kubernetes-instance.js +48 -0
  137. package/dist/kubernetes/remove-persistent-data.js +19 -0
  138. package/dist/kubernetes/resolve-pod-name.js +42 -0
  139. package/dist/kubernetes/resolve-pod-name.spec.js +81 -0
  140. package/dist/kubernetes/resources.js +12 -0
  141. package/dist/kubernetes/restore-kubernetes-data.js +42 -0
  142. package/dist/kubernetes/store-kubernetes-data.js +39 -0
  143. package/dist/kubernetes/volumes.js +64 -0
  144. package/dist/log.js +69 -69
  145. package/dist/log.spec.js +131 -0
  146. package/dist/logging/grouped-logger.js +17 -15
  147. package/dist/logging/grouped-logger.spec.js +84 -0
  148. package/dist/logging/interactive-logger.js +1 -1
  149. package/dist/logging/interactive-logger.spec.js +57 -0
  150. package/dist/logging/live-logger.js +2 -2
  151. package/dist/logging/live-logger.spec.js +37 -0
  152. package/dist/logging/loggers.spec.js +154 -0
  153. package/dist/optimizer/calculate-checksum.spec.js +34 -0
  154. package/dist/optimizer/get-cache-directory.js +6 -6
  155. package/dist/optimizer/get-cache-directory.spec.js +59 -0
  156. package/dist/optimizer/get-work-cache-stats.js +53 -0
  157. package/dist/optimizer/get-work-cache-stats.spec.js +79 -0
  158. package/dist/{parser/build-file-task.js → optimizer/work-cache-stats.js} +1 -1
  159. package/dist/optimizer/work-task-cache-description.js +25 -0
  160. package/dist/optimizer/work-task-cache-description.spec.js +45 -0
  161. package/dist/parser/default-build-file.js +14 -7
  162. package/dist/parser/default-build-file.spec.js +48 -0
  163. package/dist/parser/parse-label-arguments.spec.js +27 -0
  164. package/dist/parser/read-build-file.js +2 -13
  165. package/dist/parser/read-build-file.spec.js +89 -0
  166. package/dist/parser/read-env-file.js +4 -5
  167. package/dist/parser/read-env-file.spec.js +42 -0
  168. package/dist/planner/utils/append-work-dependencies.js +55 -0
  169. package/dist/planner/utils/append-work-environment.js +22 -0
  170. package/dist/planner/utils/append-work-needs.js +18 -0
  171. package/dist/planner/utils/append-work-service.js +107 -0
  172. package/dist/planner/utils/append-work-service.spec.js +71 -0
  173. package/dist/planner/utils/append-work-task.js +81 -0
  174. package/dist/planner/utils/get-container-user.js +14 -0
  175. package/dist/planner/utils/get-container-user.spec.js +30 -0
  176. package/dist/planner/utils/get-default-kube-config.js +10 -0
  177. package/dist/planner/utils/get-default-kube-config.spec.js +11 -0
  178. package/dist/planner/utils/get-work-runtime.js +44 -0
  179. package/dist/planner/utils/normalize-path.js +1 -1
  180. package/dist/planner/utils/normalize-path.spec.js +24 -0
  181. package/dist/planner/utils/parse-work-command.js +80 -0
  182. package/dist/planner/utils/parse-work-command.spec.js +21 -0
  183. package/dist/planner/utils/parse-work-generate.js +38 -0
  184. package/dist/planner/utils/parse-work-generate.spec.js +45 -0
  185. package/dist/planner/utils/{parse-work-node-mount.js → parse-work-mount.js} +10 -7
  186. package/dist/planner/utils/{parse-work-node-mount.spec.js → parse-work-mount.spec.js} +14 -11
  187. package/dist/planner/utils/parse-work-mounts.js +13 -0
  188. package/dist/planner/utils/parse-work-mounts.spec.js +19 -0
  189. package/dist/planner/utils/{parse-work-node-port.js → parse-work-port.js} +11 -8
  190. package/dist/planner/utils/parse-work-port.spec.js +24 -0
  191. package/dist/planner/utils/parse-work-ports.js +10 -0
  192. package/dist/planner/utils/parse-work-ports.spec.js +24 -0
  193. package/dist/planner/utils/parse-work-source.js +72 -0
  194. package/dist/planner/utils/parse-work-source.spec.js +58 -0
  195. package/dist/planner/utils/parse-work-volume.js +45 -0
  196. package/dist/planner/utils/parse-work-volume.spec.js +18 -0
  197. package/dist/planner/utils/plan-work-tasks.js +41 -0
  198. package/dist/planner/utils/plan-work-tasks.spec.js +30 -0
  199. package/dist/planner/utils/plan-work-volume.js +1 -0
  200. package/dist/planner/utils/plan-work-volume.spec.js +33 -0
  201. package/dist/planner/utils/split-name.js +2 -2
  202. package/dist/planner/utils/split-name.spec.js +16 -0
  203. package/dist/planner/utils/template-value.js +1 -2
  204. package/dist/planner/utils/template-value.spec.js +14 -0
  205. package/dist/planner/validate.js +71 -38
  206. package/dist/planner/validate.spec.js +251 -0
  207. package/dist/planner/work-cache-id.js +12 -0
  208. package/dist/planner/work-cache-id.spec.js +173 -0
  209. package/dist/planner/work-command.js +3 -0
  210. package/dist/planner/work-environment.js +3 -0
  211. package/dist/planner/work-healthcheck.js +3 -0
  212. package/dist/planner/{work-node-status.js → work-item-status.js} +16 -62
  213. package/dist/{parser/build-file-service.js → planner/work-item-validation.js} +1 -1
  214. package/dist/planner/work-item.js +16 -0
  215. package/dist/{optimizer/work-node-cache-stats.js → planner/work-kubernetes-selector.js} +1 -1
  216. package/dist/planner/{work-nodes.js → work-port.js} +1 -1
  217. package/dist/planner/work-runtime-docker.js +224 -0
  218. package/dist/planner/work-runtime-kubernetes.js +264 -0
  219. package/dist/planner/work-runtime-local.js +109 -0
  220. package/dist/planner/work-runtime-local.spec.js +193 -0
  221. package/dist/planner/work-service-id.js +15 -5
  222. package/dist/planner/work-source.js +3 -0
  223. package/dist/planner/work-task.js +8 -0
  224. package/dist/program-commands.spec.js +84 -0
  225. package/dist/program.js +219 -73
  226. package/dist/program.spec.js +34 -11
  227. package/dist/run-program.js +28 -0
  228. package/dist/{executer/process.js → runtime/runtime.js} +1 -1
  229. package/dist/schema/build-file-base-task-schema.js +27 -0
  230. package/dist/schema/build-file-container-service-schema.js +28 -0
  231. package/dist/schema/build-file-container-task-schema.js +13 -0
  232. package/dist/schema/build-file-environment-schema-ingress.js +14 -0
  233. package/dist/schema/build-file-environment-schema.js +23 -0
  234. package/dist/schema/build-file-kubernetes-service-schema.js +17 -0
  235. package/dist/schema/build-file-kubernetes-service-selector-schema.js +9 -0
  236. package/dist/schema/build-file-local-platform-schema.js +9 -0
  237. package/dist/schema/build-file-local-task-schema.js +12 -0
  238. package/dist/schema/build-file-need-schema.js +12 -0
  239. package/dist/schema/build-file-schema.js +23 -0
  240. package/dist/schema/build-file-schema.spec.js +61 -0
  241. package/dist/schema/build-file-service-container-healthcheck.js +8 -0
  242. package/dist/schema/build-file-service-schema.js +15 -0
  243. package/dist/schema/build-file-task-command-schema.js +12 -0
  244. package/dist/schema/build-file-task-schema.js +12 -0
  245. package/dist/schema/build-file-volume-schema.js +14 -0
  246. package/dist/schema/cache-schema.js +31 -0
  247. package/dist/schema/doc-build-files.spec.js +223 -0
  248. package/dist/schema/envs-schema.js +6 -0
  249. package/dist/schema/labels-schema.js +6 -0
  250. package/dist/schema/parse-context.js +3 -0
  251. package/dist/schema/parse-error.js +12 -0
  252. package/dist/schema/parse-error.spec.js +18 -0
  253. package/dist/schema/reference-parser.js +209 -0
  254. package/dist/schema/reference-parser.spec.js +83 -0
  255. package/dist/schema/schema-parser.js +66 -0
  256. package/dist/schema/schema-parser.spec.js +80 -0
  257. package/dist/schema/type-guards.spec.js +23 -0
  258. package/dist/schema/work-scope-parser.js +77 -0
  259. package/dist/schema/work-scope-parser.spec.js +66 -0
  260. package/dist/service/update-service-status.js +11 -0
  261. package/dist/service/update-service-status.spec.js +27 -0
  262. package/dist/testing/ensure-local-registry.js +134 -0
  263. package/dist/testing/example-test-suite.js +16 -18
  264. package/dist/testing/expect.js +46 -22
  265. package/dist/testing/http-get.js +21 -0
  266. package/dist/testing/integration/cache.spec.js +13 -14
  267. package/dist/testing/integration/cancellation.spec.js +14 -9
  268. package/dist/testing/integration/clean.spec.js +14 -11
  269. package/dist/testing/integration/cmd.spec.js +1 -1
  270. package/dist/testing/integration/concurrency.spec.js +3 -3
  271. package/dist/testing/integration/docker-package-registry.spec.js +44 -0
  272. package/dist/testing/integration/docker-service-crash.spec.js +36 -0
  273. package/dist/testing/integration/docker.spec.js +4 -3
  274. package/dist/testing/integration/env.spec.js +9 -8
  275. package/dist/testing/integration/environment.spec.js +97 -0
  276. package/dist/testing/integration/error.spec.js +5 -4
  277. package/dist/testing/integration/export.spec.js +22 -0
  278. package/dist/testing/integration/extend.spec.js +9 -12
  279. package/dist/testing/integration/glob.spec.js +12 -20
  280. package/dist/testing/integration/include.spec.js +3 -3
  281. package/dist/testing/integration/invalid.spec.js +2 -3
  282. package/dist/testing/integration/invalid_loop.spec.js +49 -6
  283. package/dist/testing/integration/k8s-state-cache.spec.js +41 -0
  284. package/dist/testing/integration/kubernetes-service.spec.js +148 -0
  285. package/dist/testing/integration/kubernetes.spec.js +93 -9
  286. package/dist/testing/integration/labels.spec.js +6 -11
  287. package/dist/testing/integration/local.spec.js +1 -1
  288. package/dist/testing/integration/monorepo.spec.js +4 -4
  289. package/dist/testing/integration/multi-line.spec.js +3 -3
  290. package/dist/testing/integration/reference.spec.js +4 -5
  291. package/dist/testing/integration/services.spec.js +22 -4
  292. package/dist/testing/integration/store.spec.js +15 -16
  293. package/dist/testing/integration/unknown.spec.js +20 -18
  294. package/dist/testing/integration/validate.spec.js +143 -26
  295. package/dist/testing/integration/watch-dependency.spec.js +11 -8
  296. package/dist/testing/integration/watch.spec.js +15 -16
  297. package/dist/testing/requires-kubernetes.js +18 -0
  298. package/dist/testing/requires-linux-containers.js +18 -0
  299. package/dist/testing/requires-windows-containers.js +18 -0
  300. package/dist/testing/test-case.js +75 -0
  301. package/dist/testing/test-streams.js +28 -0
  302. package/dist/testing/testing-timeout.js +32 -0
  303. package/dist/utils/abort-event.js +10 -4
  304. package/dist/utils/abort-event.spec.js +46 -0
  305. package/dist/utils/buffer-context.js +44 -0
  306. package/dist/utils/buffer-context.spec.js +38 -0
  307. package/dist/utils/ci.spec.js +53 -0
  308. package/dist/utils/emitter.spec.js +34 -0
  309. package/dist/utils/empty-writable.spec.js +18 -0
  310. package/dist/utils/environment-config.js +4 -1
  311. package/dist/utils/environment-config.spec.js +26 -0
  312. package/dist/utils/fail-never.spec.js +9 -0
  313. package/dist/version.js +9 -0
  314. package/dist/version.spec.js +12 -0
  315. package/package.json +41 -23
  316. package/specs/build-file/caches/spec.md +114 -0
  317. package/specs/build-file/environment-variables/spec.md +82 -0
  318. package/specs/build-file/includes/spec.md +60 -0
  319. package/specs/build-file/references/spec.md +56 -0
  320. package/specs/build-file/spec.md +62 -0
  321. package/specs/cli/clean/spec.md +85 -0
  322. package/specs/cli/down/spec.md +85 -0
  323. package/specs/cli/execute/spec.md +101 -0
  324. package/specs/cli/init/spec.md +64 -0
  325. package/specs/cli/ls/spec.md +66 -0
  326. package/specs/cli/package/spec.md +110 -0
  327. package/specs/cli/spec.md +73 -0
  328. package/specs/cli/store-restore/spec.md +74 -0
  329. package/specs/cli/up/spec.md +80 -0
  330. package/specs/cli/validate/spec.md +70 -0
  331. package/specs/labels/spec.md +91 -0
  332. package/specs/service/container/spec.md +120 -0
  333. package/specs/service/kubernetes/spec.md +97 -0
  334. package/specs/service/spec.md +105 -0
  335. package/specs/task/caching/spec.md +107 -0
  336. package/specs/task/container/spec.md +118 -0
  337. package/specs/task/dependencies/spec.md +70 -0
  338. package/specs/task/extending/spec.md +74 -0
  339. package/specs/task/kubernetes/spec.md +125 -0
  340. package/specs/task/needs/spec.md +59 -0
  341. package/specs/task/spec.md +87 -0
  342. package/specs/task/watching/spec.md +69 -0
  343. package/dist/console/console-context-mock.js +0 -14
  344. package/dist/environment/get-process-env.js +0 -15
  345. package/dist/executer/create-scheduler-state.js +0 -32
  346. package/dist/executer/docker-node.js +0 -123
  347. package/dist/executer/hierarchy-scheduler.js +0 -94
  348. package/dist/executer/local-node.js +0 -57
  349. package/dist/executer/schedule.js +0 -137
  350. package/dist/executer/start-node.js +0 -67
  351. package/dist/executer/watch-node.js +0 -56
  352. package/dist/executer/watch-service.js +0 -54
  353. package/dist/file/get-file-context-mock.js +0 -187
  354. package/dist/file/get-file-context-mock.spec.js +0 -56
  355. package/dist/get-work-context.js +0 -29
  356. package/dist/optimizer/get-work-node-cache-stats.js +0 -104
  357. package/dist/optimizer/read-work-node-cache.js +0 -19
  358. package/dist/optimizer/work-node-cache-description.js +0 -32
  359. package/dist/optimizer/write-work-node-cache.js +0 -21
  360. package/dist/parser/build-file-task-command.js +0 -3
  361. package/dist/parser/build-file-task-platform.js +0 -3
  362. package/dist/parser/build-file-task-source.js +0 -3
  363. package/dist/parser/get-build-file.js +0 -9
  364. package/dist/parser/parse-boolean.js +0 -29
  365. package/dist/parser/parse-boolean.spec.js +0 -48
  366. package/dist/parser/parse-build-file-references.js +0 -35
  367. package/dist/parser/parse-build-file-services.js +0 -58
  368. package/dist/parser/parse-build-file-task-command.js +0 -36
  369. package/dist/parser/parse-build-file-task-source.js +0 -63
  370. package/dist/parser/parse-build-file.js +0 -125
  371. package/dist/parser/parse-context.js +0 -13
  372. package/dist/parser/parse-envs.js +0 -29
  373. package/dist/parser/parse-healthcheck.js +0 -28
  374. package/dist/parser/parse-service-selector.js +0 -39
  375. package/dist/parser/parse-string-array.js +0 -20
  376. package/dist/parser/parse-string-map.js +0 -30
  377. package/dist/parser/parse-string.js +0 -20
  378. package/dist/planner/utils/get-container-mounts.js +0 -24
  379. package/dist/planner/utils/parse-work-service-volume.js +0 -23
  380. package/dist/planner/utils/plan-work-command.js +0 -21
  381. package/dist/planner/utils/plan-work-dependency.js +0 -36
  382. package/dist/planner/utils/plan-work-node.js +0 -293
  383. package/dist/planner/utils/plan-work-nodes.js +0 -78
  384. package/dist/planner/utils/plan-work-tree.js +0 -15
  385. package/dist/planner/work-context.js +0 -23
  386. package/dist/planner/work-node-command.js +0 -3
  387. package/dist/planner/work-node-id.js +0 -12
  388. package/dist/planner/work-node-id.spec.js +0 -106
  389. package/dist/planner/work-node-path.js +0 -2
  390. package/dist/planner/work-node-source.js +0 -3
  391. package/dist/planner/work-node-validation.js +0 -3
  392. package/dist/planner/work-node.js +0 -8
  393. package/dist/planner/work-service-volume.js +0 -3
  394. package/dist/planner/work-services.js +0 -3
  395. package/dist/start-watch-processes.js +0 -28
  396. package/dist/testing/cli.js +0 -73
  397. package/dist/testing/create-build-file.js +0 -9
  398. package/dist/testing/get-logger.js +0 -23
  399. package/dist/testing/get-node.js +0 -12
  400. package/dist/testing/get-test-context.js +0 -19
  401. package/dist/testing/integration/program.spec.js +0 -25
  402. package/dist/testing/lazy.js +0 -17
  403. package/dist/testing/start-watch-processes.js +0 -29
  404. package/dist/testing/test-suite-options.js +0 -3
  405. package/dist/utils/abortable-function.js +0 -71
  406. package/logs/cache-console.log +0 -0
  407. package/logs/cache-status.log +0 -6
  408. package/logs/cache-stout.log +0 -0
  409. package/logs/cancellation-console.log +0 -0
  410. package/logs/cancellation-status.log +0 -3
  411. package/logs/cancellation-stout.log +0 -3
  412. package/logs/clean-console.log +0 -0
  413. package/logs/clean-status.log +0 -37
  414. package/logs/clean-stout.log +0 -95
  415. package/logs/cmd-console.log +0 -0
  416. package/logs/cmd-status.log +0 -8
  417. package/logs/cmd-stout.log +0 -9
  418. package/logs/concurrency-console.log +0 -0
  419. package/logs/concurrency-status.log +0 -14
  420. package/logs/concurrency-stout.log +0 -88
  421. package/logs/docker-console.log +0 -0
  422. package/logs/docker-status.log +0 -14
  423. package/logs/docker-stout.log +0 -39
  424. package/logs/env-console.log +0 -1
  425. package/logs/env-status.log +0 -1
  426. package/logs/env-stout.log +0 -0
  427. package/logs/error-console.log +0 -0
  428. package/logs/error-status.log +0 -10
  429. package/logs/error-stout.log +0 -36
  430. package/logs/extend-console.log +0 -0
  431. package/logs/extend-status.log +0 -1
  432. package/logs/extend-stout.log +0 -0
  433. package/logs/glob-console.log +0 -28
  434. package/logs/glob-status.log +0 -23
  435. package/logs/glob-stout.log +0 -52
  436. package/logs/hello-world-node-console.log +0 -0
  437. package/logs/hello-world-node-status.log +0 -37
  438. package/logs/hello-world-node-stout.log +0 -41
  439. package/logs/include-console.log +0 -0
  440. package/logs/include-status.log +0 -3
  441. package/logs/include-stout.log +0 -0
  442. package/logs/invalid-console.log +0 -0
  443. package/logs/invalid-status.log +0 -1
  444. package/logs/invalid-stout.log +0 -0
  445. package/logs/invalid_loop-console.log +0 -0
  446. package/logs/invalid_loop-status.log +0 -1
  447. package/logs/invalid_loop-stout.log +0 -11
  448. package/logs/labels-console.log +0 -0
  449. package/logs/labels-status.log +0 -1
  450. package/logs/labels-stout.log +0 -0
  451. package/logs/local-console.log +0 -0
  452. package/logs/local-status.log +0 -7
  453. package/logs/local-stout.log +0 -8
  454. package/logs/monorepo-console.log +0 -0
  455. package/logs/monorepo-status.log +0 -152
  456. package/logs/monorepo-stout.log +0 -2354
  457. package/logs/multi-line-console.log +0 -0
  458. package/logs/multi-line-status.log +0 -1
  459. package/logs/multi-line-stout.log +0 -0
  460. package/logs/reference-console.log +0 -0
  461. package/logs/reference-status.log +0 -5
  462. package/logs/reference-stout.log +0 -0
  463. package/logs/services-console.log +0 -0
  464. package/logs/services-status.log +0 -129
  465. package/logs/services-stout.log +0 -639
  466. package/logs/store-restore-console.log +0 -0
  467. package/logs/store-restore-status.log +0 -40
  468. package/logs/store-restore-stout.log +0 -97
  469. package/logs/unknown-console.log +0 -3
  470. package/logs/unknown-status.log +0 -1
  471. package/logs/unknown-stout.log +0 -0
  472. package/logs/validate-console.log +0 -0
  473. package/logs/validate-status.log +0 -2
  474. package/logs/validate-stout.log +0 -0
  475. package/logs/watch-console.log +0 -0
  476. package/logs/watch-dependency-console.log +0 -0
  477. package/logs/watch-dependency-status.log +0 -176
  478. package/logs/watch-dependency-stout.log +0 -779
  479. package/logs/watch-status.log +0 -100
  480. package/logs/watch-stout.log +0 -349
package/dist/cli.js CHANGED
@@ -1,97 +1,127 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getCli = exports.isCliService = exports.isCliTask = void 0;
4
- const plan_work_nodes_1 = require("./planner/utils/plan-work-nodes");
5
- const create_scheduler_state_1 = require("./executer/create-scheduler-state");
3
+ exports.getCli = exports.Cli = exports.isCliService = exports.isCliTask = void 0;
4
+ const plan_work_tasks_1 = require("./planner/utils/plan-work-tasks");
6
5
  const ci_1 = require("./utils/ci");
7
6
  const get_logger_1 = require("./console/get-logger");
8
- const schedule_1 = require("./executer/schedule");
9
7
  const event_cache_1 = require("./executer/event-cache");
10
8
  const validate_1 = require("./planner/validate");
11
9
  const process_manager_1 = require("./executer/process-manager");
12
- const remove_container_1 = require("./docker/remove-container");
10
+ const update_service_status_1 = require("./service/update-service-status");
11
+ const check_for_loop_1 = require("./executer/scheduler/check-for-loop");
12
+ const state_1 = require("./executer/state");
13
+ const get_scheduler_execute_result_1 = require("./executer/get-scheduler-execute-result");
14
+ const reset_work_tree_1 = require("./executer/reset-work-tree");
15
+ const execute_work_tree_1 = require("./executer/execute-work-tree");
16
+ const package_1 = require("./docker/package");
13
17
  const isCliTask = (val) => val.type === 'task';
14
18
  exports.isCliTask = isCliTask;
15
19
  const isCliService = (val) => val.type === 'service';
16
20
  exports.isCliService = isCliService;
17
- function getCli(workTree, environment) {
18
- return {
19
- execWatch(options) {
20
- const processManager = new process_manager_1.ProcessManager(environment, options?.workers ?? 0);
21
- const state = (0, create_scheduler_state_1.createSchedulerState)({
22
- services: workTree.services,
23
- nodes: workTree.nodes,
24
- watch: options?.watch ?? false,
25
- logMode: options?.logMode ?? ci_1.isCI ? 'live' : 'interactive',
26
- cacheMethod: options?.cacheDefault ?? 'checksum',
27
- });
28
- const logMode = options?.logMode ?? (ci_1.isCI ? 'live' : 'interactive');
29
- const logger = (0, get_logger_1.getLogger)(logMode, state, environment);
30
- return {
31
- state,
32
- processManager,
33
- start: async () => {
34
- const result = await (0, schedule_1.schedule)(processManager, state, environment);
35
- await logger.complete(result, environment);
36
- return result;
37
- },
38
- };
39
- },
40
- async shutdown() {
41
- for (const node of (0, plan_work_nodes_1.iterateWorkNodes)(workTree.nodes)) {
42
- const containers = await environment.docker.listContainers({
43
- all: true,
44
- filters: {
45
- label: [`hammerkit-id=${node.id}`],
46
- },
47
- });
48
- for (const container of containers) {
49
- await (0, remove_container_1.removeContainer)(environment.docker.getContainer(container.Id));
50
- }
51
- }
52
- for (const service of (0, plan_work_nodes_1.iterateWorkServices)(workTree.services)) {
53
- const containers = await environment.docker.listContainers({
54
- all: true,
55
- filters: {
56
- label: [`hammerkit-id=${service.id}`],
57
- },
58
- });
59
- for (const container of containers) {
60
- await (0, remove_container_1.removeContainer)(environment.docker.getContainer(container.Id));
21
+ class Cli {
22
+ constructor(workTree, environment) {
23
+ this.workTree = workTree;
24
+ this.environment = environment;
25
+ }
26
+ setup(type, options) {
27
+ const processManager = new process_manager_1.ProcessManager(options?.workers ?? 0);
28
+ const logMode = options?.logMode ?? (ci_1.isCI ? 'live' : 'interactive');
29
+ const workTree = (0, reset_work_tree_1.resetWorkTree)(this.workTree, type);
30
+ const processWorkTree = new state_1.State(workTree, {
31
+ subStates: [
32
+ ...Object.values(workTree.services).map((s) => s.state),
33
+ ...Object.values(workTree.tasks).map((s) => s.state),
34
+ ],
35
+ });
36
+ const logger = (0, get_logger_1.getLogger)(logMode, processWorkTree, this.environment);
37
+ return {
38
+ state: processWorkTree,
39
+ start: async () => {
40
+ (0, check_for_loop_1.checkForLoop)(workTree);
41
+ if (!(0, plan_work_tasks_1.hasError)(workTree)) {
42
+ await (0, update_service_status_1.updateServiceStatus)(workTree);
43
+ await (0, execute_work_tree_1.executeWorkTree)(workTree, this.environment, {
44
+ daemon: options?.daemon ?? false,
45
+ watch: options?.watch ?? false,
46
+ logMode,
47
+ cacheDefault: options?.cacheDefault ?? 'checksum',
48
+ workers: options?.workers ?? 0,
49
+ processManager,
50
+ type,
51
+ });
61
52
  }
62
- }
63
- },
64
- async exec(options) {
65
- return this.execWatch(options).start();
66
- },
67
- async clean(options) {
68
- await (0, event_cache_1.cleanCache)(workTree, environment, {
69
- service: options?.service ?? false,
70
- });
71
- },
72
- async restore(path) {
73
- await (0, event_cache_1.restoreCache)(path, workTree, environment);
74
- },
75
- async store(path) {
76
- await (0, event_cache_1.storeCache)(path, workTree, environment);
77
- },
78
- ls() {
79
- return [
80
- ...Array.from((0, plan_work_nodes_1.iterateWorkServices)(workTree.services)).map((item) => ({ item, type: 'service' })),
81
- ...Array.from((0, plan_work_nodes_1.iterateWorkNodes)(workTree.nodes)).map((item) => ({ item, type: 'task' })),
82
- ];
83
- },
84
- validate() {
85
- return (0, validate_1.validate)(workTree, environment);
86
- },
87
- node(name) {
88
- const node = Object.values(workTree.nodes).find((n) => n.name == name);
89
- if (!node) {
90
- throw new Error(`unable to find node ${name}`);
91
- }
92
- return node;
93
- },
94
- };
53
+ const result = (0, get_scheduler_execute_result_1.getSchedulerExecuteResult)(workTree);
54
+ await logger.complete(result, this.environment);
55
+ return result;
56
+ },
57
+ };
58
+ }
59
+ up(options) {
60
+ return this.setup('up', options);
61
+ }
62
+ async runUp(options) {
63
+ const run = this.up(options);
64
+ return await run.start();
65
+ }
66
+ down() {
67
+ return this.setup('down', {});
68
+ }
69
+ async runDown() {
70
+ const run = await this.down();
71
+ return await run.start();
72
+ }
73
+ exec(options) {
74
+ return this.setup('execute', options);
75
+ }
76
+ async runExec(options) {
77
+ const run = this.exec(options);
78
+ return await run.start();
79
+ }
80
+ async clean(options) {
81
+ await (0, event_cache_1.cleanCache)(this.workTree, this.environment, options);
82
+ }
83
+ async restore(path) {
84
+ await (0, event_cache_1.restoreCache)(this.environment, path, this.workTree);
85
+ }
86
+ async package(options) {
87
+ await (0, package_1.packageWorkTree)(this.workTree, this.environment, options);
88
+ }
89
+ async store(path) {
90
+ await (0, event_cache_1.storeCache)(this.environment, path, this.workTree);
91
+ }
92
+ services() {
93
+ return Array.from((0, plan_work_tasks_1.iterateWorkServices)(this.workTree)).map((item) => ({
94
+ item,
95
+ type: 'service',
96
+ }));
97
+ }
98
+ tasks() {
99
+ return Array.from((0, plan_work_tasks_1.iterateWorkTasks)(this.workTree)).map((item) => ({ item, type: 'task' }));
100
+ }
101
+ ls() {
102
+ return [...this.services(), ...this.tasks()];
103
+ }
104
+ validate() {
105
+ return (0, validate_1.validate)(this.workTree, this.environment);
106
+ }
107
+ task(name) {
108
+ const task = this.workTree.tasks[name];
109
+ if (!task) {
110
+ throw new Error(`unable to find task ${name}`);
111
+ }
112
+ return task;
113
+ }
114
+ service(name) {
115
+ const service = this.workTree.services[name];
116
+ if (!service) {
117
+ throw new Error(`unable to find service ${name}`);
118
+ }
119
+ return service;
120
+ }
121
+ }
122
+ exports.Cli = Cli;
123
+ function getCli(workTree, environment) {
124
+ return new Cli(workTree, environment);
95
125
  }
96
126
  exports.getCli = getCli;
97
127
  //# sourceMappingURL=cli.js.map
package/dist/cli.spec.js CHANGED
@@ -1,5 +1,23 @@
1
1
  "use strict";
2
- describe('cli', () => {
3
- it('should warn about empty cli', () => { });
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const path_1 = require("path");
4
+ const test_case_1 = require("./testing/test-case");
5
+ const program_1 = require("./program");
6
+ // Drives the real parse pipeline (createCli) over an in-memory build file and
7
+ // then exercises Cli lookups against the resulting work tree — a real "not
8
+ // found" situation, no mocking.
9
+ describe('Cli', () => {
10
+ it('service() throws for an unknown service name', async () => {
11
+ const testCase = (0, test_case_1.createTestCase)('cli-service', {
12
+ '.hammerkit.yaml': {
13
+ services: { api: { image: 'nginx', ports: [] } },
14
+ tasks: { build: { cmds: ['tsc'], needs: ['api'] } },
15
+ },
16
+ });
17
+ await testCase.setup(async (cwd, environment) => {
18
+ const cli = await (0, program_1.createCli)((0, path_1.join)(cwd, '.hammerkit.yaml'), environment, { taskName: 'build' });
19
+ expect(() => cli.service('missing')).toThrow('unable to find service missing');
20
+ });
21
+ });
4
22
  });
5
23
  //# sourceMappingURL=cli.spec.js.map
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ // Verifies getLogger dispatches to the right logger by name and rejects an
3
+ // unknown mode via failNever — the actual loggers are tested elsewhere.
4
+ Object.defineProperty(exports, "__esModule", { value: true });
5
+ vi.mock('../logging/grouped-logger', () => ({ groupedLogger: vi.fn(() => 'grouped-instance') }));
6
+ vi.mock('../logging/live-logger', () => ({ liveLogger: vi.fn(() => 'live-instance') }));
7
+ vi.mock('../logging/interactive-logger', () => ({ interactiveLogger: vi.fn(() => 'interactive-instance') }));
8
+ const get_logger_1 = require("./get-logger");
9
+ describe('getLogger', () => {
10
+ it('returns the grouped logger for mode "grouped"', () => {
11
+ expect((0, get_logger_1.getLogger)('grouped', {}, {})).toBe('grouped-instance');
12
+ });
13
+ it('returns the live logger for mode "live"', () => {
14
+ expect((0, get_logger_1.getLogger)('live', {}, {})).toBe('live-instance');
15
+ });
16
+ it('returns the interactive logger for mode "interactive"', () => {
17
+ expect((0, get_logger_1.getLogger)('interactive', {}, {})).toBe('interactive-instance');
18
+ });
19
+ it('throws on an unknown mode (failNever)', () => {
20
+ expect(() => (0, get_logger_1.getLogger)('bogus', {}, {})).toThrow();
21
+ });
22
+ });
23
+ //# sourceMappingURL=get-logger.spec.js.map
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const package_1 = require("./package");
4
+ describe('docker/getDefaultPlatform', () => {
5
+ const realArch = process.arch;
6
+ function setArch(arch) {
7
+ Object.defineProperty(process, 'arch', { value: arch, configurable: true });
8
+ }
9
+ afterEach(() => {
10
+ Object.defineProperty(process, 'arch', { value: realArch, configurable: true });
11
+ });
12
+ it('maps x64 to linux/amd64', () => {
13
+ setArch('x64');
14
+ expect((0, package_1.getDefaultPlatform)()).toBe('linux/amd64');
15
+ });
16
+ it('maps arm64 to linux/arm64', () => {
17
+ setArch('arm64');
18
+ expect((0, package_1.getDefaultPlatform)()).toBe('linux/arm64');
19
+ });
20
+ it('maps arm to linux/arm', () => {
21
+ setArch('arm');
22
+ expect((0, package_1.getDefaultPlatform)()).toBe('linux/arm');
23
+ });
24
+ it('falls back to linux/amd64 for unknown architectures', () => {
25
+ setArch('mips');
26
+ expect((0, package_1.getDefaultPlatform)()).toBe('linux/amd64');
27
+ });
28
+ });
29
+ //# sourceMappingURL=get-default-platform.spec.js.map
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const path_1 = require("path");
4
+ const package_1 = require("./package");
5
+ // helper to build OS-correct absolute-ish paths
6
+ const p = (...segs) => path_1.sep + segs.join(path_1.sep);
7
+ describe('longestCommonPrefix (package build context root)', () => {
8
+ it('returns the directory of a single source, not the file itself', () => {
9
+ // regression: a single source used to yield the full file path, so the
10
+ // build-context copy targeted a directory and failed with EISDIR.
11
+ expect((0, package_1.longestCommonPrefix)([p('a', 'b', 'hello.txt')])).toBe(p('a', 'b'));
12
+ });
13
+ it('returns the common parent of files in the same directory', () => {
14
+ expect((0, package_1.longestCommonPrefix)([p('a', 'x.txt'), p('a', 'y.txt')])).toBe(p('a'));
15
+ });
16
+ it('returns the common ancestor across nested directories', () => {
17
+ expect((0, package_1.longestCommonPrefix)([p('a', 'x.txt'), p('a', 'b', 'y.txt')])).toBe(p('a'));
18
+ });
19
+ it('compares per path segment, not per character', () => {
20
+ expect((0, package_1.longestCommonPrefix)([p('a', 'foo'), p('a', 'foobar')])).toBe(p('a'));
21
+ });
22
+ it('returns empty for no sources', () => {
23
+ expect((0, package_1.longestCommonPrefix)([])).toBe('');
24
+ });
25
+ });
26
+ //# sourceMappingURL=longest-common-prefix.spec.js.map
@@ -0,0 +1,283 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.longestCommonPrefix = exports.packageWorkTree = exports.getDefaultPlatform = void 0;
4
+ const plan_work_tasks_1 = require("../planner/utils/plan-work-tasks");
5
+ const work_item_1 = require("../planner/work-item");
6
+ const execute_docker_1 = require("../executer/execute-docker");
7
+ const node_os_1 = require("node:os");
8
+ const path_1 = require("path");
9
+ const log_1 = require("../log");
10
+ // Default the build platform to the host architecture so a packaged image runs
11
+ // where it was built unless the caller overrides it with `--platform`. Maps
12
+ // node's `process.arch` to docker's platform arch naming.
13
+ function getDefaultPlatform() {
14
+ const archByNodeArch = {
15
+ x64: 'amd64',
16
+ arm64: 'arm64',
17
+ arm: 'arm',
18
+ };
19
+ const arch = archByNodeArch[process.arch] ?? 'amd64';
20
+ return `linux/${arch}`;
21
+ }
22
+ exports.getDefaultPlatform = getDefaultPlatform;
23
+ async function packageWorkTree(workTree, environment, options) {
24
+ if (workTree.environment.type !== 'docker') {
25
+ throw new Error('only docker environments are supported');
26
+ }
27
+ const docker = (0, execute_docker_1.getContainerCli)(workTree.environment);
28
+ const platform = options.platform ?? getDefaultPlatform();
29
+ const tag = options.tag ?? 'latest';
30
+ for (const service of (0, plan_work_tasks_1.iterateWorkServices)(workTree)) {
31
+ if ((0, work_item_1.isContainerWorkServiceItem)(service)) {
32
+ environment.console.info(`preparing files for ${service.name}`);
33
+ const definition = getServiceInstructions(service, options);
34
+ const buildDir = (0, path_1.join)((0, node_os_1.tmpdir)(), service.id());
35
+ const dockerFileName = (0, path_1.join)(buildDir, 'Dockerfile');
36
+ const dockerFileContent = definition.instructions.join('\n');
37
+ await environment.file.createDirectory(buildDir);
38
+ await environment.file.writeFile(dockerFileName, dockerFileContent);
39
+ environment.console.debug(`create dockerfile ${dockerFileName}`);
40
+ environment.console.debug(`with cwd ${definition.cwd}`);
41
+ const src = ['Dockerfile'];
42
+ for (const source of definition.sources) {
43
+ const path = (0, path_1.relative)(definition.cwd, source.absolutePath);
44
+ environment.console.debug(`copying ${source.absolutePath} to ${(0, path_1.join)(buildDir, path)}`);
45
+ await environment.file.copy(source.absolutePath, (0, path_1.join)(buildDir, path));
46
+ src.push(path);
47
+ }
48
+ const imageName = `${options.registry}/${service.name}:${tag}`;
49
+ environment.console.info(`building image ${imageName} for ${service.name} (${platform})`);
50
+ const buildStream = await docker.buildImage({
51
+ src,
52
+ context: buildDir,
53
+ }, {
54
+ t: imageName,
55
+ platform,
56
+ abortSignal: environment.abortCtrl.signal,
57
+ });
58
+ await new Promise((resolve, reject) => {
59
+ docker.modem.followProgress(buildStream, (err, res) => {
60
+ if (err) {
61
+ environment.console.error((0, log_1.getErrorMessage)(err));
62
+ reject(err);
63
+ return;
64
+ }
65
+ // followProgress returns every build message in `res`, so a
66
+ // non-empty array is normal on success. Only fail when an entry
67
+ // actually carries an error.
68
+ const failure = (res ?? []).find((i) => 'error' in i && !!i.error);
69
+ if (failure && 'error' in failure) {
70
+ const detail = failure.errorDetail?.message ?? failure.error ?? 'unknown error';
71
+ environment.console.error(detail);
72
+ reject(new Error(`build failed: ${detail}`));
73
+ }
74
+ else {
75
+ resolve();
76
+ }
77
+ }, (res) => {
78
+ if (res.stream) {
79
+ if (res.stream === '\n') {
80
+ return;
81
+ }
82
+ if (res.stream.endsWith('\n')) {
83
+ environment.console.info(res.stream.substr(0, res.stream.length - 1));
84
+ }
85
+ else {
86
+ environment.console.info(res.stream);
87
+ }
88
+ }
89
+ });
90
+ });
91
+ environment.console.info(`generated image ${imageName} for ${service.name}`);
92
+ if (options.push) {
93
+ environment.console.info(`pushing image ${imageName} to ${options.registry}`);
94
+ const img = docker.getImage(imageName);
95
+ const pushStream = await img.push({
96
+ abortSignal: environment.abortCtrl.signal,
97
+ authconfig: {
98
+ username: options.username || '',
99
+ password: options.password || '',
100
+ serveraddress: options.registry,
101
+ },
102
+ });
103
+ await new Promise((resolve, reject) => {
104
+ docker.modem.followProgress(pushStream, (err, res) => (err ? reject(err) : resolve(res)), (res) => {
105
+ if (res.stream) {
106
+ environment.console.info(res.stream);
107
+ }
108
+ });
109
+ });
110
+ environment.console.info(`pushed image ${imageName} to ${options.registry}`);
111
+ }
112
+ }
113
+ }
114
+ }
115
+ exports.packageWorkTree = packageWorkTree;
116
+ function getDependencySources(service, taskIds) {
117
+ const result = [...service.data.src.filter((s) => !s.inherited)];
118
+ taskIds.push(service.id());
119
+ for (const dep of service.deps) {
120
+ if (taskIds.includes(dep.id())) {
121
+ continue;
122
+ }
123
+ if ((0, work_item_1.isLocalWorkTaskItem)(dep)) {
124
+ throw new Error(`local tasks (${dep.name}) are not yet supported`);
125
+ }
126
+ if ((0, work_item_1.isContainerWorkTaskItem)(dep)) {
127
+ result.push(...getDependencySources(dep, taskIds));
128
+ }
129
+ }
130
+ return result;
131
+ }
132
+ function getDependencyCwd(cwd, service) {
133
+ const sources = getDependencySources(service, []);
134
+ return longestCommonPrefix(sources.map((s) => s.absolutePath));
135
+ }
136
+ // Longest common *directory* of the given (absolute file) paths. Compared per
137
+ // path segment, not per character, so `/a/foo` and `/a/foobar` share `/a`, not
138
+ // `/a/foo`. When every path is identical (e.g. a single source) the shared
139
+ // prefix would be the file itself, so the final segment is dropped to land on
140
+ // its directory — otherwise the build context copy targets a directory and
141
+ // fails with EISDIR.
142
+ function longestCommonPrefix(strs) {
143
+ if (strs.length === 0) {
144
+ return '';
145
+ }
146
+ const segments = strs.map((s) => s.split(path_1.sep));
147
+ const minLength = Math.min(...segments.map((s) => s.length));
148
+ const common = [];
149
+ for (let i = 0; i < minLength; i++) {
150
+ const segment = segments[0][i];
151
+ if (segments.every((s) => s[i] === segment)) {
152
+ common.push(segment);
153
+ }
154
+ else {
155
+ break;
156
+ }
157
+ }
158
+ if (common.length > 0 && segments.every((s) => s.length === common.length)) {
159
+ common.pop();
160
+ }
161
+ return common.join(path_1.sep);
162
+ }
163
+ exports.longestCommonPrefix = longestCommonPrefix;
164
+ // Root the packaged files under a real directory instead of the image's `/`.
165
+ // Building at `/` breaks tooling that walks up for config and treats the root
166
+ // specially — e.g. `npm install` fails with `Tracker "idealTree" already
167
+ // exists` when WORKDIR is `/` (which happens whenever a task's cwd is the build
168
+ // context root). Paths inside the image become `${CONTAINER_ROOT}/<relative>`.
169
+ const CONTAINER_ROOT = '/hammerkit';
170
+ function toContainerPath(relativePath) {
171
+ const normalized = relativePath.split(path_1.sep).join('/');
172
+ return normalized === '' ? CONTAINER_ROOT : `${CONTAINER_ROOT}/${normalized}`;
173
+ }
174
+ function getServiceInstructions(service, options) {
175
+ const dependencyCwd = getDependencyCwd(service.data.cwd, service);
176
+ const tasks = {};
177
+ const deps = getDependencyInstructions(dependencyCwd, service, tasks);
178
+ // const orderedDeps = Object.entries(tasks).sort(([, a], [, b]) => a.order - b.order)
179
+ const instructions = [
180
+ ...Object.values(tasks).flatMap((t) => t.instructions),
181
+ `FROM ${service.data.image} as service-${service.id()}`,
182
+ `LABEL hammerkit.dev/id=${service.id()}`,
183
+ `LABEL hammerkit.dev/name=${service.name}`,
184
+ ...Object.entries(service.data.envs.variables).map(([key, value]) => `ENV ${key}=${value}`),
185
+ ...service.data.ports.map((p) => `EXPOSE ${p.containerPort}`),
186
+ `WORKDIR ${toContainerPath((0, path_1.relative)(dependencyCwd, service.data.cwd))}`,
187
+ options.overrideUser ? 'RUN (addgroup -g 1000 hammerkit && adduser -u 1000 -G hammerkit -s /bin/sh) || true' : '',
188
+ ...service.data.src.map((s) => `COPY ${(0, path_1.relative)(dependencyCwd, s.absolutePath)} ${toContainerPath((0, path_1.relative)(dependencyCwd, s.absolutePath))}`),
189
+ ...deps.flatMap((d) => d.exports),
190
+ ...(options.overrideUser
191
+ ? service.data.src
192
+ .filter((s) => !s.inherited)
193
+ .map((v) => `RUN chown -R 1000:1000 ${toContainerPath((0, path_1.relative)(dependencyCwd, v.absolutePath))}`)
194
+ : []),
195
+ ...service.data.volumes
196
+ .filter((v) => !v.inherited)
197
+ .map((v) => `VOLUME ${toContainerPath((0, path_1.relative)(dependencyCwd, v.containerPath))}`),
198
+ ...(options.overrideUser
199
+ ? service.data.volumes.map((v) => `RUN chown -R 1000:1000 ${toContainerPath((0, path_1.relative)(dependencyCwd, v.containerPath))}`)
200
+ : []),
201
+ options.overrideUser ? 'USER 1000:1000' : '',
202
+ ];
203
+ if (service.data.cmd) {
204
+ instructions.push(`CMD [${[service.data.cmd.parsed.command, ...service.data.cmd.parsed.args].map((p) => `"${p}"`).join(', ')}]`);
205
+ }
206
+ return {
207
+ id: service.id(),
208
+ instructions,
209
+ cwd: dependencyCwd,
210
+ exports: [],
211
+ deps,
212
+ order: 0,
213
+ sources: [
214
+ ...Object.values(tasks).flatMap((t) => t.sources),
215
+ ...service.data.src
216
+ .filter((s) => !s.inherited)
217
+ .map((s) => ({
218
+ absolutePath: s.absolutePath,
219
+ matcher: s.matcher,
220
+ })),
221
+ ],
222
+ };
223
+ }
224
+ function getDependencyInstructions(cwd, task, taskIds) {
225
+ return task.deps.map((dep) => {
226
+ if (taskIds[dep.id()]) {
227
+ return taskIds[dep.id()];
228
+ }
229
+ else {
230
+ const data = dep.data;
231
+ if (data.type === 'local-task') {
232
+ throw new Error(`local tasks (${task.name}) are not yet supported`);
233
+ }
234
+ return getTaskInstructions(cwd, { ...dep, data }, taskIds);
235
+ }
236
+ });
237
+ }
238
+ function resolveRecursiveDependencies(deps, result) {
239
+ for (const dep of deps) {
240
+ if (result[dep.id]) {
241
+ continue;
242
+ }
243
+ else {
244
+ result[dep.id] = dep;
245
+ resolveRecursiveDependencies(dep.deps, result);
246
+ }
247
+ }
248
+ return Object.values(result);
249
+ }
250
+ function getTaskInstructions(cwd, task, taskIds) {
251
+ const deps = getDependencyInstructions(cwd, task, taskIds);
252
+ const deepDeps = resolveRecursiveDependencies(deps, {});
253
+ const instructions = {
254
+ id: task.id(),
255
+ instructions: [
256
+ `FROM ${task.data.image} as task-${task.id()}`,
257
+ ...Object.entries(task.data.envs.variables).map(([key, value]) => `ENV ${key}=${value}`),
258
+ `WORKDIR ${toContainerPath((0, path_1.relative)(cwd, task.data.cwd))}`,
259
+ ...task.data.mounts.map((m) => `COPY ${(0, path_1.relative)(cwd, m.localPath)} ${toContainerPath((0, path_1.relative)(cwd, m.containerPath))}`),
260
+ ...deepDeps.flatMap((t) => t.sources.map((s) => `COPY --from=task-${t.id} ${toContainerPath((0, path_1.relative)(cwd, s.absolutePath))} ${toContainerPath((0, path_1.relative)(cwd, s.absolutePath))}`)),
261
+ ...deepDeps.flatMap((d) => d.exports),
262
+ ...task.data.src
263
+ .filter((s) => !s.inherited)
264
+ .map((s) => `COPY ${(0, path_1.relative)(cwd, s.absolutePath)} ${toContainerPath((0, path_1.relative)(cwd, s.absolutePath))}`),
265
+ ...task.data.cmds.map((command) => `RUN ${command.cmd}`),
266
+ '####################',
267
+ ],
268
+ cwd,
269
+ sources: [
270
+ ...task.data.src.filter((s) => !s.inherited).map((s) => ({ absolutePath: s.absolutePath, matcher: s.matcher })),
271
+ ],
272
+ exports: [
273
+ ...task.data.generates
274
+ .filter((g) => !g.inherited)
275
+ .map((generate) => `COPY --from=task-${task.id()} ${toContainerPath((0, path_1.relative)(cwd, generate.path))} ${toContainerPath((0, path_1.relative)(cwd, generate.path))}`),
276
+ ],
277
+ deps,
278
+ order: deps.reduce((acc, dep) => Math.max(acc, dep.order), 0) + 1,
279
+ };
280
+ taskIds[task.id()] = instructions;
281
+ return instructions;
282
+ }
283
+ //# sourceMappingURL=package.js.map