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
@@ -0,0 +1,53 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getStateKey = exports.getWorkCacheStats = void 0;
4
+ const calculate_checksum_1 = require("./calculate-checksum");
5
+ const path_1 = require("path");
6
+ const crypto_1 = require("crypto");
7
+ async function addWorkCacheStats(result, cwd, path, matcher, context) {
8
+ const exists = await context.file.exists(path);
9
+ if (!exists) {
10
+ return;
11
+ }
12
+ const stats = await context.file.stats(path);
13
+ if (stats.type === 'file') {
14
+ if (matcher(path)) {
15
+ const checksum = await (0, calculate_checksum_1.calculateChecksum)(context, path);
16
+ result.files[(0, path_1.relative)(cwd, path)] = { lastModified: stats.lastModified, checksum };
17
+ }
18
+ }
19
+ else if (stats.type === 'directory') {
20
+ const files = await context.file.listFiles(path);
21
+ for (const file of files) {
22
+ const subPath = (0, path_1.join)(path, file);
23
+ if (matcher(subPath)) {
24
+ await addWorkCacheStats(result, cwd, (0, path_1.join)(path, file), matcher, context);
25
+ }
26
+ }
27
+ }
28
+ }
29
+ async function getWorkCacheStats(work, environment) {
30
+ const result = {
31
+ created: new Date(),
32
+ files: {},
33
+ };
34
+ for (const src of work.src) {
35
+ await addWorkCacheStats(result, work.cwd, src.absolutePath, (file) => src.matcher(file, work.cwd), environment);
36
+ }
37
+ return result;
38
+ }
39
+ exports.getWorkCacheStats = getWorkCacheStats;
40
+ function getStateKey(stats, cacheMethod) {
41
+ const contents = [];
42
+ for (const key of Object.keys(stats.files)) {
43
+ if (cacheMethod === 'checksum') {
44
+ contents.push(`${key}:${stats.files[key].checksum}`);
45
+ }
46
+ else if (cacheMethod === 'modify-date') {
47
+ contents.push(`${key}:${stats.files[key].lastModified}`);
48
+ }
49
+ }
50
+ return (0, crypto_1.createHash)('md5').update(contents.join(',')).digest('hex');
51
+ }
52
+ exports.getStateKey = getStateKey;
53
+ //# sourceMappingURL=get-work-cache-stats.js.map
@@ -0,0 +1,79 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const path_1 = require("path");
4
+ const os_1 = require("os");
5
+ const fs_1 = require("fs");
6
+ const get_work_cache_stats_1 = require("./get-work-cache-stats");
7
+ const environment_mock_1 = require("../executer/environment-mock");
8
+ function stats(files) {
9
+ return { created: new Date(0), files };
10
+ }
11
+ describe('getStateKey', () => {
12
+ const sample = stats({
13
+ 'a.txt': { lastModified: 1000, checksum: 'aaa' },
14
+ 'b.txt': { lastModified: 2000, checksum: 'bbb' },
15
+ });
16
+ it('is deterministic for identical stats', () => {
17
+ expect((0, get_work_cache_stats_1.getStateKey)(sample, 'checksum')).toBe((0, get_work_cache_stats_1.getStateKey)(sample, 'checksum'));
18
+ });
19
+ it('produces different keys for checksum vs modify-date', () => {
20
+ expect((0, get_work_cache_stats_1.getStateKey)(sample, 'checksum')).not.toBe((0, get_work_cache_stats_1.getStateKey)(sample, 'modify-date'));
21
+ });
22
+ it('changes when a checksum changes (checksum method)', () => {
23
+ const changed = stats({
24
+ 'a.txt': { lastModified: 1000, checksum: 'aaa' },
25
+ 'b.txt': { lastModified: 2000, checksum: 'CHANGED' },
26
+ });
27
+ expect((0, get_work_cache_stats_1.getStateKey)(changed, 'checksum')).not.toBe((0, get_work_cache_stats_1.getStateKey)(sample, 'checksum'));
28
+ });
29
+ it('ignores checksum changes when using modify-date', () => {
30
+ const changed = stats({
31
+ 'a.txt': { lastModified: 1000, checksum: 'aaa' },
32
+ 'b.txt': { lastModified: 2000, checksum: 'CHANGED' },
33
+ });
34
+ expect((0, get_work_cache_stats_1.getStateKey)(changed, 'modify-date')).toBe((0, get_work_cache_stats_1.getStateKey)(sample, 'modify-date'));
35
+ });
36
+ it('returns a constant key for method "none" regardless of files', () => {
37
+ expect((0, get_work_cache_stats_1.getStateKey)(sample, 'none')).toBe((0, get_work_cache_stats_1.getStateKey)(stats({}), 'none'));
38
+ });
39
+ });
40
+ describe('getWorkCacheStats', () => {
41
+ let dir;
42
+ beforeEach(() => {
43
+ dir = (0, fs_1.mkdtempSync)((0, path_1.join)((0, os_1.tmpdir)(), 'hammerkit-stats-'));
44
+ });
45
+ afterEach(() => {
46
+ (0, fs_1.rmSync)(dir, { recursive: true, force: true });
47
+ });
48
+ function src(absolutePath, matcher = () => true) {
49
+ return { absolutePath, source: absolutePath, matcher };
50
+ }
51
+ it('returns empty files when src has no entries', async () => {
52
+ const env = (0, environment_mock_1.environmentMock)(dir);
53
+ const stats = await (0, get_work_cache_stats_1.getWorkCacheStats)({ cwd: dir, src: [] }, env);
54
+ expect(stats.files).toEqual({});
55
+ });
56
+ it('skips a src path that does not exist (early return)', async () => {
57
+ const env = (0, environment_mock_1.environmentMock)(dir);
58
+ const stats = await (0, get_work_cache_stats_1.getWorkCacheStats)({ cwd: dir, src: [src((0, path_1.join)(dir, 'missing'))] }, env);
59
+ expect(stats.files).toEqual({});
60
+ });
61
+ it('records a single file with checksum and lastModified', async () => {
62
+ (0, fs_1.writeFileSync)((0, path_1.join)(dir, 'a.txt'), 'hello');
63
+ const env = (0, environment_mock_1.environmentMock)(dir);
64
+ const stats = await (0, get_work_cache_stats_1.getWorkCacheStats)({ cwd: dir, src: [src((0, path_1.join)(dir, 'a.txt'))] }, env);
65
+ expect(stats.files['a.txt']).toBeDefined();
66
+ expect(stats.files['a.txt'].checksum).toMatch(/^[0-9a-f]+$/);
67
+ expect(stats.files['a.txt'].lastModified).toBeGreaterThan(0);
68
+ });
69
+ it('walks a directory recursively and respects the matcher', async () => {
70
+ (0, fs_1.mkdirSync)((0, path_1.join)(dir, 'sub'));
71
+ (0, fs_1.writeFileSync)((0, path_1.join)(dir, 'sub', 'keep.txt'), 'k');
72
+ (0, fs_1.writeFileSync)((0, path_1.join)(dir, 'sub', 'skip.md'), 's');
73
+ const env = (0, environment_mock_1.environmentMock)(dir);
74
+ const stats = await (0, get_work_cache_stats_1.getWorkCacheStats)({ cwd: dir, src: [src((0, path_1.join)(dir, 'sub'), (file) => file.endsWith('.txt'))] }, env);
75
+ expect(Object.keys(stats.files)).toContain((0, path_1.join)('sub', 'keep.txt'));
76
+ expect(Object.keys(stats.files)).not.toContain((0, path_1.join)('sub', 'skip.md'));
77
+ });
78
+ });
79
+ //# sourceMappingURL=get-work-cache-stats.spec.js.map
@@ -1,3 +1,3 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- //# sourceMappingURL=build-file-task.js.map
3
+ //# sourceMappingURL=work-cache-stats.js.map
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getWorkTaskCacheDescription = void 0;
4
+ const os_1 = require("os");
5
+ const replace_env_variables_1 = require("../environment/replace-env-variables");
6
+ function getWorkTaskCacheDescription(task) {
7
+ const envs = (0, replace_env_variables_1.getEnvironmentVariables)(task.envs);
8
+ return {
9
+ shell: task.shell ?? undefined,
10
+ platform: task.type === 'container-task' ? task.image : (0, os_1.platform)(),
11
+ generates: task.generates.map((g) => g.path).sort() ?? undefined,
12
+ src: task.src.map((s) => s.source).sort() ?? undefined,
13
+ envs: Object.keys(envs)
14
+ .sort()
15
+ .reduce((map, key) => {
16
+ map[key] = envs[key];
17
+ return map;
18
+ }, {}) ?? undefined,
19
+ cmds: task.cmds.map((c) => ({ cmd: c.cmd, cwd: c.cwd })),
20
+ mounts: task.type === 'container-task' ? task.mounts.map((m) => m.mount).sort() : undefined,
21
+ cwd: task.cwd,
22
+ };
23
+ }
24
+ exports.getWorkTaskCacheDescription = getWorkTaskCacheDescription;
25
+ //# sourceMappingURL=work-task-cache-description.js.map
@@ -0,0 +1,45 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const os_1 = require("os");
4
+ const work_task_cache_description_1 = require("./work-task-cache-description");
5
+ const baseTask = {
6
+ name: 'build',
7
+ cwd: '/work',
8
+ description: null,
9
+ src: [{ source: 'b' }, { source: 'a' }],
10
+ generates: [{ path: 'out/b' }, { path: 'out/a' }],
11
+ envs: { variables: { B: '2', A: '1' }, replacements: [] },
12
+ cmds: [{ cwd: '/work', cmd: 'tsc' }],
13
+ scope: {},
14
+ labels: {},
15
+ shell: '/bin/sh',
16
+ caching: {},
17
+ continuous: false,
18
+ };
19
+ describe('getWorkTaskCacheDescription', () => {
20
+ it('describes a container task with image as platform and sorted mounts', () => {
21
+ const task = {
22
+ ...baseTask,
23
+ type: 'container-task',
24
+ image: 'node:alpine',
25
+ user: null,
26
+ mounts: [{ mount: 'b:b' }, { mount: 'a:a' }],
27
+ };
28
+ const d = (0, work_task_cache_description_1.getWorkTaskCacheDescription)(task);
29
+ expect(d.platform).toBe('node:alpine');
30
+ expect(d.mounts).toEqual(['a:a', 'b:b']);
31
+ expect(d.src).toEqual(['a', 'b']);
32
+ expect(d.generates).toEqual(['out/a', 'out/b']);
33
+ expect(Object.keys(d.envs)).toEqual(['A', 'B']); // sorted
34
+ expect(d.cmds).toEqual([{ cwd: '/work', cmd: 'tsc' }]);
35
+ expect(d.cwd).toBe('/work');
36
+ expect(d.shell).toBe('/bin/sh');
37
+ });
38
+ it('describes a local task with the host platform and no mounts', () => {
39
+ const task = { ...baseTask, type: 'local-task' };
40
+ const d = (0, work_task_cache_description_1.getWorkTaskCacheDescription)(task);
41
+ expect(d.platform).toBe((0, os_1.platform)());
42
+ expect(d.mounts).toBeUndefined();
43
+ });
44
+ });
45
+ //# sourceMappingURL=work-task-cache-description.spec.js.map
@@ -1,22 +1,29 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getDefaultBuildFilename = void 0;
3
+ exports.getBuildFilename = void 0;
4
4
  const path_1 = require("path");
