hammerkit 1.26.0 → 1.27.0-next.10

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 (128) hide show
  1. package/build.schema.json +62 -1
  2. package/dist/cache/backends/local-cache-backend.js +10 -2
  3. package/dist/cache/backends/registry-cache-backend.js +2 -2
  4. package/dist/cache/explain.js +13 -11
  5. package/dist/cli.js +3 -0
  6. package/dist/docker/item-network.js +471 -0
  7. package/dist/docker/pull.js +4 -2
  8. package/dist/docker/remove-orphaned-containers.js +13 -6
  9. package/dist/environment/replace-env-variables.js +8 -6
  10. package/dist/executer/await-completed-dependencies.js +2 -1
  11. package/dist/executer/check-readiness.js +2 -2
  12. package/dist/executer/docker-service.js +24 -13
  13. package/dist/executer/docker-task.js +18 -29
  14. package/dist/executer/event-cache.js +24 -2
  15. package/dist/executer/execute-command.js +18 -5
  16. package/dist/executer/execute-docker.js +4 -1
  17. package/dist/executer/execution-steps.js +33 -7
  18. package/dist/executer/get-docker-executor.js +14 -7
  19. package/dist/executer/scheduler/enqueue-next.js +17 -3
  20. package/dist/executer/watch-loop.js +2 -2
  21. package/dist/executer/watch-state-key.js +1 -1
  22. package/dist/file/within-root.js +42 -0
  23. package/dist/harness/connect.js +99 -0
  24. package/dist/harness/format.js +73 -0
  25. package/dist/harness/mcp-command.js +59 -0
  26. package/dist/harness/mcp.js +432 -0
  27. package/dist/harness/opencode.js +492 -0
  28. package/dist/harness/pi.js +217 -0
  29. package/dist/harness/sandbox-client.js +411 -0
  30. package/dist/index.js +33 -36
  31. package/dist/kubernetes/apply.js +42 -1
  32. package/dist/kubernetes/await-running-state.js +33 -1
  33. package/dist/kubernetes/claim-layout.js +71 -0
  34. package/dist/kubernetes/ensure-http-route.js +1 -1
  35. package/dist/kubernetes/ensure-kubernetes-deployment-exists.js +46 -28
  36. package/dist/kubernetes/ensure-kubernetes-persistent-volume-claim-exists.js +132 -5
  37. package/dist/kubernetes/ensure-kubernetes-service-exists.js +27 -11
  38. package/dist/kubernetes/ensure-persistent-data.js +75 -24
  39. package/dist/kubernetes/get-service-ip.js +16 -2
  40. package/dist/kubernetes/job-placement.js +99 -0
  41. package/dist/kubernetes/job-secrets.js +320 -0
  42. package/dist/kubernetes/kept-claims.js +203 -0
  43. package/dist/kubernetes/kubernetes-instance.js +10 -2
  44. package/dist/kubernetes/network-gate.js +71 -0
  45. package/dist/kubernetes/network-policy.js +583 -0
  46. package/dist/kubernetes/remove-persistent-data.js +3 -1
  47. package/dist/kubernetes/resources.js +37 -4
  48. package/dist/kubernetes/restore-kubernetes-data.js +28 -7
  49. package/dist/kubernetes/secrets.js +7 -9
  50. package/dist/kubernetes/store-kubernetes-data.js +1 -1
  51. package/dist/kubernetes/volumes.js +104 -12
  52. package/dist/log.js +1 -1
  53. package/dist/main.js +41 -0
  54. package/dist/network/egress-proxy.js +407 -0
  55. package/dist/network/port-relay.js +35 -0
  56. package/dist/optimizer/get-work-cache-stats.js +16 -0
  57. package/dist/optimizer/work-task-cache-description.js +5 -2
  58. package/dist/planner/service-definition.js +5 -0
  59. package/dist/planner/utils/append-work-dependencies.js +5 -2
  60. package/dist/planner/utils/append-work-environment.js +2 -0
  61. package/dist/planner/utils/append-work-service.js +5 -0
  62. package/dist/planner/utils/append-work-task.js +20 -1
  63. package/dist/planner/utils/assert-item-paths.js +50 -0
  64. package/dist/planner/utils/hosted-volumes.js +35 -0
  65. package/dist/planner/utils/task-arguments.js +3 -0
  66. package/dist/planner/work-network.js +193 -0
  67. package/dist/planner/work-runtime-docker.js +43 -1
  68. package/dist/planner/work-runtime-kubernetes.js +370 -111
  69. package/dist/planner/work-runtime-local.js +2 -1
  70. package/dist/program.js +33 -5
  71. package/dist/remote/annotations.js +115 -0
  72. package/dist/remote/bundle-text.js +24 -0
  73. package/dist/remote/bundle.js +9 -1
  74. package/dist/remote/remote-commands.js +15 -3
  75. package/dist/remote/remote-work-commands.js +272 -71
  76. package/dist/remote/server-client.js +18 -5
  77. package/dist/remote/source-manifest.js +15 -2
  78. package/dist/remote/token-source.js +67 -0
  79. package/dist/schema/build-file-base-task-schema.js +7 -0
  80. package/dist/schema/build-file-container-service-schema.js +8 -0
  81. package/dist/schema/build-file-container-task-schema.js +3 -0
  82. package/dist/schema/build-file-environment-schema.js +9 -0
  83. package/dist/schema/network-schema.js +78 -0
  84. package/dist/schema/reference-parser.js +2 -0
  85. package/dist/schema/schema-parser.js +16 -3
  86. package/dist/schema/work-scope-parser.js +5 -0
  87. package/dist/secrets/command-secret-provider.js +73 -10
  88. package/dist/secrets/github-app-token-command.js +26 -0
  89. package/dist/secrets/github-app-token.js +191 -0
  90. package/dist/server/accounts-api.js +9 -2
  91. package/dist/server/definitions-api.js +69 -47
  92. package/dist/server/definitions.js +76 -51
  93. package/dist/server/executor.js +156 -41
  94. package/dist/server/git-checkout.js +72 -8
  95. package/dist/server/kubernetes-backend.js +603 -0
  96. package/dist/server/kubernetes-sandbox-storage.js +997 -0
  97. package/dist/server/oauth.js +12 -0
  98. package/dist/server/plan.js +88 -2
  99. package/dist/server/policy.js +104 -15
  100. package/dist/server/proposals-api.js +24 -40
  101. package/dist/server/proposals.js +12 -25
  102. package/dist/server/repo-access.js +37 -6
  103. package/dist/server/run-logs.js +217 -0
  104. package/dist/server/run-plan.js +48 -2
  105. package/dist/server/run-request.js +29 -10
  106. package/dist/server/run-store.js +5 -0
  107. package/dist/server/run-worker-command.js +13 -1
  108. package/dist/server/run-worker.js +121 -24
  109. package/dist/server/runs.js +191 -10
  110. package/dist/server/sandbox-docker.js +62 -0
  111. package/dist/server/sandbox-files-api.js +269 -0
  112. package/dist/server/sandbox-files.js +1054 -0
  113. package/dist/server/sandbox-patch.js +481 -0
  114. package/dist/server/sandbox-pod-command.js +15 -0
  115. package/dist/server/sandbox-pod.js +146 -0
  116. package/dist/server/sandbox-storage.js +462 -0
  117. package/dist/server/sandboxes-api.js +216 -0
  118. package/dist/server/sandboxes.js +519 -0
  119. package/dist/server/server-command.js +39 -20
  120. package/dist/server/server-config.js +443 -22
  121. package/dist/server/server.js +219 -40
  122. package/dist/utils/abort-on-signals.js +46 -6
  123. package/dist/utils/run-id.js +12 -0
  124. package/dist/utils/tar.js +25 -0
  125. package/harness/opencode.ts +11 -0
  126. package/harness/pi.ts +7 -0
  127. package/package.json +8 -2
  128. package/dist/remote/text-diff.js +0 -89
