1import * as Alchemy from "alchemy";
2import * as Effect from "effect/Effect";
3import * as FileSystem from "effect/FileSystem";
4import * as Path from "effect/Path";
5import * as Stream from "effect/Stream";
6import * as ChildProcess from "effect/process/ChildProcess";
7import * as ChildProcessSpawner from "effect/process/ChildProcessSpawner";
8
9const run = Effect.fn(function* (bin: string, args: string[], cwd?: string) {
10 const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
11 const result = yield* ChildProcess.make(bin, args, {
12 cwd,
13 stdin: "ignore",
14 stdout: "pipe",
15 stderr: "pipe",
16 detached: false,
17 extendEnv: true,
18 }).pipe(
19 spawner.spawn,
20 Effect.flatMap((child) =>
21 Effect.all(
22 {
23 exitCode: child.exitCode,
24 stderr: child.stderr.pipe(Stream.decodeText, Stream.mkString),
25 },
26 { concurrency: "unbounded" },
27 ),
28 ),
29 );
30 if (result.exitCode !== 0) {
31 return yield* Effect.fail(
32 new Error(
33 `${bin} ${args.join(" ")} exited ${result.exitCode}: ${result.stderr}`,
34 ),
35 );
36 }
37});
38
39/**
40 * Deploy-time Action that fetches the AWS HyperPod Helm chart (the
41 * MANDATORY dependencies — health-monitoring agent, training operators,
42 * device plugins, RBAC — that SageMaker validates before an EKS-orchestrated
43 * cluster will attach) and vendors its subcharts. Returns the local chart
44 * path for `Kubernetes.HelmChart` to render.
45 */
46export const FetchHyperPodChart = Alchemy.Action(
47 "FetchHyperPodChart",
48 (input: { repo: string }) =>
49 Effect.gen(function* () {
50 const fs = yield* FileSystem.FileSystem;
51 const path = yield* Path.Path;
52 const cwd = yield* Effect.sync(() => process.cwd());
53 const cloneDir = path.join(cwd, ".alchemy", "cache", "hyperpod-cli");
54 if (!(yield* fs.exists(path.join(cloneDir, "helm_chart")))) {
55 yield* run("git", ["clone", "--depth", "1", input.repo, cloneDir]);
56 }
57 const chartPath = path.join(cloneDir, "helm_chart", "HyperPodHelmChart");
58 yield* run("helm", ["dependency", "update", chartPath]);
59 return { chartPath };
60 }),
61);