5
- async function getDefaultBuildFilename(folder, env) {
5
+ async function getBuildFilename(path, env) {
6
6
  const fileNames = ['.hammerkit.yaml', '.hammerkit.yml', 'build.yaml'];
7
+ const exists = await env.file.exists(path);
8
+ if (exists) {
9
+ const stats = await env.file.stats(path);
10
+ if (stats.type === 'file') {
11
+ return path;
12
+ }
13
+ }
7
14
  const existingFiles = [];
8
15
  for (const fileName of fileNames) {
9
- if (await env.file.exists((0, path_1.join)(folder, fileName))) {
16
+ if (await env.file.exists((0, path_1.join)(path, fileName))) {
10
17
  existingFiles.push(fileName);
11
18
  }
12
19
  }
13
20
  if (existingFiles.length > 1) {
14
- env.console.warn(`multiple hammerkit files ${existingFiles.join(', ')} in ${folder}`);
21
+ env.console.warn(`multiple hammerkit files ${existingFiles.join(', ')} in ${path}`);
15
22
  }
16
23
  if (existingFiles.length > 0) {
17
- return existingFiles[0];
24
+ return (0, path_1.join)(path, existingFiles[0]);
18
25
  }
19
- return fileNames[0];
26
+ return (0, path_1.join)(path, fileNames[0]);
20
27
  }
21
- exports.getDefaultBuildFilename = getDefaultBuildFilename;
28
+ exports.getBuildFilename = getBuildFilename;
22
29
  //# sourceMappingURL=default-build-file.js.map
@@ -0,0 +1,48 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const path_1 = require("path");
4
+ const os_1 = require("os");
5
+ const fs_1 = require("fs");
6
+ const environment_mock_1 = require("../executer/environment-mock");
7
+ const default_build_file_1 = require("./default-build-file");
8
+ describe('getBuildFilename', () => {
9
+ let dir;
10
+ beforeEach(() => {
11
+ dir = (0, fs_1.mkdtempSync)((0, path_1.join)((0, os_1.tmpdir)(), 'hammerkit-getbuildfilename-'));
12
+ });
13
+ afterEach(() => {
14
+ (0, fs_1.rmSync)(dir, { recursive: true, force: true });
15
+ });
16
+ it('returns the path itself when it points at an existing file', async () => {
17
+ const file = (0, path_1.join)(dir, '.hammerkit.yaml');
18
+ (0, fs_1.writeFileSync)(file, 'tasks: {}\n');
19
+ expect(await (0, default_build_file_1.getBuildFilename)(file, (0, environment_mock_1.environmentMock)(dir))).toBe(file);
20
+ });
21
+ it('falls back to <dir>/.hammerkit.yaml when the directory has no build file', async () => {
22
+ expect(await (0, default_build_file_1.getBuildFilename)(dir, (0, environment_mock_1.environmentMock)(dir))).toBe((0, path_1.join)(dir, '.hammerkit.yaml'));
23
+ });
24
+ it('picks an existing build file in the directory', async () => {
25
+ (0, fs_1.writeFileSync)((0, path_1.join)(dir, 'build.yaml'), 'tasks: {}\n');
26
+ expect(await (0, default_build_file_1.getBuildFilename)(dir, (0, environment_mock_1.environmentMock)(dir))).toBe((0, path_1.join)(dir, 'build.yaml'));
27
+ });
28
+ it('prefers .hammerkit.yaml when multiple build files coexist and warns', async () => {
29
+ (0, fs_1.writeFileSync)((0, path_1.join)(dir, '.hammerkit.yaml'), 'tasks: {}\n');
30
+ (0, fs_1.writeFileSync)((0, path_1.join)(dir, 'build.yaml'), 'tasks: {}\n');
31
+ const env = (0, environment_mock_1.environmentMock)(dir);
32
+ const warn = vi.spyOn(env.console, 'warn').mockImplementation(() => undefined);
33
+ const result = await (0, default_build_file_1.getBuildFilename)(dir, env);
34
+ expect(result).toBe((0, path_1.join)(dir, '.hammerkit.yaml'));
35
+ expect(warn).toHaveBeenCalledWith(expect.stringContaining('multiple hammerkit files'));
36
+ });
37
+ it('handles a missing path by returning <path>/.hammerkit.yaml', async () => {
38
+ const missing = (0, path_1.join)(dir, 'does-not-exist');
39
+ expect(await (0, default_build_file_1.getBuildFilename)(missing, (0, environment_mock_1.environmentMock)(dir))).toBe((0, path_1.join)(missing, '.hammerkit.yaml'));
40
+ });
41
+ it('ignores a path that exists but is neither a file nor a build dir match', async () => {
42
+ const sub = (0, path_1.join)(dir, 'sub');
43
+ (0, fs_1.mkdirSync)(sub);
44
+ // empty directory exists but has no build files; falls back to default
45
+ expect(await (0, default_build_file_1.getBuildFilename)(sub, (0, environment_mock_1.environmentMock)(dir))).toBe((0, path_1.join)(sub, '.hammerkit.yaml'));
46
+ });
47
+ });
48
+ //# sourceMappingURL=default-build-file.spec.js.map
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const parse_label_arguments_1 = require("./parse-label-arguments");
4
+ describe('parse-label-arguments', () => {
5
+ it('parses a single key=value argument', () => {
6
+ expect((0, parse_label_arguments_1.parseLabelArguments)(['app=web'])).toEqual({ app: ['web'] });
7
+ });
8
+ it('collects multiple values for the same key', () => {
9
+ expect((0, parse_label_arguments_1.parseLabelArguments)(['app=web', 'app=api'])).toEqual({ app: ['web', 'api'] });
10
+ });
11
+ it('dedupes repeated values', () => {
12
+ expect((0, parse_label_arguments_1.parseLabelArguments)(['app=web', 'app=web'])).toEqual({ app: ['web'] });
13
+ });
14
+ it('keeps distinct keys separate', () => {
15
+ expect((0, parse_label_arguments_1.parseLabelArguments)(['app=web', 'tier=frontend'])).toEqual({ app: ['web'], tier: ['frontend'] });
16
+ });
17
+ it('returns an empty object for no arguments', () => {
18
+ expect((0, parse_label_arguments_1.parseLabelArguments)([])).toEqual({});
19
+ });
20
+ it('throws when an argument has no value', () => {
21
+ expect(() => (0, parse_label_arguments_1.parseLabelArguments)(['app'])).toThrow('invalid label app');
22
+ });
23
+ it('throws when an argument has multiple equals signs', () => {
24
+ expect(() => (0, parse_label_arguments_1.parseLabelArguments)(['app=web=extra'])).toThrow('invalid label app=web=extra');
25
+ });
26
+ });
27
+ //# sourceMappingURL=parse-label-arguments.spec.js.map
@@ -1,16 +1,13 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.readBuildFile = exports.read = exports.write = void 0;
3
+ exports.read = exports.write = void 0;
4
4
  const yaml_1 = require("yaml");
5
- const parse_build_file_1 = require("./parse-build-file");
6
5
  async function write(filename, content, context) {
7
6
  await context.file.writeFile(filename, (0, yaml_1.stringify)(content));
8
7
  }
9
8
  exports.write = write;
10
9
  async function read(fileName, context) {
11
- context.status
12
- .context({ type: 'cli', id: 'general', name: 'hammerkit' })
13
- .write('debug', `read ${fileName} build file`);
10
+ context.status.context({ type: 'cli', name: 'hammerkit' }).write('debug', `read ${fileName} build file`);
14
11
  let content;
15
12
  try {
16
13
  content = await context.file.read(fileName);
@@ -31,12 +28,4 @@ async function read(fileName, context) {
31
28
  }
32
29
  }
33
30
  exports.read = read;
34
- async function readBuildFile(fileName, files, context) {
35
- if (files[fileName]) {
36
- return files[fileName];
37
- }
38
- const input = await read(fileName, context);
39
- return (0, parse_build_file_1.parseBuildFile)(fileName, files, input, context);
40
- }
41
- exports.readBuildFile = readBuildFile;
42
31
  //# sourceMappingURL=read-build-file.js.map
@@ -0,0 +1,89 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ const path_1 = require("path");
27
+ const os_1 = require("os");
28
+ const fs_1 = require("fs");
29
+ const yaml = __importStar(require("yaml"));
30
+ const environment_mock_1 = require("../executer/environment-mock");
31
+ const read_build_file_1 = require("./read-build-file");
32
+ // Re-export the real module through a plain (mutable) object so a single test can
33
+ // spyOn parse. A true ESM namespace has non-configurable exports that vi.spyOn
34
+ // cannot redefine; the spread keeps the real parse/stringify for every other test.
35
+ vi.mock('yaml', async () => ({ ...(await vi.importActual('yaml')) }));
36
+ describe('read-build-file', () => {
37
+ let scratch;
38
+ beforeEach(() => {
39
+ scratch = (0, fs_1.mkdtempSync)((0, path_1.join)((0, os_1.tmpdir)(), 'hammerkit-read-'));
40
+ });
41
+ afterEach(() => {
42
+ (0, fs_1.rmSync)(scratch, { recursive: true, force: true });
43
+ });
44
+ describe('read', () => {
45
+ it('parses a yaml build file into an object', async () => {
46
+ const env = (0, environment_mock_1.environmentMock)(scratch);
47
+ const file = (0, path_1.join)(scratch, '.hammerkit.yaml');
48
+ (0, fs_1.writeFileSync)(file, 'tasks:\n build:\n cmds:\n - echo hi\n');
49
+ const result = await (0, read_build_file_1.read)(file, env);
50
+ expect(result.tasks.build.cmds).toEqual(['echo hi']);
51
+ });
52
+ it('throws a readable error for a missing file', async () => {
53
+ const env = (0, environment_mock_1.environmentMock)(scratch);
54
+ await expect((0, read_build_file_1.read)((0, path_1.join)(scratch, 'does-not-exist.yaml'), env)).rejects.toThrow(/unable to read/);
55
+ });
56
+ it('throws a readable error for malformed yaml', async () => {
57
+ const env = (0, environment_mock_1.environmentMock)(scratch);
58
+ const file = (0, path_1.join)(scratch, '.hammerkit.yaml');
59
+ // tabs are not valid yaml indentation
60
+ (0, fs_1.writeFileSync)(file, 'tasks:\n\t- build\n');
61
+ await expect((0, read_build_file_1.read)(file, env)).rejects.toThrow(/unable to parse/);
62
+ });
63
+ it('rethrows non-Error throws from the yaml parser unchanged', async () => {
64
+ // Stub yaml.parse to throw a non-Error value so the `else throw e` branch
65
+ // in read() is exercised (the wrap-with-message branch only handles Error).
66
+ const spy = vi.spyOn(yaml, 'parse').mockImplementation(() => {
67
+ // eslint-disable-next-line @typescript-eslint/no-throw-literal
68
+ throw 'a plain string';
69
+ });
70
+ try {
71
+ const env = (0, environment_mock_1.environmentMock)(scratch);
72
+ const file = (0, path_1.join)(scratch, '.hammerkit.yaml');
73
+ (0, fs_1.writeFileSync)(file, 'x: 1\n');
74
+ await expect((0, read_build_file_1.read)(file, env)).rejects.toBe('a plain string');
75
+ }
76
+ finally {
77
+ spy.mockRestore();
78
+ }
79
+ });
80
+ });
81
+ describe('write', () => {
82
+ it('serializes the value as yaml via the environment file context', async () => {
83
+ const env = (0, environment_mock_1.environmentMock)(scratch);
84
+ await (0, read_build_file_1.write)((0, path_1.join)(scratch, 'out.yaml'), { tasks: { hi: { cmds: ['echo hi'] } } }, env);
85
+ expect((0, fs_1.readFileSync)((0, path_1.join)(scratch, 'out.yaml'), 'utf8')).toMatch(/tasks:\n\s+hi:\n\s+cmds:\n\s+- echo hi/);
86
+ });
87
+ });
88
+ });
89
+ //# sourceMappingURL=read-build-file.spec.js.map
@@ -2,11 +2,11 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.readEnvFile = void 0;
4
4
  const path_1 = require("path");
5
- async function readEnvFile(path, baseEnv, environment) {
5
+ async function readEnvFile(path, environment, baseEnv = {}) {
6
6
  const directory = (0, path_1.join)(path, '.env');
7
7
  let envs = { ...baseEnv };
8
8
  if ((0, path_1.basename)(path) !== path) {
9
- envs = { ...(await readEnvFile((0, path_1.basename)(path), envs, environment)) };
9
+ envs = { ...(await readEnvFile((0, path_1.basename)(path), environment, envs)) };
10
10
  }
11
11
  const exists = await environment.file.exists(directory);
12
12
  if (!exists) {
@@ -16,10 +16,9 @@ async function readEnvFile(path, baseEnv, environment) {
16
16
  for (const envVar of envFile) {
17
17
  const index = envVar.indexOf('=');
18
18
  if (index > 0) {
19
- const key = envVar.substr(0, index);
20
- const value = envVar.substr(index + 1);
19
+ const key = envVar.substring(0, index);
20
+ const value = envVar.substring(index + 1);
21
21
  if (!envs[key]) {
22
- environment.console.debug(`load env variable ${key} from ${directory} file`);
23
22
  envs[key] = value;
24
23
  }
25
24
  }
@@ -0,0 +1,42 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const path_1 = require("path");
4
+ const read_env_file_1 = require("./read-env-file");
5
+ // Build an Environment whose file context serves .env files from an in-memory map
6
+ // keyed by directory. readEnvFile asks for `join(<dir>, '.env')`, so build the
7
+ // keys the same way (native separators) — keeps the test correct on Windows too.
8
+ function envWithFiles(dirs) {
9
+ const files = {};
10
+ for (const [dir, content] of Object.entries(dirs)) {
11
+ files[(0, path_1.join)(dir, '.env')] = content;
12
+ }
13
+ return {
14
+ file: {
15
+ exists: vi.fn(async (p) => p in files),
16
+ read: vi.fn(async (p) => files[p]),
17
+ },
18
+ };
19
+ }
20
+ describe('read-env-file', () => {
21
+ it('parses KEY=VALUE pairs from a .env file', async () => {
22
+ const env = envWithFiles({ proj: 'A=1\nB=2' });
23
+ expect(await (0, read_env_file_1.readEnvFile)('proj', env)).toEqual({ A: '1', B: '2' });
24
+ });
25
+ it('keeps "=" characters in the value and skips lines without "="', async () => {
26
+ const env = envWithFiles({ proj: 'URL=http://x?y=z\nNOEQ\n\nC=3' });
27
+ expect(await (0, read_env_file_1.readEnvFile)('proj', env)).toEqual({ URL: 'http://x?y=z', C: '3' });
28
+ });
29
+ it('does not overwrite values already present in baseEnv', async () => {
30
+ const env = envWithFiles({ proj: 'A=fromfile\nB=2' });
31
+ expect(await (0, read_env_file_1.readEnvFile)('proj', env, { A: 'base' })).toEqual({ A: 'base', B: '2' });
32
+ });
33
+ it('returns the base env when no .env file exists', async () => {
34
+ const env = envWithFiles({});
35
+ expect(await (0, read_env_file_1.readEnvFile)('proj', env, { X: 'y' })).toEqual({ X: 'y' });
36
+ });
37
+ it('reads the basename .env first, then the full path', async () => {
38
+ const env = envWithFiles({ b: 'FROM_B=1', 'a/b': 'FROM_AB=2' });
39
+ expect(await (0, read_env_file_1.readEnvFile)('a/b', env)).toEqual({ FROM_B: '1', FROM_AB: '2' });
40
+ });
41
+ });
42
+ //# sourceMappingURL=read-env-file.spec.js.map
@@ -0,0 +1,55 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.appendWorkDependencies = void 0;
4
+ const work_task_1 = require("../work-task");
5
+ const work_service_1 = require("../work-service");
6
+ const append_work_task_1 = require("./append-work-task");
7
+ const label_values_1 = require("../../executer/label-values");
8
+ function appendWorkDependencies(workTree, referenced, item, environment, context) {
9
+ for (const dep of referenced.deps) {
10
+ const depNode = (0, append_work_task_1.appendWorkTask)(workTree, dep.cwd, dep.task, environment, context);
11
+ item.deps.push(depNode);
12
+ item.data.labels = (0, label_values_1.mergeLabels)(item.data.labels, depNode.data.labels);
13
+ if ((0, work_task_1.isWorkTask)(item.data) || (0, work_service_1.isContainerWorkService)(item.data)) {
14
+ for (const src of depNode.data.src) {
15
+ if (!item.data.src.some((s) => s.absolutePath === src.absolutePath)) {
16
+ item.data.src.push({ ...src, inherited: depNode });
17
+ }
18
+ }
19
+ }
20
+ if (((0, work_task_1.isContainerWorkTask)(depNode.data) || (0, work_service_1.isContainerWorkService)(depNode.data)) &&
21
+ ((0, work_task_1.isContainerWorkTask)(item.data) || (0, work_service_1.isContainerWorkService)(item.data))) {
22
+ for (const generate of depNode.data.generates) {
23
+ if (generate.isFile) {
24
+ // TODO check if thats correct
25
+ continue;
26
+ }
27
+ if (item.data.type === 'container-service') {
28
+ if (!item.data.volumes.some((v) => v.name === generate.volumeName)) {
29
+ item.data.volumes.push({
30
+ name: generate.volumeName,
31
+ export: false,
32
+ resetOnChange: false,
33
+ containerPath: generate.path,
34
+ inherited: depNode,
35
+ });
36
+ }
37
+ }
38
+ else {
39
+ if (!item.data.generates.some((v) => v.volumeName === generate.volumeName)) {
40
+ item.data.generates.push({
41
+ volumeName: generate.volumeName,
42
+ export: false,
43
+ resetOnChange: false,
44
+ path: generate.path,
45
+ inherited: depNode,
46
+ isFile: false,
47
+ });
48
+ }
49
+ }
50
+ }
51
+ }
52
+ }
53
+ }
54
+ exports.appendWorkDependencies = appendWorkDependencies;
55
+ //# sourceMappingURL=append-work-dependencies.js.map
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.appendWorkEnvironment = void 0;
4
+ function appendWorkEnvironment(referenced) {
5
+ if ('docker' in referenced.schema) {
6
+ return {
7
+ type: 'docker',
8
+ host: referenced.schema.docker.host,
9
+ };
10
+ }
11
+ else {
12
+ return {
13
+ type: 'kubernetes',
14
+ context: referenced.schema.kubernetes.context,
15
+ kubeConfig: referenced.schema.kubernetes.kubeconfig,
16
+ ingresses: referenced.schema.kubernetes.ingresses || [],
17
+ namespace: referenced.schema.kubernetes.namespace ?? 'default',
18
+ };
19
+ }
20
+ }
21
+ exports.appendWorkEnvironment = appendWorkEnvironment;
22
+ //# sourceMappingURL=append-work-environment.js.map
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.appendWorkNeeds = void 0;
4
+ const append_work_service_1 = require("./append-work-service");
5
+ function appendWorkNeeds(workTree, referenced, item, environment, context) {
6
+ for (const need of referenced.needs) {
7
+ const serviceNeed = (0, append_work_service_1.appendWorkService)(workTree, need.service, environment, context);
8
+ item.needs.push({
9
+ service: serviceNeed,
10
+ name: need.relativeName,
11
+ });
12
+ if (!serviceNeed.requiredBy.some((r) => r.name === item.name)) {
13
+ serviceNeed.requiredBy.push(item);
14
+ }
15
+ }
16
+ }
17
+ exports.appendWorkNeeds = appendWorkNeeds;
18
+ //# sourceMappingURL=append-work-needs.js.map