@@ -1,21 +1,38 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.restoreKubernetesData = void 0;
3
+ exports.restoreKubernetesData = exports.getRestoreTarget = void 0;
4
4
  const event_cache_1 = require("../executer/event-cache");
5
5
  const log_1 = require("../log");
6
- const path_1 = require("path");
7
6
  const volumes_1 = require("./volumes");
8
7
  const ensure_persistent_data_1 = require("./ensure-persistent-data");
9
- async function restoreKubernetesData(work, kubernetes, instance, environment, path) {
10
- const persistence = await (0, volumes_1.getKubernetesPersistence)(work);
8
+ const claim_layout_1 = require("./claim-layout");
9
+ // Where the upload pod (which mounts the work's claim at /dev/hammerkit/<id>) unpacks the
10
+ // archive of an output: the output's place in the claim, which its mount reads
11
+ function getRestoreTarget(work, path) {
12
+ return `/dev/hammerkit/${work.id()}/${(0, claim_layout_1.getClaimSubPath)(work, path)}`;
13
+ }
14
+ exports.getRestoreTarget = getRestoreTarget;
15
+ async function restoreKubernetesData(work, kubernetes, instance, environment, path,
16
+ // the kept claim of the work holds what an earlier run left, which goes first
17
+ options = {}) {
18
+ const persistence = await (0, volumes_1.getKubernetesPersistence)(work, kubernetes);
11
19
  await (0, ensure_persistent_data_1.getPodForPersistence)(instance, kubernetes, work, persistence, 'write', async (name) => {
20
+ if (options.reset) {
21
+ await (0, ensure_persistent_data_1.clearClaim)(instance, kubernetes, work, name);
22
+ }
12
23
  for (const generatedArchive of (0, event_cache_1.getArchivePaths)(work.data, path)) {
13
24
  if (!(await environment.file.exists(generatedArchive.filename))) {
14
25
  continue;
15
26
  }
16
- const targetPath = `/dev/hammerkit/${work.id()}/${(0, path_1.basename)(generatedArchive.path)}`;
17
- const res = await instance.exec.exec(kubernetes.namespace, name, 'volume', ['tar', 'xzf', '-', '-C', targetPath], process.stdout, process.stderr, environment.file.readStream(generatedArchive.filename), false, (status) => {
18
- work.status.write('debug', `upload ${generatedArchive.filename} to ${name}: ${status}`);
27
+ const targetPath = getRestoreTarget(work, generatedArchive.path);
28
+ // a claim made for this run (a server removes the claims of a run when it
29
+ // ends) does not have the directory of the output yet
30
+ let failure = null;
31
+ const res = await instance.exec.exec(kubernetes.namespace, name, 'volume', ['sh', '-c', 'mkdir -p "$1" && tar xzf - -C "$1"', 'sh', targetPath], process.stdout, process.stderr, environment.file.readStream(generatedArchive.filename), false, (status) => {
32
+ work.status.write('debug', `upload ${generatedArchive.filename} to ${name}: ${status.status}`);
33
+ if (status.status !== 'Success') {
34
+ failure = status.message ?? status.reason ?? 'unknown';
35
+ }
19
36
  });
20
37
  await new Promise((resolve, reject) => {
21
38
  try {
@@ -27,6 +44,10 @@ async function restoreKubernetesData(work, kubernetes, instance, environment, pa
27
44
  reject(err);
28
45
  });
29
46
  res.on('close', () => {
47
+ if (failure) {
48
+ reject(new Error(`unable to restore ${generatedArchive.path} into ${name}: ${failure}`));
49
+ return;
50
+ }
30
51
  work.status.write('debug', `uploaded ${generatedArchive.filename} to ${name}:${targetPath}`);
31
52
  resolve();
32
53
  });
@@ -6,17 +6,17 @@ const apply_1 = require("./apply");
6
6
  const resources_1 = require("./resources");
7
7
  const version_1 = require("../version");
8
8
  const SECRET_VOLUME_NAME = 'hammerkit-secrets';
9
- function getSecretResourceName(item) {
10
- return (0, resources_1.getResourceName)(item, '-secrets');
9
+ function getSecretResourceName(item, kubernetes) {
10
+ return (0, resources_1.getResourceName)(item, kubernetes, '-secrets');
11
11
  }
12
12
  exports.getSecretResourceName = getSecretResourceName;
13
13
  // The values go into a Secret of the item; the pod only references it, so no
14
14
  // value is part of a Job or Deployment spec.
15
- function getKubernetesSecretRefs(item, secrets) {
15
+ function getKubernetesSecretRefs(item, kubernetes, secrets) {
16
16
  if (secrets.length === 0) {
17
17
  return { env: [], mounts: [], volumes: [] };
18
18
  }
19
- const secretName = getSecretResourceName(item);
19
+ const secretName = getSecretResourceName(item, kubernetes);
20
20
  const refs = {
21
21
  env: [],
22
22
  mounts: [],
@@ -49,13 +49,11 @@ async function ensureKubernetesSecret(instance, kubernetes, item, secrets, envir
49
49
  apiVersion: 'v1',
50
50
  metadata: {
51
51
  namespace: kubernetes.namespace,
52
- name: getSecretResourceName(item),
52
+ name: getSecretResourceName(item, kubernetes),
53
53
  annotations: {
54
54
  'hammerkit.dev/version': (0, version_1.getVersion)(),
55
55
  },
56
- labels: {
57
- 'hammerkit.dev/id': item.id(),
58
- },
56
+ labels: (0, resources_1.getItemLabels)(item, kubernetes),
59
57
  },
60
58
  type: 'Opaque',
61
59
  stringData,
@@ -66,7 +64,7 @@ exports.ensureKubernetesSecret = ensureKubernetesSecret;
66
64
  async function removeKubernetesSecret(instance, kubernetes, item) {
67
65
  try {
68
66
  await instance.coreApi.deleteNamespacedSecret({
69
- name: getSecretResourceName(item),
67
+ name: getSecretResourceName(item, kubernetes),
70
68
  namespace: kubernetes.namespace,
71
69
  });
72
70
  }
@@ -6,7 +6,7 @@ const event_cache_1 = require("../executer/event-cache");
6
6
  const volumes_1 = require("./volumes");
7
7
  const ensure_persistent_data_1 = require("./ensure-persistent-data");
8
8
  async function storeKubernetesData(work, kubernetes, instance, environment, path) {
9
- const persistence = await (0, volumes_1.getKubernetesPersistence)(work);
9
+ const persistence = await (0, volumes_1.getKubernetesPersistence)(work, kubernetes);
10
10
  await (0, ensure_persistent_data_1.getPodForPersistence)(instance, kubernetes, work, persistence, 'read', async (name) => {
11
11
  for (const generatedArchive of (0, event_cache_1.getArchivePaths)(work.data, path)) {
12
12
  const writerStream = environment.file.createWriteStream(generatedArchive.filename);
@@ -1,37 +1,90 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.appendVolume = exports.getKubernetesPersistence = exports.getVolumeName = void 0;
3
+ exports.getSandboxAffinity = exports.SANDBOX_LABEL = exports.getWorkspacePodSpec = exports.appendVolume = exports.getKubernetesPersistence = exports.getVolumeName = void 0;
4
4
  const path_1 = require("path");
5
- function getVolumeName(service) {
6
- return 'hammerkit-' + service.id();
5
+ const fs_1 = require("fs");
6
+ const kept_claims_1 = require("./kept-claims");
7
+ const claim_layout_1 = require("./claim-layout");
8
+ function getVolumeName(service, kubernetes) {
9
+ return (0, kept_claims_1.getClaimName)(service, kubernetes);
7
10
  }
8
11
  exports.getVolumeName = getVolumeName;
9
- async function getKubernetesPersistence(work) {
10
- const persistence = { volumes: [], sources: [], mounts: [], initCommands: [] };
12
+ const WORKSPACE_VOLUME = 'hammerkit-sandbox';
13
+ // The path of `path` below the root of a sandbox's files, or undefined when it is not
14
+ // below it
15
+ function workspacePath(workspace, path) {
16
+ const rel = (0, path_1.relative)(workspace.root, path);
17
+ if (rel.startsWith('..') || (0, path_1.isAbsolute)(rel)) {
18
+ return undefined;
19
+ }
20
+ return [workspace.subPath, ...rel.split(path_1.sep).filter((part) => part.length > 0)].join('/');
21
+ }
22
+ // A path of a sandbox is mounted from its claim, read and write as on a host's docker,
23
+ // so what the task writes is in the sandbox afterwards. A path that is not in the
24
+ // sandbox is left out: Kubernetes would make a directory of it in the claim.
25
+ function appendWorkspaceMount(workspace, persistence, containerPath, localPath, isFile, readOnly) {
26
+ const subPath = workspacePath(workspace, localPath);
27
+ if (subPath === undefined) {
28
+ return false;
29
+ }
30
+ if (!(0, fs_1.existsSync)(localPath)) {
31
+ return true;
32
+ }
33
+ if (persistence.workspace.length === 0) {
34
+ persistence.workspace.push({ name: WORKSPACE_VOLUME, persistentVolumeClaim: { claimName: workspace.claim } });
35
+ }
36
+ persistence.mounts.push({
37
+ mount: { readOnly, mountPath: containerPath, name: WORKSPACE_VOLUME, subPath },
38
+ uploadPath: '',
39
+ cwd: isFile ? (0, path_1.dirname)(containerPath) : containerPath,
40
+ workspace: true,
41
+ });
42
+ return true;
43
+ }
44
+ async function getKubernetesPersistence(work, kubernetes) {
45
+ const persistence = {
46
+ volumes: [],
47
+ sizes: {},
48
+ kept: [],
49
+ workspace: [],
50
+ sources: [],
51
+ mounts: [],
52
+ initCommands: [],
53
+ };
54
+ const workspace = kubernetes.server?.workspace;
11
55
  for (const mount of work.data.mounts) {
12
- appendVolume(work, persistence, mount.containerPath, mount.localPath, mount.isFile, true);
56
+ if (workspace &&
57
+ appendWorkspaceMount(workspace, persistence, mount.containerPath, mount.localPath, mount.isFile, mount.readOnly)) {
58
+ continue;
59
+ }
60
+ appendVolume(work, persistence, mount.containerPath, mount.localPath, mount.isFile, true, kubernetes);
13
61
  }
14
62
  for (const src of work.data.src) {
15
63
  if (src.inherited) {
16
64
  continue;
17
65
  }
18
- appendVolume(work, persistence, src.absolutePath, src.absolutePath, src.isFile, true); // TODO matcher
66
+ if (workspace &&
67
+ appendWorkspaceMount(workspace, persistence, src.absolutePath, src.absolutePath, src.isFile, false)) {
68
+ continue;
69
+ }
70
+ appendVolume(work, persistence, src.absolutePath, src.absolutePath, src.isFile, true, kubernetes); // TODO matcher
19
71
  }
20
72
  if (work.data.type === 'container-task') {
21
73
  for (const generate of work.data.generates) {
22
- appendVolume(generate.inherited ?? work, persistence, generate.path, null, false, !!generate.inherited);
74
+ appendVolume(generate.inherited ?? work, persistence, generate.path, null, false, !!generate.inherited, kubernetes);
23
75
  }
24
76
  }
25
77
  else {
26
78
  for (const volume of work.data.volumes) {
27
- appendVolume(volume.inherited ?? work, persistence, volume.containerPath, null, false, !!volume.inherited || volume.readOnly);
79
+ appendVolume(volume.inherited ?? work, persistence, volume.containerPath, null, false, !!volume.inherited || volume.readOnly, kubernetes);
28
80
  }
29
81
  }
30
82
  return persistence;
31
83
  }
32
84
  exports.getKubernetesPersistence = getKubernetesPersistence;
33
- function appendVolume(sourceWork, persistence, containerPath, localPath, isFile, readOnly) {
34
- const volumeName = getVolumeName(sourceWork);
85
+ function appendVolume(sourceWork, persistence, containerPath, localPath, isFile, readOnly, kubernetes) {
86
+ const volumeName = getVolumeName(sourceWork, kubernetes);
87
+ const subPath = (0, claim_layout_1.getClaimSubPath)(sourceWork, containerPath);
35
88
  const existVolume = persistence.volumes.some((v) => v.name === volumeName);
36
89
  if (!existVolume) {
37
90
  persistence.volumes.push({
@@ -40,13 +93,17 @@ function appendVolume(sourceWork, persistence, containerPath, localPath, isFile,
40
93
  claimName: volumeName,
41
94
  },
42
95
  });
96
+ persistence.sizes[volumeName] = 'volumeSize' in sourceWork.data ? sourceWork.data.volumeSize : null;
97
+ if ((0, kept_claims_1.isKeptClaim)(sourceWork, kubernetes)) {
98
+ persistence.kept.push(volumeName);
99
+ }
43
100
  }
44
101
  persistence.mounts.push({
45
102
  mount: {
46
103
  readOnly,
47
104
  mountPath: containerPath,
48
105
  name: volumeName,
49
- subPath: (0, path_1.basename)(containerPath),
106
+ subPath,
50
107
  },
51
108
  uploadPath: `/dev/hammerkit/${sourceWork.id()}`,
52
109
  cwd: isFile ? (0, path_1.dirname)(containerPath) : containerPath,
@@ -56,9 +113,44 @@ function appendVolume(sourceWork, persistence, containerPath, localPath, isFile,
56
113
  localPath: localPath,
57
114
  matcher: () => true, // TODO
58
115
  containerPath,
116
+ subPath,
59
117
  stateKey: '', // TODO
60
118
  });
61
119
  }
62
120
  }
63
121
  exports.appendVolume = appendVolume;
122
+ /**
123
+ * What a pod that mounts the claim of a sandbox needs: its label, and to go where the
124
+ * other pods that mount it run. A claim is usually `ReadWriteOnce`, which several pods
125
+ * share only on one node; the first pod (no other one runs) goes anywhere. The pod of the
126
+ * sandbox's files runs on the first pool while a run works, so a task on another pool
127
+ * would never start: it is refused.
128
+ */
129
+ function getWorkspacePodSpec(kubernetes, persistence, task) {
130
+ const workspace = kubernetes.server?.workspace;
131
+ if (!workspace || persistence.workspace.length === 0) {
132
+ return { labels: {} };
133
+ }
134
+ const first = kubernetes.server?.pools[0]?.name;
135
+ if (task?.pool && first && task.pool !== first) {
136
+ throw new Error(`task ${task.name}: runs on the pool ${task.pool}, and the tasks of a run on a sandbox run on the first pool, ${first}, where its files are`);
137
+ }
138
+ return {
139
+ labels: { [exports.SANDBOX_LABEL]: workspace.label },
140
+ affinity: getSandboxAffinity(workspace.label),
141
+ };
142
+ }
143
+ exports.getWorkspacePodSpec = getWorkspacePodSpec;
144
+ // the label of the pods that mount the claim of a sandbox
145
+ exports.SANDBOX_LABEL = 'hammerkit.dev/sandbox';
146
+ function getSandboxAffinity(label) {
147
+ return {
148
+ podAffinity: {
149
+ requiredDuringSchedulingIgnoredDuringExecution: [
150
+ { labelSelector: { matchLabels: { [exports.SANDBOX_LABEL]: label } }, topologyKey: 'kubernetes.io/hostname' },
151
+ ],
152
+ },
153
+ };
154
+ }
155
+ exports.getSandboxAffinity = getSandboxAffinity;
64
156
  //# sourceMappingURL=volumes.js.map
package/dist/log.js CHANGED
@@ -216,7 +216,7 @@ function writeWorkItemLogToConsole(env, log, maxNodeNameLength) {
216
216
  exports.writeWorkItemLogToConsole = writeWorkItemLogToConsole;
217
217
  function formatDate(date) {
218
218
  return colors_1.default.grey(`[${date.getFullYear()}-${(date.getMonth() + 1).toString().padStart(2, '0')}-${date
219
- .getDay()
219
+ .getDate()
220
220
  .toString()
221
221
  .padStart(2, '0')} ${date.getHours().toString().padStart(2, '0')}:${date
222
222
  .getMinutes()
package/dist/main.js ADDED
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ // The CLI: what `hammerkit` runs, for all but the command of a sandbox's pod (see index.ts).
4
+ const log_1 = require("./log");
5
+ const get_file_context_1 = require("./file/get-file-context");
6
+ const work_item_status_1 = require("./planner/work-item-status");
7
+ const redact_1 = require("./utils/redact");
8
+ const empty_writable_1 = require("./utils/empty-writable");
9
+ const run_program_1 = require("./run-program");
10
+ const abort_on_signals_1 = require("./utils/abort-on-signals");
11
+ const abortCtrl = new AbortController();
12
+ (0, abort_on_signals_1.abortOnSignals)(process, abortCtrl);
13
+ let settled = false;
14
+ // A run that never settles (a task waiting on something that can't happen)
15
+ // lets the event loop drain, and Node then exits 0: CI would report success
16
+ // for a build that never finished. Fail loudly instead.
17
+ process.on('beforeExit', () => {
18
+ if (!settled) {
19
+ process.stderr.write('hammerkit stopped before the run finished\n');
20
+ process.exitCode = 1;
21
+ }
22
+ });
23
+ const secrets = (0, redact_1.createSecretRegistry)();
24
+ (0, run_program_1.runProgram)({
25
+ cwd: process.cwd(),
26
+ abortCtrl,
27
+ processEnvs: process.env,
28
+ file: (0, get_file_context_1.getFileContext)(process.cwd()),
29
+ console: (0, log_1.consoleContext)(process.stdout),
30
+ status: (0, work_item_status_1.statusConsole)((0, empty_writable_1.emptyWritable)(), secrets),
31
+ secrets,
32
+ stdout: process.stdout,
33
+ stderr: process.stderr,
34
+ stdoutColumns: process.stdout.columns,
35
+ }, process.argv, false).then(() => {
36
+ settled = true;
37
+ }, () => {
38
+ settled = true;
39
+ process.exit(1);
40
+ });
41
+ //# sourceMappingURL=main.js.map