hammerkit 1.5.1 → 1.6.0-alpha.2

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
@@ -0,0 +1,53 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ensureHttpRoute = exports.HTTP_ROUTE_KIND = exports.HTTP_ROUTE_API_VERSION = void 0;
4
+ const apply_1 = require("./apply");
5
+ const resources_1 = require("./resources");
6
+ exports.HTTP_ROUTE_API_VERSION = 'gateway.networking.k8s.io/v1';
7
+ exports.HTTP_ROUTE_KIND = 'HTTPRoute';
8
+ async function ensureHttpRoute(instance, env, ingress, service) {
9
+ if (!ingress.gateway) {
10
+ throw new Error(`httproute for ${ingress.host} requires a "gateway" (the parent Gateway name)`);
11
+ }
12
+ const resource = {
13
+ apiVersion: exports.HTTP_ROUTE_API_VERSION,
14
+ kind: exports.HTTP_ROUTE_KIND,
15
+ metadata: {
16
+ name: ingress.host,
17
+ namespace: env.namespace,
18
+ labels: {
19
+ 'hammerkit.dev/id': service.id(),
20
+ },
21
+ },
22
+ spec: {
23
+ parentRefs: [
24
+ {
25
+ name: ingress.gateway,
26
+ ...(ingress.gatewayNamespace ? { namespace: ingress.gatewayNamespace } : {}),
27
+ },
28
+ ],
29
+ hostnames: [ingress.host],
30
+ rules: [
31
+ {
32
+ matches: [
33
+ {
34
+ path: {
35
+ type: 'PathPrefix',
36
+ value: ingress.path ?? '/',
37
+ },
38
+ },
39
+ ],
40
+ backendRefs: [
41
+ {
42
+ name: (0, resources_1.getResourceName)(service),
43
+ port: ingress.servicePort ?? service.data.ports[0].containerPort,
44
+ },
45
+ ],
46
+ },
47
+ ],
48
+ },
49
+ };
50
+ return await (0, apply_1.apply)(instance, resource);
51
+ }
52
+ exports.ensureHttpRoute = ensureHttpRoute;
53
+ //# sourceMappingURL=ensure-http-route.js.map
@@ -0,0 +1,70 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const ensure_http_route_1 = require("./ensure-http-route");
4
+ function httpError(statusCode) {
5
+ return Object.assign(new Error(`http ${statusCode}`), { statusCode });
6
+ }
7
+ function makeInstance(objectApi) {
8
+ return { objectApi };
9
+ }
10
+ const env = { type: 'kubernetes', namespace: 'demo', context: 'ctx', ingresses: [] };
11
+ const service = {
12
+ name: 'api',
13
+ id: () => 'abc123',
14
+ data: { ports: [{ containerPort: 3000, hostPort: null }] },
15
+ };
16
+ function ingress(overrides = {}) {
17
+ return {
18
+ kind: 'httproute',
19
+ host: 'api.example.com',
20
+ service: 'api',
21
+ gateway: 'web',
22
+ ...overrides,
23
+ };
24
+ }
25
+ describe('ensureHttpRoute', () => {
26
+ it('creates an HTTPRoute with the expected shape', async () => {
27
+ const read = vi.fn().mockRejectedValue(httpError(404));
28
+ const create = vi.fn().mockResolvedValue({ body: {} });
29
+ await (0, ensure_http_route_1.ensureHttpRoute)(makeInstance({ read, create }), env, ingress(), service);
30
+ expect(create).toHaveBeenCalledTimes(1);
31
+ expect(create.mock.calls[0][0]).toMatchObject({
32
+ apiVersion: 'gateway.networking.k8s.io/v1',
33
+ kind: 'HTTPRoute',
34
+ metadata: { name: 'api.example.com', namespace: 'demo', labels: { 'hammerkit.dev/id': 'abc123' } },
35
+ spec: {
36
+ parentRefs: [{ name: 'web' }],
37
+ hostnames: ['api.example.com'],
38
+ rules: [
39
+ {
40
+ matches: [{ path: { type: 'PathPrefix', value: '/' } }],
41
+ backendRefs: [{ name: 'api-abc123', port: 3000 }],
42
+ },
43
+ ],
44
+ },
45
+ });
46
+ });
47
+ it('uses servicePort, path and gatewayNamespace when provided', async () => {
48
+ const read = vi.fn().mockRejectedValue(httpError(404));
49
+ const create = vi.fn().mockResolvedValue({ body: {} });
50
+ await (0, ensure_http_route_1.ensureHttpRoute)(makeInstance({ read, create }), env, ingress({ servicePort: 8080, path: '/api', gatewayNamespace: 'gateways' }), service);
51
+ expect(create.mock.calls[0][0]).toMatchObject({
52
+ spec: {
53
+ parentRefs: [{ name: 'web', namespace: 'gateways' }],
54
+ rules: [
55
+ {
56
+ matches: [{ path: { type: 'PathPrefix', value: '/api' } }],
57
+ backendRefs: [{ name: 'api-abc123', port: 8080 }],
58
+ },
59
+ ],
60
+ },
61
+ });
62
+ });
63
+ it('throws when no gateway is set', async () => {
64
+ const read = vi.fn();
65
+ const create = vi.fn();
66
+ await expect((0, ensure_http_route_1.ensureHttpRoute)(makeInstance({ read, create }), env, ingress({ gateway: undefined }), service)).rejects.toThrow(/requires a "gateway"/);
67
+ expect(create).not.toHaveBeenCalled();
68
+ });
69
+ });
70
+ //# sourceMappingURL=ensure-http-route.spec.js.map
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ensureIngress = void 0;
4
+ const apply_1 = require("./apply");
5
+ const resources_1 = require("./resources");
6
+ async function ensureIngress(instance, env, ingress, service) {
7
+ const resource = {
8
+ kind: 'Ingress',
9
+ apiVersion: 'networking.k8s.io/v1',
10
+ metadata: {
11
+ name: ingress.host,
12
+ namespace: env.namespace,
13
+ annotations: {
14
+ 'cert-manager.io/cluster-issuer': 'hammerkit-issuer',
15
+ },
16
+ labels: {
17
+ 'hammerkit.dev/id': service.id(),
18
+ },
19
+ },
20
+ spec: {
21
+ ingressClassName: 'nginx',
22
+ rules: [
23
+ {
24
+ host: ingress.host,
25
+ http: {
26
+ paths: [
27
+ {
28
+ path: ingress.path ?? '/',
29
+ pathType: 'Prefix',
30
+ backend: {
31
+ service: {
32
+ name: (0, resources_1.getResourceName)(service),
33
+ port: {
34
+ number: ingress.servicePort ?? service.data.ports[0].containerPort,
35
+ },
36
+ },
37
+ },
38
+ },
39
+ ],
40
+ },
41
+ },
42
+ ],
43
+ tls: [
44
+ {
45
+ secretName: `${ingress.host}-tls`,
46
+ hosts: [ingress.host],
47
+ },
48
+ ],
49
+ },
50
+ };
51
+ return await (0, apply_1.apply)(instance, resource);
52
+ }
53
+ exports.ensureIngress = ensureIngress;
54
+ //# sourceMappingURL=ensure-ingress.js.map
@@ -0,0 +1,105 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ensureKubernetesDeploymentExists = void 0;
4
+ const work_item_1 = require("../planner/work-item");
5
+ const apply_1 = require("./apply");
6
+ const get_service_ip_1 = require("./get-service-ip");
7
+ const version_1 = require("../version");
8
+ const replace_env_variables_1 = require("../environment/replace-env-variables");
9
+ const await_running_state_1 = require("./await-running-state");
10
+ const resources_1 = require("./resources");
11
+ async function ensureKubernetesDeploymentExists(instance, env, service, persistence, stateKey) {
12
+ const hostAliases = [];
13
+ for (const need of service.needs) {
14
+ if (!(0, work_item_1.isContainerWorkServiceItem)(need.service)) {
15
+ continue;
16
+ }
17
+ const ip = await (0, get_service_ip_1.getServiceIp)(instance, env, need.service);
18
+ if (!ip) {
19
+ throw new Error(`unable to get service ip for ${need.name}`);
20
+ }
21
+ hostAliases.push({
22
+ ip,
23
+ hostnames: [need.name],
24
+ });
25
+ }
26
+ const envs = (0, replace_env_variables_1.getEnvironmentVariables)(service.data.envs);
27
+ const name = (0, resources_1.getResourceName)(service);
28
+ const probe = service.data.healthcheck
29
+ ? {
30
+ exec: {
31
+ command: [service.data.healthcheck.cmd.parsed.command, ...service.data.healthcheck.cmd.parsed.args],
32
+ },
33
+ periodSeconds: 5,
34
+ failureThreshold: 3,
35
+ }
36
+ : undefined;
37
+ const deployment = {
38
+ kind: 'Deployment',
39
+ apiVersion: 'apps/v1',
40
+ metadata: {
41
+ namespace: env.namespace,
42
+ name: name,
43
+ annotations: {
44
+ 'hammerkit.dev/version': (0, version_1.getVersion)(),
45
+ },
46
+ labels: {
47
+ 'hammerkit.dev/id': service.id(),
48
+ 'hammerkit.dev/state': stateKey,
49
+ },
50
+ },
51
+ spec: {
52
+ selector: {
53
+ matchLabels: {
54
+ 'hammerkit.dev/id': service.id(),
55
+ },
56
+ },
57
+ replicas: 1,
58
+ template: {
59
+ metadata: {
60
+ labels: {
61
+ 'hammerkit.dev/id': service.id(),
62
+ 'hammerkit.dev/state': stateKey,
63
+ },
64
+ },
65
+ spec: {
66
+ hostAliases: hostAliases,
67
+ containers: [
68
+ {
69
+ name: service.name.replace(/:/, '-'),
70
+ image: service.data.image,
71
+ workingDir: service.data.cwd ?? undefined,
72
+ env: Object.entries(envs).map(([key, value]) => ({
73
+ name: key,
74
+ value: value,
75
+ })),
76
+ command: service.data.cmd ? [service.data.cmd.parsed.command] : undefined,
77
+ args: service.data.cmd ? service.data.cmd.parsed.args : undefined,
78
+ ports: service.data.ports.map((p) => ({
79
+ containerPort: p.containerPort,
80
+ })),
81
+ readinessProbe: probe,
82
+ livenessProbe: probe,
83
+ volumeMounts: persistence.mounts.map((m) => m.mount),
84
+ },
85
+ {
86
+ name: 'debug',
87
+ image: service.data.image,
88
+ command: ['sleep'],
89
+ args: ['3600'],
90
+ volumeMounts: persistence.mounts.map((m) => m.mount),
91
+ },
92
+ ],
93
+ volumes: persistence.volumes,
94
+ },
95
+ },
96
+ },
97
+ };
98
+ const deploy = await (0, apply_1.apply)(instance, deployment);
99
+ if (deploy.status?.readyReplicas ?? 0 > 0) {
100
+ return;
101
+ }
102
+ await (0, await_running_state_1.awaitDeployRunningState)(instance, env, name);
103
+ }
104
+ exports.ensureKubernetesDeploymentExists = ensureKubernetesDeploymentExists;
105
+ //# sourceMappingURL=ensure-kubernetes-deployment-exists.js.map
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ensureKubernetesPersistentVolumeClaimExists = void 0;
4
+ const apply_1 = require("./apply");
5
+ const version_1 = require("../version");
6
+ async function ensureKubernetesPersistentVolumeClaimExists(instance, env, volume, service) {
7
+ const pvc = {
8
+ kind: 'PersistentVolumeClaim',
9
+ apiVersion: 'v1',
10
+ metadata: {
11
+ namespace: env.namespace,
12
+ name: volume.name,
13
+ annotations: {
14
+ 'hammerkit.dev/version': (0, version_1.getVersion)(),
15
+ },
16
+ labels: {
17
+ 'hammerkit.dev/id': service.id(),
18
+ },
19
+ },
20
+ spec: {
21
+ accessModes: ['ReadWriteOnce'],
22
+ storageClassName: env.storageClass,
23
+ resources: {
24
+ requests: {
25
+ storage: '1Gi',
26
+ },
27
+ },
28
+ },
29
+ };
30
+ service.status.console('stdout', `ensure volume ${volume.name}`);
31
+ // Don't block on the PVC reaching "Bound". Storage classes with
32
+ // volumeBindingMode WaitForFirstConsumer (docker-desktop's "standard",
33
+ // k3d/k3s local-path, most cloud defaults) keep the claim Pending until a pod
34
+ // mounts it — and hammerkit creates that pod (upload pod / deployment) only
35
+ // after this call. Waiting here deadlocks until the test times out. k8s binds
36
+ // the claim when the consuming pod is scheduled, so applying it is enough.
37
+ return await (0, apply_1.apply)(instance, pvc);
38
+ }
39
+ exports.ensureKubernetesPersistentVolumeClaimExists = ensureKubernetesPersistentVolumeClaimExists;
40
+ //# sourceMappingURL=ensure-kubernetes-persistent-volume-claim-exists.js.map
@@ -0,0 +1,36 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ensureKubernetesServiceExists = void 0;
4
+ const apply_1 = require("./apply");
5
+ const resources_1 = require("./resources");
6
+ const version_1 = require("../version");
7
+ async function ensureKubernetesServiceExists(instance, env, service) {
8
+ const name = (0, resources_1.getResourceName)(service);
9
+ const svc = {
10
+ kind: 'Service',
11
+ apiVersion: 'v1',
12
+ metadata: {
13
+ namespace: env.namespace,
14
+ name,
15
+ annotations: {
16
+ 'hammerkit.dev/version': (0, version_1.getVersion)(),
17
+ },
18
+ labels: {
19
+ 'hammerkit.dev/id': service.id(),
20
+ },
21
+ },
22
+ spec: {
23
+ type: 'ClusterIP',
24
+ selector: {
25
+ 'hammerkit.dev/id': service.id(),
26
+ },
27
+ ports: service.data.ports.map((port) => ({
28
+ port: port.hostPort ?? port.containerPort,
29
+ targetPort: port.containerPort,
30
+ })),
31
+ },
32
+ };
33
+ return await (0, apply_1.apply)(instance, svc);
34
+ }
35
+ exports.ensureKubernetesServiceExists = ensureKubernetesServiceExists;
36
+ //# sourceMappingURL=ensure-kubernetes-service-exists.js.map
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ensureNamespace = void 0;
4
+ function statusCodeOf(e) {
5
+ const err = e;
6
+ return err?.statusCode ?? err?.response?.statusCode ?? err?.body?.code;
7
+ }
8
+ /**
9
+ * Idempotently make sure `namespace` exists. hammerkit does not otherwise
10
+ * create namespaces — deployments/services/jobs are applied straight into
11
+ * `env.namespace` and silently fail to schedule if it is missing. Creating it
12
+ * up front lets build files (and the integration suite) use per-job /
13
+ * per-suite namespaces for isolation without a separate `kubectl create ns`.
14
+ *
15
+ * Safe to call concurrently: a 409 from a racing create is treated as success.
16
+ */
17
+ async function ensureNamespace(instance, namespace) {
18
+ try {
19
+ await instance.coreApi.readNamespace(namespace);
20
+ return;
21
+ }
22
+ catch (e) {
23
+ if (statusCodeOf(e) !== 404) {
24
+ throw e;
25
+ }
26
+ }
27
+ try {
28
+ await instance.coreApi.createNamespace({
29
+ metadata: {
30
+ name: namespace,
31
+ labels: { 'hammerkit.dev/managed': 'true' },
32
+ },
33
+ });
34
+ }
35
+ catch (e) {
36
+ // another worker created it between our read and create
37
+ if (statusCodeOf(e) !== 409) {
38
+ throw e;
39
+ }
40
+ }
41
+ }
42
+ exports.ensureNamespace = ensureNamespace;
43
+ //# sourceMappingURL=ensure-namespace.js.map
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const ensure_namespace_1 = require("./ensure-namespace");
4
+ function httpError(statusCode) {
5
+ return Object.assign(new Error(`http ${statusCode}`), { statusCode });
6
+ }
7
+ function makeInstance(coreApi) {
8
+ return { coreApi };
9
+ }
10
+ describe('ensureNamespace', () => {
11
+ it('does nothing when the namespace already exists', async () => {
12
+ const readNamespace = vi.fn().mockResolvedValue({ body: {} });
13
+ const createNamespace = vi.fn();
14
+ await (0, ensure_namespace_1.ensureNamespace)(makeInstance({ readNamespace, createNamespace }), 'demo');
15
+ expect(readNamespace).toHaveBeenCalledWith('demo');
16
+ expect(createNamespace).not.toHaveBeenCalled();
17
+ });
18
+ it('creates the namespace (labeled managed) when missing', async () => {
19
+ const readNamespace = vi.fn().mockRejectedValue(httpError(404));
20
+ const createNamespace = vi.fn().mockResolvedValue({ body: {} });
21
+ await (0, ensure_namespace_1.ensureNamespace)(makeInstance({ readNamespace, createNamespace }), 'demo');
22
+ expect(createNamespace).toHaveBeenCalledTimes(1);
23
+ expect(createNamespace.mock.calls[0][0]).toMatchObject({
24
+ metadata: { name: 'demo', labels: { 'hammerkit.dev/managed': 'true' } },
25
+ });
26
+ });
27
+ it('swallows a 409 from a racing create', async () => {
28
+ const readNamespace = vi.fn().mockRejectedValue(httpError(404));
29
+ const createNamespace = vi.fn().mockRejectedValue(httpError(409));
30
+ await expect((0, ensure_namespace_1.ensureNamespace)(makeInstance({ readNamespace, createNamespace }), 'demo')).resolves.toBeUndefined();
31
+ });
32
+ it('rethrows unexpected read errors', async () => {
33
+ const readNamespace = vi.fn().mockRejectedValue(httpError(500));
34
+ const createNamespace = vi.fn();
35
+ await expect((0, ensure_namespace_1.ensureNamespace)(makeInstance({ readNamespace, createNamespace }), 'demo')).rejects.toThrow();
36
+ expect(createNamespace).not.toHaveBeenCalled();
37
+ });
38
+ });
39
+ //# sourceMappingURL=ensure-namespace.spec.js.map
@@ -0,0 +1,158 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ensurePersistentData = exports.getPodForPersistence = void 0;
4
+ const apply_1 = require("./apply");
5
+ const path_1 = require("path");
6
+ const tar_1 = require("tar");
7
+ const resources_1 = require("./resources");
8
+ const await_running_state_1 = require("./await-running-state");
9
+ const sleep_1 = require("../utils/sleep");
10
+ const version_1 = require("../version");
11
+ const log_1 = require("../log");
12
+ const ensure_kubernetes_persistent_volume_claim_exists_1 = require("./ensure-kubernetes-persistent-volume-claim-exists");
13
+ // A previous run that crashed between creating an upload/download pod and its
14
+ // `finally` cleanup leaves a pod behind under the same deterministic name. apply()
15
+ // would then patch that stale pod in place — and if it is stuck in a terminal
16
+ // phase the subsequent awaitRunningState never resolves. Force-delete any leftover
17
+ // and wait for it to disappear before scheduling a fresh one.
18
+ async function removeStalePod(instance, namespace, name) {
19
+ try {
20
+ await instance.coreApi.deleteNamespacedPod(name, namespace, undefined, undefined, 0);
21
+ }
22
+ catch (e) {
23
+ if ((0, apply_1.statusCodeOf)(e) === 404) {
24
+ return;
25
+ }
26
+ throw e;
27
+ }
28
+ for (let attempt = 0; attempt < 30; attempt++) {
29
+ try {
30
+ await instance.coreApi.readNamespacedPod(name, namespace);
31
+ }
32
+ catch (e) {
33
+ if ((0, apply_1.statusCodeOf)(e) === 404) {
34
+ return;
35
+ }
36
+ throw e;
37
+ }
38
+ await (0, sleep_1.sleep)(500);
39
+ }
40
+ }
41
+ async function getPodForPersistence(instance, env, service, persistence, type, fn) {
42
+ if (persistence.volumes.length === 0) {
43
+ return;
44
+ }
45
+ const mounts = type === 'read'
46
+ ? persistence.mounts.map((m) => m.mount)
47
+ : persistence.mounts.reduce((array, v) => {
48
+ if (!array.some((i) => i.name === v.mount.name)) {
49
+ array.push({
50
+ mountPath: v.uploadPath,
51
+ name: v.mount.name,
52
+ readOnly: false,
53
+ });
54
+ }
55
+ return array;
56
+ }, []);
57
+ // Guarantee the claims exist right before scheduling the pod that mounts
58
+ // them. ensurePersistentData also creates them, but store/restore reach this
59
+ // function directly, and a claim shared with another work item can be removed
60
+ // concurrently — without this the pod would hang Pending on "pvc not found".
61
+ for (const volume of persistence.volumes) {
62
+ await (0, ensure_kubernetes_persistent_volume_claim_exists_1.ensureKubernetesPersistentVolumeClaimExists)(instance, env, volume, service);
63
+ }
64
+ const name = (0, resources_1.getResourceName)(service, type === 'write' ? '-upload' : '-download');
65
+ const podSpec = {
66
+ kind: 'Pod',
67
+ apiVersion: 'v1',
68
+ metadata: {
69
+ namespace: env.namespace,
70
+ name,
71
+ labels: {
72
+ 'hammerkit.dev/id': service.id(),
73
+ },
74
+ annotations: {
75
+ 'hammerkit.dev/version': (0, version_1.getVersion)(),
76
+ },
77
+ },
78
+ spec: {
79
+ containers: [
80
+ {
81
+ name: 'volume',
82
+ image: 'alpine',
83
+ command: ['sh'],
84
+ tty: true,
85
+ volumeMounts: mounts,
86
+ },
87
+ ],
88
+ volumes: persistence.volumes,
89
+ },
90
+ };
91
+ service.status.console('stdout', `create pod ${name}`);
92
+ await removeStalePod(instance, env.namespace, name);
93
+ const pod = await (0, apply_1.apply)(instance, podSpec);
94
+ if (pod.status?.phase !== 'Running') {
95
+ service.status.console('stdout', `await running state ${name}`);
96
+ await (0, await_running_state_1.awaitRunningState)(instance, env, name, 'Running');
97
+ }
98
+ try {
99
+ await fn(name);
100
+ }
101
+ finally {
102
+ service.status.console('stdout', `delete pod ${name}`);
103
+ await instance.coreApi.deleteNamespacedPod(name, env.namespace);
104
+ }
105
+ }
106
+ exports.getPodForPersistence = getPodForPersistence;
107
+ async function ensurePersistentData(instance, env, environment, service, persistence) {
108
+ // Dedupe of already-uploaded state (skip the upload when the persisted state
109
+ // key still matches) needs an in-cluster state marker per volume — deferred
110
+ // post-1.6.0, tracked in FOLLOWUPS.md alongside the volumes.ts stateKey/matcher.
111
+ for (const volume of persistence.volumes) {
112
+ await (0, ensure_kubernetes_persistent_volume_claim_exists_1.ensureKubernetesPersistentVolumeClaimExists)(instance, env, volume, service);
113
+ }
114
+ if (persistence.sources.length === 0) {
115
+ return;
116
+ }
117
+ service.status.console('stdout', 'start upload container');
118
+ await getPodForPersistence(instance, env, service, persistence, 'write', async (name) => {
119
+ for (const source of persistence.sources) {
120
+ // skip sources that don't exist on disk — nothing to upload
121
+ if (!(await environment.file.exists(source.localPath))) {
122
+ continue;
123
+ }
124
+ const fileItem = (0, path_1.basename)(source.localPath);
125
+ const data = (0, tar_1.create)({
126
+ cwd: (0, path_1.dirname)(source.localPath),
127
+ filter(path) {
128
+ return source.matcher(path, source.localPath);
129
+ },
130
+ }, [fileItem]);
131
+ service.status.console('stdout', `upload ${source.localPath}`);
132
+ const targetPath = `/dev/hammerkit/${service.id()}`;
133
+ const res = await instance.exec.exec(env.namespace, name, 'volume', ['tar', 'xf', '-', '-C', targetPath], process.stdout, process.stderr, data, false, (status) => {
134
+ service.status.write('debug', `upload ${source.localPath} to ${name}: ${status}`);
135
+ });
136
+ await new Promise((resolve, reject) => {
137
+ try {
138
+ res.on('open', () => {
139
+ service.status.write('debug', `start upload of ${source} to ${name}:${targetPath}`);
140
+ });
141
+ res.on('error', (err) => {
142
+ service.status.write('error', `error during upload of ${source.localPath} to ${name}: ${(0, log_1.getErrorMessage)(err)}`);
143
+ reject(err);
144
+ });
145
+ res.on('close', () => {
146
+ service.status.write('debug', `uploaded ${source.localPath} to ${name}:${targetPath}`);
147
+ resolve();
148
+ });
149
+ }
150
+ catch (e) {
151
+ reject(e);
152
+ }
153
+ });
154
+ }
155
+ });
156
+ }
157
+ exports.ensurePersistentData = ensurePersistentData;
158
+ //# sourceMappingURL=ensure-persistent-data.js.map
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getServiceIp = void 0;
4
+ const resources_1 = require("./resources");
5
+ async function getServiceIp(instance, env, workService) {
6
+ const name = (0, resources_1.getResourceName)(workService);
7
+ const svc = await instance.coreApi.readNamespacedService(name, env.namespace);
8
+ return svc.body.spec?.clusterIP ?? null;
9
+ }
10
+ exports.getServiceIp = getServiceIp;
11
+ //# sourceMappingURL=get-service-ip.js.map
@@ -0,0 +1,48 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createKubernetesInstances = void 0;
4
+ const client_node_1 = require("@kubernetes/client-node");
5
+ const log_1 = require("../log");
6
+ function createKubernetesInstances(kubernetes) {
7
+ const kc = new client_node_1.KubeConfig();
8
+ try {
9
+ if (kubernetes.kubeConfig) {
10
+ kc.loadFromFile(kubernetes.kubeConfig);
11
+ }
12
+ else {
13
+ kc.loadFromDefault();
14
+ }
15
+ kc.setCurrentContext(kubernetes.context);
16
+ const coreApi = kc.makeApiClient(client_node_1.CoreV1Api);
17
+ const batchApi = kc.makeApiClient(client_node_1.BatchV1Api);
18
+ const appsApi = kc.makeApiClient(client_node_1.AppsV1Api);
19
+ const networkingApi = kc.makeApiClient(client_node_1.NetworkingV1Api);
20
+ const objectApi = kc.makeApiClient(client_node_1.KubernetesObjectApi);
21
+ const exec = new client_node_1.Exec(kc);
22
+ const watch = new client_node_1.Watch(kc);
23
+ return {
24
+ objectApi,
25
+ networkingApi,
26
+ watch,
27
+ exec,
28
+ appsApi,
29
+ coreApi,
30
+ batchApi,
31
+ };
32
+ }
33
+ catch (e) {
34
+ if ((0, log_1.getErrorMessage)(e) === 'No active cluster!') {
35
+ if (kubernetes.kubeConfig) {
36
+ throw new Error(`No cluster found for context ${kubernetes.context} in ${kubernetes.kubeConfig}`);
37
+ }
38
+ else {
39
+ throw new Error(`No cluster found for context ${kubernetes.context}`);
40
+ }
41
+ }
42
+ else {
43
+ throw e;
44
+ }
45
+ }
46
+ }
47
+ exports.createKubernetesInstances = createKubernetesInstances;
48
+ //# sourceMappingURL=kubernetes-instance.js.map