spawnfile 0.1.1 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +79 -396
- package/dist/cli/modelCommands.d.ts +3 -0
- package/dist/cli/modelCommands.js +68 -0
- package/dist/cli/runCli.d.ts +6 -1
- package/dist/cli/runCli.js +12 -67
- package/dist/cli/runtimeCommands.d.ts +3 -0
- package/dist/cli/runtimeCommands.js +20 -0
- package/dist/cli/surfaceCommands.d.ts +3 -0
- package/dist/cli/surfaceCommands.js +98 -0
- package/dist/compiler/agentSurfaces.js +51 -5
- package/dist/compiler/buildCompilePlan.js +36 -40
- package/dist/compiler/buildCompilePlanRuntime.d.ts +14 -0
- package/dist/compiler/buildCompilePlanRuntime.js +39 -0
- package/dist/compiler/buildCompilePlanTeams.d.ts +5 -0
- package/dist/compiler/buildCompilePlanTeams.js +38 -0
- package/dist/compiler/compilePlanHelpers.js +4 -1
- package/dist/compiler/compileProject.js +62 -13
- package/dist/compiler/compileProjectSupport.d.ts +17 -0
- package/dist/compiler/compileProjectSupport.js +136 -0
- package/dist/compiler/containerArtifacts.d.ts +6 -1
- package/dist/compiler/containerArtifacts.js +26 -4
- package/dist/compiler/containerArtifactsPlans.js +16 -1
- package/dist/compiler/containerArtifactsRender.d.ts +4 -2
- package/dist/compiler/containerArtifactsRender.js +21 -126
- package/dist/compiler/containerArtifactsTypes.d.ts +7 -0
- package/dist/compiler/containerEntrypointRender.d.ts +12 -0
- package/dist/compiler/containerEntrypointRender.js +186 -0
- package/dist/compiler/index.d.ts +2 -0
- package/dist/compiler/index.js +2 -0
- package/dist/compiler/interactiveSurfaceScopes.d.ts +2 -0
- package/dist/compiler/interactiveSurfaceScopes.js +21 -0
- package/dist/compiler/moltnetArtifacts.d.ts +27 -0
- package/dist/compiler/moltnetArtifacts.js +204 -0
- package/dist/compiler/moltnetBinaries.d.ts +4 -0
- package/dist/compiler/moltnetBinaries.js +103 -0
- package/dist/compiler/moltnetClientConfig.d.ts +11 -0
- package/dist/compiler/moltnetClientConfig.js +89 -0
- package/dist/compiler/moltnetRepresentativeResolution.d.ts +16 -0
- package/dist/compiler/moltnetRepresentativeResolution.js +86 -0
- package/dist/compiler/moltnetResolution.d.ts +3 -0
- package/dist/compiler/moltnetResolution.js +201 -0
- package/dist/compiler/runProject.js +1 -1
- package/dist/compiler/surfaceDefinitions.d.ts +55 -0
- package/dist/compiler/surfaceDefinitions.js +204 -0
- package/dist/compiler/teamContextHelpers.d.ts +18 -0
- package/dist/compiler/teamContextHelpers.js +112 -0
- package/dist/compiler/teamContextSupport.d.ts +4 -0
- package/dist/compiler/teamContextSupport.js +264 -0
- package/dist/compiler/teamContextSupport.testHelpers.d.ts +16 -0
- package/dist/compiler/teamContextSupport.testHelpers.js +68 -0
- package/dist/compiler/teamContextTypes.d.ts +28 -0
- package/dist/compiler/teamContextTypes.js +1 -0
- package/dist/compiler/teamRoster.d.ts +12 -0
- package/dist/compiler/teamRoster.js +48 -0
- package/dist/compiler/teamRosterEntries.d.ts +13 -0
- package/dist/compiler/teamRosterEntries.js +230 -0
- package/dist/compiler/teamRosterTypes.d.ts +45 -0
- package/dist/compiler/teamRosterTypes.js +1 -0
- package/dist/compiler/types.d.ts +72 -6
- package/dist/compiler/updateProjectRuntime.d.ts +9 -0
- package/dist/compiler/updateProjectRuntime.js +67 -0
- package/dist/compiler/updateProjectSurfaces.d.ts +8 -0
- package/dist/compiler/updateProjectSurfaces.js +106 -0
- package/dist/manifest/loadManifest.js +4 -4
- package/dist/manifest/renderSpawnfile.js +74 -8
- package/dist/manifest/scaffold.js +1 -3
- package/dist/manifest/schemas.d.ts +227 -17
- package/dist/manifest/schemas.js +62 -20
- package/dist/manifest/surfaceSchemas.d.ts +154 -0
- package/dist/manifest/surfaceSchemas.js +77 -5
- package/dist/runtime/common.js +3 -0
- package/dist/runtime/openclaw/adapter.js +38 -5
- package/dist/runtime/openclaw/moltnet.d.ts +12 -0
- package/dist/runtime/openclaw/moltnet.js +124 -0
- package/dist/runtime/openclaw/surfaces.js +3 -0
- package/dist/runtime/picoclaw/adapter.js +27 -8
- package/dist/runtime/picoclaw/pico.d.ts +2 -0
- package/dist/runtime/picoclaw/pico.js +2 -0
- package/dist/runtime/picoclaw/surfaces.js +11 -0
- package/dist/runtime/tinyclaw/adapter.js +22 -8
- package/dist/runtime/tinyclaw/runAuth.js +28 -1
- package/dist/runtime/tinyclaw/surfaces.js +8 -0
- package/dist/runtime/types.d.ts +11 -0
- package/package.json +4 -2
- package/runtimes.yaml +4 -4
|
@@ -1,23 +1,19 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
2
|
import { chmod } from "node:fs/promises";
|
|
3
|
-
import { ensureDirectory, removeDirectory
|
|
3
|
+
import { ensureDirectory, removeDirectory } from "../filesystem/index.js";
|
|
4
4
|
import { createCompileReport, createDiagnostic, writeCompileReport } from "../report/index.js";
|
|
5
5
|
import { DEFAULT_OUTPUT_DIRECTORY } from "../shared/index.js";
|
|
6
6
|
import { assertRuntimeCanCompile, createRuntimeLifecycleDiagnostics, getRuntimeAdapter } from "../runtime/index.js";
|
|
7
7
|
import { buildCompilePlan } from "./buildCompilePlan.js";
|
|
8
8
|
import { createContainerArtifacts } from "./containerArtifacts.js";
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
await ensureDirectory(path.dirname(targetPath));
|
|
13
|
-
await writeUtf8File(targetPath, file.content);
|
|
14
|
-
}));
|
|
15
|
-
};
|
|
9
|
+
import { injectMoltnetWorkspaceFiles, injectTeamCompileSupportFiles, prepareTeamCompileSupport, writeEmittedFiles } from "./compileProjectSupport.js";
|
|
10
|
+
import { generateMoltnetArtifacts } from "./moltnetArtifacts.js";
|
|
11
|
+
import { stageMoltnetBinaries } from "./moltnetBinaries.js";
|
|
16
12
|
const createTeamCapabilities = (outcome, message) => [
|
|
17
13
|
{ key: "team.members", message, outcome },
|
|
18
|
-
{ key: "team.
|
|
19
|
-
{ key: "team.
|
|
20
|
-
{ key: "team.
|
|
14
|
+
{ key: "team.mode", message, outcome },
|
|
15
|
+
{ key: "team.lead", message, outcome },
|
|
16
|
+
{ key: "team.external", message, outcome },
|
|
21
17
|
{ key: "team.shared", message, outcome },
|
|
22
18
|
{ key: "team.nested", message, outcome }
|
|
23
19
|
];
|
|
@@ -148,6 +144,46 @@ const enforcePolicy = (nodeReport, policyMode, onDegrade) => {
|
|
|
148
144
|
}
|
|
149
145
|
}
|
|
150
146
|
};
|
|
147
|
+
const createIdentityCapabilities = (node) => [
|
|
148
|
+
...(node.surfaces?.slack?.identity
|
|
149
|
+
? [{
|
|
150
|
+
key: "surfaces.slack.identity",
|
|
151
|
+
message: "Declared Slack identity was preserved for roster output",
|
|
152
|
+
outcome: "supported"
|
|
153
|
+
}]
|
|
154
|
+
: []),
|
|
155
|
+
...(node.surfaces?.discord?.identity
|
|
156
|
+
? [{
|
|
157
|
+
key: "surfaces.discord.identity",
|
|
158
|
+
message: "Declared Discord identity was preserved for roster output",
|
|
159
|
+
outcome: "supported"
|
|
160
|
+
}]
|
|
161
|
+
: []),
|
|
162
|
+
...(node.surfaces?.telegram?.identity
|
|
163
|
+
? [{
|
|
164
|
+
key: "surfaces.telegram.identity",
|
|
165
|
+
message: "Declared Telegram identity was preserved for roster output",
|
|
166
|
+
outcome: "supported"
|
|
167
|
+
}]
|
|
168
|
+
: []),
|
|
169
|
+
...(node.surfaces?.whatsapp?.identity
|
|
170
|
+
? [{
|
|
171
|
+
key: "surfaces.whatsapp.identity",
|
|
172
|
+
message: "Declared WhatsApp identity was preserved for roster output",
|
|
173
|
+
outcome: "supported"
|
|
174
|
+
}]
|
|
175
|
+
: [])
|
|
176
|
+
];
|
|
177
|
+
const augmentNodeReports = (compiledNodes, support) => {
|
|
178
|
+
for (const compiled of compiledNodes) {
|
|
179
|
+
if (compiled.value.kind === "team") {
|
|
180
|
+
compiled.report.capabilities.push(...(support.capabilitiesByTeamSource.get(compiled.value.source) ?? []));
|
|
181
|
+
compiled.report.diagnostics.push(...(support.diagnosticsByTeamSource.get(compiled.value.source) ?? []));
|
|
182
|
+
continue;
|
|
183
|
+
}
|
|
184
|
+
compiled.report.capabilities.push(...createIdentityCapabilities(compiled.value));
|
|
185
|
+
}
|
|
186
|
+
};
|
|
151
187
|
export const compileProject = async (inputPath, options = {}) => {
|
|
152
188
|
const plan = await buildCompilePlan(inputPath);
|
|
153
189
|
const outputDirectory = path.resolve(options.outputDirectory ?? DEFAULT_OUTPUT_DIRECTORY);
|
|
@@ -155,21 +191,34 @@ export const compileProject = async (inputPath, options = {}) => {
|
|
|
155
191
|
await removeDirectory(outputDirectory);
|
|
156
192
|
}
|
|
157
193
|
await ensureDirectory(outputDirectory);
|
|
194
|
+
const teamCompileSupport = await prepareTeamCompileSupport(plan);
|
|
158
195
|
const nodeReports = [];
|
|
159
196
|
const compiledNodes = [];
|
|
160
197
|
for (const node of plan.nodes) {
|
|
161
198
|
let compiled;
|
|
162
199
|
if (node.kind === "agent") {
|
|
163
200
|
compiled = await compileAgentNode(outputDirectory, node);
|
|
201
|
+
await injectTeamCompileSupportFiles(outputDirectory, compiled, teamCompileSupport);
|
|
164
202
|
}
|
|
165
203
|
else {
|
|
166
204
|
compiled = await compileTeamNode(outputDirectory, node);
|
|
167
205
|
}
|
|
168
|
-
enforcePolicy(compiled.report, node.value.policyMode, node.value.policyOnDegrade);
|
|
169
206
|
nodeReports.push(compiled.report);
|
|
170
207
|
compiledNodes.push(compiled);
|
|
171
208
|
}
|
|
172
|
-
|
|
209
|
+
augmentNodeReports(compiledNodes, teamCompileSupport);
|
|
210
|
+
for (const compiled of compiledNodes) {
|
|
211
|
+
enforcePolicy(compiled.report, compiled.value.policyMode, compiled.value.policyOnDegrade);
|
|
212
|
+
}
|
|
213
|
+
const moltnetArtifacts = await generateMoltnetArtifacts(plan);
|
|
214
|
+
const hasStagedMoltnetBinaries = moltnetArtifacts
|
|
215
|
+
? await stageMoltnetBinaries(outputDirectory)
|
|
216
|
+
: false;
|
|
217
|
+
await injectMoltnetWorkspaceFiles(outputDirectory, compiledNodes, moltnetArtifacts);
|
|
218
|
+
const containerArtifacts = await createContainerArtifacts(plan, compiledNodes, {
|
|
219
|
+
hasStagedMoltnetBinaries,
|
|
220
|
+
moltnet: moltnetArtifacts
|
|
221
|
+
});
|
|
173
222
|
await writeEmittedFiles(outputDirectory, containerArtifacts.files);
|
|
174
223
|
await Promise.all(containerArtifacts.executablePaths.map((filePath) => chmod(path.join(outputDirectory, filePath), 0o755)));
|
|
175
224
|
const report = createCompileReport(plan.root, nodeReports, [], containerArtifacts.report);
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type EmittedFile } from "../runtime/index.js";
|
|
2
|
+
import type { MoltnetArtifacts } from "./moltnetArtifacts.js";
|
|
3
|
+
import type { TeamCompileSupport } from "./teamContextSupport.js";
|
|
4
|
+
import type { ResolvedAgentNode, ResolvedTeamNode } from "./types.js";
|
|
5
|
+
export { prepareTeamCompileSupport } from "./teamContextSupport.js";
|
|
6
|
+
export type { TeamCompileSupport } from "./teamContextSupport.js";
|
|
7
|
+
export interface CompiledNodeOutput {
|
|
8
|
+
emittedFiles: EmittedFile[];
|
|
9
|
+
kind: "agent" | "team";
|
|
10
|
+
report: {
|
|
11
|
+
output_dir: string | null;
|
|
12
|
+
};
|
|
13
|
+
value: ResolvedAgentNode | ResolvedTeamNode;
|
|
14
|
+
}
|
|
15
|
+
export declare const writeEmittedFiles: (outputDirectory: string, files: EmittedFile[]) => Promise<void>;
|
|
16
|
+
export declare const injectTeamCompileSupportFiles: (outputDirectory: string, compiled: CompiledNodeOutput, support: TeamCompileSupport) => Promise<void>;
|
|
17
|
+
export declare const injectMoltnetWorkspaceFiles: (outputDirectory: string, compiledNodes: CompiledNodeOutput[], artifacts: MoltnetArtifacts | null) => Promise<void>;
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { execFile as execFileCallback } from "node:child_process";
|
|
2
|
+
import { chmod, readFile } from "node:fs/promises";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { promisify } from "node:util";
|
|
5
|
+
import { ensureDirectory, writeUtf8File } from "../filesystem/index.js";
|
|
6
|
+
import { getRuntimeAdapter } from "../runtime/index.js";
|
|
7
|
+
import { SpawnfileError } from "../shared/index.js";
|
|
8
|
+
import { resolveMoltnetCliCommand } from "./moltnetBinaries.js";
|
|
9
|
+
import { createMoltnetClientConfigFiles, resolveMoltnetWorkspaceLayout } from "./moltnetClientConfig.js";
|
|
10
|
+
export { prepareTeamCompileSupport } from "./teamContextSupport.js";
|
|
11
|
+
const execFile = promisify(execFileCallback);
|
|
12
|
+
const resolveAgentWorkspacePaths = (node) => {
|
|
13
|
+
const systemInstructionSurface = getRuntimeAdapter(node.runtime.name).systemInstructionSurface;
|
|
14
|
+
if (!systemInstructionSurface) {
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
const systemInstructionPath = systemInstructionSurface.resolvePath({ node });
|
|
18
|
+
const systemInstructionDirectory = path.posix.dirname(systemInstructionPath);
|
|
19
|
+
return {
|
|
20
|
+
systemInstructionPath,
|
|
21
|
+
spawnfileDirectory: systemInstructionDirectory === "."
|
|
22
|
+
? ".spawnfile"
|
|
23
|
+
: `${systemInstructionDirectory}/.spawnfile`
|
|
24
|
+
};
|
|
25
|
+
};
|
|
26
|
+
const upsertEmittedFile = (emittedFiles, nextFile) => {
|
|
27
|
+
const existing = emittedFiles.find((file) => file.path === nextFile.path);
|
|
28
|
+
if (existing) {
|
|
29
|
+
existing.content = nextFile.content;
|
|
30
|
+
return existing;
|
|
31
|
+
}
|
|
32
|
+
emittedFiles.push(nextFile);
|
|
33
|
+
return nextFile;
|
|
34
|
+
};
|
|
35
|
+
export const writeEmittedFiles = async (outputDirectory, files) => {
|
|
36
|
+
await Promise.all(files.map(async (file) => {
|
|
37
|
+
const targetPath = path.join(outputDirectory, file.path);
|
|
38
|
+
await ensureDirectory(path.dirname(targetPath));
|
|
39
|
+
await writeUtf8File(targetPath, file.content);
|
|
40
|
+
if (file.mode !== undefined) {
|
|
41
|
+
await chmod(targetPath, file.mode);
|
|
42
|
+
}
|
|
43
|
+
}));
|
|
44
|
+
};
|
|
45
|
+
export const injectTeamCompileSupportFiles = async (outputDirectory, compiled, support) => {
|
|
46
|
+
if (compiled.kind !== "agent" ||
|
|
47
|
+
compiled.value.kind !== "agent" ||
|
|
48
|
+
!compiled.report.output_dir) {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
const supportFiles = support.filesByAgentSource.get(compiled.value.source);
|
|
52
|
+
if (!supportFiles || supportFiles.length === 0) {
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
const workspacePaths = resolveAgentWorkspacePaths(compiled.value);
|
|
56
|
+
if (!workspacePaths) {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
const filesToWrite = supportFiles.map((file) => upsertEmittedFile(compiled.emittedFiles, {
|
|
60
|
+
...file,
|
|
61
|
+
path: file.path.startsWith(".spawnfile/") || file.path === "TEAM.md"
|
|
62
|
+
? path.posix.join(path.posix.dirname(workspacePaths.spawnfileDirectory), file.path)
|
|
63
|
+
: file.path
|
|
64
|
+
}));
|
|
65
|
+
const rosterBlock = "\n\n<!-- spawnfile-team-context:start -->\n" +
|
|
66
|
+
"## Spawnfile Team Context\n\n" +
|
|
67
|
+
"Read `.spawnfile/team-contexts.md` and `.spawnfile/team-contexts.yaml` for generated team membership, representative context, and surface bindings.\n" +
|
|
68
|
+
"<!-- spawnfile-team-context:end -->\n";
|
|
69
|
+
const existingAgentsMd = compiled.emittedFiles.find((file) => file.path === workspacePaths.systemInstructionPath);
|
|
70
|
+
filesToWrite.push(existingAgentsMd
|
|
71
|
+
? (() => {
|
|
72
|
+
existingAgentsMd.content += rosterBlock;
|
|
73
|
+
return existingAgentsMd;
|
|
74
|
+
})()
|
|
75
|
+
: upsertEmittedFile(compiled.emittedFiles, {
|
|
76
|
+
content: rosterBlock.trimStart(),
|
|
77
|
+
path: workspacePaths.systemInstructionPath
|
|
78
|
+
}));
|
|
79
|
+
await writeEmittedFiles(path.join(outputDirectory, compiled.report.output_dir), filesToWrite);
|
|
80
|
+
};
|
|
81
|
+
export const injectMoltnetWorkspaceFiles = async (outputDirectory, compiledNodes, artifacts) => {
|
|
82
|
+
if (!artifacts) {
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
let moltnetCliCommand = null;
|
|
86
|
+
for (const compiled of compiledNodes) {
|
|
87
|
+
if (compiled.kind !== "agent" ||
|
|
88
|
+
compiled.value.kind !== "agent" ||
|
|
89
|
+
!compiled.report.output_dir) {
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
const runtimeOutputDirectory = path.join(outputDirectory, compiled.report.output_dir);
|
|
93
|
+
const moltnetClientConfigFiles = createMoltnetClientConfigFiles(compiled.value, artifacts);
|
|
94
|
+
if (moltnetClientConfigFiles.length === 0) {
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
const layout = resolveMoltnetWorkspaceLayout(compiled.value.runtime.name, compiled.value.name);
|
|
98
|
+
const workspacePath = path.join(runtimeOutputDirectory, layout.workspaceRootPath);
|
|
99
|
+
for (const file of moltnetClientConfigFiles) {
|
|
100
|
+
upsertEmittedFile(compiled.emittedFiles, file);
|
|
101
|
+
}
|
|
102
|
+
await writeEmittedFiles(runtimeOutputDirectory, moltnetClientConfigFiles);
|
|
103
|
+
if (!moltnetCliCommand) {
|
|
104
|
+
moltnetCliCommand = await resolveMoltnetCliCommand();
|
|
105
|
+
}
|
|
106
|
+
try {
|
|
107
|
+
await execFile(moltnetCliCommand, [
|
|
108
|
+
"skill",
|
|
109
|
+
"install",
|
|
110
|
+
"--runtime",
|
|
111
|
+
layout.cliRuntime,
|
|
112
|
+
"--workspace",
|
|
113
|
+
workspacePath
|
|
114
|
+
]);
|
|
115
|
+
}
|
|
116
|
+
catch (error) {
|
|
117
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
118
|
+
throw new SpawnfileError("compile_error", `Unable to install the Moltnet skill into ${compiled.value.name}: ${reason}`);
|
|
119
|
+
}
|
|
120
|
+
const moltnetSkillFiles = await Promise.all(layout.skillPaths.map(async (filePath) => {
|
|
121
|
+
try {
|
|
122
|
+
return {
|
|
123
|
+
content: await readFile(path.join(runtimeOutputDirectory, filePath), "utf8"),
|
|
124
|
+
path: filePath
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
catch (error) {
|
|
128
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
129
|
+
throw new SpawnfileError("compile_error", `Moltnet skill install for ${compiled.value.name} did not produce ${filePath}: ${reason}`);
|
|
130
|
+
}
|
|
131
|
+
}));
|
|
132
|
+
for (const file of moltnetSkillFiles) {
|
|
133
|
+
upsertEmittedFile(compiled.emittedFiles, file);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
};
|
|
@@ -1,4 +1,9 @@
|
|
|
1
|
+
import type { MoltnetArtifacts } from "./moltnetArtifacts.js";
|
|
1
2
|
import type { CompiledNodeArtifact, GeneratedContainerArtifacts } from "./containerArtifactsTypes.js";
|
|
2
3
|
import type { CompilePlan } from "./types.js";
|
|
3
4
|
export type { CompiledNodeArtifact, GeneratedContainerArtifacts } from "./containerArtifactsTypes.js";
|
|
4
|
-
export
|
|
5
|
+
export interface ContainerArtifactOptions {
|
|
6
|
+
hasStagedMoltnetBinaries?: boolean;
|
|
7
|
+
moltnet?: MoltnetArtifacts | null;
|
|
8
|
+
}
|
|
9
|
+
export declare const createContainerArtifacts: (plan: CompilePlan, compiledNodes: CompiledNodeArtifact[], options?: ContainerArtifactOptions) => Promise<GeneratedContainerArtifacts>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createEnvVariableMap, createRuntimeTargetPlans } from "./containerArtifactsPlans.js";
|
|
2
2
|
import { createRootfsFiles, renderDockerfile, renderEntrypoint, renderEnvExample } from "./containerArtifactsRender.js";
|
|
3
|
-
export const createContainerArtifacts = async (plan, compiledNodes) => {
|
|
3
|
+
export const createContainerArtifacts = async (plan, compiledNodes, options = {}) => {
|
|
4
4
|
const runtimePlans = await createRuntimeTargetPlans(plan, compiledNodes);
|
|
5
5
|
const envVariables = [...createEnvVariableMap(compiledNodes, runtimePlans).values()].sort((left, right) => left.name.localeCompare(right.name));
|
|
6
6
|
const requiredSecrets = envVariables
|
|
@@ -17,12 +17,24 @@ export const createContainerArtifacts = async (plan, compiledNodes) => {
|
|
|
17
17
|
.sort();
|
|
18
18
|
const files = [
|
|
19
19
|
...createRootfsFiles(runtimePlans),
|
|
20
|
+
...(options.moltnet?.files ?? []),
|
|
20
21
|
{
|
|
21
|
-
content: await renderDockerfile(runtimePlans
|
|
22
|
+
content: await renderDockerfile(runtimePlans, {
|
|
23
|
+
hasMoltnet: Boolean(options.moltnet),
|
|
24
|
+
hasStagedMoltnetBinaries: options.hasStagedMoltnetBinaries,
|
|
25
|
+
moltnetPublishedPorts: options.moltnet?.publishedPorts ?? []
|
|
26
|
+
}),
|
|
22
27
|
path: "Dockerfile"
|
|
23
28
|
},
|
|
24
29
|
{
|
|
25
|
-
content: renderEntrypoint(runtimePlans, requiredSecrets.filter((secretName) => !modelSecretsRequired.includes(secretName))
|
|
30
|
+
content: renderEntrypoint(runtimePlans, requiredSecrets.filter((secretName) => !modelSecretsRequired.includes(secretName)), {
|
|
31
|
+
moltnet: options.moltnet
|
|
32
|
+
? {
|
|
33
|
+
bridgePlans: options.moltnet.bridgePlans,
|
|
34
|
+
serverPlans: options.moltnet.serverPlans
|
|
35
|
+
}
|
|
36
|
+
: undefined
|
|
37
|
+
}),
|
|
26
38
|
path: "entrypoint.sh"
|
|
27
39
|
},
|
|
28
40
|
{
|
|
@@ -30,7 +42,9 @@ export const createContainerArtifacts = async (plan, compiledNodes) => {
|
|
|
30
42
|
path: ".env.example"
|
|
31
43
|
}
|
|
32
44
|
];
|
|
33
|
-
const
|
|
45
|
+
const runtimePorts = runtimePlans.flatMap((plan) => plan.publishedPort ? [plan.publishedPort] : []);
|
|
46
|
+
const moltnetPorts = options.moltnet?.publishedPorts ?? [];
|
|
47
|
+
const ports = [...new Set([...runtimePorts, ...moltnetPorts])].sort((left, right) => left - right);
|
|
34
48
|
const runtimeHomes = [
|
|
35
49
|
...new Set(runtimePlans.flatMap((plan) => (plan.instancePaths.homePath ? [plan.instancePaths.homePath] : [])))
|
|
36
50
|
].sort();
|
|
@@ -48,6 +62,14 @@ export const createContainerArtifacts = async (plan, compiledNodes) => {
|
|
|
48
62
|
return {
|
|
49
63
|
executablePaths: ["entrypoint.sh"],
|
|
50
64
|
files,
|
|
65
|
+
...(options.moltnet
|
|
66
|
+
? {
|
|
67
|
+
moltnet: {
|
|
68
|
+
bridgePlans: options.moltnet.bridgePlans,
|
|
69
|
+
serverPlans: options.moltnet.serverPlans
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
: {}),
|
|
51
73
|
report: {
|
|
52
74
|
dockerfile: "Dockerfile",
|
|
53
75
|
entrypoint: "entrypoint.sh",
|
|
@@ -76,6 +76,9 @@ export const createEnvVariableMap = (compiledNodes, runtimePlans) => {
|
|
|
76
76
|
for (const variable of runtimePlan.meta.env ?? []) {
|
|
77
77
|
register(variable.name, variable.required, variable.description, "runtime");
|
|
78
78
|
}
|
|
79
|
+
for (const binding of runtimePlan.targetConfigEnvBindings ?? []) {
|
|
80
|
+
register(binding.envName, true, `Injected into ${runtimePlan.runtimeName} runtime config`, "runtime");
|
|
81
|
+
}
|
|
79
82
|
}
|
|
80
83
|
return variables;
|
|
81
84
|
};
|
|
@@ -115,6 +118,13 @@ const resolveTargetModelAuthMethods = (target, inputs) => {
|
|
|
115
118
|
}
|
|
116
119
|
return Object.fromEntries([...methods.entries()].sort(([left], [right]) => left.localeCompare(right)));
|
|
117
120
|
};
|
|
121
|
+
const resolveTargetExposure = (target, inputs) => {
|
|
122
|
+
const sourceIds = new Set(target.sourceIds ?? []);
|
|
123
|
+
if (sourceIds.size === 0) {
|
|
124
|
+
return false;
|
|
125
|
+
}
|
|
126
|
+
return inputs.some((input) => sourceIds.has(input.id) && input.value.kind === "agent" && input.value.expose === true);
|
|
127
|
+
};
|
|
118
128
|
export const createRuntimeTargetPlans = async (plan, compiledNodes) => {
|
|
119
129
|
const runtimeNames = Object.keys(plan.runtimes).sort();
|
|
120
130
|
const runtimePlans = [];
|
|
@@ -135,6 +145,7 @@ export const createRuntimeTargetPlans = async (plan, compiledNodes) => {
|
|
|
135
145
|
targets.forEach((target, index) => {
|
|
136
146
|
assertTargetHasConfig(runtimeName, target.id, adapter.container, target.files);
|
|
137
147
|
const instancePaths = resolveInstancePaths(runtimeName, target.id, adapter.container);
|
|
148
|
+
const portStride = adapter.container.portStride ?? 1;
|
|
138
149
|
runtimePlans.push({
|
|
139
150
|
configEnvBindings: resolveTargetConfigEnvBindings(adapter.container, target) ?? [],
|
|
140
151
|
envFiles: resolveTargetEnvFiles(instancePaths.configPath, target),
|
|
@@ -143,9 +154,13 @@ export const createRuntimeTargetPlans = async (plan, compiledNodes) => {
|
|
|
143
154
|
meta: adapter.container,
|
|
144
155
|
modelAuthMethods: resolveTargetModelAuthMethods(target, targetInputs),
|
|
145
156
|
modelSecretsRequired: resolveTargetModelSecrets(target, targetInputs),
|
|
146
|
-
port: adapter.container.port ? adapter.container.port + index : undefined,
|
|
157
|
+
port: adapter.container.port ? adapter.container.port + (index * portStride) : undefined,
|
|
158
|
+
publishedPort: resolveTargetExposure(target, targetInputs) && adapter.container.port
|
|
159
|
+
? adapter.container.port + (index * portStride)
|
|
160
|
+
: undefined,
|
|
147
161
|
runtimeName,
|
|
148
162
|
runtimeRoot: recipe.runtimeRoot,
|
|
163
|
+
targetConfigEnvBindings: target.configEnvBindings,
|
|
149
164
|
targetFiles: target.files
|
|
150
165
|
});
|
|
151
166
|
});
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type { EmittedFile } from "../runtime/index.js";
|
|
2
2
|
import type { ContainerEnvVariable, RuntimeTargetPlan } from "./containerArtifactsTypes.js";
|
|
3
|
+
import type { EntrypointOptions } from "./containerEntrypointRender.js";
|
|
4
|
+
export { renderEntrypoint } from "./containerEntrypointRender.js";
|
|
5
|
+
export type { EntrypointOptions } from "./containerEntrypointRender.js";
|
|
3
6
|
export declare const renderEnvExample: (variables: ContainerEnvVariable[]) => string;
|
|
4
|
-
export declare const renderDockerfile: (runtimePlans: RuntimeTargetPlan[]) => Promise<string>;
|
|
7
|
+
export declare const renderDockerfile: (runtimePlans: RuntimeTargetPlan[], options?: EntrypointOptions) => Promise<string>;
|
|
5
8
|
export declare const createRootfsFiles: (runtimePlans: RuntimeTargetPlan[]) => EmittedFile[];
|
|
6
|
-
export declare const renderEntrypoint: (runtimePlans: RuntimeTargetPlan[], requiredSecrets: string[]) => string;
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
2
|
import { createRuntimeInstallRecipe } from "../runtime/index.js";
|
|
3
3
|
import { SpawnfileError } from "../shared/index.js";
|
|
4
|
+
export { renderEntrypoint } from "./containerEntrypointRender.js";
|
|
5
|
+
import { MOLTNET_BIN_DIRECTORY, MOLTNET_BINARY_NAMES } from "./moltnetBinaries.js";
|
|
4
6
|
const CONTAINER_ROOTFS_ROOT = "container/rootfs";
|
|
5
7
|
const GATEWAY_PORT_PLACEHOLDER = "<gateway-port>";
|
|
8
|
+
const MOLTNET_INSTALL_SCRIPT_URL = "https://moltnet.dev/install.sh";
|
|
6
9
|
const WORKSPACE_PLACEHOLDER = "<workspace-path>";
|
|
7
10
|
const shellQuote = (value) => `'${value.replace(/'/g, `'\"'\"'`)}'`;
|
|
8
11
|
const extractNodeMajorVersion = (image) => Number(image.match(/^node:(\d+)/)?.[1] ?? "0");
|
|
@@ -44,7 +47,7 @@ export const renderEnvExample = (variables) => {
|
|
|
44
47
|
}
|
|
45
48
|
return `${lines.join("\n").trimEnd()}\n`;
|
|
46
49
|
};
|
|
47
|
-
export const renderDockerfile = async (runtimePlans) => {
|
|
50
|
+
export const renderDockerfile = async (runtimePlans, options = {}) => {
|
|
48
51
|
const runtimeNames = [...new Set(runtimePlans.map((plan) => plan.runtimeName))];
|
|
49
52
|
const runtimeRecipes = await Promise.all(runtimeNames.map((runtimeName) => createRuntimeInstallRecipe(runtimeName)));
|
|
50
53
|
const baseImage = selectBaseImage(runtimePlans);
|
|
@@ -52,20 +55,33 @@ export const renderDockerfile = async (runtimePlans) => {
|
|
|
52
55
|
const systemDeps = [
|
|
53
56
|
...new Set([
|
|
54
57
|
...runtimePlans.flatMap((plan) => plan.meta.systemDeps),
|
|
58
|
+
...(options.hasMoltnet && !options.hasStagedMoltnetBinaries
|
|
59
|
+
? ["ca-certificates", "curl", "tar"]
|
|
60
|
+
: []),
|
|
55
61
|
...(needsJsonEnvWriter ? ["python3"] : [])
|
|
56
62
|
])
|
|
57
63
|
].sort();
|
|
58
64
|
const globalNpmPackages = [
|
|
59
65
|
...new Set(runtimePlans.flatMap((plan) => plan.meta.globalNpmPackages ?? []))
|
|
60
66
|
].sort();
|
|
61
|
-
const
|
|
62
|
-
const
|
|
67
|
+
const runtimePorts = runtimePlans.flatMap((plan) => plan.publishedPort ? [plan.publishedPort] : []);
|
|
68
|
+
const moltnetPorts = options.moltnetPublishedPorts ?? [];
|
|
69
|
+
const exposedPorts = [...new Set([...runtimePorts, ...moltnetPorts])].sort((left, right) => left - right);
|
|
70
|
+
const lines = [];
|
|
71
|
+
lines.push(`FROM ${baseImage}`);
|
|
72
|
+
lines.push("USER root", "", "WORKDIR /opt/spawnfile");
|
|
63
73
|
if (systemDeps.length > 0) {
|
|
64
74
|
lines.push(createPackageInstallCommand(systemDeps), "");
|
|
65
75
|
}
|
|
66
76
|
if (globalNpmPackages.length > 0) {
|
|
67
77
|
lines.push(createNpmPackageInstallCommand(globalNpmPackages), "");
|
|
68
78
|
}
|
|
79
|
+
if (options.hasMoltnet && options.hasStagedMoltnetBinaries) {
|
|
80
|
+
lines.push(`COPY ${MOLTNET_BIN_DIRECTORY}/ /usr/local/bin/`, `RUN chmod +x ${MOLTNET_BINARY_NAMES.map((binaryName) => `/usr/local/bin/${binaryName}`).join(" ")}`, "");
|
|
81
|
+
}
|
|
82
|
+
else if (options.hasMoltnet) {
|
|
83
|
+
lines.push(`RUN MOLTNET_INSTALL_DIR=/usr/local/bin sh -c ${shellQuote(`curl -fsSL ${MOLTNET_INSTALL_SCRIPT_URL} | sh`)}`, "");
|
|
84
|
+
}
|
|
69
85
|
for (const recipe of runtimeRecipes) {
|
|
70
86
|
for (const copyCommand of recipe.copyCommands) {
|
|
71
87
|
lines.push(copyCommand);
|
|
@@ -76,7 +92,8 @@ export const renderDockerfile = async (runtimePlans) => {
|
|
|
76
92
|
lines.push("");
|
|
77
93
|
}
|
|
78
94
|
lines.push('RUN if ! id -u spawnfile >/dev/null 2>&1; then useradd --create-home --home-dir /home/spawnfile --shell /bin/bash spawnfile; fi', "");
|
|
79
|
-
lines.push("COPY container/rootfs/ /", "COPY .env.example /opt/spawnfile/.env.example", 'COPY entrypoint.sh /opt/spawnfile/entrypoint.sh', "RUN chmod +x /opt/spawnfile/entrypoint.sh"
|
|
95
|
+
lines.push("COPY container/rootfs/ /", "COPY .env.example /opt/spawnfile/.env.example", 'COPY entrypoint.sh /opt/spawnfile/entrypoint.sh', "RUN chmod +x /opt/spawnfile/entrypoint.sh");
|
|
96
|
+
lines.push("RUN mkdir -p /var/lib/spawnfile && chown -R spawnfile:spawnfile /var/lib/spawnfile /opt/spawnfile");
|
|
80
97
|
if (exposedPorts.length > 0) {
|
|
81
98
|
lines.push(`EXPOSE ${exposedPorts.join(" ")}`);
|
|
82
99
|
}
|
|
@@ -84,32 +101,6 @@ export const renderDockerfile = async (runtimePlans) => {
|
|
|
84
101
|
lines.push('ENTRYPOINT ["/opt/spawnfile/entrypoint.sh"]');
|
|
85
102
|
return `${lines.join("\n").trimEnd()}\n`;
|
|
86
103
|
};
|
|
87
|
-
const createEnvironmentAssignments = (plan) => {
|
|
88
|
-
const envAssignments = [];
|
|
89
|
-
if (plan.instancePaths.homePath) {
|
|
90
|
-
envAssignments.push(`HOME=${shellQuote(plan.instancePaths.homePath)}`);
|
|
91
|
-
}
|
|
92
|
-
if (plan.meta.homeEnv && plan.instancePaths.homePath) {
|
|
93
|
-
envAssignments.push(`${plan.meta.homeEnv}=${shellQuote(plan.instancePaths.homePath)}`);
|
|
94
|
-
}
|
|
95
|
-
if (plan.meta.configPathEnv) {
|
|
96
|
-
envAssignments.push(`${plan.meta.configPathEnv}=${shellQuote(plan.instancePaths.configPath)}`);
|
|
97
|
-
}
|
|
98
|
-
if (plan.meta.portEnv && plan.port) {
|
|
99
|
-
envAssignments.push(`${plan.meta.portEnv}=${shellQuote(String(plan.port))}`);
|
|
100
|
-
}
|
|
101
|
-
for (const [name, value] of Object.entries(plan.meta.staticEnv ?? {}).sort(([left], [right]) => left.localeCompare(right))) {
|
|
102
|
-
envAssignments.push(`${name}=${shellQuote(value)}`);
|
|
103
|
-
}
|
|
104
|
-
return envAssignments;
|
|
105
|
-
};
|
|
106
|
-
const createEnvFileWrites = (plan) => plan.envFiles.map((binding) => `write_env_file ${shellQuote(binding.envName)} ${shellQuote(binding.filePath)}`);
|
|
107
|
-
const createConfigEnvWrites = (plan) => (plan.configEnvBindings ?? []).map((binding) => `apply_json_env_value ${shellQuote(plan.instancePaths.configPath)} ${shellQuote(binding.envName)} ${shellQuote(binding.jsonPath)}`);
|
|
108
|
-
const resolveStartCommand = (plan) => plan.meta.startCommand
|
|
109
|
-
.map((token) => token
|
|
110
|
-
.replaceAll("<runtime-root>", plan.runtimeRoot)
|
|
111
|
-
.replaceAll("<port>", plan.port ? String(plan.port) : ""))
|
|
112
|
-
.filter((token) => token.length > 0);
|
|
113
104
|
export const createRootfsFiles = (runtimePlans) => runtimePlans.flatMap((plan) => plan.targetFiles.map((file) => {
|
|
114
105
|
if (file.path === plan.meta.configFileName) {
|
|
115
106
|
return {
|
|
@@ -139,99 +130,3 @@ export const createRootfsFiles = (runtimePlans) => runtimePlans.flatMap((plan) =
|
|
|
139
130
|
}
|
|
140
131
|
throw new SpawnfileError("runtime_error", `Container target ${plan.id} for ${plan.runtimeName} emitted unsupported path ${file.path}`);
|
|
141
132
|
}));
|
|
142
|
-
export const renderEntrypoint = (runtimePlans, requiredSecrets) => {
|
|
143
|
-
const lines = [
|
|
144
|
-
"#!/usr/bin/env bash",
|
|
145
|
-
"set -euo pipefail",
|
|
146
|
-
"",
|
|
147
|
-
"require_env() {",
|
|
148
|
-
' local name=\"$1\"',
|
|
149
|
-
' if [ -z \"${!name:-}\" ]; then',
|
|
150
|
-
' echo \"Missing required env: $name\" >&2',
|
|
151
|
-
" exit 1",
|
|
152
|
-
" fi",
|
|
153
|
-
"}",
|
|
154
|
-
"",
|
|
155
|
-
"require_file() {",
|
|
156
|
-
' local target=\"$1\"',
|
|
157
|
-
' if [ ! -f \"$target\" ]; then',
|
|
158
|
-
' echo \"Missing required file: $target\" >&2',
|
|
159
|
-
" exit 1",
|
|
160
|
-
" fi",
|
|
161
|
-
"}",
|
|
162
|
-
"",
|
|
163
|
-
"write_env_file() {",
|
|
164
|
-
' local name=\"$1\"',
|
|
165
|
-
' local target=\"$2\"',
|
|
166
|
-
' if [ -z \"${!name:-}\" ]; then',
|
|
167
|
-
" return",
|
|
168
|
-
" fi",
|
|
169
|
-
' mkdir -p \"$(dirname \"$target\")\"',
|
|
170
|
-
' printf %s \"${!name:-}\" > \"$target\"',
|
|
171
|
-
"}",
|
|
172
|
-
"",
|
|
173
|
-
"apply_json_env_value() {",
|
|
174
|
-
' local target=\"$1\"',
|
|
175
|
-
' local name=\"$2\"',
|
|
176
|
-
' local json_path=\"$3\"',
|
|
177
|
-
' if [ -z \"${!name:-}\" ]; then',
|
|
178
|
-
" return",
|
|
179
|
-
" fi",
|
|
180
|
-
" python3 - \"$target\" \"$name\" \"$json_path\" <<'PY'",
|
|
181
|
-
"import json",
|
|
182
|
-
"import os",
|
|
183
|
-
"import sys",
|
|
184
|
-
"",
|
|
185
|
-
"target_path = sys.argv[1]",
|
|
186
|
-
"env_name = sys.argv[2]",
|
|
187
|
-
"json_path = sys.argv[3].split('.')",
|
|
188
|
-
"value = os.environ.get(env_name)",
|
|
189
|
-
"if value is None:",
|
|
190
|
-
" raise SystemExit(0)",
|
|
191
|
-
"",
|
|
192
|
-
"with open(target_path, encoding='utf-8') as handle:",
|
|
193
|
-
" data = json.load(handle)",
|
|
194
|
-
"",
|
|
195
|
-
"cursor = data",
|
|
196
|
-
"for part in json_path[:-1]:",
|
|
197
|
-
" child = cursor.get(part)",
|
|
198
|
-
" if not isinstance(child, dict):",
|
|
199
|
-
" child = {}",
|
|
200
|
-
" cursor[part] = child",
|
|
201
|
-
" cursor = child",
|
|
202
|
-
"",
|
|
203
|
-
"cursor[json_path[-1]] = value",
|
|
204
|
-
"",
|
|
205
|
-
"with open(target_path, 'w', encoding='utf-8') as handle:",
|
|
206
|
-
" json.dump(data, handle, indent=2)",
|
|
207
|
-
" handle.write('\\n')",
|
|
208
|
-
"PY",
|
|
209
|
-
"}",
|
|
210
|
-
""
|
|
211
|
-
];
|
|
212
|
-
for (const secretName of requiredSecrets) {
|
|
213
|
-
lines.push(`require_env ${shellQuote(secretName)}`);
|
|
214
|
-
}
|
|
215
|
-
if (requiredSecrets.length > 0) {
|
|
216
|
-
lines.push("");
|
|
217
|
-
}
|
|
218
|
-
if (runtimePlans.length === 1) {
|
|
219
|
-
const plan = runtimePlans[0];
|
|
220
|
-
const commandTokens = resolveStartCommand(plan);
|
|
221
|
-
const envAssignments = createEnvironmentAssignments(plan);
|
|
222
|
-
const envFileWrites = createEnvFileWrites(plan);
|
|
223
|
-
const configEnvWrites = createConfigEnvWrites(plan);
|
|
224
|
-
lines.push(`mkdir -p ${shellQuote(plan.instancePaths.workspacePath)}`, `require_file ${shellQuote(plan.instancePaths.configPath)}`, ...envFileWrites, ...configEnvWrites, `${envAssignments.join(" ")} exec ${commandTokens.map(shellQuote).join(" ")}`);
|
|
225
|
-
return `${lines.join("\n").trimEnd()}\n`;
|
|
226
|
-
}
|
|
227
|
-
lines.push("PIDS=()", "", "terminate_children() {", ' for pid in "${PIDS[@]:-}"; do', ' kill "$pid" 2>/dev/null || true', " done", "}", "", "trap terminate_children INT TERM EXIT", "");
|
|
228
|
-
for (const plan of runtimePlans) {
|
|
229
|
-
const commandTokens = resolveStartCommand(plan);
|
|
230
|
-
const envAssignments = createEnvironmentAssignments(plan);
|
|
231
|
-
const envFileWrites = createEnvFileWrites(plan);
|
|
232
|
-
const configEnvWrites = createConfigEnvWrites(plan);
|
|
233
|
-
lines.push(`mkdir -p ${shellQuote(plan.instancePaths.workspacePath)}`, `require_file ${shellQuote(plan.instancePaths.configPath)}`, ...envFileWrites, ...configEnvWrites, `${envAssignments.join(" ")} ${commandTokens.map(shellQuote).join(" ")} &`, 'PIDS+=("$!")', "");
|
|
234
|
-
}
|
|
235
|
-
lines.push('if [ "${#PIDS[@]}" -eq 0 ]; then', ' echo "No runtime targets were generated for this compile output" >&2', " exit 1", "fi", "", "status=0", 'for pid in "${PIDS[@]}"; do', ' if ! wait "$pid"; then', " status=1", " fi", "done", "", 'exit "$status"');
|
|
236
|
-
return `${lines.join("\n").trimEnd()}\n`;
|
|
237
|
-
};
|
|
@@ -2,6 +2,7 @@ import type { ContainerReport } from "../report/index.js";
|
|
|
2
2
|
import type { EmittedFile, RuntimeContainerConfigEnvBinding, RuntimeContainerMeta } from "../runtime/index.js";
|
|
3
3
|
import type { ModelAuthMethod } from "../shared/index.js";
|
|
4
4
|
import type { ResolvedAgentNode, ResolvedTeamNode } from "./types.js";
|
|
5
|
+
import type { MoltnetBridgePlan, MoltnetServerPlan } from "./moltnetArtifacts.js";
|
|
5
6
|
export interface ContainerEnvVariable {
|
|
6
7
|
categories: Array<"model" | "project" | "runtime" | "surface">;
|
|
7
8
|
description: string;
|
|
@@ -24,8 +25,10 @@ export interface RuntimeTargetPlan {
|
|
|
24
25
|
modelAuthMethods: Record<string, ModelAuthMethod>;
|
|
25
26
|
modelSecretsRequired: string[];
|
|
26
27
|
port?: number;
|
|
28
|
+
publishedPort?: number;
|
|
27
29
|
runtimeName: string;
|
|
28
30
|
runtimeRoot: string;
|
|
31
|
+
targetConfigEnvBindings?: RuntimeContainerConfigEnvBinding[];
|
|
29
32
|
targetFiles: EmittedFile[];
|
|
30
33
|
}
|
|
31
34
|
export interface CompiledNodeArtifact {
|
|
@@ -38,5 +41,9 @@ export interface CompiledNodeArtifact {
|
|
|
38
41
|
export interface GeneratedContainerArtifacts {
|
|
39
42
|
executablePaths: string[];
|
|
40
43
|
files: EmittedFile[];
|
|
44
|
+
moltnet?: {
|
|
45
|
+
bridgePlans: MoltnetBridgePlan[];
|
|
46
|
+
serverPlans: MoltnetServerPlan[];
|
|
47
|
+
};
|
|
41
48
|
report: ContainerReport;
|
|
42
49
|
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { RuntimeTargetPlan } from "./containerArtifactsTypes.js";
|
|
2
|
+
import type { MoltnetArtifacts } from "./moltnetArtifacts.js";
|
|
3
|
+
export interface EntrypointOptions {
|
|
4
|
+
hasMoltnet?: boolean;
|
|
5
|
+
hasStagedMoltnetBinaries?: boolean;
|
|
6
|
+
moltnet?: {
|
|
7
|
+
bridgePlans: MoltnetArtifacts["bridgePlans"];
|
|
8
|
+
serverPlans: MoltnetArtifacts["serverPlans"];
|
|
9
|
+
};
|
|
10
|
+
moltnetPublishedPorts?: number[];
|
|
11
|
+
}
|
|
12
|
+
export declare const renderEntrypoint: (runtimePlans: RuntimeTargetPlan[], requiredSecrets: string[], options?: EntrypointOptions) => string;
|