alasio 4.0.0
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.
- package/dist/cli/src/cluster/docker.js +219 -0
- package/dist/cli/src/cluster/docker.js.map +1 -0
- package/dist/cli/src/cluster/local.js +392 -0
- package/dist/cli/src/cluster/local.js.map +1 -0
- package/dist/cli/src/commands/common.js +108 -0
- package/dist/cli/src/commands/common.js.map +1 -0
- package/dist/cli/src/commands/down.js +26 -0
- package/dist/cli/src/commands/down.js.map +1 -0
- package/dist/cli/src/commands/init.js +314 -0
- package/dist/cli/src/commands/init.js.map +1 -0
- package/dist/cli/src/commands/lake.js +33 -0
- package/dist/cli/src/commands/lake.js.map +1 -0
- package/dist/cli/src/commands/login.js +38 -0
- package/dist/cli/src/commands/login.js.map +1 -0
- package/dist/cli/src/commands/logs.js +27 -0
- package/dist/cli/src/commands/logs.js.map +1 -0
- package/dist/cli/src/commands/restart.js +23 -0
- package/dist/cli/src/commands/restart.js.map +1 -0
- package/dist/cli/src/commands/status.js +58 -0
- package/dist/cli/src/commands/status.js.map +1 -0
- package/dist/cli/src/commands/uninstall.js +47 -0
- package/dist/cli/src/commands/uninstall.js.map +1 -0
- package/dist/cli/src/commands/up.js +33 -0
- package/dist/cli/src/commands/up.js.map +1 -0
- package/dist/cli/src/commands/upgrade.js +50 -0
- package/dist/cli/src/commands/upgrade.js.map +1 -0
- package/dist/cli/src/commands.js +16 -0
- package/dist/cli/src/commands.js.map +1 -0
- package/dist/cli/src/config.js +169 -0
- package/dist/cli/src/config.js.map +1 -0
- package/dist/cli/src/images.js +7 -0
- package/dist/cli/src/images.js.map +1 -0
- package/dist/cli/src/install.js +39 -0
- package/dist/cli/src/install.js.map +1 -0
- package/dist/cli/src/kube/api.js +231 -0
- package/dist/cli/src/kube/api.js.map +1 -0
- package/dist/cli/src/kube/apply.js +98 -0
- package/dist/cli/src/kube/apply.js.map +1 -0
- package/dist/cli/src/kube/rollout.js +166 -0
- package/dist/cli/src/kube/rollout.js.map +1 -0
- package/dist/cli/src/main.js +30 -0
- package/dist/cli/src/main.js.map +1 -0
- package/dist/cli/src/manifests/agent-sandbox.js +89 -0
- package/dist/cli/src/manifests/agent-sandbox.js.map +1 -0
- package/dist/cli/src/manifests/alasio.js +367 -0
- package/dist/cli/src/manifests/alasio.js.map +1 -0
- package/dist/cli/src/manifests/common.js +157 -0
- package/dist/cli/src/manifests/common.js.map +1 -0
- package/dist/cli/src/manifests/config.js +283 -0
- package/dist/cli/src/manifests/config.js.map +1 -0
- package/dist/cli/src/manifests/index.js +20 -0
- package/dist/cli/src/manifests/index.js.map +1 -0
- package/dist/cli/src/manifests/lake.js +56 -0
- package/dist/cli/src/manifests/lake.js.map +1 -0
- package/dist/cli/src/manifests/neon.js +656 -0
- package/dist/cli/src/manifests/neon.js.map +1 -0
- package/dist/cli/src/manifests/network-policies.js +86 -0
- package/dist/cli/src/manifests/network-policies.js.map +1 -0
- package/dist/cli/src/manifests/object-store.js +204 -0
- package/dist/cli/src/manifests/object-store.js.map +1 -0
- package/dist/cli/src/manifests/sandboxes.agents.x-k8s.io.json +6295 -0
- package/dist/cli/src/release.js +15 -0
- package/dist/cli/src/release.js.map +1 -0
- package/dist/cli/src/secrets.js +49 -0
- package/dist/cli/src/secrets.js.map +1 -0
- package/dist/cli/src/target.js +55 -0
- package/dist/cli/src/target.js.map +1 -0
- package/dist/cli/src/telegram.js +27 -0
- package/dist/cli/src/telegram.js.map +1 -0
- package/dist/src/kube/config.js +99 -0
- package/dist/src/kube/config.js.map +1 -0
- package/package.json +32 -0
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/** `alasio login codex`: Codex's device login, run in alasio's pod, at this terminal. */
|
|
2
|
+
import { PassThrough } from "node:stream";
|
|
3
|
+
import { Effect } from "effect";
|
|
4
|
+
import { Command } from "effect/cli";
|
|
5
|
+
import { KubeApi } from "../kube/api.js";
|
|
6
|
+
import { NAMESPACE, RELEASE } from "../manifests/common.js";
|
|
7
|
+
import { CommandFailed, onCluster, runningPod } from "./common.js";
|
|
8
|
+
/** Codex's login by a code entered on another device, as alasio's image installs Codex (Dockerfile). */
|
|
9
|
+
export const CODEX_LOGIN = ["/opt/alasio/node_modules/.bin/codex", "login", "--device-auth"];
|
|
10
|
+
/**
|
|
11
|
+
* What is typed at this process's terminal, while `use` runs with it: raw, so it reaches
|
|
12
|
+
* the command in the pod as typed, and let go of after, as it was, so this process can
|
|
13
|
+
* end.
|
|
14
|
+
*/
|
|
15
|
+
const terminalInput = (use) => Effect.acquireUseRelease(Effect.sync(() => {
|
|
16
|
+
const input = new PassThrough();
|
|
17
|
+
if (process.stdin.isTTY)
|
|
18
|
+
process.stdin.setRawMode(true);
|
|
19
|
+
process.stdin.pipe(input);
|
|
20
|
+
return input;
|
|
21
|
+
}), use, (input) => Effect.sync(() => {
|
|
22
|
+
process.stdin.unpipe(input);
|
|
23
|
+
process.stdin.pause();
|
|
24
|
+
if (process.stdin.isTTY)
|
|
25
|
+
process.stdin.setRawMode(false);
|
|
26
|
+
input.end();
|
|
27
|
+
}));
|
|
28
|
+
const codex = Command.make("codex", {}, () => onCluster(() => Effect.gen(function* () {
|
|
29
|
+
const kube = yield* KubeApi;
|
|
30
|
+
const pod = yield* runningPod(RELEASE);
|
|
31
|
+
// The terminal itself, not alasio's output: what Codex asks and is answered is the operator's.
|
|
32
|
+
const exitCode = yield* terminalInput((stdin) => kube.exec({ namespace: NAMESPACE, pod, container: RELEASE }, CODEX_LOGIN, { stdin, stdout: process.stdout, stderr: process.stderr, tty: process.stdout.isTTY }));
|
|
33
|
+
if (exitCode !== 0)
|
|
34
|
+
return yield* new CommandFailed({ command: "codex login", exitCode });
|
|
35
|
+
}))).pipe(Command.withShortDescription("Log Codex in"), Command.withDescription("Runs Codex's device login in alasio's pod, at this terminal: Codex shows a code to enter on a page it names, " +
|
|
36
|
+
"and keeps the login on alasio's volume, so it is done once."));
|
|
37
|
+
export const login = Command.make("login").pipe(Command.withSubcommands([codex]), Command.withShortDescription("Log a harness in"), Command.withDescription("Logs a harness in, in alasio's pod. Claude Code needs none: alasio init gives it a token."));
|
|
38
|
+
//# sourceMappingURL=login.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"login.js","sourceRoot":"","sources":["../../../../src/commands/login.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/** `alasio logs [component]`: what alasio, or one of its components, logs. */
|
|
2
|
+
import { Duration, Effect, Option, Stdio, Stream } from "effect";
|
|
3
|
+
import { Argument, Command, Flag } from "effect/cli";
|
|
4
|
+
import { KubeApi } from "../kube/api.js";
|
|
5
|
+
import { NAMESPACE } from "../manifests/common.js";
|
|
6
|
+
import { component, onCluster, podsOf, sinceFlag } from "./common.js";
|
|
7
|
+
export const logs = Command.make("logs", {
|
|
8
|
+
component: Argument.String("component").pipe(Argument.withDefault("alasio"), Argument.withDescription("The component: alasio (the default), or another, such as lake or neon-compute; alasio status lists them")),
|
|
9
|
+
follow: Flag.Boolean("follow").pipe(Flag.withAlias("f"), Flag.withDefault(false), Flag.withDescription("Keep following what it logs")),
|
|
10
|
+
since: sinceFlag,
|
|
11
|
+
}, ({ component: name, follow, since }) => onCluster(() => Effect.gen(function* () {
|
|
12
|
+
const kube = yield* KubeApi;
|
|
13
|
+
const stdio = yield* Stdio.Stdio;
|
|
14
|
+
const found = yield* component(name);
|
|
15
|
+
const pods = yield* podsOf(found);
|
|
16
|
+
const container = found.workload.spec?.template?.spec?.containers?.[0]?.name ?? name;
|
|
17
|
+
const sinceSeconds = Option.map(since, (duration) => Math.ceil(Duration.toSeconds(duration)));
|
|
18
|
+
// A component of several pods (the safekeepers, say) has each line said with its pod's name.
|
|
19
|
+
const prefixed = pods.length > 1;
|
|
20
|
+
const streams = pods.map((pod) => {
|
|
21
|
+
const podName = pod.metadata?.name ?? "";
|
|
22
|
+
return kube.logs(NAMESPACE, podName, { container, follow, sinceSeconds: Option.getOrUndefined(sinceSeconds) }).pipe(Stream.decodeText(), Stream.splitLines, Stream.map((line) => `${prefixed ? `[${podName}] ` : ""}${line}\n`));
|
|
23
|
+
});
|
|
24
|
+
yield* Stream.mergeAll(streams, { concurrency: "unbounded" }).pipe(Stream.run(stdio.stdout()));
|
|
25
|
+
}))).pipe(Command.withShortDescription("Show what alasio, or one of its components, logs"), Command.withDescription("Shows what alasio's pod logs, or a component's pods: each line of a component of several pods begins with its pod's name. " +
|
|
26
|
+
"With --follow it keeps following until interrupted; with --since, only what was logged since then."));
|
|
27
|
+
//# sourceMappingURL=logs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logs.js","sourceRoot":"","sources":["../../../../src/commands/logs.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/** `alasio restart`: a rollout restart of alasio's Deployment, waited for. */
|
|
2
|
+
import { Console, Effect } from "effect";
|
|
3
|
+
import { Command } from "effect/cli";
|
|
4
|
+
import { kind, KubeApi } from "../kube/api.js";
|
|
5
|
+
import { awaitReady } from "../kube/rollout.js";
|
|
6
|
+
import { NAMESPACE, RELEASE } from "../manifests/common.js";
|
|
7
|
+
import { onCluster, timeoutFlag, waitOptions } from "./common.js";
|
|
8
|
+
/** alasio's Deployment. */
|
|
9
|
+
const DEPLOYMENT = { ...kind("Deployment"), namespace: NAMESPACE, name: RELEASE };
|
|
10
|
+
/**
|
|
11
|
+
* The manager the restart's annotation is patched as: not alasio, whose applies would
|
|
12
|
+
* otherwise take it back off, restarting alasio again.
|
|
13
|
+
*/
|
|
14
|
+
const RESTART_MANAGER = "alasio-restart";
|
|
15
|
+
export const restart = Command.make("restart", { timeout: timeoutFlag }, ({ timeout }) => onCluster(() => Effect.gen(function* () {
|
|
16
|
+
const kube = yield* KubeApi;
|
|
17
|
+
yield* kube.patch(DEPLOYMENT, { spec: { template: { metadata: { annotations: { "kubectl.kubernetes.io/restartedAt": new Date().toISOString() } } } } }, RESTART_MANAGER);
|
|
18
|
+
yield* Effect.logInfo("restarting alasio");
|
|
19
|
+
yield* awaitReady([DEPLOYMENT], waitOptions(timeout));
|
|
20
|
+
yield* Console.log("alasio restarted; a turn it was running continues.");
|
|
21
|
+
}))).pipe(Command.withShortDescription("Restart alasio"), Command.withDescription("Restarts alasio's pod, as a rollout restart of its Deployment does, and waits until it runs again. " +
|
|
22
|
+
"Conversations survive it: a turn it was running continues once alasio is back, and workspaces keep running through it."));
|
|
23
|
+
//# sourceMappingURL=restart.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"restart.js","sourceRoot":"","sources":["../../../../src/commands/restart.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAErC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAElE,2BAA2B;AAC3B,MAAM,UAAU,GAAG,EAAE,GAAG,IAAI,CAAC,YAAY,CAAC,EAAE,SAAS,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;AAElF;;;GAGG;AACH,MAAM,eAAe,GAAG,gBAAgB,CAAC;AAEzC,MAAM,CAAC,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,SAAS,EAAE,EAAE,OAAO,EAAE,WAAW,EAAE,EAAE,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CACvF,SAAS,CAAC,GAAG,EAAE,CACb,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;IAClB,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,OAAO,CAAC;IAC5B,KAAK,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,EAAE,EAAE,IAAI,EAAE,EAAE,QAAQ,EAAE,EAAE,QAAQ,EAAE,EAAE,WAAW,EAAE,EAAE,mCAAmC,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,eAAe,CAAC,CAAC;IACzK,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,mBAAmB,CAAC,CAAC;IAC3C,KAAK,CAAC,CAAC,UAAU,CAAC,CAAC,UAAU,CAAC,EAAE,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC;IACtD,KAAK,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,oDAAoD,CAAC,CAAC;AAC3E,CAAC,CAAC,CACH,CAAC,CAAC,IAAI,CACL,OAAO,CAAC,oBAAoB,CAAC,gBAAgB,CAAC,EAC9C,OAAO,CAAC,eAAe,CACrB,qGAAqG;IACnG,wHAAwH,CAC3H,CACF,CAAC"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/** `alasio status`: what runs, and whether it is healthy. */
|
|
2
|
+
import { Console, Effect, Schema } from "effect";
|
|
3
|
+
import { Command } from "effect/cli";
|
|
4
|
+
import { LocalCluster } from "../cluster/local.js";
|
|
5
|
+
import { loadConfig } from "../config.js";
|
|
6
|
+
import { describeRef, kind, KubeApi, refOf } from "../kube/api.js";
|
|
7
|
+
import { INSTALLATION_SELECTOR } from "../kube/apply.js";
|
|
8
|
+
import { diagnose, readiness } from "../kube/rollout.js";
|
|
9
|
+
import { RELEASE } from "../manifests/common.js";
|
|
10
|
+
import { describeTarget, kubeApi, localCluster, resolveTarget } from "../target.js";
|
|
11
|
+
import { ClusterNotRunning } from "./common.js";
|
|
12
|
+
/** Some of alasio's workloads do not run as they should. */
|
|
13
|
+
export class Unhealthy extends Schema.TaggedError()("Unhealthy", {
|
|
14
|
+
notReady: Schema.Number,
|
|
15
|
+
of: Schema.Number,
|
|
16
|
+
}) {
|
|
17
|
+
get message() {
|
|
18
|
+
return this.of === 0
|
|
19
|
+
? "alasio is not installed in this cluster: alasio up installs it"
|
|
20
|
+
: `${this.notReady} of alasio's ${this.of} workloads are not ready`;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
export const status = Command.make("status", {}, () => Effect.gen(function* () {
|
|
24
|
+
const config = yield* loadConfig;
|
|
25
|
+
const target = yield* resolveTarget(config);
|
|
26
|
+
if (target._tag === "Local") {
|
|
27
|
+
const { docker, nodes } = yield* Effect.provide(Effect.flatMap(LocalCluster, (cluster) => cluster.status), localCluster(target.cluster));
|
|
28
|
+
yield* Console.log(`cluster ${target.cluster.name}, in Docker ${docker}:`);
|
|
29
|
+
yield* Console.log(nodes.length > 0 ? nodes.map(({ name, state }) => ` ${name}: ${state}`).join("\n") : " not made");
|
|
30
|
+
const server = nodes.find(({ role }) => role === "server");
|
|
31
|
+
if (server?.state !== "running")
|
|
32
|
+
return yield* new ClusterNotRunning({ cluster: target.cluster.name, made: server !== undefined });
|
|
33
|
+
}
|
|
34
|
+
yield* Effect.provide(Effect.gen(function* () {
|
|
35
|
+
const kube = yield* KubeApi;
|
|
36
|
+
const workloads = (yield* Effect.forEach(["Deployment", "StatefulSet"], (name) => kube.list(kind(name), { labelSelector: INSTALLATION_SELECTOR })))
|
|
37
|
+
.flat()
|
|
38
|
+
.sort((a, b) => (a.metadata?.name ?? "").localeCompare(b.metadata?.name ?? ""));
|
|
39
|
+
const version = workloads.find((object) => object.kind === "Deployment" && object.metadata?.name === RELEASE)?.metadata?.labels?.["app.kubernetes.io/version"];
|
|
40
|
+
yield* Console.log(`alasio${version ? ` ${version}` : ""}, in ${describeTarget(target)} (${kube.server}):`);
|
|
41
|
+
let notReady = 0;
|
|
42
|
+
for (const workload of workloads) {
|
|
43
|
+
const state = readiness(workload);
|
|
44
|
+
if (state._tag === "Ready") {
|
|
45
|
+
yield* Console.log(` ${describeRef(refOf(workload))}: ready`);
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
notReady += 1;
|
|
49
|
+
yield* Console.log(` ${describeRef(refOf(workload))}: ${state._tag === "Waiting" ? state.status : state.reason}`);
|
|
50
|
+
for (const line of yield* diagnose(refOf(workload)))
|
|
51
|
+
yield* Console.log(` ${line}`);
|
|
52
|
+
}
|
|
53
|
+
if (workloads.length === 0 || notReady > 0)
|
|
54
|
+
return yield* new Unhealthy({ notReady, of: workloads.length });
|
|
55
|
+
}), kubeApi(target));
|
|
56
|
+
})).pipe(Command.withShortDescription("Say what runs, and whether it is healthy"), Command.withDescription("Says where alasio runs (and, for the cluster on this machine, its nodes), its version, and each of its workloads: " +
|
|
57
|
+
"ready, or what it is at and why. Exits with 1 when something is not ready."));
|
|
58
|
+
//# sourceMappingURL=status.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status.js","sourceRoot":"","sources":["../../../../src/commands/status.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/** `alasio uninstall [--purge]`: removes alasio, and with --purge its data and the cluster on this machine. */
|
|
2
|
+
import { Console, Effect, FileSystem, Schema } from "effect";
|
|
3
|
+
import { Command, Flag, Prompt } from "effect/cli";
|
|
4
|
+
import { LocalCluster } from "../cluster/local.js";
|
|
5
|
+
import { loadConfig } from "../config.js";
|
|
6
|
+
import { removeInstallation } from "../kube/apply.js";
|
|
7
|
+
import { describeTarget, localCluster, resolveTarget } from "../target.js";
|
|
8
|
+
import { onCluster, timeoutFlag, waitOptions } from "./common.js";
|
|
9
|
+
/** The operator did not confirm. */
|
|
10
|
+
export class NotConfirmed extends Schema.TaggedError()("NotConfirmed", {}) {
|
|
11
|
+
get message() {
|
|
12
|
+
return "nothing was removed";
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
export const uninstall = Command.make("uninstall", {
|
|
16
|
+
purge: Flag.Boolean("purge").pipe(Flag.withDefault(false), Flag.withDescription("Also remove alasio's data: its database, its own and its workspaces' volumes, its Secrets; and the cluster on this machine, if that is where it runs")),
|
|
17
|
+
yes: Flag.Boolean("yes").pipe(Flag.withAlias("y"), Flag.withDefault(false), Flag.withDescription("Do not ask for confirmation")),
|
|
18
|
+
timeout: timeoutFlag,
|
|
19
|
+
}, ({ purge, yes, timeout }) => Effect.gen(function* () {
|
|
20
|
+
const config = yield* loadConfig;
|
|
21
|
+
const target = yield* resolveTarget(config);
|
|
22
|
+
const where = describeTarget(target);
|
|
23
|
+
const confirmed = yes || (yield* Prompt.run(Prompt.Confirm({
|
|
24
|
+
message: purge
|
|
25
|
+
? `Remove alasio and all its data from ${where}${target._tag === "Local" ? ", and the cluster itself" : ""}? This cannot be undone`
|
|
26
|
+
: `Remove alasio from ${where}, keeping its data?`,
|
|
27
|
+
initial: false,
|
|
28
|
+
})));
|
|
29
|
+
if (!confirmed)
|
|
30
|
+
return yield* new NotConfirmed();
|
|
31
|
+
if (purge && target._tag === "Local") {
|
|
32
|
+
// The cluster is alasio's own: removing it, with its volumes and storage, removes everything.
|
|
33
|
+
yield* Effect.provide(Effect.flatMap(LocalCluster, (cluster) => cluster.remove({ volumes: true, storage: true })), localCluster(target.cluster));
|
|
34
|
+
yield* Effect.flatMap(FileSystem.FileSystem, (fs) => fs.remove(target.kubeconfig.path, { force: true }));
|
|
35
|
+
yield* Console.log(`alasio and the cluster ${target.cluster.name} are removed, with all their data; the config at ${config.path} is kept.`);
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
const removed = yield* onCluster(() => removeInstallation({ purge }, waitOptions(timeout)));
|
|
39
|
+
yield* Console.log(removed.length === 0
|
|
40
|
+
? `alasio is not installed in ${where}.`
|
|
41
|
+
: purge
|
|
42
|
+
? `alasio is removed from ${where}, with all its data.`
|
|
43
|
+
: `alasio is removed from ${where}; its volumes, namespaces and Secrets are kept, and alasio up installs it again with them.`);
|
|
44
|
+
})).pipe(Command.withShortDescription("Remove alasio"), Command.withDescription("Removes alasio's objects from its cluster, after confirmation, keeping what holds data: volumes, namespaces (with alasio's Secrets " +
|
|
45
|
+
"and its workspaces), and the Sandbox CRD, so alasio up installs it again as it was. With --purge it removes those too, and " +
|
|
46
|
+
"when alasio runs in the cluster it made on this machine, that cluster with all it keeps. The config file is kept either way."));
|
|
47
|
+
//# sourceMappingURL=uninstall.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"uninstall.js","sourceRoot":"","sources":["../../../../src/commands/uninstall.ts"],"names":[],"mappings":"AAAA,+GAA+G;AAC/G,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC7D,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAEnD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC3E,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAElE,oCAAoC;AACpC,MAAM,OAAO,YAAa,SAAQ,MAAM,CAAC,WAAW,EAAgB,CAAC,cAAc,EAAE,EAAE,CAAC;IACtF,IAAa,OAAO;QAClB,OAAO,qBAAqB,CAAC;IAC/B,CAAC;CACF;AAED,MAAM,CAAC,MAAM,SAAS,GAAG,OAAO,CAAC,IAAI,CACnC,WAAW,EACX;IACE,KAAK,EAAE,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,IAAI,CAC/B,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,EACvB,IAAI,CAAC,eAAe,CAAC,sJAAsJ,CAAC,CAC7K;IACD,GAAG,EAAE,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC,eAAe,CAAC,6BAA6B,CAAC,CAAC;IAChI,OAAO,EAAE,WAAW;CACrB,EACD,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,OAAO,EAAE,EAAE,EAAE,CAC1B,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;IAClB,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,UAAU,CAAC;IACjC,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC;IAC5C,MAAM,KAAK,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC;IACrC,MAAM,SAAS,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC;QACzD,OAAO,EAAE,KAAK;YACZ,CAAC,CAAC,uCAAuC,KAAK,GAAG,MAAM,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,0BAA0B,CAAC,CAAC,CAAC,EAAE,yBAAyB;YACnI,CAAC,CAAC,sBAAsB,KAAK,qBAAqB;QACpD,OAAO,EAAE,KAAK;KACf,CAAC,CAAC,CAAC,CAAC;IACL,IAAI,CAAC,SAAS;QAAE,OAAO,KAAK,CAAC,CAAC,IAAI,YAAY,EAAE,CAAC;IACjD,IAAI,KAAK,IAAI,MAAM,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;QACrC,8FAA8F;QAC9F,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,YAAY,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,YAAY,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;QACjJ,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,UAAU,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;QACzG,KAAK,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,0BAA0B,MAAM,CAAC,OAAO,CAAC,IAAI,oDAAoD,MAAM,CAAC,IAAI,WAAW,CAAC,CAAC;QAC5I,OAAO;IACT,CAAC;IACD,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,SAAS,CAAC,GAAG,EAAE,CAAC,kBAAkB,CAAC,EAAE,KAAK,EAAE,EAAE,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;IAC5F,KAAK,CAAC,CAAC,OAAO,CAAC,GAAG,CAChB,OAAO,CAAC,MAAM,KAAK,CAAC;QAClB,CAAC,CAAC,8BAA8B,KAAK,GAAG;QACxC,CAAC,CAAC,KAAK;YACP,CAAC,CAAC,0BAA0B,KAAK,sBAAsB;YACvD,CAAC,CAAC,0BAA0B,KAAK,4FAA4F,CAChI,CAAC;AACJ,CAAC,CAAC,CACL,CAAC,IAAI,CACJ,OAAO,CAAC,oBAAoB,CAAC,eAAe,CAAC,EAC7C,OAAO,CAAC,eAAe,CACrB,qIAAqI;IACnI,6HAA6H;IAC7H,8HAA8H,CACjI,CACF,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/** `alasio up`: makes or starts the local cluster, applies alasio, and waits until it runs. */
|
|
2
|
+
import { Console, Effect } from "effect";
|
|
3
|
+
import { Command } from "effect/cli";
|
|
4
|
+
import { LocalCluster } from "../cluster/local.js";
|
|
5
|
+
import { loadConfig } from "../config.js";
|
|
6
|
+
import { install } from "../install.js";
|
|
7
|
+
import { VERSION } from "../release.js";
|
|
8
|
+
import { describeTarget, kubeApi, localCluster, resolveTarget } from "../target.js";
|
|
9
|
+
import { timeoutFlag, waitOptions } from "./common.js";
|
|
10
|
+
/** Makes or starts the local cluster when it is the target, writing its kubeconfig; nothing for another. */
|
|
11
|
+
export const ensureCluster = (target) => target._tag === "Local"
|
|
12
|
+
? Effect.provide(Effect.flatMap(LocalCluster, (cluster) => cluster.up(target.kubeconfig.path)), localCluster(target.cluster))
|
|
13
|
+
: Effect.void;
|
|
14
|
+
/** Where alasio runs, and what the operator does next. */
|
|
15
|
+
export const announce = (target, { bot, claude }) => Console.log([
|
|
16
|
+
`alasio ${VERSION} runs in ${describeTarget(target)}.`,
|
|
17
|
+
"",
|
|
18
|
+
`Message ${bot.username ? `@${bot.username}` : "your bot"} on Telegram to talk to it.`,
|
|
19
|
+
...(claude ? [] : ["Claude Code has no token yet: alasio init asks for one, which `claude setup-token` makes."]),
|
|
20
|
+
"Codex logs in once, in alasio: alasio login codex",
|
|
21
|
+
"alasio status says how it is, and alasio logs --follow follows it.",
|
|
22
|
+
].join("\n"));
|
|
23
|
+
/** Brings up what `config` describes, waiting `timeout` at most for it to run. */
|
|
24
|
+
export const bringUp = Effect.fnUntraced(function* (config, timeout) {
|
|
25
|
+
const target = yield* resolveTarget(config);
|
|
26
|
+
yield* ensureCluster(target);
|
|
27
|
+
const installed = yield* Effect.provide(install(config, waitOptions(timeout)), kubeApi(target));
|
|
28
|
+
yield* announce(target, installed);
|
|
29
|
+
});
|
|
30
|
+
export const up = Command.make("up", { timeout: timeoutFlag }, ({ timeout }) => Effect.flatMap(loadConfig, (config) => bringUp(config, timeout))).pipe(Command.withShortDescription("Start alasio, installing or updating it"), Command.withDescription("Makes the cluster on this machine, or starts it, when that is where alasio runs; applies alasio as the config says, " +
|
|
31
|
+
"with this version's images; and waits until it runs, saying what it waits for. Run it again after changing the config. " +
|
|
32
|
+
"Past --timeout it says what is still not running and why."));
|
|
33
|
+
//# sourceMappingURL=up.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"up.js","sourceRoot":"","sources":["../../../../src/commands/up.ts"],"names":[],"mappings":"AAAA,+FAA+F;AAC/F,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAErC,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,UAAU,EAAuB,MAAM,cAAc,CAAC;AAC/D,OAAO,EAAE,OAAO,EAAkB,MAAM,eAAe,CAAC;AACxD,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxC,OAAO,EAAE,cAAc,EAAE,OAAO,EAAE,YAAY,EAAuB,aAAa,EAAE,MAAM,cAAc,CAAC;AACzG,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAEvD,4GAA4G;AAC5G,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,MAAsB,EAAE,EAAE,CACtD,MAAM,CAAC,IAAI,KAAK,OAAO;IACrB,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,YAAY,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,EAAE,YAAY,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAC7H,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC;AAElB,0DAA0D;AAC1D,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,MAAsB,EAAE,EAAE,GAAG,EAAE,MAAM,EAAa,EAAuB,EAAE,CAClG,OAAO,CAAC,GAAG,CACT;IACE,UAAU,OAAO,YAAY,cAAc,CAAC,MAAM,CAAC,GAAG;IACtD,EAAE;IACF,WAAW,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,UAAU,6BAA6B;IACtF,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,2FAA2F,CAAC,CAAC;IAChH,mDAAmD;IACnD,oEAAoE;CACrE,CAAC,IAAI,CAAC,IAAI,CAAC,CACb,CAAC;AAEJ,kFAAkF;AAClF,MAAM,CAAC,MAAM,OAAO,GAAG,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAC,MAAsB,EAAE,OAA0C;IACnH,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC;IAC5C,KAAK,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC;IAC7B,MAAM,SAAS,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;IAChG,KAAK,CAAC,CAAC,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;AACrC,CAAC,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,OAAO,EAAE,WAAW,EAAE,EAAE,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CACpJ,OAAO,CAAC,oBAAoB,CAAC,yCAAyC,CAAC,EACvE,OAAO,CAAC,eAAe,CACrB,sHAAsH;IACpH,yHAAyH;IACzH,2DAA2D,CAC9D,CACF,CAAC"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { Console, Effect } from "effect";
|
|
2
|
+
import { Command } from "effect/cli";
|
|
3
|
+
import { loadConfig } from "../config.js";
|
|
4
|
+
import { install, installationObjects, installConfig } from "../install.js";
|
|
5
|
+
import { kind, KubeApi } from "../kube/api.js";
|
|
6
|
+
import { INSTALLATION_SELECTOR } from "../kube/apply.js";
|
|
7
|
+
import { RELEASE } from "../manifests/common.js";
|
|
8
|
+
import { VERSION } from "../release.js";
|
|
9
|
+
import { kubeApi, resolveTarget } from "../target.js";
|
|
10
|
+
import { timeoutFlag, waitOptions } from "./common.js";
|
|
11
|
+
import { announce, ensureCluster } from "./up.js";
|
|
12
|
+
const WORKLOADS = ["Deployment", "StatefulSet", "CronJob"];
|
|
13
|
+
/** The images each workload of `objects` runs, by its name. */
|
|
14
|
+
function imagesOf(objects) {
|
|
15
|
+
return new Map(objects
|
|
16
|
+
.filter((object) => WORKLOADS.some((name) => name === object.kind))
|
|
17
|
+
.map((object) => {
|
|
18
|
+
const { spec } = object;
|
|
19
|
+
const pod = spec?.template?.spec ?? spec?.jobTemplate?.spec?.template?.spec;
|
|
20
|
+
const images = [...(pod?.initContainers ?? []), ...(pod?.containers ?? [])].map(({ image }) => image ?? "");
|
|
21
|
+
return [object.metadata?.name ?? "", [...new Set(images)].join(", ")];
|
|
22
|
+
}));
|
|
23
|
+
}
|
|
24
|
+
/** What changes from the images `before` to those `after`, one line a workload, with the version of alasio's own. */
|
|
25
|
+
function imageChanges(before, after) {
|
|
26
|
+
if (before.version === null)
|
|
27
|
+
return [`alasio is not installed yet: installing ${VERSION}`];
|
|
28
|
+
const changed = [...after].filter(([name, images]) => before.images.get(name) !== images);
|
|
29
|
+
if (changed.length === 0)
|
|
30
|
+
return [`alasio ${before.version} already runs this version's images; applying it again`];
|
|
31
|
+
return [
|
|
32
|
+
before.version === VERSION ? `alasio ${VERSION}, with other images:` : `alasio ${before.version} → ${VERSION}:`,
|
|
33
|
+
...changed.map(([name, images]) => ` ${name}: ${before.images.get(name) ?? "(new)"} → ${images}`),
|
|
34
|
+
];
|
|
35
|
+
}
|
|
36
|
+
export const upgrade = Command.make("upgrade", { timeout: timeoutFlag }, ({ timeout }) => Effect.gen(function* () {
|
|
37
|
+
const config = yield* loadConfig;
|
|
38
|
+
const target = yield* resolveTarget(config);
|
|
39
|
+
yield* ensureCluster(target);
|
|
40
|
+
yield* Effect.provide(Effect.gen(function* () {
|
|
41
|
+
const kube = yield* KubeApi;
|
|
42
|
+
const running = (yield* Effect.forEach(WORKLOADS, (name) => kube.list(kind(name), { labelSelector: INSTALLATION_SELECTOR }))).flat();
|
|
43
|
+
const version = running.find((object) => object.kind === "Deployment" && object.metadata?.name === RELEASE)?.metadata?.labels?.["app.kubernetes.io/version"] ?? null;
|
|
44
|
+
const desired = installationObjects(yield* installConfig(config));
|
|
45
|
+
yield* Console.log(imageChanges({ version, images: imagesOf(running) }, imagesOf(desired)).join("\n"));
|
|
46
|
+
yield* announce(target, yield* install(config, waitOptions(timeout)));
|
|
47
|
+
}), kubeApi(target));
|
|
48
|
+
})).pipe(Command.withShortDescription("Upgrade alasio to this version"), Command.withDescription("Does what alasio up does, with the images this version of alasio's package pins, after saying which images change " +
|
|
49
|
+
"and from which version of alasio. Run as npx alasio@latest upgrade to upgrade to the latest release."));
|
|
50
|
+
//# sourceMappingURL=upgrade.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"upgrade.js","sourceRoot":"","sources":["../../../../src/commands/upgrade.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/** The `alasio` command and its subcommands, each in a module of its own (./commands/). */
|
|
2
|
+
import { Command } from "effect/cli";
|
|
3
|
+
import { down } from "./commands/down.js";
|
|
4
|
+
import { init } from "./commands/init.js";
|
|
5
|
+
import { lake } from "./commands/lake.js";
|
|
6
|
+
import { login } from "./commands/login.js";
|
|
7
|
+
import { logs } from "./commands/logs.js";
|
|
8
|
+
import { restart } from "./commands/restart.js";
|
|
9
|
+
import { status } from "./commands/status.js";
|
|
10
|
+
import { uninstall } from "./commands/uninstall.js";
|
|
11
|
+
import { up } from "./commands/up.js";
|
|
12
|
+
import { upgrade } from "./commands/upgrade.js";
|
|
13
|
+
import { ConfigFlag } from "./config.js";
|
|
14
|
+
export const alasio = Command.make("alasio").pipe(Command.withDescription("Coding agents you talk to from Telegram: Claude Code and Codex, each conversation with a workspace of its own. " +
|
|
15
|
+
"alasio init sets it up, alasio up starts it, in a cluster alasio makes on this machine or one a kubeconfig reaches."), Command.withSubcommands([init, up, status, logs, restart, upgrade, login, lake, down, uninstall]), Command.withGlobalFlags([ConfigFlag]));
|
|
16
|
+
//# sourceMappingURL=commands.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"commands.js","sourceRoot":"","sources":["../../../src/commands.ts"],"names":[],"mappings":"AAAA,2FAA2F;AAC3F,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAErC,OAAO,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAC;AAC1C,OAAO,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAC;AAC1C,OAAO,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAC;AAC1C,OAAO,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AAC5C,OAAO,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAC;AAC1C,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAChD,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AACpD,OAAO,EAAE,EAAE,EAAE,MAAM,kBAAkB,CAAC;AACtC,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,MAAM,CAAC,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,IAAI,CAC/C,OAAO,CAAC,eAAe,CACrB,iHAAiH;IAC/G,qHAAqH,CACxH,EACD,OAAO,CAAC,eAAe,CAAC,CAAC,IAAI,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,CAAC,CAAC,EACjG,OAAO,CAAC,eAAe,CAAC,CAAC,UAAU,CAAC,CAAC,CACtC,CAAC"}
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The operator's config: where alasio runs, and how it is installed. It is a JSON file,
|
|
3
|
+
* $XDG_CONFIG_HOME/alasio/config.json (~/.config/alasio/config.json) unless --config says
|
|
4
|
+
* another, readable by its owner alone, in a directory only its owner opens; `alasio
|
|
5
|
+
* init` writes it, and an operator may edit it. It holds no secret: alasio's Secrets are
|
|
6
|
+
* in the cluster alone (./secrets.ts).
|
|
7
|
+
*
|
|
8
|
+
* {
|
|
9
|
+
* "target": { "local": { "name": "alasio", "apiPort": 41873 } },
|
|
10
|
+
* "install": { "telemetry": { "otlpEndpoint": "http://collector.example.com:4318" } }
|
|
11
|
+
* }
|
|
12
|
+
*
|
|
13
|
+
* The target is the cluster alasio makes on this machine (./cluster/local.ts), with its
|
|
14
|
+
* API server on `apiPort` of the loopback and its volumes in `storagePath`
|
|
15
|
+
* ($XDG_DATA_HOME/alasio/storage unless given), its nodes pulling through the
|
|
16
|
+
* `registries` it is given, or one a kubeconfig reaches:
|
|
17
|
+
* `{ "kubeconfig": { "path": "/home/me/.kube/config", "context": "prod" } }`, both keys
|
|
18
|
+
* optional. The installation is the install configuration (./manifests/config.ts), every
|
|
19
|
+
* key optional, but for the Secrets of the bot and of Claude Code, which alasio names.
|
|
20
|
+
*/
|
|
21
|
+
import { randomUUID } from "node:crypto";
|
|
22
|
+
import { homedir } from "node:os";
|
|
23
|
+
import { dirname, join, resolve } from "node:path";
|
|
24
|
+
import { Config, Effect, FileSystem, Option, Predicate, Result, Schema } from "effect";
|
|
25
|
+
import { Flag, GlobalFlag } from "effect/cli";
|
|
26
|
+
import { AbsolutePath, decodeInstallConfig, defaulted, describeIssue, matching, NonEmpty } from "./manifests/config.js";
|
|
27
|
+
import { CLAUDE_SECRET, TELEGRAM_SECRET } from "./secrets.js";
|
|
28
|
+
/** `--config`, the operator config's path, given before or after the command. */
|
|
29
|
+
export const ConfigFlag = GlobalFlag.Setting("config")({
|
|
30
|
+
flag: Flag.String("config").pipe(Flag.optional, Flag.withMetavar("path"), Flag.withDescription("The config file to use, instead of $XDG_CONFIG_HOME/alasio/config.json (~/.config/alasio/config.json)")),
|
|
31
|
+
});
|
|
32
|
+
const Port = Schema.Int.check(Schema.isBetween({ minimum: 1, maximum: 65535 }, { message: "must be a port from 1 to 65535" }));
|
|
33
|
+
const Ipv4 = matching(/^(\d{1,3}\.){3}\d{1,3}$/u, "must be an IPv4 address");
|
|
34
|
+
const Url = matching(/^https?:\/\/.+$/u, "must be an http(s) URL");
|
|
35
|
+
/**
|
|
36
|
+
* The registries the local cluster's nodes pull images from, as k3s's registries.yaml
|
|
37
|
+
* says them, its keys in camel case: a registry's mirrors, by its host (`*` for every
|
|
38
|
+
* one), and its TLS, whose files are the nodes', as `mounts` mounts them. A registry's
|
|
39
|
+
* login is a secret, which the config does not hold, so there is none: the registries are
|
|
40
|
+
* ones that ask for none.
|
|
41
|
+
*/
|
|
42
|
+
const Registries = Schema.Struct({
|
|
43
|
+
mirrors: defaulted(Schema.Record(NonEmpty, Schema.Struct({
|
|
44
|
+
endpoint: Schema.Array(Url).check(Schema.isMinLength(1, { message: "must name an endpoint" })),
|
|
45
|
+
rewrite: Schema.optionalKey(Schema.Record(Schema.String, Schema.String)),
|
|
46
|
+
})), {}),
|
|
47
|
+
configs: defaulted(Schema.Record(NonEmpty, Schema.Struct({
|
|
48
|
+
tls: Schema.Struct({
|
|
49
|
+
caFile: Schema.optionalKey(AbsolutePath),
|
|
50
|
+
certFile: Schema.optionalKey(AbsolutePath),
|
|
51
|
+
keyFile: Schema.optionalKey(AbsolutePath),
|
|
52
|
+
insecureSkipVerify: Schema.optionalKey(Schema.Boolean),
|
|
53
|
+
}),
|
|
54
|
+
})), {}),
|
|
55
|
+
});
|
|
56
|
+
/** The cluster alasio makes on this machine, its LocalClusterOptions. */
|
|
57
|
+
const LocalTarget = Schema.Struct({
|
|
58
|
+
name: defaulted(matching(/^[a-z0-9]([-a-z0-9]{0,40}[a-z0-9])?$/u, "must be a name of lowercase letters, digits and dashes"), "alasio"),
|
|
59
|
+
apiPort: Port.annotateKey({ messageMissingKey: "is required: alasio init chooses one" }),
|
|
60
|
+
subnet: Schema.optionalKey(matching(/^(\d{1,3}\.){3}\d{1,3}\/\d{1,2}$/u, "must be an IPv4 subnet, such as 172.30.0.0/24")),
|
|
61
|
+
hostAliases: defaulted(Schema.Array(Schema.Struct({ ip: Ipv4, hostnames: Schema.Array(NonEmpty).check(Schema.isMinLength(1, { message: "must name a host" })) })), []),
|
|
62
|
+
mounts: defaulted(Schema.Array(Schema.Struct({ source: AbsolutePath, target: AbsolutePath, readOnly: Schema.optionalKey(Schema.Boolean) })), []),
|
|
63
|
+
storagePath: Schema.optionalKey(AbsolutePath),
|
|
64
|
+
/** The node image, such as one built from cluster/node on this machine; this version's unless given. */
|
|
65
|
+
image: Schema.optionalKey(NonEmpty),
|
|
66
|
+
agents: defaulted(Schema.Int.check(Schema.isBetween({ minimum: 0, maximum: 16 }, { message: "must be from 0 to 16" })), 0),
|
|
67
|
+
registries: Schema.optionalKey(Registries),
|
|
68
|
+
});
|
|
69
|
+
/** A cluster a kubeconfig reaches: the default kubeconfig and its current context unless they are given. */
|
|
70
|
+
const KubeconfigTarget = Schema.Struct({ path: Schema.optionalKey(AbsolutePath), context: Schema.optionalKey(NonEmpty) });
|
|
71
|
+
const Target = Schema.Union([Schema.Struct({ local: LocalTarget }), Schema.Struct({ kubeconfig: KubeconfigTarget })]);
|
|
72
|
+
const OperatorConfigSchema = Schema.Struct({
|
|
73
|
+
target: Target.annotateKey({ messageMissingKey: "is required: alasio init writes it" }),
|
|
74
|
+
install: defaulted(Schema.Record(Schema.String, Schema.Unknown), {}),
|
|
75
|
+
});
|
|
76
|
+
/** The config file is not what alasio runs from: where, and which key and why. */
|
|
77
|
+
export class OperatorConfigError extends Schema.TaggedError()("OperatorConfigError", {
|
|
78
|
+
path: Schema.String,
|
|
79
|
+
reason: Schema.String,
|
|
80
|
+
}) {
|
|
81
|
+
get message() {
|
|
82
|
+
return `${this.path}: ${this.reason}`;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
/** There is no config file yet. */
|
|
86
|
+
export class NotInitialized extends Schema.TaggedError()("NotInitialized", {
|
|
87
|
+
path: Schema.String,
|
|
88
|
+
}) {
|
|
89
|
+
get message() {
|
|
90
|
+
return `there is no alasio config at ${this.path}: alasio init makes one`;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* The install configuration of `install`, with the Secrets alasio names: the bot's,
|
|
95
|
+
* and Claude Code's when `claude`, as alasio finds Claude Code's login in its home when
|
|
96
|
+
* there is none.
|
|
97
|
+
*/
|
|
98
|
+
export function installConfigOf(install, { claude }) {
|
|
99
|
+
const alasio = Predicate.isObject(install["alasio"]) ? install["alasio"] : {};
|
|
100
|
+
const own = ["telegram", "claude"].find((key) => Predicate.hasProperty(alasio, key));
|
|
101
|
+
if (own)
|
|
102
|
+
return Result.fail(`install.alasio.${own} is alasio's own to say: its Secret is the one alasio init writes`);
|
|
103
|
+
return Result.mapBoth(decodeInstallConfig({ ...install, alasio: { ...alasio, telegram: { existingSecret: TELEGRAM_SECRET }, claude: { existingSecret: claude ? CLAUDE_SECRET : "" } } }), { onFailure: (error) => `install.${error.message}`, onSuccess: (config) => config });
|
|
104
|
+
}
|
|
105
|
+
/** The config `input` (parsed JSON) is, checked: a key alasio does not know is refused. */
|
|
106
|
+
export function decodeOperatorConfig(path, input) {
|
|
107
|
+
const decoded = Schema.decodeUnknownResult(OperatorConfigSchema)(input, { onExcessProperty: "error" });
|
|
108
|
+
if (Result.isFailure(decoded))
|
|
109
|
+
return Result.fail(new OperatorConfigError({ path, reason: describeIssue(decoded.failure.issue) }));
|
|
110
|
+
const { target, install } = decoded.success;
|
|
111
|
+
const checked = installConfigOf(install, { claude: true });
|
|
112
|
+
if (Result.isFailure(checked))
|
|
113
|
+
return Result.fail(new OperatorConfigError({ path, reason: checked.failure }));
|
|
114
|
+
return Result.succeed({ path, file: input, target, install });
|
|
115
|
+
}
|
|
116
|
+
/** `$name`, or `fallback` under the home directory when it is unset or empty, as XDG says. */
|
|
117
|
+
const xdgHome = (name, fallback) => Effect.gen(function* () {
|
|
118
|
+
const given = yield* Config.option(Config.String(name));
|
|
119
|
+
if (Option.isSome(given) && given.value.trim())
|
|
120
|
+
return given.value;
|
|
121
|
+
const home = yield* Config.String("HOME").pipe(Config.withDefault(homedir()));
|
|
122
|
+
return join(home, fallback);
|
|
123
|
+
});
|
|
124
|
+
/** Where the config file is: --config's path, or $XDG_CONFIG_HOME/alasio/config.json. */
|
|
125
|
+
export const configPath = Effect.gen(function* () {
|
|
126
|
+
const flag = yield* ConfigFlag;
|
|
127
|
+
if (Option.isSome(flag))
|
|
128
|
+
return resolve(flag.value);
|
|
129
|
+
return join(yield* xdgHome("XDG_CONFIG_HOME", ".config"), "alasio", "config.json");
|
|
130
|
+
});
|
|
131
|
+
/** Where the local cluster's volumes are unless its target says: $XDG_DATA_HOME/alasio/storage. */
|
|
132
|
+
export const defaultStoragePath = Effect.map(xdgHome("XDG_DATA_HOME", ".local/share"), (data) => join(data, "alasio", "storage"));
|
|
133
|
+
/** The kubeconfig of the local cluster, beside the config file. */
|
|
134
|
+
export const localKubeconfigPath = (config) => join(dirname(config.path), "kubeconfig");
|
|
135
|
+
/** The config at `path`, or null when there is none. */
|
|
136
|
+
export const readConfig = Effect.fnUntraced(function* (path) {
|
|
137
|
+
const fs = yield* FileSystem.FileSystem;
|
|
138
|
+
if (!(yield* fs.exists(path)))
|
|
139
|
+
return null;
|
|
140
|
+
const text = yield* fs.readFileString(path);
|
|
141
|
+
const parsed = yield* Effect.try({
|
|
142
|
+
try: () => JSON.parse(text),
|
|
143
|
+
catch: (cause) => new OperatorConfigError({ path, reason: `is not JSON: ${cause instanceof Error ? cause.message : String(cause)}` }),
|
|
144
|
+
});
|
|
145
|
+
return yield* Effect.fromResult(decodeOperatorConfig(path, parsed));
|
|
146
|
+
});
|
|
147
|
+
/** The config at configPath, which must exist. */
|
|
148
|
+
export const loadConfig = Effect.gen(function* () {
|
|
149
|
+
const path = yield* configPath;
|
|
150
|
+
const config = yield* readConfig(path);
|
|
151
|
+
if (!config)
|
|
152
|
+
return yield* new NotInitialized({ path });
|
|
153
|
+
return config;
|
|
154
|
+
});
|
|
155
|
+
/**
|
|
156
|
+
* Writes `file` to `path`, checked first, readable by its owner alone: whole, beside it,
|
|
157
|
+
* then moved over it. A directory made for it only its owner opens.
|
|
158
|
+
*/
|
|
159
|
+
export const writeConfig = Effect.fnUntraced(function* (path, file) {
|
|
160
|
+
const config = yield* Effect.fromResult(decodeOperatorConfig(path, file));
|
|
161
|
+
const fs = yield* FileSystem.FileSystem;
|
|
162
|
+
if (!(yield* fs.exists(dirname(path))))
|
|
163
|
+
yield* fs.makeDirectory(dirname(path), { recursive: true, mode: 0o700 });
|
|
164
|
+
const written = `${path}.${randomUUID()}`;
|
|
165
|
+
yield* fs.writeFileString(written, `${JSON.stringify(file, null, 2)}\n`, { flag: "wx", mode: 0o600 });
|
|
166
|
+
yield* fs.rename(written, path);
|
|
167
|
+
return config;
|
|
168
|
+
});
|
|
169
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../../src/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/** How alasio names the images it runs. */
|
|
2
|
+
import { VERSION } from "./release.js";
|
|
3
|
+
/** `image`'s reference, pinned by its digest when it has one. */
|
|
4
|
+
export function imageReference(image) {
|
|
5
|
+
return `${image.repository}:${image.tag || VERSION}${image.digest ? `@${image.digest}` : ""}`;
|
|
6
|
+
}
|
|
7
|
+
//# sourceMappingURL=images.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"images.js","sourceRoot":"","sources":["../../../src/images.ts"],"names":[],"mappings":"AAAA,2CAA2C;AAC3C,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AASvC,iEAAiE;AACjE,MAAM,UAAU,cAAc,CAAC,KAAe;IAC5C,OAAO,GAAG,KAAK,CAAC,UAAU,IAAI,KAAK,CAAC,GAAG,IAAI,OAAO,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;AAChG,CAAC"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { Effect, Result, Schema } from "effect";
|
|
2
|
+
import { installConfigOf, OperatorConfigError } from "./config.js";
|
|
3
|
+
import { KubeApi } from "./kube/api.js";
|
|
4
|
+
import { applyInstallation, labelled } from "./kube/apply.js";
|
|
5
|
+
import { labels, NAMESPACE } from "./manifests/common.js";
|
|
6
|
+
import { manifests } from "./manifests/index.js";
|
|
7
|
+
import { readClaudeToken, readTelegramBot } from "./secrets.js";
|
|
8
|
+
/** alasio's namespace. */
|
|
9
|
+
const NAMESPACE_OBJECT = { apiVersion: "v1", kind: "Namespace", metadata: { name: NAMESPACE, labels: labels("alasio") } };
|
|
10
|
+
/** The objects of the installation `config` describes. */
|
|
11
|
+
export function installationObjects(config) {
|
|
12
|
+
return [NAMESPACE_OBJECT, ...manifests(config)];
|
|
13
|
+
}
|
|
14
|
+
/** alasio's namespace, applied as the installation's, so its Secrets can be written before the rest of it is. */
|
|
15
|
+
export const applyNamespace = Effect.flatMap(KubeApi, (kube) => kube.apply(labelled(NAMESPACE_OBJECT))).pipe(Effect.asVoid);
|
|
16
|
+
/** The cluster has no bot's Secret: alasio has not been given its bot. */
|
|
17
|
+
export class BotNotSet extends Schema.TaggedError()("BotNotSet", {}) {
|
|
18
|
+
get message() {
|
|
19
|
+
return "alasio has no Telegram bot in this cluster yet: alasio init gives it one";
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
/** The install configuration of `config`, which names Claude Code's Secret when the cluster has it. */
|
|
23
|
+
export const installConfig = Effect.fnUntraced(function* (config) {
|
|
24
|
+
const claude = (yield* readClaudeToken) !== null;
|
|
25
|
+
const install = installConfigOf(config.install, { claude });
|
|
26
|
+
if (Result.isFailure(install))
|
|
27
|
+
return yield* new OperatorConfigError({ path: config.path, reason: install.failure });
|
|
28
|
+
return install.success;
|
|
29
|
+
});
|
|
30
|
+
/** Applies the installation `config` describes, once its bot is set, and waits until it runs. */
|
|
31
|
+
export const install = Effect.fnUntraced(function* (config, options) {
|
|
32
|
+
const bot = yield* readTelegramBot;
|
|
33
|
+
if (!bot)
|
|
34
|
+
return yield* new BotNotSet();
|
|
35
|
+
const settings = yield* installConfig(config);
|
|
36
|
+
yield* applyInstallation(installationObjects(settings), options);
|
|
37
|
+
return { bot, claude: settings.alasio.claude.existingSecret !== "" };
|
|
38
|
+
});
|
|
39
|
+
//# sourceMappingURL=install.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"install.js","sourceRoot":"","sources":["../../../src/install.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhD,OAAO,EAAE,eAAe,EAAuB,mBAAmB,EAAE,MAAM,aAAa,CAAC;AACxF,OAAO,EAAE,OAAO,EAAqB,MAAM,eAAe,CAAC;AAC3D,OAAO,EAAmB,iBAAiB,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAE/E,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAE1D,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACjD,OAAO,EAAE,eAAe,EAAE,eAAe,EAAoB,MAAM,cAAc,CAAC;AAElF,0BAA0B;AAC1B,MAAM,gBAAgB,GAAgB,EAAE,UAAU,EAAE,IAAI,EAAE,IAAI,EAAE,WAAW,EAAE,QAAQ,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;AAEvI,0DAA0D;AAC1D,MAAM,UAAU,mBAAmB,CAAC,MAAqB;IACvD,OAAO,CAAC,gBAAgB,EAAE,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC;AAClD,CAAC;AAED,iHAAiH;AACjH,MAAM,CAAC,MAAM,cAAc,GAA+C,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,IAAI,CACtJ,MAAM,CAAC,MAAM,CACd,CAAC;AAEF,0EAA0E;AAC1E,MAAM,OAAO,SAAU,SAAQ,MAAM,CAAC,WAAW,EAAa,CAAC,WAAW,EAAE,EAAE,CAAC;IAC7E,IAAa,OAAO;QAClB,OAAO,0EAA0E,CAAC;IACpF,CAAC;CACF;AAED,uGAAuG;AACvG,MAAM,CAAC,MAAM,aAAa,GAAG,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAC,MAAsB;IAC7E,MAAM,MAAM,GAAG,CAAC,KAAK,CAAC,CAAC,eAAe,CAAC,KAAK,IAAI,CAAC;IACjD,MAAM,OAAO,GAAG,eAAe,CAAC,MAAM,CAAC,OAAO,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;IAC5D,IAAI,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC;QAAE,OAAO,KAAK,CAAC,CAAC,IAAI,mBAAmB,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;IACrH,OAAO,OAAO,CAAC,OAAO,CAAC;AACzB,CAAC,CAAC,CAAC;AAQH,iGAAiG;AACjG,MAAM,CAAC,MAAM,OAAO,GAAG,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,EAChD,MAAsB,EACtB,OAAoB;IAEpB,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,eAAe,CAAC;IACnC,IAAI,CAAC,GAAG;QAAE,OAAO,KAAK,CAAC,CAAC,IAAI,SAAS,EAAE,CAAC;IACxC,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC;IAC9C,KAAK,CAAC,CAAC,iBAAiB,CAAC,mBAAmB,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC,CAAC;IACjE,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,cAAc,KAAK,EAAE,EAAE,CAAC;AACvE,CAAC,CAAC,CAAC"}
|