spawnfile 0.1.10 → 0.1.12
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/README.md +13 -2
- package/dist/cli/lifecycleCommands.js +101 -1
- package/dist/cli/modelCommands.js +3 -0
- package/dist/cli/resolveCommandInput.d.ts +19 -0
- package/dist/cli/resolveCommandInput.js +25 -0
- package/dist/cli/runCli.d.ts +4 -1
- package/dist/cli/runCli.js +37 -13
- package/dist/cli/runtimeCommands.js +1 -0
- package/dist/cli/statusCommand.d.ts +42 -0
- package/dist/cli/statusCommand.js +394 -0
- package/dist/cli/surfaceCommands.js +4 -0
- package/dist/compiler/agentSurfaces.js +2 -4
- package/dist/compiler/buildCompilePlanTeams.js +3 -1
- package/dist/compiler/compileProject.js +19 -10
- package/dist/compiler/compileProjectSupport.d.ts +1 -0
- package/dist/compiler/compileProjectSupport.js +1 -1
- package/dist/compiler/containerArtifacts.d.ts +1 -0
- package/dist/compiler/containerArtifacts.js +208 -32
- package/dist/compiler/containerArtifactsPlans.js +7 -4
- package/dist/compiler/containerArtifactsRender.d.ts +7 -1
- package/dist/compiler/containerArtifactsRender.js +6 -0
- package/dist/compiler/containerArtifactsTypes.d.ts +9 -0
- package/dist/compiler/containerEntrypointRender.js +18 -31
- package/dist/compiler/index.d.ts +1 -0
- package/dist/compiler/index.js +1 -0
- package/dist/compiler/moltnetArtifacts.d.ts +2 -0
- package/dist/compiler/moltnetArtifacts.js +58 -99
- package/dist/compiler/moltnetClientConfig.d.ts +2 -2
- package/dist/compiler/moltnetClientConfig.js +16 -23
- package/dist/compiler/moltnetConfigLowering.d.ts +3 -0
- package/dist/compiler/moltnetConfigLowering.js +13 -2
- package/dist/compiler/moltnetNodeConfig.d.ts +27 -0
- package/dist/compiler/moltnetNodeConfig.js +68 -0
- package/dist/compiler/moltnetResolution.js +1 -1
- package/dist/compiler/moltnetRoomMemberships.js +1 -2
- package/dist/compiler/moltnetRoomPolicyCompatibility.d.ts +4 -0
- package/dist/compiler/moltnetRoomPolicyCompatibility.js +28 -0
- package/dist/compiler/moltnetRuntimeConfig.d.ts +1 -1
- package/dist/compiler/moltnetRuntimeConfig.js +1 -13
- package/dist/compiler/networkBinding.d.ts +14 -0
- package/dist/compiler/networkBinding.js +34 -0
- package/dist/compiler/publishProject.d.ts +13 -0
- package/dist/compiler/publishProject.js +72 -0
- package/dist/compiler/runProject.d.ts +26 -12
- package/dist/compiler/runProject.js +102 -125
- package/dist/compiler/runProjectAuth.d.ts +5 -0
- package/dist/compiler/runProjectAuth.js +98 -0
- package/dist/compiler/runProjectDocker.d.ts +19 -0
- package/dist/compiler/runProjectDocker.js +57 -0
- package/dist/compiler/types.d.ts +3 -2
- package/dist/compiler/upProject.d.ts +6 -0
- package/dist/compiler/upProject.js +42 -8
- package/dist/compiler/view/buildOrganizationView.js +27 -3
- package/dist/compiler/view/declarations.d.ts +4 -0
- package/dist/compiler/view/declarations.js +104 -0
- package/dist/compiler/view/renderNetworks.js +12 -3
- package/dist/compiler/view/renderTree.js +16 -3
- package/dist/compiler/view/types.d.ts +77 -1
- package/dist/deployment/dockerInspect.d.ts +29 -0
- package/dist/deployment/dockerInspect.js +130 -0
- package/dist/deployment/dockerLabels.d.ts +16 -0
- package/dist/deployment/dockerLabels.js +32 -0
- package/dist/deployment/dockerLogs.d.ts +24 -0
- package/dist/deployment/dockerLogs.js +96 -0
- package/dist/deployment/dockerManager.d.ts +59 -0
- package/dist/deployment/dockerManager.js +76 -0
- package/dist/deployment/dockerProbeGateway.d.ts +16 -0
- package/dist/deployment/dockerProbeGateway.js +48 -0
- package/dist/deployment/homeStore.d.ts +19 -0
- package/dist/deployment/homeStore.js +130 -0
- package/dist/deployment/index.d.ts +9 -0
- package/dist/deployment/index.js +9 -0
- package/dist/deployment/names.d.ts +3 -0
- package/dist/deployment/names.js +12 -0
- package/dist/deployment/record.d.ts +76 -0
- package/dist/deployment/record.js +174 -0
- package/dist/deployment/target.d.ts +35 -0
- package/dist/deployment/target.js +96 -0
- package/dist/distribution/buildDistributionReport.d.ts +22 -0
- package/dist/distribution/buildDistributionReport.js +51 -0
- package/dist/distribution/consumeImage.d.ts +29 -0
- package/dist/distribution/consumeImage.js +254 -0
- package/dist/distribution/consumeImageSupport.d.ts +18 -0
- package/dist/distribution/consumeImageSupport.js +63 -0
- package/dist/distribution/distributionReportSchema.d.ts +84 -0
- package/dist/distribution/distributionReportSchema.js +107 -0
- package/dist/distribution/dockerRunner.d.ts +5 -0
- package/dist/distribution/dockerRunner.js +21 -0
- package/dist/distribution/extractImage.d.ts +25 -0
- package/dist/distribution/extractImage.js +96 -0
- package/dist/distribution/fingerprint.d.ts +2 -0
- package/dist/distribution/fingerprint.js +14 -0
- package/dist/distribution/imageRef.d.ts +9 -0
- package/dist/distribution/imageRef.js +65 -0
- package/dist/distribution/imageRuntimeAuth.d.ts +19 -0
- package/dist/distribution/imageRuntimeAuth.js +71 -0
- package/dist/distribution/index.d.ts +24 -0
- package/dist/distribution/index.js +16 -0
- package/dist/distribution/preflight.d.ts +11 -0
- package/dist/distribution/preflight.js +65 -0
- package/dist/distribution/projectImageView.d.ts +8 -0
- package/dist/distribution/projectImageView.js +83 -0
- package/dist/distribution/projectName.d.ts +1 -0
- package/dist/distribution/projectName.js +12 -0
- package/dist/distribution/renderImageInterface.d.ts +30 -0
- package/dist/distribution/renderImageInterface.js +86 -0
- package/dist/distribution/tarReader.d.ts +10 -0
- package/dist/distribution/tarReader.js +69 -0
- package/dist/distribution/types.d.ts +80 -0
- package/dist/distribution/types.js +4 -0
- package/dist/distribution/verifyDistributionReport.d.ts +12 -0
- package/dist/distribution/verifyDistributionReport.js +29 -0
- package/dist/filesystem/paths.d.ts +6 -0
- package/dist/filesystem/paths.js +11 -0
- package/dist/manifest/loadManifest.js +22 -2
- package/dist/manifest/renderSpawnfile.js +2 -4
- package/dist/manifest/renderSpawnfileNetworks.js +5 -0
- package/dist/manifest/schemas.d.ts +71 -41
- package/dist/manifest/surfaceSchemas.d.ts +19 -47
- package/dist/manifest/surfaceSchemas.js +3 -6
- package/dist/manifest/teamNetworkAccessSchemas.d.ts +15 -0
- package/dist/manifest/teamNetworkAccessSchemas.js +8 -0
- package/dist/manifest/teamNetworkConsoleSchemas.d.ts +7 -0
- package/dist/manifest/teamNetworkConsoleSchemas.js +19 -0
- package/dist/manifest/teamNetworkSchemas.d.ts +60 -0
- package/dist/manifest/teamNetworkSchemas.js +20 -7
- package/dist/report/createReport.d.ts +7 -1
- package/dist/report/createReport.js +28 -1
- package/dist/report/types.d.ts +43 -0
- package/dist/runtime/container.js +0 -16
- package/dist/runtime/index.d.ts +1 -0
- package/dist/runtime/index.js +1 -0
- package/dist/runtime/install.d.ts +0 -10
- package/dist/runtime/install.js +0 -45
- package/dist/runtime/openclaw/adapter.js +9 -1
- package/dist/runtime/openclaw/configAuth.d.ts +15 -0
- package/dist/runtime/openclaw/configAuth.js +46 -0
- package/dist/runtime/openclaw/runAuth.d.ts +6 -0
- package/dist/runtime/openclaw/runAuth.js +7 -55
- package/dist/runtime/openclaw/statusProbes.d.ts +2 -0
- package/dist/runtime/openclaw/statusProbes.js +31 -0
- package/dist/runtime/picoclaw/adapter.js +10 -0
- package/dist/runtime/picoclaw/runAuth.d.ts +7 -0
- package/dist/runtime/picoclaw/runAuth.js +8 -68
- package/dist/runtime/picoclaw/statusProbes.d.ts +2 -0
- package/dist/runtime/picoclaw/statusProbes.js +100 -0
- package/dist/runtime/registry.d.ts +0 -5
- package/dist/runtime/registry.js +2 -12
- package/dist/runtime/statusProbes.d.ts +16 -0
- package/dist/runtime/statusProbes.js +41 -0
- package/dist/runtime/types.d.ts +52 -1
- package/dist/shared/errors.d.ts +6 -0
- package/dist/shared/errors.js +9 -0
- package/dist/status/buildStatus.d.ts +13 -0
- package/dist/status/buildStatus.js +266 -0
- package/dist/status/compileReport.d.ts +96 -0
- package/dist/status/compileReport.js +230 -0
- package/dist/status/compiledContainerObservations.d.ts +5 -0
- package/dist/status/compiledContainerObservations.js +63 -0
- package/dist/status/deploymentLogs.d.ts +12 -0
- package/dist/status/deploymentLogs.js +45 -0
- package/dist/status/deployments.d.ts +14 -0
- package/dist/status/deployments.js +128 -0
- package/dist/status/imageStatusReport.d.ts +10 -0
- package/dist/status/imageStatusReport.js +73 -0
- package/dist/status/index.d.ts +14 -0
- package/dist/status/index.js +14 -0
- package/dist/status/moltnetProbes.d.ts +21 -0
- package/dist/status/moltnetProbes.js +240 -0
- package/dist/status/registryDrift.d.ts +28 -0
- package/dist/status/registryDrift.js +119 -0
- package/dist/status/renderStatus.d.ts +2 -0
- package/dist/status/renderStatus.js +230 -0
- package/dist/status/runtimeProbes.d.ts +13 -0
- package/dist/status/runtimeProbes.js +111 -0
- package/dist/status/selectionSubjects.d.ts +8 -0
- package/dist/status/selectionSubjects.js +77 -0
- package/dist/status/selectors.d.ts +14 -0
- package/dist/status/selectors.js +90 -0
- package/dist/status/traversal.d.ts +6 -0
- package/dist/status/traversal.js +15 -0
- package/dist/status/types.d.ts +113 -0
- package/dist/status/types.js +1 -0
- package/package.json +4 -2
- package/runtimes.yaml +22 -15
- package/dist/runtime/tinyclaw/adapter.d.ts +0 -2
- package/dist/runtime/tinyclaw/adapter.js +0 -284
- package/dist/runtime/tinyclaw/runAuth.d.ts +0 -2
- package/dist/runtime/tinyclaw/runAuth.js +0 -49
- package/dist/runtime/tinyclaw/scaffold-assets/AGENTS.md +0 -160
- package/dist/runtime/tinyclaw/scaffold-assets/CLAUDE.md +0 -5
- package/dist/runtime/tinyclaw/scaffold-assets/SOUL.md +0 -177
- package/dist/runtime/tinyclaw/scaffold.d.ts +0 -2
- package/dist/runtime/tinyclaw/scaffold.js +0 -24
- package/dist/runtime/tinyclaw/schedules.d.ts +0 -9
- package/dist/runtime/tinyclaw/schedules.js +0 -62
- package/dist/runtime/tinyclaw/surfaces.d.ts +0 -8
- package/dist/runtime/tinyclaw/surfaces.js +0 -94
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { spawn } from "node:child_process";
|
|
3
|
+
import { readFile } from "node:fs/promises";
|
|
4
|
+
import { DISTRIBUTION_REPORT_OUTPUT_FILE, verifyDistributionReport } from "../distribution/index.js";
|
|
5
|
+
import { SpawnfileError } from "../shared/index.js";
|
|
6
|
+
import { buildProject } from "./buildProject.js";
|
|
7
|
+
/* v8 ignore start -- docker push runner is covered by distribution E2E */
|
|
8
|
+
const runDockerCapture = async (command, args) => new Promise((resolve, reject) => {
|
|
9
|
+
const child = spawn(command, args, { stdio: ["ignore", "pipe", "pipe"] });
|
|
10
|
+
const stdout = [];
|
|
11
|
+
const stderr = [];
|
|
12
|
+
child.stdout.on("data", (chunk) => stdout.push(String(chunk)));
|
|
13
|
+
child.stderr.on("data", (chunk) => stderr.push(String(chunk)));
|
|
14
|
+
child.on("error", reject);
|
|
15
|
+
child.on("close", (code) => {
|
|
16
|
+
if (code === 0) {
|
|
17
|
+
resolve(stdout.join(""));
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
reject(new SpawnfileError("runtime_error", `docker ${args[0]} failed (${code}): ${stderr.join("").trim()}`));
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
/* v8 ignore stop */
|
|
24
|
+
const resolvePushedDigest = async (command, imageTag, runDocker) => {
|
|
25
|
+
try {
|
|
26
|
+
const raw = (await runDocker(command, ["image", "inspect", "--format", "{{json .RepoDigests}}", imageTag])).trim();
|
|
27
|
+
const digests = JSON.parse(raw);
|
|
28
|
+
const match = digests
|
|
29
|
+
.map((entry) => (entry.includes("@") ? entry.slice(entry.indexOf("@") + 1) : null))
|
|
30
|
+
.find((entry) => Boolean(entry));
|
|
31
|
+
return match ?? null;
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* Compiles, builds, verifies, and pushes a project image. Pre-push verification
|
|
39
|
+
* refuses to publish a report that leaks creator paths or omits secret markers.
|
|
40
|
+
*/
|
|
41
|
+
export const publishProject = async (inputPath, options = {}) => {
|
|
42
|
+
if (!options.imageTag) {
|
|
43
|
+
throw new SpawnfileError("validation_error", "publish requires --tag with a registry image reference");
|
|
44
|
+
}
|
|
45
|
+
const buildResult = await buildProject(inputPath, options);
|
|
46
|
+
const dockerCommand = options.dockerCommand ?? "docker";
|
|
47
|
+
const runDocker = options.pushRunner ?? runDockerCapture;
|
|
48
|
+
const reportPath = path.join(buildResult.outputDirectory, DISTRIBUTION_REPORT_OUTPUT_FILE);
|
|
49
|
+
let parsedReport;
|
|
50
|
+
try {
|
|
51
|
+
parsedReport = JSON.parse(await readFile(reportPath, "utf8"));
|
|
52
|
+
}
|
|
53
|
+
catch (error) {
|
|
54
|
+
/* v8 ignore next 2 -- compile always emits the report; defensive only */
|
|
55
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
56
|
+
throw new SpawnfileError("validation_error", `Unable to read distribution report for publish: ${reason}`);
|
|
57
|
+
}
|
|
58
|
+
verifyDistributionReport({
|
|
59
|
+
forbiddenPathFragments: [
|
|
60
|
+
path.resolve(inputPath),
|
|
61
|
+
buildResult.outputDirectory,
|
|
62
|
+
buildResult.report.root
|
|
63
|
+
],
|
|
64
|
+
report: parsedReport
|
|
65
|
+
});
|
|
66
|
+
await runDocker(dockerCommand, ["push", buildResult.imageTag]);
|
|
67
|
+
const digest = await resolvePushedDigest(dockerCommand, buildResult.imageTag, runDocker);
|
|
68
|
+
return {
|
|
69
|
+
...buildResult,
|
|
70
|
+
digest
|
|
71
|
+
};
|
|
72
|
+
};
|
|
@@ -1,36 +1,50 @@
|
|
|
1
1
|
import { type ResolvedAuthProfile } from "../auth/index.js";
|
|
2
|
+
import { type DockerTargetExecFile } from "../deployment/index.js";
|
|
2
3
|
import { type CompileProjectOptions, type CompileProjectResult } from "./compileProject.js";
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
containerName: string | null;
|
|
7
|
-
cwd: string;
|
|
8
|
-
detach: boolean;
|
|
9
|
-
envFilePath: string;
|
|
10
|
-
imageTag: string;
|
|
11
|
-
supportDirectory: string;
|
|
12
|
-
}
|
|
13
|
-
export type DockerRunRunner = (invocation: DockerRunInvocation) => Promise<void>;
|
|
4
|
+
import { runDockerContainer, type DockerRunInvocation, type DockerRunResult, type DockerRunRunner } from "./runProjectDocker.js";
|
|
5
|
+
export { runDockerContainer };
|
|
6
|
+
export type { DockerRunInvocation, DockerRunResult, DockerRunRunner };
|
|
14
7
|
export interface RunProjectOptions extends CompileProjectOptions {
|
|
15
8
|
authProfile?: string;
|
|
16
9
|
containerName?: string;
|
|
17
10
|
detach?: boolean;
|
|
11
|
+
deploymentName?: string;
|
|
18
12
|
dockerCommand?: string;
|
|
13
|
+
dockerContext?: string;
|
|
14
|
+
dockerHost?: string;
|
|
19
15
|
envFilePath?: string;
|
|
20
16
|
imageTag?: string;
|
|
21
17
|
runRunner?: DockerRunRunner;
|
|
18
|
+
targetExecFile?: DockerTargetExecFile;
|
|
22
19
|
}
|
|
23
20
|
export interface RunProjectResult extends CompileProjectResult {
|
|
24
21
|
authProfileName: string | null;
|
|
25
22
|
containerName: string | null;
|
|
23
|
+
deploymentRecordPath?: string | null;
|
|
26
24
|
imageTag: string;
|
|
27
25
|
}
|
|
28
26
|
export declare const createDockerRunInvocation: (compileResult: CompileProjectResult, imageTag: string, options?: {
|
|
29
27
|
authProfile?: ResolvedAuthProfile | null;
|
|
30
28
|
containerName?: string;
|
|
31
29
|
detach?: boolean;
|
|
30
|
+
deploymentName?: string;
|
|
32
31
|
dockerCommand?: string;
|
|
32
|
+
dockerContext?: string;
|
|
33
|
+
dockerHost?: string;
|
|
33
34
|
envFilePath?: string;
|
|
34
35
|
}) => Promise<DockerRunInvocation>;
|
|
35
|
-
|
|
36
|
+
interface ResolvedRunDeploymentOptions {
|
|
37
|
+
authProfile?: string;
|
|
38
|
+
containerName?: string;
|
|
39
|
+
deploymentName?: string;
|
|
40
|
+
dockerCommand?: string;
|
|
41
|
+
dockerContext?: string;
|
|
42
|
+
dockerHost?: string;
|
|
43
|
+
envFilePath?: string;
|
|
44
|
+
imageTag?: string;
|
|
45
|
+
targetExecFile?: DockerTargetExecFile;
|
|
46
|
+
}
|
|
47
|
+
export declare const resolveDetachedDeploymentOptions: (outputDirectory: string, options: ResolvedRunDeploymentOptions & {
|
|
48
|
+
detach?: boolean;
|
|
49
|
+
}) => Promise<ResolvedRunDeploymentOptions>;
|
|
36
50
|
export declare const runProject: (inputPath: string, options?: RunProjectOptions) => Promise<RunProjectResult>;
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
import os from "node:os";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { mkdtemp } from "node:fs/promises";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import { SpawnfileError } from "../shared/index.js";
|
|
4
|
+
import { requireAuthProfile } from "../auth/index.js";
|
|
5
|
+
import { ensureDirectory, fileExists, removeDirectory, writeUtf8File } from "../filesystem/index.js";
|
|
6
|
+
import { appendDockerLabelArgs, createDockerDeploymentLabels, createDockerDeploymentUnitId, createDockerProjectLabel, dockerContextNameForTarget, dockerHostValueForTarget, normalizeDeploymentName, readDeploymentRecordFromOutput, resolveDeploymentRecordPath, verifyDockerDeploymentTarget, writeDockerDeploymentRecordForRun } from "../deployment/index.js";
|
|
7
|
+
import { DEFAULT_OUTPUT_DIRECTORY, SpawnfileError } from "../shared/index.js";
|
|
9
8
|
import { compileProject } from "./compileProject.js";
|
|
10
9
|
import { createDefaultImageTag } from "./buildProject.js";
|
|
11
10
|
import { slugify } from "./helpers.js";
|
|
12
|
-
import {
|
|
11
|
+
import { runDockerContainer } from "./runProjectDocker.js";
|
|
12
|
+
import { assertDeclaredModelAuthSatisfied, assertRunEnvironmentSatisfied, prepareRuntimeAuthMounts, readRunEnvFile, renderDockerEnvFile, resolveAuthMountArgs, resolveRunEnvironment } from "./runProjectAuth.js";
|
|
13
|
+
export { runDockerContainer };
|
|
13
14
|
const resolveImageTagRoot = (inputPath) => {
|
|
14
15
|
const resolvedPath = path.resolve(inputPath);
|
|
15
16
|
return path.basename(resolvedPath).toLowerCase() === "spawnfile"
|
|
@@ -20,100 +21,6 @@ const createDefaultContainerName = (imageTag) => {
|
|
|
20
21
|
const containerName = slugify(imageTag.replaceAll("/", "-").replaceAll(":", "-"));
|
|
21
22
|
return containerName || "spawnfile-run";
|
|
22
23
|
};
|
|
23
|
-
const getImportMountTargetName = (kind) => kind === "claude-code" ? ".claude" : ".codex";
|
|
24
|
-
const createGeneratedRuntimeSecret = (secretName) => {
|
|
25
|
-
if (secretName === "OPENCLAW_GATEWAY_TOKEN" || secretName === "OPENCLAW_HOOKS_TOKEN") {
|
|
26
|
-
return randomBytes(24).toString("hex");
|
|
27
|
-
}
|
|
28
|
-
return null;
|
|
29
|
-
};
|
|
30
|
-
const hasEnvValue = (env, name) => typeof env[name] === "string" && env[name].length > 0;
|
|
31
|
-
const collectMissingRequiredSecrets = (containerReport, env, coveredModelSecrets) => {
|
|
32
|
-
const missing = new Set();
|
|
33
|
-
for (const secretName of containerReport.secrets_required) {
|
|
34
|
-
if (hasEnvValue(env, secretName)) {
|
|
35
|
-
continue;
|
|
36
|
-
}
|
|
37
|
-
if (!containerReport.model_secrets_required.includes(secretName)) {
|
|
38
|
-
missing.add(secretName);
|
|
39
|
-
continue;
|
|
40
|
-
}
|
|
41
|
-
const requiredInstances = (containerReport.runtime_instances ?? []).filter((instance) => instance.model_secrets_required.includes(secretName));
|
|
42
|
-
const isCoveredEverywhere = requiredInstances.length > 0 &&
|
|
43
|
-
requiredInstances.every((instance) => coveredModelSecrets.has(`${instance.id}:${secretName}`));
|
|
44
|
-
if (!isCoveredEverywhere) {
|
|
45
|
-
missing.add(secretName);
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
return [...missing].sort();
|
|
49
|
-
};
|
|
50
|
-
const resolveRunEnvironment = (containerReport, authProfile, envFileEnv = {}) => {
|
|
51
|
-
const env = {
|
|
52
|
-
...(authProfile?.env ?? {}),
|
|
53
|
-
...envFileEnv
|
|
54
|
-
};
|
|
55
|
-
for (const name of new Set([...Object.keys(env), ...containerReport.secrets_required])) {
|
|
56
|
-
const processValue = process.env[name];
|
|
57
|
-
if (typeof processValue === "string" && processValue.length > 0) {
|
|
58
|
-
env[name] = processValue;
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
for (const name of containerReport.runtime_secrets_required) {
|
|
62
|
-
if (hasEnvValue(env, name)) {
|
|
63
|
-
continue;
|
|
64
|
-
}
|
|
65
|
-
const generatedValue = createGeneratedRuntimeSecret(name);
|
|
66
|
-
if (generatedValue) {
|
|
67
|
-
env[name] = generatedValue;
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
for (const [name, value] of Object.entries(env)) {
|
|
71
|
-
if (value.includes("\n")) {
|
|
72
|
-
throw new SpawnfileError("validation_error", `Env value for ${name} contains a newline and cannot be written to a Docker env file`);
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
return env;
|
|
76
|
-
};
|
|
77
|
-
const assertRunEnvironmentSatisfied = (containerReport, env, coveredModelSecrets) => {
|
|
78
|
-
const missing = collectMissingRequiredSecrets(containerReport, env, coveredModelSecrets);
|
|
79
|
-
if (missing.length > 0) {
|
|
80
|
-
throw new SpawnfileError("validation_error", `Missing required runtime env: ${missing.sort().join(", ")}`);
|
|
81
|
-
}
|
|
82
|
-
};
|
|
83
|
-
const renderDockerEnvFile = (env) => `${Object.entries(env)
|
|
84
|
-
.sort(([left], [right]) => left.localeCompare(right))
|
|
85
|
-
.map(([name, value]) => `${name}=${value}`)
|
|
86
|
-
.join("\n")}\n`;
|
|
87
|
-
const readRunEnvFile = async (envFilePath) => {
|
|
88
|
-
if (!envFilePath) {
|
|
89
|
-
return {};
|
|
90
|
-
}
|
|
91
|
-
try {
|
|
92
|
-
return parseEnvFile(await readUtf8File(envFilePath));
|
|
93
|
-
}
|
|
94
|
-
catch (error) {
|
|
95
|
-
const reason = error instanceof Error ? error.message : String(error);
|
|
96
|
-
throw new SpawnfileError("validation_error", `Unable to read env file ${envFilePath}: ${reason}`);
|
|
97
|
-
}
|
|
98
|
-
};
|
|
99
|
-
const resolveAuthMountArgs = async (containerReport, authProfile) => {
|
|
100
|
-
if (!authProfile || containerReport.runtime_homes.length === 0) {
|
|
101
|
-
return [];
|
|
102
|
-
}
|
|
103
|
-
const args = [];
|
|
104
|
-
for (const [kind, entry] of Object.entries(authProfile.imports)) {
|
|
105
|
-
if (!entry) {
|
|
106
|
-
continue;
|
|
107
|
-
}
|
|
108
|
-
if (!(await fileExists(entry.path))) {
|
|
109
|
-
throw new SpawnfileError("validation_error", `Imported auth path for ${kind} does not exist: ${entry.path}`);
|
|
110
|
-
}
|
|
111
|
-
for (const runtimeHome of containerReport.runtime_homes) {
|
|
112
|
-
args.push("-v", `${entry.path}:${path.posix.join(runtimeHome, getImportMountTargetName(kind))}`);
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
return args;
|
|
116
|
-
};
|
|
117
24
|
export const createDockerRunInvocation = async (compileResult, imageTag, options = {}) => {
|
|
118
25
|
const containerReport = compileResult.report.container;
|
|
119
26
|
if (!containerReport) {
|
|
@@ -128,8 +35,17 @@ export const createDockerRunInvocation = async (compileResult, imageTag, options
|
|
|
128
35
|
assertRunEnvironmentSatisfied(containerReport, env, preparedRuntimeAuth.coveredModelSecrets);
|
|
129
36
|
await ensureDirectory(supportDirectory);
|
|
130
37
|
await writeUtf8File(envFilePath, renderDockerEnvFile(env));
|
|
38
|
+
const deploymentName = options.deploymentName
|
|
39
|
+
? normalizeDeploymentName(options.deploymentName)
|
|
40
|
+
: options.detach
|
|
41
|
+
? normalizeDeploymentName(undefined)
|
|
42
|
+
: null;
|
|
131
43
|
const containerName = options.containerName ?? createDefaultContainerName(imageTag);
|
|
132
|
-
const args =
|
|
44
|
+
const args = options.dockerContext
|
|
45
|
+
? ["--context", options.dockerContext, "run"]
|
|
46
|
+
: options.dockerHost
|
|
47
|
+
? ["--host", options.dockerHost, "run"]
|
|
48
|
+
: ["run"];
|
|
133
49
|
if (options.detach) {
|
|
134
50
|
args.push("-d");
|
|
135
51
|
}
|
|
@@ -143,6 +59,16 @@ export const createDockerRunInvocation = async (compileResult, imageTag, options
|
|
|
143
59
|
for (const mount of containerReport.persistent_mounts ?? []) {
|
|
144
60
|
args.push("-v", `${mount.volume_name}:${mount.mount_path}`);
|
|
145
61
|
}
|
|
62
|
+
if (options.detach && deploymentName) {
|
|
63
|
+
const compileFingerprint = compileResult.report.compile_fingerprint ?? "sf1:unknown";
|
|
64
|
+
appendDockerLabelArgs(args, createDockerDeploymentLabels({
|
|
65
|
+
compileFingerprint,
|
|
66
|
+
deployment: deploymentName,
|
|
67
|
+
project: createDockerProjectLabel(compileResult.report.root, compileResult.report.project_name),
|
|
68
|
+
unit: createDockerDeploymentUnitId(deploymentName),
|
|
69
|
+
version: compileResult.report.spawnfile_version
|
|
70
|
+
}));
|
|
71
|
+
}
|
|
146
72
|
args.push("--env-file", envFilePath);
|
|
147
73
|
args.push(...(await resolveAuthMountArgs(containerReport, options.authProfile ?? null)));
|
|
148
74
|
args.push(...preparedRuntimeAuth.mountArgs);
|
|
@@ -153,6 +79,9 @@ export const createDockerRunInvocation = async (compileResult, imageTag, options
|
|
|
153
79
|
containerName,
|
|
154
80
|
cwd: compileResult.outputDirectory,
|
|
155
81
|
detach: options.detach ?? false,
|
|
82
|
+
deploymentName,
|
|
83
|
+
dockerContext: options.dockerContext ?? null,
|
|
84
|
+
dockerHost: options.dockerHost ?? null,
|
|
156
85
|
envFilePath,
|
|
157
86
|
imageTag,
|
|
158
87
|
supportDirectory
|
|
@@ -163,52 +92,100 @@ export const createDockerRunInvocation = async (compileResult, imageTag, options
|
|
|
163
92
|
throw error;
|
|
164
93
|
}
|
|
165
94
|
};
|
|
166
|
-
|
|
167
|
-
const
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
95
|
+
const readExistingDeploymentRecord = async (outputDirectory, deploymentName) => {
|
|
96
|
+
const recordPath = resolveDeploymentRecordPath(outputDirectory, deploymentName);
|
|
97
|
+
if (!await fileExists(recordPath)) {
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
return readDeploymentRecordFromOutput(outputDirectory, deploymentName);
|
|
101
|
+
};
|
|
102
|
+
const firstDeploymentUnit = (record) => record.units[0] ?? null;
|
|
103
|
+
export const resolveDetachedDeploymentOptions = async (outputDirectory, options) => {
|
|
104
|
+
if (!options.detach) {
|
|
105
|
+
return options;
|
|
106
|
+
}
|
|
107
|
+
const deploymentName = normalizeDeploymentName(options.deploymentName);
|
|
108
|
+
const record = await readExistingDeploymentRecord(outputDirectory, deploymentName);
|
|
109
|
+
if (!record) {
|
|
110
|
+
return {
|
|
111
|
+
...options,
|
|
112
|
+
deploymentName
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
const unit = firstDeploymentUnit(record);
|
|
116
|
+
if (!options.dockerContext && !options.dockerHost) {
|
|
117
|
+
await verifyDockerDeploymentTarget(record.target, {
|
|
118
|
+
dockerCommand: options.dockerCommand,
|
|
119
|
+
execFile: options.targetExecFile
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
return {
|
|
123
|
+
authProfile: options.authProfile ?? record.auth_profile ?? undefined,
|
|
124
|
+
containerName: options.containerName ?? unit?.container_name ?? undefined,
|
|
125
|
+
deploymentName,
|
|
126
|
+
dockerContext: options.dockerContext ?? dockerContextNameForTarget(record.target) ?? undefined,
|
|
127
|
+
dockerHost: options.dockerHost ?? dockerHostValueForTarget(record.target) ?? undefined,
|
|
128
|
+
envFilePath: options.envFilePath ?? record.env_file,
|
|
129
|
+
imageTag: options.imageTag ?? unit?.image_tag
|
|
130
|
+
};
|
|
131
|
+
};
|
|
184
132
|
export const runProject = async (inputPath, options = {}) => {
|
|
133
|
+
const resolvedOptions = await resolveDetachedDeploymentOptions(path.resolve(options.outputDirectory ?? DEFAULT_OUTPUT_DIRECTORY), {
|
|
134
|
+
authProfile: options.authProfile,
|
|
135
|
+
containerName: options.containerName,
|
|
136
|
+
deploymentName: options.deploymentName,
|
|
137
|
+
detach: options.detach,
|
|
138
|
+
dockerCommand: options.dockerCommand,
|
|
139
|
+
dockerContext: options.dockerContext,
|
|
140
|
+
dockerHost: options.dockerHost,
|
|
141
|
+
envFilePath: options.envFilePath,
|
|
142
|
+
imageTag: options.imageTag,
|
|
143
|
+
targetExecFile: options.targetExecFile
|
|
144
|
+
});
|
|
185
145
|
const compileResult = await compileProject(inputPath, {
|
|
186
146
|
clean: options.clean,
|
|
187
147
|
outputDirectory: options.outputDirectory
|
|
188
148
|
});
|
|
189
|
-
const imageTag =
|
|
190
|
-
const authProfile =
|
|
191
|
-
? await requireAuthProfile(
|
|
149
|
+
const imageTag = resolvedOptions.imageTag ?? createDefaultImageTag(resolveImageTagRoot(inputPath));
|
|
150
|
+
const authProfile = resolvedOptions.authProfile
|
|
151
|
+
? await requireAuthProfile(resolvedOptions.authProfile)
|
|
192
152
|
: null;
|
|
193
153
|
const invocation = await createDockerRunInvocation(compileResult, imageTag, {
|
|
194
154
|
authProfile,
|
|
195
|
-
containerName:
|
|
155
|
+
containerName: resolvedOptions.containerName,
|
|
196
156
|
detach: options.detach,
|
|
157
|
+
deploymentName: resolvedOptions.deploymentName,
|
|
197
158
|
dockerCommand: options.dockerCommand,
|
|
198
|
-
|
|
159
|
+
dockerContext: resolvedOptions.dockerContext,
|
|
160
|
+
dockerHost: resolvedOptions.dockerHost,
|
|
161
|
+
envFilePath: resolvedOptions.envFilePath
|
|
199
162
|
});
|
|
163
|
+
let runMetadata;
|
|
200
164
|
try {
|
|
201
|
-
await (options.runRunner ?? runDockerContainer)(invocation);
|
|
165
|
+
runMetadata = await (options.runRunner ?? runDockerContainer)(invocation);
|
|
202
166
|
}
|
|
203
167
|
finally {
|
|
204
168
|
if (!invocation.detach) {
|
|
205
169
|
await removeDirectory(invocation.supportDirectory);
|
|
206
170
|
}
|
|
207
171
|
}
|
|
172
|
+
const deploymentRecordPath = invocation.detach && invocation.deploymentName
|
|
173
|
+
? await writeDockerDeploymentRecordForRun({
|
|
174
|
+
authProfileName: authProfile?.name ?? null,
|
|
175
|
+
envFilePath: resolvedOptions.envFilePath,
|
|
176
|
+
imageTag,
|
|
177
|
+
invocation,
|
|
178
|
+
outputDirectory: compileResult.outputDirectory,
|
|
179
|
+
report: compileResult.report,
|
|
180
|
+
runMetadata: runMetadata ?? undefined,
|
|
181
|
+
targetExecFile: options.targetExecFile
|
|
182
|
+
})
|
|
183
|
+
: null;
|
|
208
184
|
return {
|
|
209
185
|
...compileResult,
|
|
210
186
|
authProfileName: authProfile?.name ?? null,
|
|
211
187
|
containerName: invocation.containerName,
|
|
188
|
+
deploymentRecordPath,
|
|
212
189
|
imageTag
|
|
213
190
|
};
|
|
214
191
|
};
|
|
@@ -6,4 +6,9 @@ interface PreparedRunAuth {
|
|
|
6
6
|
}
|
|
7
7
|
export declare const prepareRuntimeAuthMounts: (outputDirectory: string, containerReport: ContainerReport, authProfile: ResolvedAuthProfile | null, env: Record<string, string>, tempRoot: string) => Promise<PreparedRunAuth>;
|
|
8
8
|
export declare const assertDeclaredModelAuthSatisfied: (containerReport: ContainerReport, authProfile: ResolvedAuthProfile | null) => void;
|
|
9
|
+
export declare const resolveRunEnvironment: (containerReport: ContainerReport, authProfile: ResolvedAuthProfile | null, envFileEnv?: Record<string, string>) => Record<string, string>;
|
|
10
|
+
export declare const assertRunEnvironmentSatisfied: (containerReport: ContainerReport, env: Record<string, string>, coveredModelSecrets: Set<string>) => void;
|
|
11
|
+
export declare const renderDockerEnvFile: (env: Record<string, string>) => string;
|
|
12
|
+
export declare const readRunEnvFile: (envFilePath: string | undefined) => Promise<Record<string, string>>;
|
|
13
|
+
export declare const resolveAuthMountArgs: (containerReport: ContainerReport, authProfile: ResolvedAuthProfile | null) => Promise<string[]>;
|
|
9
14
|
export {};
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { randomBytes } from "node:crypto";
|
|
3
|
+
import { parseEnvFile } from "../auth/index.js";
|
|
4
|
+
import { fileExists, readUtf8File } from "../filesystem/index.js";
|
|
1
5
|
import { SpawnfileError } from "../shared/index.js";
|
|
2
6
|
import { getRuntimeAdapter } from "../runtime/index.js";
|
|
3
7
|
const MODEL_AUTH_IMPORT_KINDS = {
|
|
@@ -57,3 +61,97 @@ export const assertDeclaredModelAuthSatisfied = (containerReport, authProfile) =
|
|
|
57
61
|
throw new SpawnfileError("validation_error", `Auth profile ${authProfile.name} is missing required auth imports: ${missingImportKinds.join(", ")}`);
|
|
58
62
|
}
|
|
59
63
|
};
|
|
64
|
+
const getImportMountTargetName = (kind) => kind === "claude-code" ? ".claude" : ".codex";
|
|
65
|
+
const createGeneratedRuntimeSecret = (secretName) => {
|
|
66
|
+
if (secretName === "OPENCLAW_GATEWAY_TOKEN" || secretName === "OPENCLAW_HOOKS_TOKEN") {
|
|
67
|
+
return randomBytes(24).toString("hex");
|
|
68
|
+
}
|
|
69
|
+
return null;
|
|
70
|
+
};
|
|
71
|
+
const hasEnvValue = (env, name) => typeof env[name] === "string" && env[name].length > 0;
|
|
72
|
+
const collectMissingRequiredSecrets = (containerReport, env, coveredModelSecrets) => {
|
|
73
|
+
const missing = new Set();
|
|
74
|
+
for (const secretName of containerReport.secrets_required) {
|
|
75
|
+
if (hasEnvValue(env, secretName)) {
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
if (!containerReport.model_secrets_required.includes(secretName)) {
|
|
79
|
+
missing.add(secretName);
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
const requiredInstances = (containerReport.runtime_instances ?? []).filter((instance) => instance.model_secrets_required.includes(secretName));
|
|
83
|
+
const isCoveredEverywhere = requiredInstances.length > 0 &&
|
|
84
|
+
requiredInstances.every((instance) => coveredModelSecrets.has(`${instance.id}:${secretName}`));
|
|
85
|
+
if (!isCoveredEverywhere) {
|
|
86
|
+
missing.add(secretName);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return [...missing].sort();
|
|
90
|
+
};
|
|
91
|
+
export const resolveRunEnvironment = (containerReport, authProfile, envFileEnv = {}) => {
|
|
92
|
+
const env = {
|
|
93
|
+
...(authProfile?.env ?? {}),
|
|
94
|
+
...envFileEnv
|
|
95
|
+
};
|
|
96
|
+
for (const name of new Set([...Object.keys(env), ...containerReport.secrets_required])) {
|
|
97
|
+
const processValue = process.env[name];
|
|
98
|
+
if (typeof processValue === "string" && processValue.length > 0) {
|
|
99
|
+
env[name] = processValue;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
for (const name of containerReport.runtime_secrets_required) {
|
|
103
|
+
if (hasEnvValue(env, name)) {
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
const generatedValue = createGeneratedRuntimeSecret(name);
|
|
107
|
+
if (generatedValue) {
|
|
108
|
+
env[name] = generatedValue;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
for (const [name, value] of Object.entries(env)) {
|
|
112
|
+
if (value.includes("\n")) {
|
|
113
|
+
throw new SpawnfileError("validation_error", `Env value for ${name} contains a newline and cannot be written to a Docker env file`);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
return env;
|
|
117
|
+
};
|
|
118
|
+
export const assertRunEnvironmentSatisfied = (containerReport, env, coveredModelSecrets) => {
|
|
119
|
+
const missing = collectMissingRequiredSecrets(containerReport, env, coveredModelSecrets);
|
|
120
|
+
if (missing.length > 0) {
|
|
121
|
+
throw new SpawnfileError("validation_error", `Missing required runtime env: ${missing.sort().join(", ")}`);
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
export const renderDockerEnvFile = (env) => `${Object.entries(env)
|
|
125
|
+
.sort(([left], [right]) => left.localeCompare(right))
|
|
126
|
+
.map(([name, value]) => `${name}=${value}`)
|
|
127
|
+
.join("\n")}\n`;
|
|
128
|
+
export const readRunEnvFile = async (envFilePath) => {
|
|
129
|
+
if (!envFilePath) {
|
|
130
|
+
return {};
|
|
131
|
+
}
|
|
132
|
+
try {
|
|
133
|
+
return parseEnvFile(await readUtf8File(envFilePath));
|
|
134
|
+
}
|
|
135
|
+
catch (error) {
|
|
136
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
137
|
+
throw new SpawnfileError("validation_error", `Unable to read env file ${envFilePath}: ${reason}`);
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
export const resolveAuthMountArgs = async (containerReport, authProfile) => {
|
|
141
|
+
if (!authProfile || containerReport.runtime_homes.length === 0) {
|
|
142
|
+
return [];
|
|
143
|
+
}
|
|
144
|
+
const args = [];
|
|
145
|
+
for (const [kind, entry] of Object.entries(authProfile.imports)) {
|
|
146
|
+
if (!entry) {
|
|
147
|
+
continue;
|
|
148
|
+
}
|
|
149
|
+
if (!(await fileExists(entry.path))) {
|
|
150
|
+
throw new SpawnfileError("validation_error", `Imported auth path for ${kind} does not exist: ${entry.path}`);
|
|
151
|
+
}
|
|
152
|
+
for (const runtimeHome of containerReport.runtime_homes) {
|
|
153
|
+
args.push("-v", `${entry.path}:${path.posix.join(runtimeHome, getImportMountTargetName(kind))}`);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
return args;
|
|
157
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export interface DockerRunInvocation {
|
|
2
|
+
args: string[];
|
|
3
|
+
command: string;
|
|
4
|
+
containerName: string | null;
|
|
5
|
+
cwd: string;
|
|
6
|
+
detach: boolean;
|
|
7
|
+
deploymentName?: string | null;
|
|
8
|
+
dockerContext?: string | null;
|
|
9
|
+
dockerHost?: string | null;
|
|
10
|
+
envFilePath: string;
|
|
11
|
+
imageTag: string;
|
|
12
|
+
supportDirectory: string;
|
|
13
|
+
}
|
|
14
|
+
export interface DockerRunResult {
|
|
15
|
+
containerId?: string;
|
|
16
|
+
imageId?: string;
|
|
17
|
+
}
|
|
18
|
+
export type DockerRunRunner = (invocation: DockerRunInvocation) => Promise<DockerRunResult | void>;
|
|
19
|
+
export declare const runDockerContainer: DockerRunRunner;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { execFile as execFileCallback, spawn } from "node:child_process";
|
|
2
|
+
import { promisify } from "node:util";
|
|
3
|
+
import { SpawnfileError } from "../shared/index.js";
|
|
4
|
+
const execFile = promisify(execFileCallback);
|
|
5
|
+
const inspectImageArgs = (invocation, containerId) => {
|
|
6
|
+
const base = invocation.dockerContext
|
|
7
|
+
? ["--context", invocation.dockerContext, "inspect"]
|
|
8
|
+
: invocation.dockerHost
|
|
9
|
+
? ["--host", invocation.dockerHost, "inspect"]
|
|
10
|
+
: ["inspect"];
|
|
11
|
+
return [...base, "--format", "{{.Image}}", containerId];
|
|
12
|
+
};
|
|
13
|
+
const inspectDetachedImageId = async (invocation, containerId) => {
|
|
14
|
+
try {
|
|
15
|
+
const { stdout } = await execFile(invocation.command, inspectImageArgs(invocation, containerId), {
|
|
16
|
+
cwd: invocation.cwd,
|
|
17
|
+
timeout: 10_000
|
|
18
|
+
});
|
|
19
|
+
return stdout.trim() || undefined;
|
|
20
|
+
}
|
|
21
|
+
catch (error) {
|
|
22
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
23
|
+
throw new SpawnfileError("runtime_error", `Unable to inspect detached container ${containerId} image id: ${message}`);
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
export const runDockerContainer = async (invocation) => new Promise((resolve, reject) => {
|
|
27
|
+
let stdout = "";
|
|
28
|
+
const child = spawn(invocation.command, invocation.args, {
|
|
29
|
+
cwd: invocation.cwd,
|
|
30
|
+
stdio: invocation.detach ? ["ignore", "pipe", "inherit"] : "inherit"
|
|
31
|
+
});
|
|
32
|
+
if (invocation.detach && child.stdout) {
|
|
33
|
+
child.stdout.setEncoding("utf8");
|
|
34
|
+
child.stdout.on("data", (chunk) => {
|
|
35
|
+
stdout += chunk;
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
child.once("error", (error) => {
|
|
39
|
+
reject(new SpawnfileError("runtime_error", `Unable to start docker run for ${invocation.imageTag}: ${error.message}`));
|
|
40
|
+
});
|
|
41
|
+
child.once("exit", (code, signal) => {
|
|
42
|
+
if (code === 0) {
|
|
43
|
+
const containerId = stdout.trim().split(/\s+/)[0];
|
|
44
|
+
if (!invocation.detach || !containerId) {
|
|
45
|
+
resolve(undefined);
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
inspectDetachedImageId(invocation, containerId)
|
|
49
|
+
.then((imageId) => resolve({ containerId, ...(imageId ? { imageId } : {}) }))
|
|
50
|
+
.catch(reject);
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
reject(new SpawnfileError("runtime_error", signal
|
|
54
|
+
? `Docker run for ${invocation.imageTag} exited from signal ${signal}`
|
|
55
|
+
: `Docker run for ${invocation.imageTag} failed with exit code ${code ?? "unknown"}`));
|
|
56
|
+
});
|
|
57
|
+
});
|
package/dist/compiler/types.d.ts
CHANGED
|
@@ -82,8 +82,7 @@ export interface ResolvedHttpSurface {
|
|
|
82
82
|
port?: number;
|
|
83
83
|
}
|
|
84
84
|
export interface ResolvedMoltnetRoomPolicy {
|
|
85
|
-
|
|
86
|
-
reply?: "auto" | "never";
|
|
85
|
+
wake?: "all" | "mentions" | "thread_only" | "never";
|
|
87
86
|
}
|
|
88
87
|
export interface ResolvedMoltnetDMConfig extends ResolvedMoltnetRoomPolicy {
|
|
89
88
|
enabled: boolean;
|
|
@@ -113,6 +112,8 @@ export interface ResolvedTeamNetworkRoom {
|
|
|
113
112
|
id: string;
|
|
114
113
|
members: string[];
|
|
115
114
|
name?: string;
|
|
115
|
+
visibility?: "public" | "private";
|
|
116
|
+
write_policy?: "members" | "operators" | "registered_agents";
|
|
116
117
|
}
|
|
117
118
|
export interface ResolvedTeamNetwork {
|
|
118
119
|
expose?: boolean;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type DockerTargetExecFile } from "../deployment/index.js";
|
|
1
2
|
import { type BuildProjectResult, type DockerBuildRunner } from "./buildProject.js";
|
|
2
3
|
import { type DockerRunRunner } from "./runProject.js";
|
|
3
4
|
import { CompileProjectOptions } from "./compileProject.js";
|
|
@@ -6,14 +7,19 @@ export interface UpProjectOptions extends CompileProjectOptions {
|
|
|
6
7
|
buildRunner?: DockerBuildRunner;
|
|
7
8
|
containerName?: string;
|
|
8
9
|
detach?: boolean;
|
|
10
|
+
deploymentName?: string;
|
|
9
11
|
dockerCommand?: string;
|
|
12
|
+
dockerContext?: string;
|
|
13
|
+
dockerHost?: string;
|
|
10
14
|
envFilePath?: string;
|
|
11
15
|
imageTag?: string;
|
|
12
16
|
runRunner?: DockerRunRunner;
|
|
17
|
+
targetExecFile?: DockerTargetExecFile;
|
|
13
18
|
}
|
|
14
19
|
export interface UpProjectResult extends BuildProjectResult {
|
|
15
20
|
authProfileName: string | null;
|
|
16
21
|
containerName: string | null;
|
|
22
|
+
deploymentRecordPath?: string | null;
|
|
17
23
|
supportDirectory: string | null;
|
|
18
24
|
}
|
|
19
25
|
export declare const upProject: (inputPath: string, options?: UpProjectOptions) => Promise<UpProjectResult>;
|