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,209 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.findService = exports.findTask = exports.parseReferences = void 0;
4
+ const build_file_task_schema_1 = require("./build-file-task-schema");
5
+ const build_file_service_schema_1 = require("./build-file-service-schema");
6
+ const split_name_1 = require("../planner/utils/split-name");
7
+ const read_env_file_1 = require("../parser/read-env-file");
8
+ const label_values_1 = require("../executer/label-values");
9
+ const merge_environment_variables_1 = require("../environment/merge-environment-variables");
10
+ const resolve_cache_1 = require("../cache/resolve-cache");
11
+ function combinePath(namePrefix, name) {
12
+ return namePrefix.length > 0 ? `${namePrefix}:${name}` : name;
13
+ }
14
+ async function parseReferences(ctx, mainScope, environment) {
15
+ const declaredCaches = {};
16
+ const reference = {
17
+ files: {},
18
+ tasks: {},
19
+ services: {},
20
+ envFiles: {},
21
+ environments: {},
22
+ caches: {},
23
+ };
24
+ for (const file of Object.values(ctx.files)) {
25
+ if (!reference.envFiles[file.cwd]) {
26
+ reference.envFiles[file.cwd] = await (0, read_env_file_1.readEnvFile)(file.cwd, environment);
27
+ }
28
+ const buildFileEnvs = file.schema.envs;
29
+ if (file.schema.tasks) {
30
+ for (const [taskName, task] of Object.entries(file.schema.tasks)) {
31
+ const taskEnvs = (0, merge_environment_variables_1.mergeEnvironmentVariables)(task.envs, buildFileEnvs);
32
+ const relativeName = combinePath(file.namePrefix, taskName);
33
+ reference.tasks[relativeName] = {
34
+ type: 'task',
35
+ schema: task,
36
+ cwd: file.cwd,
37
+ relativeName,
38
+ labels: (0, label_values_1.mergeLabels)(file.schema.labels, task.labels),
39
+ envs: taskEnvs,
40
+ scope: file,
41
+ needs: [],
42
+ deps: [],
43
+ };
44
+ }
45
+ }
46
+ if (file.schema.environments) {
47
+ for (const [envName, env] of Object.entries(file.schema.environments)) {
48
+ reference.environments[envName] = {
49
+ type: 'environment',
50
+ schema: env,
51
+ scope: file,
52
+ name: envName,
53
+ };
54
+ }
55
+ }
56
+ if (file.schema.caches) {
57
+ for (const [cacheName, cache] of Object.entries(file.schema.caches)) {
58
+ declaredCaches[cacheName] = cache;
59
+ }
60
+ }
61
+ if (file.schema.services) {
62
+ for (const [serviceName, service] of Object.entries(file.schema.services)) {
63
+ const relativeName = combinePath(file.namePrefix, serviceName);
64
+ const serviceEnvs = (0, merge_environment_variables_1.mergeEnvironmentVariables)((0, build_file_service_schema_1.isBuildFileKubernetesServiceSchema)(service) ? {} : service.envs, buildFileEnvs);
65
+ reference.services[relativeName] = {
66
+ type: 'service',
67
+ schema: service,
68
+ cwd: file.cwd,
69
+ relativeName,
70
+ labels: (0, label_values_1.mergeLabels)(file.schema.labels, service.labels),
71
+ scope: file,
72
+ needs: [],
73
+ deps: [],
74
+ envs: serviceEnvs,
75
+ };
76
+ }
77
+ }
78
+ }
79
+ for (const task of Object.values(reference.tasks)) {
80
+ applySchemaExtension(reference, task);
81
+ resolveDeps(reference, task, task.scope, task.schema);
82
+ resolveNeeds(reference, task, task.scope, task.schema);
83
+ }
84
+ for (const service of Object.values(reference.services)) {
85
+ resolveDeps(reference, service, service.scope, service.schema);
86
+ resolveNeeds(reference, service, service.scope, service.schema);
87
+ }
88
+ reference.caches = (0, resolve_cache_1.withBuiltinCaches)(declaredCaches);
89
+ return reference;
90
+ }
91
+ exports.parseReferences = parseReferences;
92
+ function applySchemaExtension(reference, task) {
93
+ if (!task.schema.extend) {
94
+ return;
95
+ }
96
+ const extend = findTask(reference, task.scope, task.schema.extend, null).task;
97
+ applySchemaExtension(reference, extend);
98
+ task.schema.shell = task.schema.shell ?? extend.schema.shell;
99
+ task.schema.cache = task.schema.cache ?? extend.schema.cache;
100
+ task.schema.cmds = extendArray(task.schema.cmds, extend.schema.cmds);
101
+ task.schema.src = extendArray(task.schema.src, extend.schema.src);
102
+ task.schema.generates = extendArray(task.schema.generates, extend.schema.generates);
103
+ task.schema.labels = extendObject(task.schema.labels, extend.schema.labels);
104
+ task.envs = (0, merge_environment_variables_1.mergeEnvironmentVariables)(task.envs, extend.schema.envs);
105
+ if ((0, build_file_task_schema_1.isBuildFileContainerTaskSchema)(extend.schema)) {
106
+ const taskSchema = task.schema;
107
+ taskSchema.image = taskSchema.image ?? extend.schema.image;
108
+ taskSchema.mounts = extendArray(taskSchema.mounts, extend.schema.mounts);
109
+ }
110
+ resolveNeeds(reference, task, extend.scope, extend.schema);
111
+ resolveDeps(reference, task, extend.scope, extend.schema);
112
+ }
113
+ function extendArray(base, extend) {
114
+ if (!extend) {
115
+ return base;
116
+ }
117
+ if (!base) {
118
+ return [...extend];
119
+ }
120
+ return [...extend, ...base];
121
+ }
122
+ function extendObject(base, extend) {
123
+ if (!extend) {
124
+ return base;
125
+ }
126
+ if (!base) {
127
+ return { ...extend };
128
+ }
129
+ return { ...extend, ...base };
130
+ }
131
+ function resolveDeps(reference, taskOrService, scope, schema) {
132
+ for (const depName of schema.deps || []) {
133
+ const depTask = findTask(reference, scope, depName, null);
134
+ taskOrService.deps.push({
135
+ task: depTask.task,
136
+ type: depTask.type,
137
+ cwd: depTask.type === 'include' ? taskOrService.cwd : depTask.task.cwd,
138
+ relativeName: depName,
139
+ });
140
+ }
141
+ }
142
+ function resolveNeeds(reference, taskOrService, scope, schema) {
143
+ if ((0, build_file_service_schema_1.isBuildFileKubernetesServiceSchema)(schema)) {
144
+ return;
145
+ }
146
+ for (const needName of schema.needs || []) {
147
+ if (typeof needName === 'string') {
148
+ taskOrService.needs.push({
149
+ relativeName: needName,
150
+ service: findService(reference, scope, needName),
151
+ });
152
+ }
153
+ else {
154
+ taskOrService.needs.push({
155
+ relativeName: needName.name,
156
+ service: findService(reference, scope, needName.service),
157
+ });
158
+ }
159
+ }
160
+ }
161
+ function findTask(ctx, scope, name, type) {
162
+ const ref = (0, split_name_1.splitName)(name);
163
+ if (ref.prefix) {
164
+ if (scope.references[ref.prefix]) {
165
+ return findTask(ctx, scope.references[ref.prefix].scope, ref.name, scope.references[ref.prefix].type);
166
+ }
167
+ else if (scope.schema.tasks && scope.schema.tasks[name]) {
168
+ return resolveTask(ctx, scope, name, type ?? 'build-file');
169
+ }
170
+ }
171
+ else if (scope.schema.tasks && scope.schema.tasks[ref.name]) {
172
+ return resolveTask(ctx, scope, ref.name, type ?? 'build-file');
173
+ }
174
+ throw new Error('unable to find ' + name); // TODO improve
175
+ }
176
+ exports.findTask = findTask;
177
+ function resolveTask(ctx, scope, name, type) {
178
+ const fullName = combinePath(scope.namePrefix, name);
179
+ const buildFileTask = ctx.tasks[fullName];
180
+ if (!buildFileTask) {
181
+ throw new Error('unable to find ' + fullName);
182
+ }
183
+ return { task: buildFileTask, type };
184
+ }
185
+ function findService(ctx, scope, name) {
186
+ const ref = (0, split_name_1.splitName)(name);
187
+ if (ref.prefix) {
188
+ if (scope.references[ref.prefix]) {
189
+ return findService(ctx, scope.references[ref.prefix].scope, ref.name);
190
+ }
191
+ else if (scope.schema.services && scope.schema.services[name]) {
192
+ return resolveService(ctx, scope, name);
193
+ }
194
+ }
195
+ else if (scope.schema.services && scope.schema.services[ref.name]) {
196
+ return resolveService(ctx, scope, name);
197
+ }
198
+ throw new Error('unable to find ' + name); // TODO improve
199
+ }
200
+ exports.findService = findService;
201
+ function resolveService(ctx, scope, name) {
202
+ const fullName = combinePath(scope.namePrefix, name);
203
+ const service = ctx.services[fullName];
204
+ if (!service) {
205
+ throw new Error('unable to find ' + fullName);
206
+ }
207
+ return service;
208
+ }
209
+ //# sourceMappingURL=reference-parser.js.map
@@ -0,0 +1,83 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const test_case_1 = require("../testing/test-case");
4
+ const program_1 = require("../program");
5
+ const path_1 = require("path");
6
+ // Drive the full parse pipeline (schema-parser -> parseReferences -> getWorkContext)
7
+ // over an in-memory build file and assert on the resulting work tree. This exercises
8
+ // reference resolution: deps, needs, label merging and schema `extend`.
9
+ async function withCli(buildFile, scope, fn) {
10
+ const testCase = (0, test_case_1.createTestCase)('reference-parser', { '.hammerkit.yaml': buildFile });
11
+ await testCase.setup(async (cwd, environment) => {
12
+ const cli = await (0, program_1.createCli)((0, path_1.join)(cwd, '.hammerkit.yaml'), environment, scope);
13
+ await fn(cli);
14
+ });
15
+ }
16
+ describe('reference-parser', () => {
17
+ it('resolves task dependencies', async () => {
18
+ await withCli({
19
+ tasks: {
20
+ install: { cmds: ['npm install'] },
21
+ build: { cmds: ['tsc'], deps: ['install'] },
22
+ },
23
+ }, { taskName: 'build' }, (cli) => {
24
+ const build = cli.task('build');
25
+ expect(build.deps.map((d) => d.name)).toEqual(['install']);
26
+ });
27
+ });
28
+ it('resolves service needs', async () => {
29
+ await withCli({
30
+ services: {
31
+ api: { image: 'nginx', ports: [] },
32
+ },
33
+ tasks: {
34
+ build: { cmds: ['tsc'], needs: ['api'] },
35
+ },
36
+ }, { taskName: 'build' }, (cli) => {
37
+ const build = cli.task('build');
38
+ expect(build.needs.map((n) => n.service.name)).toEqual(['api']);
39
+ });
40
+ });
41
+ it('merges build-file labels with task labels', async () => {
42
+ await withCli({
43
+ labels: { app: 'web' },
44
+ tasks: {
45
+ build: { cmds: ['tsc'], labels: { tier: 'backend' } },
46
+ },
47
+ }, { taskName: 'build' }, (cli) => {
48
+ expect(cli.task('build').data.labels).toEqual({ app: ['web'], tier: ['backend'] });
49
+ });
50
+ });
51
+ it('applies schema extend (image, cmds, labels)', async () => {
52
+ await withCli({
53
+ tasks: {
54
+ base: { image: 'node', cmds: ['a'] },
55
+ child: { extend: 'base', cmds: ['b'] },
56
+ },
57
+ }, { taskName: 'child' }, (cli) => {
58
+ const child = cli.task('child').data;
59
+ // child inherits the base image and is therefore a container task
60
+ expect(child.type).toBe('container-task');
61
+ expect(child.image).toBe('node');
62
+ // extendArray prepends the extended task's cmds before the child's own
63
+ expect(child.cmds).toHaveLength(2);
64
+ });
65
+ });
66
+ it('throws when a dependency cannot be found', async () => {
67
+ const testCase = (0, test_case_1.createTestCase)('reference-parser', {
68
+ '.hammerkit.yaml': { tasks: { build: { cmds: ['tsc'], deps: ['missing'] } } },
69
+ });
70
+ await testCase.setup(async (cwd, environment) => {
71
+ await expect((0, program_1.createCli)((0, path_1.join)(cwd, '.hammerkit.yaml'), environment, { taskName: 'build' })).rejects.toThrow('unable to find missing');
72
+ });
73
+ });
74
+ it('throws when a needed service cannot be found', async () => {
75
+ const testCase = (0, test_case_1.createTestCase)('reference-parser', {
76
+ '.hammerkit.yaml': { tasks: { build: { cmds: ['tsc'], needs: ['missingsvc'] } } },
77
+ });
78
+ await testCase.setup(async (cwd, environment) => {
79
+ await expect((0, program_1.createCli)((0, path_1.join)(cwd, '.hammerkit.yaml'), environment, { taskName: 'build' })).rejects.toThrow('unable to find missingsvc');
80
+ });
81
+ });
82
+ });
83
+ //# sourceMappingURL=reference-parser.spec.js.map
@@ -0,0 +1,66 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.appendBuildFile = exports.createParseContext = void 0;
4
+ const build_file_schema_1 = require("./build-file-schema");
5
+ const read_build_file_1 = require("../parser/read-build-file");
6
+ const path_1 = require("path");
7
+ const default_build_file_1 = require("../parser/default-build-file");
8
+ const parse_error_1 = require("./parse-error");
9
+ async function createParseContext(fileName, environment) {
10
+ const ctx = {
11
+ files: {},
12
+ };
13
+ const scope = await appendBuildFile((0, path_1.dirname)(fileName), ctx, environment, fileName, []);
14
+ return { ctx, scope };
15
+ }
16
+ exports.createParseContext = createParseContext;
17
+ async function appendBuildFile(cwd, ctx, environment, fileName, namePrefix) {
18
+ const relativeName = namePrefix.join(':');
19
+ const key = `${cwd}:${fileName}`;
20
+ if (ctx.files[key]) {
21
+ return ctx.files[key];
22
+ }
23
+ const input = await (0, read_build_file_1.read)(fileName, environment);
24
+ const result = await build_file_schema_1.buildFileSchema.safeParseAsync(input);
25
+ if (result.success) {
26
+ const scope = {
27
+ fileName,
28
+ cwd,
29
+ schema: result.data,
30
+ namePrefix: relativeName,
31
+ references: {},
32
+ };
33
+ ctx.files[key] = scope;
34
+ if (scope.schema.references) {
35
+ for (const referenceName of Object.keys(scope.schema.references)) {
36
+ const reference = scope.schema.references[referenceName];
37
+ const referenceFilename = await (0, default_build_file_1.getBuildFilename)((0, path_1.join)(scope.cwd, reference), environment);
38
+ const referenceScope = await appendBuildFile((0, path_1.dirname)(referenceFilename), ctx, environment, referenceFilename, [
39
+ ...namePrefix,
40
+ referenceName,
41
+ ]);
42
+ if (scope.references[referenceName]) {
43
+ throw new Error(referenceName + ' already exists');
44
+ }
45
+ scope.references[referenceName] = { type: 'reference', scope: referenceScope };
46
+ }
47
+ }
48
+ if (scope.schema.includes) {
49
+ for (const includeName of Object.keys(scope.schema.includes)) {
50
+ const include = scope.schema.includes[includeName];
51
+ const includeFilename = await (0, default_build_file_1.getBuildFilename)((0, path_1.join)((0, path_1.dirname)(scope.fileName), include), environment);
52
+ const includeScope = await appendBuildFile(cwd, ctx, environment, includeFilename, [...namePrefix, includeName]);
53
+ if (scope.references[includeName]) {
54
+ throw new Error(includeName + ' already exists');
55
+ }
56
+ scope.references[includeName] = { type: 'include', scope: includeScope };
57
+ }
58
+ }
59
+ return scope;
60
+ }
61
+ else {
62
+ throw new parse_error_1.ParseError(result.error, fileName);
63
+ }
64
+ }
65
+ exports.appendBuildFile = appendBuildFile;
66
+ //# sourceMappingURL=schema-parser.js.map
@@ -0,0 +1,80 @@
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 schema_parser_1 = require("./schema-parser");
8
+ const parse_error_1 = require("./parse-error");
9
+ describe('createParseContext', () => {
10
+ let scratch;
11
+ beforeEach(() => {
12
+ scratch = (0, fs_1.mkdtempSync)((0, path_1.join)((0, os_1.tmpdir)(), 'hammerkit-schema-'));
13
+ });
14
+ afterEach(() => {
15
+ (0, fs_1.rmSync)(scratch, { recursive: true, force: true });
16
+ });
17
+ function writeBuildFile(content) {
18
+ const file = (0, path_1.join)(scratch, '.hammerkit.yaml');
19
+ (0, fs_1.writeFileSync)(file, content);
20
+ return file;
21
+ }
22
+ it('parses a valid build file', async () => {
23
+ const env = (0, environment_mock_1.environmentMock)(scratch);
24
+ const file = writeBuildFile('tasks:\n build:\n cmds:\n - echo hi\n');
25
+ const { scope } = await (0, schema_parser_1.createParseContext)(file, env);
26
+ expect(scope.schema.tasks?.build).toBeDefined();
27
+ });
28
+ it('rejects an unknown top-level key (strict schema)', async () => {
29
+ const env = (0, environment_mock_1.environmentMock)(scratch);
30
+ const file = writeBuildFile('bogus: true\ntasks:\n build:\n cmds:\n - echo hi\n');
31
+ await expect((0, schema_parser_1.createParseContext)(file, env)).rejects.toBeInstanceOf(parse_error_1.ParseError);
32
+ });
33
+ it('rejects a task with an invalid command shape', async () => {
34
+ const env = (0, environment_mock_1.environmentMock)(scratch);
35
+ const file = writeBuildFile('tasks:\n build:\n cmds: 42\n');
36
+ await expect((0, schema_parser_1.createParseContext)(file, env)).rejects.toBeInstanceOf(parse_error_1.ParseError);
37
+ });
38
+ it('resolves a reference to another build file', async () => {
39
+ const env = (0, environment_mock_1.environmentMock)(scratch);
40
+ const sub = (0, path_1.join)(scratch, 'sub');
41
+ (0, fs_1.writeFileSync)((0, path_1.join)(scratch, '.hammerkit.yaml'), 'references:\n lib: sub\ntasks:\n build:\n cmds:\n - echo root\n');
42
+ // create the referenced build file
43
+ (0, fs_1.mkdirSync)(sub);
44
+ (0, fs_1.writeFileSync)((0, path_1.join)(sub, '.hammerkit.yaml'), 'tasks:\n lib-build:\n cmds:\n - echo lib\n');
45
+ const { scope } = await (0, schema_parser_1.createParseContext)((0, path_1.join)(scratch, '.hammerkit.yaml'), env);
46
+ expect(scope.references['lib']).toBeDefined();
47
+ expect(scope.references['lib'].scope.schema.tasks?.['lib-build']).toBeDefined();
48
+ });
49
+ it('resolves an include (sibling build file merged under a name)', async () => {
50
+ const env = (0, environment_mock_1.environmentMock)(scratch);
51
+ (0, fs_1.writeFileSync)((0, path_1.join)(scratch, 'common.yaml'), 'tasks:\n shared:\n cmds:\n - echo s\n');
52
+ (0, fs_1.writeFileSync)((0, path_1.join)(scratch, '.hammerkit.yaml'), 'includes:\n npm: common.yaml\n');
53
+ const { scope } = await (0, schema_parser_1.createParseContext)((0, path_1.join)(scratch, '.hammerkit.yaml'), env);
54
+ expect(scope.references['npm']).toBeDefined();
55
+ expect(scope.references['npm'].type).toBe('include');
56
+ expect(scope.references['npm'].scope.schema.tasks?.['shared']).toBeDefined();
57
+ });
58
+ it('throws when an include and a reference share the same name', async () => {
59
+ const env = (0, environment_mock_1.environmentMock)(scratch);
60
+ const sub = (0, path_1.join)(scratch, 'sub');
61
+ (0, fs_1.mkdirSync)(sub);
62
+ (0, fs_1.writeFileSync)((0, path_1.join)(sub, '.hammerkit.yaml'), 'tasks:\n x:\n cmds:\n - echo x\n');
63
+ (0, fs_1.writeFileSync)((0, path_1.join)(scratch, 'inc.yaml'), 'tasks:\n y:\n cmds:\n - echo y\n');
64
+ (0, fs_1.writeFileSync)((0, path_1.join)(scratch, '.hammerkit.yaml'), 'references:\n lib: sub\nincludes:\n lib: inc.yaml\n');
65
+ await expect((0, schema_parser_1.createParseContext)((0, path_1.join)(scratch, '.hammerkit.yaml'), env)).rejects.toThrow(/lib already exists/);
66
+ });
67
+ it('reuses an already-parsed build file when reached again (cache hit)', async () => {
68
+ const env = (0, environment_mock_1.environmentMock)(scratch);
69
+ const sub = (0, path_1.join)(scratch, 'sub');
70
+ (0, fs_1.mkdirSync)(sub);
71
+ (0, fs_1.writeFileSync)((0, path_1.join)(sub, '.hammerkit.yaml'), 'tasks:\n s:\n cmds:\n - echo s\n');
72
+ (0, fs_1.writeFileSync)((0, path_1.join)(scratch, '.hammerkit.yaml'), 'references:\n a: sub\n b: sub\n');
73
+ const { ctx, scope } = await (0, schema_parser_1.createParseContext)((0, path_1.join)(scratch, '.hammerkit.yaml'), env);
74
+ // Both references point at sub/.hammerkit.yaml and must end up at the same
75
+ // parsed ParseScope (the second appendBuildFile hits the ctx.files cache).
76
+ expect(scope.references['a'].scope).toBe(scope.references['b'].scope);
77
+ expect(Object.keys(ctx.files)).toHaveLength(2); // root + sub (sub cached on second visit)
78
+ });
79
+ });
80
+ //# sourceMappingURL=schema-parser.spec.js.map
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const build_file_service_schema_1 = require("./build-file-service-schema");
4
+ const build_file_task_schema_1 = require("./build-file-task-schema");
5
+ describe('service/task type guards', () => {
6
+ it('isBuildFileContainerSchema discriminates by `image` presence', () => {
7
+ expect((0, build_file_service_schema_1.isBuildFileContainerSchema)({ image: 'node' })).toBe(true);
8
+ expect((0, build_file_service_schema_1.isBuildFileContainerSchema)({ selector: { name: 'n', type: 't' } })).toBe(false);
9
+ });
10
+ it('isBuildFileKubernetesServiceSchema discriminates by `selector` presence', () => {
11
+ expect((0, build_file_service_schema_1.isBuildFileKubernetesServiceSchema)({ selector: { name: 'n', type: 't' } })).toBe(true);
12
+ expect((0, build_file_service_schema_1.isBuildFileKubernetesServiceSchema)({ image: 'node' })).toBe(false);
13
+ });
14
+ it('isBuildFileContainerTaskSchema returns true iff the task has an image', () => {
15
+ expect((0, build_file_task_schema_1.isBuildFileContainerTaskSchema)({ image: 'node' })).toBe(true);
16
+ expect((0, build_file_task_schema_1.isBuildFileContainerTaskSchema)({ cmds: ['x'] })).toBe(false);
17
+ });
18
+ it('isBuildFileLocalTaskSchema returns true iff the task has no image', () => {
19
+ expect((0, build_file_task_schema_1.isBuildFileLocalTaskSchema)({ cmds: ['x'] })).toBe(true);
20
+ expect((0, build_file_task_schema_1.isBuildFileLocalTaskSchema)({ image: 'node' })).toBe(false);
21
+ });
22
+ });
23
+ //# sourceMappingURL=type-guards.spec.js.map
@@ -0,0 +1,77 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getWorkContext = exports.defaultEnvironment = void 0;
4
+ const work_scope_1 = require("../executer/work-scope");
5
+ const label_values_1 = require("../executer/label-values");
6
+ const append_work_service_1 = require("../planner/utils/append-work-service");
7
+ const append_work_task_1 = require("../planner/utils/append-work-task");
8
+ const append_work_environment_1 = require("../planner/utils/append-work-environment");
9
+ function defaultEnvironment(context) {
10
+ if ('default' in context.environments) {
11
+ const defaultEnv = context.environments['default'];
12
+ return (0, append_work_environment_1.appendWorkEnvironment)(defaultEnv);
13
+ }
14
+ return {
15
+ type: 'docker',
16
+ };
17
+ }
18
+ exports.defaultEnvironment = defaultEnvironment;
19
+ function getWorkContext(context, scope, environment) {
20
+ const workTree = { services: {}, environment: defaultEnvironment(context), tasks: {} };
21
+ const filteredWorkTree = { services: {}, environment: defaultEnvironment(context), tasks: {} };
22
+ for (const [envName, env] of Object.entries(context.environments)) {
23
+ if (envName === scope.environmentName) {
24
+ filteredWorkTree.environment = (0, append_work_environment_1.appendWorkEnvironment)(env);
25
+ workTree.environment = filteredWorkTree.environment;
26
+ }
27
+ }
28
+ for (const task of Object.values(context.tasks)) {
29
+ const item = (0, append_work_task_1.appendWorkTask)(workTree, task.cwd, task, environment, context);
30
+ if (matchesTaskWorkScope(item, scope)) {
31
+ applyTask(filteredWorkTree, item);
32
+ }
33
+ }
34
+ for (const service of Object.values(context.services)) {
35
+ const item = (0, append_work_service_1.appendWorkService)(workTree, service, environment, context);
36
+ if (matchesServiceWorkScope(item.data, scope)) {
37
+ applyService(filteredWorkTree, item);
38
+ }
39
+ }
40
+ return filteredWorkTree;
41
+ }
42
+ exports.getWorkContext = getWorkContext;
43
+ function applyTask(workTree, item) {
44
+ if (workTree.tasks[item.name]) {
45
+ return;
46
+ }
47
+ workTree.tasks[item.name] = item;
48
+ applyNeedsAndDeps(workTree, item);
49
+ }
50
+ function applyService(workTree, item) {
51
+ if (workTree.services[item.name]) {
52
+ return;
53
+ }
54
+ workTree.services[item.name] = item;
55
+ applyNeedsAndDeps(workTree, item);
56
+ }
57
+ function applyNeedsAndDeps(workTree, item) {
58
+ for (const dep of item.deps) {
59
+ applyTask(workTree, dep);
60
+ }
61
+ for (const need of item.needs) {
62
+ applyService(workTree, need.service);
63
+ }
64
+ }
65
+ function matchesTaskWorkScope(task, scope) {
66
+ if ((0, work_scope_1.isContextTaskFilter)(scope)) {
67
+ return task.name === scope.taskName;
68
+ }
69
+ return (0, label_values_1.appliesToLabels)(task.data.labels, scope);
70
+ }
71
+ function matchesServiceWorkScope(service, scope) {
72
+ if ((0, work_scope_1.isContextTaskFilter)(scope)) {
73
+ return false;
74
+ }
75
+ return (0, label_values_1.appliesToLabels)(service.labels, scope);
76
+ }
77
+ //# sourceMappingURL=work-scope-parser.js.map
@@ -0,0 +1,66 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const work_scope_parser_1 = require("./work-scope-parser");
4
+ const test_case_1 = require("../testing/test-case");
5
+ const program_1 = require("../program");
6
+ const path_1 = require("path");
7
+ async function withCli(buildFile, scope, fn) {
8
+ const testCase = (0, test_case_1.createTestCase)('work-scope-parser', { '.hammerkit.yaml': buildFile });
9
+ await testCase.setup(async (cwd, environment) => {
10
+ const cli = await (0, program_1.createCli)((0, path_1.join)(cwd, '.hammerkit.yaml'), environment, scope);
11
+ await fn(cli);
12
+ });
13
+ }
14
+ describe('work-scope-parser', () => {
15
+ describe('defaultEnvironment', () => {
16
+ it('falls back to docker when no default environment is declared', () => {
17
+ expect((0, work_scope_parser_1.defaultEnvironment)({ environments: {} })).toEqual({ type: 'docker' });
18
+ });
19
+ it('uses a declared docker default environment', () => {
20
+ const context = {
21
+ environments: { default: { schema: { docker: { host: 'tcp://remote:2375' } } } },
22
+ };
23
+ expect((0, work_scope_parser_1.defaultEnvironment)(context)).toEqual({ type: 'docker', host: 'tcp://remote:2375' });
24
+ });
25
+ it('uses a declared kubernetes default environment', () => {
26
+ const context = {
27
+ environments: { default: { schema: { kubernetes: { context: 'prod' } } } },
28
+ };
29
+ expect((0, work_scope_parser_1.defaultEnvironment)(context)).toEqual({
30
+ type: 'kubernetes',
31
+ context: 'prod',
32
+ ingresses: [],
33
+ namespace: 'default',
34
+ });
35
+ });
36
+ });
37
+ describe('getWorkContext (via createCli)', () => {
38
+ it('includes only the requested task and its dependencies', async () => {
39
+ await withCli({
40
+ tasks: {
41
+ install: { cmds: ['npm install'] },
42
+ build: { cmds: ['tsc'], deps: ['install'] },
43
+ lint: { cmds: ['eslint'] },
44
+ },
45
+ }, { taskName: 'build' }, (cli) => {
46
+ const names = cli
47
+ .tasks()
48
+ .map((t) => t.item.name)
49
+ .sort();
50
+ expect(names).toEqual(['build', 'install']);
51
+ expect(() => cli.task('lint')).toThrow('unable to find task lint');
52
+ });
53
+ });
54
+ it('filters tasks by label', async () => {
55
+ await withCli({
56
+ tasks: {
57
+ build: { cmds: ['tsc'], labels: { app: 'web' } },
58
+ lint: { cmds: ['eslint'], labels: { app: 'tool' } },
59
+ },
60
+ }, { filterLabels: { app: ['web'] } }, (cli) => {
61
+ expect(cli.tasks().map((t) => t.item.name)).toEqual(['build']);
62
+ });
63
+ });
64
+ });
65
+ });
66
+ //# sourceMappingURL=work-scope-parser.spec.js.map
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.updateServiceStatus = void 0;
4
+ const plan_work_tasks_1 = require("../planner/utils/plan-work-tasks");
5
+ async function updateServiceStatus(workTree) {
6
+ for (const service of (0, plan_work_tasks_1.iterateWorkServices)(workTree)) {
7
+ await service.runtime.initialize(service.state);
8
+ }
9
+ }
10
+ exports.updateServiceStatus = updateServiceStatus;
11
+ //# sourceMappingURL=update-service-status.js.map
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const update_service_status_1 = require("./update-service-status");
4
+ function fakeService(initialize) {
5
+ return {
6
+ state: { current: { type: 'pending' } },
7
+ runtime: { initialize },
8
+ };
9
+ }
10
+ describe('updateServiceStatus', () => {
11
+ it('calls initialize(state) on every service runtime', async () => {
12
+ const a = vi.fn().mockResolvedValue(undefined);
13
+ const b = vi.fn().mockResolvedValue(undefined);
14
+ const workTree = {
15
+ services: { svcA: fakeService(a), svcB: fakeService(b) },
16
+ tasks: {},
17
+ };
18
+ await (0, update_service_status_1.updateServiceStatus)(workTree);
19
+ expect(a).toHaveBeenCalledTimes(1);
20
+ expect(b).toHaveBeenCalledTimes(1);
21
+ });
22
+ it('is a no-op when the work tree has no services', async () => {
23
+ const workTree = { services: {}, tasks: {} };
24
+ await expect((0, update_service_status_1.updateServiceStatus)(workTree)).resolves.toBeUndefined();
25
+ });
26
+ });
27
+ //# sourceMappingURL=update-service-status.spec.js.map