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
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { SpawnfileError } from "../shared/index.js";
|
|
2
|
-
import { createMoltnetOpenTokenDirectory, createMoltnetNativeServerConfig, createMoltnetNodeConfigPath, createMoltnetServerConfigPath, resolveMoltnetBaseUrl,
|
|
2
|
+
import { createMoltnetOpenTokenDirectory, createMoltnetNativeServerConfig, createMoltnetNodeConfigPath, createMoltnetServerConfigPath, resolveMoltnetBaseUrl, resolveMoltnetStorePersistenceMountPath } from "./moltnetConfigLowering.js";
|
|
3
|
+
import { assertNetworkBindingEnvUniqueness } from "./networkBinding.js";
|
|
3
4
|
import { listConcreteMoltnetRoomMemberIds } from "./moltnetRoomMemberships.js";
|
|
4
|
-
import {
|
|
5
|
+
import { assertCompatibleMoltnetNetworkName, assertCompatibleMoltnetRoomPolicy, assertCompatibleMoltnetServer } from "./moltnetRoomPolicyCompatibility.js";
|
|
6
|
+
import { createMoltnetNodeConfigContent } from "./moltnetNodeConfig.js";
|
|
5
7
|
import { createShortHash, slugify } from "./helpers.js";
|
|
6
8
|
const DEFAULT_MOLTNET_PORT = 8787;
|
|
7
9
|
const ROOTFS_PREFIX = "container/rootfs";
|
|
@@ -39,6 +41,8 @@ export const generateMoltnetArtifacts = async (plan) => {
|
|
|
39
41
|
if (existingPlan.baseUrl !== resolveMoltnetBaseUrl(server)) {
|
|
40
42
|
throw new SpawnfileError("validation_error", `Duplicate Moltnet network ${network.id} declares conflicting server URL`);
|
|
41
43
|
}
|
|
44
|
+
assertCompatibleMoltnetNetworkName(network.id, existingPlan.name, network.name);
|
|
45
|
+
assertCompatibleMoltnetServer(network.id, existingPlan.server, server);
|
|
42
46
|
for (const room of network.rooms) {
|
|
43
47
|
const concreteMembers = listConcreteMoltnetRoomMemberIds(plan, teamNode.value, network.id, room);
|
|
44
48
|
const existingRoom = existingPlan.rooms.find((entry) => entry.id === room.id);
|
|
@@ -46,12 +50,18 @@ export const generateMoltnetArtifacts = async (plan) => {
|
|
|
46
50
|
existingRoom.members = [
|
|
47
51
|
...new Set([...existingRoom.members, ...concreteMembers])
|
|
48
52
|
].sort();
|
|
53
|
+
assertCompatibleMoltnetRoomPolicy(network.id, room.id, "visibility", existingRoom.visibility, room.visibility);
|
|
54
|
+
assertCompatibleMoltnetRoomPolicy(network.id, room.id, "write_policy", existingRoom.write_policy, room.write_policy);
|
|
55
|
+
existingRoom.visibility ??= room.visibility;
|
|
56
|
+
existingRoom.write_policy ??= room.write_policy;
|
|
49
57
|
}
|
|
50
58
|
else {
|
|
51
59
|
existingPlan.rooms.push({
|
|
52
60
|
id: room.id,
|
|
53
61
|
members: concreteMembers,
|
|
54
|
-
...(room.name ? { name: room.name } : {})
|
|
62
|
+
...(room.name ? { name: room.name } : {}),
|
|
63
|
+
...(room.visibility ? { visibility: room.visibility } : {}),
|
|
64
|
+
...(room.write_policy ? { write_policy: room.write_policy } : {})
|
|
55
65
|
});
|
|
56
66
|
}
|
|
57
67
|
}
|
|
@@ -73,7 +83,9 @@ export const generateMoltnetArtifacts = async (plan) => {
|
|
|
73
83
|
rooms: network.rooms.map((room) => ({
|
|
74
84
|
id: room.id,
|
|
75
85
|
members: listConcreteMoltnetRoomMemberIds(plan, teamNode.value, network.id, room),
|
|
76
|
-
...(room.name ? { name: room.name } : {})
|
|
86
|
+
...(room.name ? { name: room.name } : {}),
|
|
87
|
+
...(room.visibility ? { visibility: room.visibility } : {}),
|
|
88
|
+
...(room.write_policy ? { write_policy: room.write_policy } : {})
|
|
77
89
|
})),
|
|
78
90
|
server,
|
|
79
91
|
secretPatches: [],
|
|
@@ -99,38 +111,35 @@ export const generateMoltnetArtifacts = async (plan) => {
|
|
|
99
111
|
throw new SpawnfileError("validation_error", `Moltnet persistent mount ${mount.id} resolves to conflicting targets`);
|
|
100
112
|
}
|
|
101
113
|
};
|
|
102
|
-
for (const
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
114
|
+
for (const serverPlan of serverPlans.values()) {
|
|
115
|
+
if (serverPlan.mode !== "managed" || serverPlan.server.mode !== "managed" || !serverPlan.configPath) {
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
const native = createMoltnetNativeServerConfig({
|
|
119
|
+
networkId: serverPlan.networkId,
|
|
120
|
+
networkName: serverPlan.name,
|
|
121
|
+
rooms: serverPlan.rooms,
|
|
122
|
+
server: serverPlan.server
|
|
123
|
+
});
|
|
124
|
+
serverPlan.secretPatches = native.secretPatches;
|
|
125
|
+
configFiles.push({
|
|
126
|
+
content: `${JSON.stringify(native.config, null, 2)}\n`,
|
|
127
|
+
mode: 0o600,
|
|
128
|
+
path: createMoltnetServerConfigPath(serverPlan.id)
|
|
129
|
+
});
|
|
130
|
+
const storeMountPath = resolveMoltnetStorePersistenceMountPath(serverPlan.networkId, serverPlan.server.store);
|
|
131
|
+
if (storeMountPath) {
|
|
132
|
+
const mountId = `moltnet-${serverPlan.networkId}-store`;
|
|
133
|
+
const store = serverPlan.server.store;
|
|
134
|
+
const volumeName = store.kind === "sqlite" || store.kind === "json"
|
|
135
|
+
? store.persistence?.name
|
|
136
|
+
: undefined;
|
|
137
|
+
addPersistentMount({
|
|
138
|
+
id: mountId,
|
|
139
|
+
mountPath: storeMountPath,
|
|
140
|
+
reason: `managed Moltnet ${serverPlan.server.store.kind} store for ${serverPlan.networkId}`,
|
|
141
|
+
volumeName: createPersistentVolumeName(plan.root, mountId, volumeName)
|
|
119
142
|
});
|
|
120
|
-
const storeMountPath = resolveMoltnetStorePersistenceMountPath(network.id, network.server.store);
|
|
121
|
-
if (storeMountPath) {
|
|
122
|
-
const mountId = `moltnet-${network.id}-store`;
|
|
123
|
-
const store = network.server.store;
|
|
124
|
-
const volumeName = store.kind === "sqlite" || store.kind === "json"
|
|
125
|
-
? store.persistence?.name
|
|
126
|
-
: undefined;
|
|
127
|
-
addPersistentMount({
|
|
128
|
-
id: mountId,
|
|
129
|
-
mountPath: storeMountPath,
|
|
130
|
-
reason: `managed Moltnet ${network.server.store.kind} store for ${network.id}`,
|
|
131
|
-
volumeName: createPersistentVolumeName(plan.root, mountId, volumeName)
|
|
132
|
-
});
|
|
133
|
-
}
|
|
134
143
|
}
|
|
135
144
|
}
|
|
136
145
|
for (const node of plan.nodes) {
|
|
@@ -169,10 +178,15 @@ export const generateMoltnetArtifacts = async (plan) => {
|
|
|
169
178
|
throw new SpawnfileError("validation_error", `Duplicate Moltnet node attachment for ${attachment.network}/${attachment.memberId}`);
|
|
170
179
|
}
|
|
171
180
|
nodePlanKeys.add(nodePlanKey);
|
|
172
|
-
const
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
181
|
+
const nodeConfig = createMoltnetNodeConfigContent({
|
|
182
|
+
agentNode,
|
|
183
|
+
attachment: { ...attachment, memberId: attachment.memberId },
|
|
184
|
+
networkServer: serverPlan.server,
|
|
185
|
+
nodeSlug: node.slug,
|
|
186
|
+
plan,
|
|
187
|
+
serverPlan
|
|
188
|
+
});
|
|
189
|
+
const { clientAuth, usesPerAttachmentOpenToken } = nodeConfig;
|
|
176
190
|
if (usesPerAttachmentOpenToken && clientAuth.tokenPath) {
|
|
177
191
|
const mountId = `agent-${node.slug}-moltnet-tokens`;
|
|
178
192
|
addPersistentMount({
|
|
@@ -183,66 +197,7 @@ export const generateMoltnetArtifacts = async (plan) => {
|
|
|
183
197
|
});
|
|
184
198
|
}
|
|
185
199
|
configFiles.push({
|
|
186
|
-
content:
|
|
187
|
-
version: "moltnet.node.v1",
|
|
188
|
-
moltnet: {
|
|
189
|
-
base_url: serverPlan.baseUrl,
|
|
190
|
-
network_id: attachment.network,
|
|
191
|
-
...(clientAuth.mode === "none"
|
|
192
|
-
? {}
|
|
193
|
-
: { auth_mode: clientAuth.mode }),
|
|
194
|
-
...(clientAuth.staticToken
|
|
195
|
-
? { static_token: true }
|
|
196
|
-
: {}),
|
|
197
|
-
...(!usesPerAttachmentOpenToken && clientAuth.tokenEnv
|
|
198
|
-
? {
|
|
199
|
-
token_env: clientAuth.tokenEnv
|
|
200
|
-
}
|
|
201
|
-
: {}),
|
|
202
|
-
...(!usesPerAttachmentOpenToken && clientAuth.tokenPath
|
|
203
|
-
? {
|
|
204
|
-
token_path: clientAuth.tokenPath
|
|
205
|
-
}
|
|
206
|
-
: {})
|
|
207
|
-
},
|
|
208
|
-
attachments: [
|
|
209
|
-
{
|
|
210
|
-
agent: {
|
|
211
|
-
id: attachment.memberId,
|
|
212
|
-
name: agentNode.name
|
|
213
|
-
},
|
|
214
|
-
...(usesPerAttachmentOpenToken
|
|
215
|
-
? {
|
|
216
|
-
moltnet: {
|
|
217
|
-
...(clientAuth.tokenEnv ? { token_env: clientAuth.tokenEnv } : {}),
|
|
218
|
-
...(clientAuth.tokenPath ? { token_path: clientAuth.tokenPath } : {})
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
: {}),
|
|
222
|
-
runtime: resolveRuntimeConfig(plan, agentNode, node.slug, attachment.network, attachment.memberId),
|
|
223
|
-
...(attachment.rooms
|
|
224
|
-
? {
|
|
225
|
-
rooms: Object.entries(attachment.rooms)
|
|
226
|
-
.sort(([left], [right]) => left.localeCompare(right))
|
|
227
|
-
.map(([roomId, policy]) => ({
|
|
228
|
-
id: roomId,
|
|
229
|
-
...(policy.read ? { read: policy.read } : {}),
|
|
230
|
-
...(policy.reply ? { reply: policy.reply } : {})
|
|
231
|
-
}))
|
|
232
|
-
}
|
|
233
|
-
: {}),
|
|
234
|
-
...(attachment.dms
|
|
235
|
-
? {
|
|
236
|
-
dms: {
|
|
237
|
-
enabled: attachment.dms.enabled,
|
|
238
|
-
...(attachment.dms.read ? { read: attachment.dms.read } : {}),
|
|
239
|
-
...(attachment.dms.reply ? { reply: attachment.dms.reply } : {})
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
: {})
|
|
243
|
-
}
|
|
244
|
-
]
|
|
245
|
-
}, null, 2)}\n`,
|
|
200
|
+
content: nodeConfig.content,
|
|
246
201
|
mode: 0o600,
|
|
247
202
|
path: configPath
|
|
248
203
|
});
|
|
@@ -253,6 +208,10 @@ export const generateMoltnetArtifacts = async (plan) => {
|
|
|
253
208
|
}
|
|
254
209
|
}
|
|
255
210
|
const managedServerPlans = [...serverPlans.values()].filter((serverPlan) => serverPlan.mode === "managed");
|
|
211
|
+
assertNetworkBindingEnvUniqueness([...serverPlans.values()].map((serverPlan) => ({
|
|
212
|
+
id: serverPlan.networkId,
|
|
213
|
+
members: [...new Set(serverPlan.rooms.flatMap((room) => room.members))]
|
|
214
|
+
})));
|
|
256
215
|
return {
|
|
257
216
|
files: configFiles,
|
|
258
217
|
nodePlans: nodePlans.sort((left, right) => left.configPath.localeCompare(right.configPath)),
|
|
@@ -7,5 +7,5 @@ export interface MoltnetWorkspaceLayout {
|
|
|
7
7
|
skillPaths: string[];
|
|
8
8
|
workspaceRootPath: string;
|
|
9
9
|
}
|
|
10
|
-
export declare const resolveMoltnetWorkspaceLayout: (runtimeName: string,
|
|
11
|
-
export declare const createMoltnetClientConfigFiles: (node: ResolvedAgentNode, artifacts: MoltnetArtifacts) => EmittedFile[];
|
|
10
|
+
export declare const resolveMoltnetWorkspaceLayout: (runtimeName: string, _agentName: string) => MoltnetWorkspaceLayout;
|
|
11
|
+
export declare const createMoltnetClientConfigFiles: (node: ResolvedAgentNode, artifacts: MoltnetArtifacts, agentSlug?: string) => EmittedFile[];
|
|
@@ -19,16 +19,17 @@ const findServerPlan = (artifacts, attachment) => {
|
|
|
19
19
|
}
|
|
20
20
|
return plan;
|
|
21
21
|
};
|
|
22
|
-
const createAttachmentConfig = (node, artifacts, attachment) => {
|
|
22
|
+
const createAttachmentConfig = (node, artifacts, attachment, agentSlug) => {
|
|
23
23
|
if (!attachment.memberId) {
|
|
24
24
|
throw new SpawnfileError("compile_error", `Moltnet client config requires a resolved member id for ${node.name}`);
|
|
25
25
|
}
|
|
26
26
|
const serverPlan = findServerPlan(artifacts, attachment);
|
|
27
|
-
const auth = resolveMoltnetClientAuth(serverPlan.server, attachment.network, attachment.memberId);
|
|
27
|
+
const auth = resolveMoltnetClientAuth(serverPlan.server, attachment.network, attachment.memberId, agentSlug);
|
|
28
28
|
return {
|
|
29
29
|
agent_name: node.name,
|
|
30
30
|
auth: {
|
|
31
31
|
mode: auth.mode,
|
|
32
|
+
...(auth.registration ? { registration: auth.registration } : {}),
|
|
32
33
|
...(auth.tokenEnv ? { token_env: auth.tokenEnv } : {}),
|
|
33
34
|
...(auth.tokenPath ? { token_path: auth.tokenPath } : {})
|
|
34
35
|
},
|
|
@@ -37,8 +38,7 @@ const createAttachmentConfig = (node, artifacts, attachment) => {
|
|
|
37
38
|
? {
|
|
38
39
|
dms: {
|
|
39
40
|
enabled: attachment.dms.enabled,
|
|
40
|
-
...(attachment.dms.
|
|
41
|
-
...(attachment.dms.reply ? { reply: attachment.dms.reply } : {})
|
|
41
|
+
...(attachment.dms.wake ? { wake: attachment.dms.wake } : {})
|
|
42
42
|
}
|
|
43
43
|
}
|
|
44
44
|
: {}),
|
|
@@ -49,16 +49,20 @@ const createAttachmentConfig = (node, artifacts, attachment) => {
|
|
|
49
49
|
? {
|
|
50
50
|
rooms: Object.entries(attachment.rooms)
|
|
51
51
|
.sort(([left], [right]) => left.localeCompare(right))
|
|
52
|
-
.map(([roomId, policy]) =>
|
|
53
|
-
id
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
52
|
+
.map(([roomId, policy]) => {
|
|
53
|
+
const room = serverPlan.rooms.find((entry) => entry.id === roomId);
|
|
54
|
+
return {
|
|
55
|
+
id: roomId,
|
|
56
|
+
...(room?.visibility ? { visibility: room.visibility } : {}),
|
|
57
|
+
...(room?.write_policy ? { write_policy: room.write_policy } : {}),
|
|
58
|
+
...(policy.wake ? { wake: policy.wake } : {})
|
|
59
|
+
};
|
|
60
|
+
})
|
|
57
61
|
}
|
|
58
62
|
: {})
|
|
59
63
|
};
|
|
60
64
|
};
|
|
61
|
-
export const resolveMoltnetWorkspaceLayout = (runtimeName,
|
|
65
|
+
export const resolveMoltnetWorkspaceLayout = (runtimeName, _agentName) => {
|
|
62
66
|
if (runtimeName === "openclaw" || runtimeName === "picoclaw") {
|
|
63
67
|
return {
|
|
64
68
|
clientConfigPath: `workspace/${GENERATED_CONFIG_PATH}`,
|
|
@@ -67,20 +71,9 @@ export const resolveMoltnetWorkspaceLayout = (runtimeName, agentName) => {
|
|
|
67
71
|
workspaceRootPath: "workspace"
|
|
68
72
|
};
|
|
69
73
|
}
|
|
70
|
-
if (runtimeName === "tinyclaw") {
|
|
71
|
-
return {
|
|
72
|
-
clientConfigPath: `workspace/${agentName}/${GENERATED_CONFIG_PATH}`,
|
|
73
|
-
cliRuntime: runtimeName,
|
|
74
|
-
skillPaths: [
|
|
75
|
-
`workspace/${agentName}/.agents/skills/${GENERATED_SKILL_NAME}/SKILL.md`,
|
|
76
|
-
`workspace/${agentName}/.claude/skills/${GENERATED_SKILL_NAME}/SKILL.md`
|
|
77
|
-
],
|
|
78
|
-
workspaceRootPath: `workspace/${agentName}`
|
|
79
|
-
};
|
|
80
|
-
}
|
|
81
74
|
throw new SpawnfileError("compile_error", `Moltnet client config does not know how to emit files for runtime ${runtimeName}`);
|
|
82
75
|
};
|
|
83
|
-
export const createMoltnetClientConfigFiles = (node, artifacts) => {
|
|
76
|
+
export const createMoltnetClientConfigFiles = (node, artifacts, agentSlug) => {
|
|
84
77
|
const attachments = node.surfaces?.moltnet;
|
|
85
78
|
if (!attachments || attachments.length === 0) {
|
|
86
79
|
return [];
|
|
@@ -88,7 +81,7 @@ export const createMoltnetClientConfigFiles = (node, artifacts) => {
|
|
|
88
81
|
const layout = resolveMoltnetWorkspaceLayout(node.runtime.name, node.name);
|
|
89
82
|
return [
|
|
90
83
|
{
|
|
91
|
-
content: createConfigContent(node, attachments.map((attachment) => createAttachmentConfig(node, artifacts, attachment))),
|
|
84
|
+
content: createConfigContent(node, attachments.map((attachment) => createAttachmentConfig(node, artifacts, attachment, agentSlug))),
|
|
92
85
|
path: layout.clientConfigPath
|
|
93
86
|
}
|
|
94
87
|
];
|
|
@@ -5,6 +5,7 @@ export interface MoltnetSecretPatch {
|
|
|
5
5
|
}
|
|
6
6
|
export interface MoltnetClientAuthPlan {
|
|
7
7
|
mode: "bearer" | "none" | "open";
|
|
8
|
+
registration?: "disabled" | "open" | "token";
|
|
8
9
|
staticToken?: boolean;
|
|
9
10
|
tokenEnv?: string;
|
|
10
11
|
tokenPath?: string;
|
|
@@ -13,6 +14,8 @@ export interface MoltnetNativeRoomConfig {
|
|
|
13
14
|
id: string;
|
|
14
15
|
members: string[];
|
|
15
16
|
name?: string;
|
|
17
|
+
visibility?: "public" | "private";
|
|
18
|
+
write_policy?: "members" | "operators" | "registered_agents";
|
|
16
19
|
}
|
|
17
20
|
export interface MoltnetNativeServerConfigInput {
|
|
18
21
|
networkId: string;
|
|
@@ -55,14 +55,19 @@ export const resolveMoltnetClientAuth = (server, networkId, memberId, agentSlug)
|
|
|
55
55
|
return { mode: "none" };
|
|
56
56
|
}
|
|
57
57
|
const client = server.auth.client;
|
|
58
|
-
|
|
58
|
+
const registrationOpen = server.auth.mode === "open" || server.auth.agent_registration === "open";
|
|
59
|
+
if (registrationOpen && !client) {
|
|
59
60
|
return {
|
|
60
61
|
mode: "open",
|
|
62
|
+
registration: "open",
|
|
61
63
|
tokenPath: createMoltnetOpenTokenPath(networkId, memberId, agentSlug)
|
|
62
64
|
};
|
|
63
65
|
}
|
|
64
66
|
if (!client) {
|
|
65
|
-
return {
|
|
67
|
+
return {
|
|
68
|
+
mode: server.auth.mode,
|
|
69
|
+
...(server.auth.agent_registration ? { registration: server.auth.agent_registration } : {})
|
|
70
|
+
};
|
|
66
71
|
}
|
|
67
72
|
const tokenEnv = client.token_env
|
|
68
73
|
?? (client.token_id && server.mode === "managed"
|
|
@@ -70,6 +75,7 @@ export const resolveMoltnetClientAuth = (server, networkId, memberId, agentSlug)
|
|
|
70
75
|
: undefined);
|
|
71
76
|
return {
|
|
72
77
|
mode: server.auth.mode,
|
|
78
|
+
...(server.auth.agent_registration ? { registration: server.auth.agent_registration } : {}),
|
|
73
79
|
...(client.static_token ? { staticToken: true } : {}),
|
|
74
80
|
...(tokenEnv ? { tokenEnv } : {}),
|
|
75
81
|
...(client.token_path ? { tokenPath: client.token_path } : {})
|
|
@@ -129,6 +135,7 @@ export const createMoltnetNativeServerConfig = ({ networkId, networkName, rooms,
|
|
|
129
135
|
},
|
|
130
136
|
server: {
|
|
131
137
|
listen_addr: renderMoltnetListenAddr(server),
|
|
138
|
+
...(server.console ? { console: server.console } : {}),
|
|
132
139
|
...(server.human_ingress !== undefined ? { human_ingress: server.human_ingress } : {}),
|
|
133
140
|
...(server.direct_messages !== undefined ? { direct_messages: server.direct_messages } : {}),
|
|
134
141
|
...(server.debug_events !== undefined ? { debug_events: server.debug_events } : {}),
|
|
@@ -139,12 +146,16 @@ export const createMoltnetNativeServerConfig = ({ networkId, networkName, rooms,
|
|
|
139
146
|
},
|
|
140
147
|
auth: {
|
|
141
148
|
mode: server.auth.mode,
|
|
149
|
+
...(server.auth.public_read !== undefined ? { public_read: server.auth.public_read } : {}),
|
|
150
|
+
...(server.auth.agent_registration ? { agent_registration: server.auth.agent_registration } : {}),
|
|
142
151
|
...(tokens.length > 0 ? { tokens } : {})
|
|
143
152
|
},
|
|
144
153
|
storage: storageConfigFor(networkId, server.store),
|
|
145
154
|
rooms: rooms.map((room) => ({
|
|
146
155
|
id: room.id,
|
|
147
156
|
...(room.name ? { name: room.name } : {}),
|
|
157
|
+
...(room.visibility ? { visibility: room.visibility } : {}),
|
|
158
|
+
...(room.write_policy ? { write_policy: room.write_policy } : {}),
|
|
148
159
|
members: room.members
|
|
149
160
|
})),
|
|
150
161
|
...(pairings.length > 0 ? { pairings } : {})
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { TeamNetworkServer } from "../manifest/index.js";
|
|
2
|
+
import { type MoltnetClientAuthPlan } from "./moltnetConfigLowering.js";
|
|
3
|
+
import type { CompilePlan, ResolvedAgentNode, ResolvedMoltnetAttachment } from "./types.js";
|
|
4
|
+
interface MoltnetNodeConfigServerPlan {
|
|
5
|
+
baseUrl: string;
|
|
6
|
+
rooms: Array<{
|
|
7
|
+
id: string;
|
|
8
|
+
visibility?: "public" | "private";
|
|
9
|
+
write_policy?: "members" | "operators" | "registered_agents";
|
|
10
|
+
}>;
|
|
11
|
+
}
|
|
12
|
+
export interface MoltnetNodeConfigResult {
|
|
13
|
+
clientAuth: MoltnetClientAuthPlan;
|
|
14
|
+
content: string;
|
|
15
|
+
usesPerAttachmentOpenToken: boolean;
|
|
16
|
+
}
|
|
17
|
+
export declare const createMoltnetNodeConfigContent: ({ agentNode, attachment, networkServer, nodeSlug, plan, serverPlan }: {
|
|
18
|
+
agentNode: ResolvedAgentNode;
|
|
19
|
+
attachment: ResolvedMoltnetAttachment & {
|
|
20
|
+
memberId: string;
|
|
21
|
+
};
|
|
22
|
+
networkServer: TeamNetworkServer;
|
|
23
|
+
nodeSlug: string;
|
|
24
|
+
plan: CompilePlan;
|
|
25
|
+
serverPlan: MoltnetNodeConfigServerPlan;
|
|
26
|
+
}) => MoltnetNodeConfigResult;
|
|
27
|
+
export {};
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { resolveMoltnetClientAuth } from "./moltnetConfigLowering.js";
|
|
2
|
+
import { resolveRuntimeConfig } from "./moltnetRuntimeConfig.js";
|
|
3
|
+
export const createMoltnetNodeConfigContent = ({ agentNode, attachment, networkServer, nodeSlug, plan, serverPlan }) => {
|
|
4
|
+
const clientAuth = resolveMoltnetClientAuth(networkServer, attachment.network, attachment.memberId, nodeSlug);
|
|
5
|
+
const usesPerAttachmentOpenToken = clientAuth.mode === "open" &&
|
|
6
|
+
clientAuth.staticToken !== true &&
|
|
7
|
+
Boolean(clientAuth.tokenEnv || clientAuth.tokenPath);
|
|
8
|
+
return {
|
|
9
|
+
clientAuth,
|
|
10
|
+
content: `${JSON.stringify({
|
|
11
|
+
version: "moltnet.node.v1",
|
|
12
|
+
moltnet: {
|
|
13
|
+
base_url: serverPlan.baseUrl,
|
|
14
|
+
network_id: attachment.network,
|
|
15
|
+
...(clientAuth.mode === "none" ? {} : { auth_mode: clientAuth.mode }),
|
|
16
|
+
...(clientAuth.registration ? { registration: clientAuth.registration } : {}),
|
|
17
|
+
...(clientAuth.staticToken ? { static_token: true } : {}),
|
|
18
|
+
...(!usesPerAttachmentOpenToken && clientAuth.tokenEnv
|
|
19
|
+
? { token_env: clientAuth.tokenEnv }
|
|
20
|
+
: {}),
|
|
21
|
+
...(!usesPerAttachmentOpenToken && clientAuth.tokenPath
|
|
22
|
+
? { token_path: clientAuth.tokenPath }
|
|
23
|
+
: {})
|
|
24
|
+
},
|
|
25
|
+
attachments: [
|
|
26
|
+
{
|
|
27
|
+
agent: {
|
|
28
|
+
id: attachment.memberId,
|
|
29
|
+
name: agentNode.name
|
|
30
|
+
},
|
|
31
|
+
...(usesPerAttachmentOpenToken
|
|
32
|
+
? {
|
|
33
|
+
moltnet: {
|
|
34
|
+
...(clientAuth.tokenEnv ? { token_env: clientAuth.tokenEnv } : {}),
|
|
35
|
+
...(clientAuth.tokenPath ? { token_path: clientAuth.tokenPath } : {})
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
: {}),
|
|
39
|
+
runtime: resolveRuntimeConfig(plan, agentNode, nodeSlug, attachment.network, attachment.memberId),
|
|
40
|
+
...(attachment.rooms
|
|
41
|
+
? {
|
|
42
|
+
rooms: Object.entries(attachment.rooms)
|
|
43
|
+
.sort(([left], [right]) => left.localeCompare(right))
|
|
44
|
+
.map(([roomId, policy]) => {
|
|
45
|
+
const room = serverPlan.rooms.find((entry) => entry.id === roomId);
|
|
46
|
+
return {
|
|
47
|
+
id: roomId,
|
|
48
|
+
...(room?.visibility ? { visibility: room.visibility } : {}),
|
|
49
|
+
...(room?.write_policy ? { write_policy: room.write_policy } : {}),
|
|
50
|
+
...(policy.wake ? { wake: policy.wake } : {})
|
|
51
|
+
};
|
|
52
|
+
})
|
|
53
|
+
}
|
|
54
|
+
: {}),
|
|
55
|
+
...(attachment.dms
|
|
56
|
+
? {
|
|
57
|
+
dms: {
|
|
58
|
+
enabled: attachment.dms.enabled,
|
|
59
|
+
...(attachment.dms.wake ? { wake: attachment.dms.wake } : {})
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
: {})
|
|
63
|
+
}
|
|
64
|
+
]
|
|
65
|
+
}, null, 2)}\n`,
|
|
66
|
+
usesPerAttachmentOpenToken
|
|
67
|
+
};
|
|
68
|
+
};
|
|
@@ -52,7 +52,7 @@ const synthesizeRepresentativeAttachments = (memberships) => memberships
|
|
|
52
52
|
teamSource: membership.declaringTeamSource
|
|
53
53
|
}));
|
|
54
54
|
const roomPolicyKey = (policy) => JSON.stringify(policy ?? {});
|
|
55
|
-
const hasRoomPolicy = (policy) => policy.
|
|
55
|
+
const hasRoomPolicy = (policy) => policy.wake !== undefined;
|
|
56
56
|
const mergeAttachment = (target, next, nodeName) => {
|
|
57
57
|
if (target.dms &&
|
|
58
58
|
next.dms &&
|
|
@@ -16,8 +16,7 @@ const findTeamBySource = (plan, source) => {
|
|
|
16
16
|
return node.value;
|
|
17
17
|
};
|
|
18
18
|
const clonePolicy = (policy) => ({
|
|
19
|
-
...(policy.
|
|
20
|
-
...(policy.reply ? { reply: policy.reply } : {})
|
|
19
|
+
...(policy.wake ? { wake: policy.wake } : {})
|
|
21
20
|
});
|
|
22
21
|
const findDirectRoomPolicy = (plan, teamNode, agentSource, memberId, networkId, roomId) => {
|
|
23
22
|
const agentNode = findAgentBySource(plan, agentSource);
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { TeamNetworkServer } from "../manifest/index.js";
|
|
2
|
+
export declare const assertCompatibleMoltnetNetworkName: (networkId: string, existing: string | undefined, next: string | undefined) => void;
|
|
3
|
+
export declare const assertCompatibleMoltnetServer: (networkId: string, existing: TeamNetworkServer, next: TeamNetworkServer) => void;
|
|
4
|
+
export declare const assertCompatibleMoltnetRoomPolicy: (networkId: string, roomId: string, field: "visibility" | "write_policy", existing: string | undefined, next: string | undefined) => void;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { SpawnfileError } from "../shared/index.js";
|
|
2
|
+
const stableStringify = (value) => {
|
|
3
|
+
if (Array.isArray(value)) {
|
|
4
|
+
return `[${value.map(stableStringify).join(",")}]`;
|
|
5
|
+
}
|
|
6
|
+
if (value && typeof value === "object") {
|
|
7
|
+
return `{${Object.entries(value).sort(([left], [right]) => left.localeCompare(right)).map(([key, entry]) => `${JSON.stringify(key)}:${stableStringify(entry)}`).join(",")}}`;
|
|
8
|
+
}
|
|
9
|
+
return JSON.stringify(value);
|
|
10
|
+
};
|
|
11
|
+
export const assertCompatibleMoltnetNetworkName = (networkId, existing, next) => {
|
|
12
|
+
if (existing !== undefined && next !== undefined && existing !== next) {
|
|
13
|
+
throw new SpawnfileError("validation_error", `Duplicate Moltnet network ${networkId} declares conflicting network name: ${existing} vs ${next}`);
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
export const assertCompatibleMoltnetServer = (networkId, existing, next) => {
|
|
17
|
+
if (stableStringify(existing.auth) !== stableStringify(next.auth)) {
|
|
18
|
+
throw new SpawnfileError("validation_error", `Duplicate Moltnet network ${networkId} declares conflicting server.auth policy`);
|
|
19
|
+
}
|
|
20
|
+
if (stableStringify(existing) !== stableStringify(next)) {
|
|
21
|
+
throw new SpawnfileError("validation_error", `Duplicate Moltnet network ${networkId} declares conflicting server definition`);
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
export const assertCompatibleMoltnetRoomPolicy = (networkId, roomId, field, existing, next) => {
|
|
25
|
+
if (existing !== undefined && next !== undefined && existing !== next) {
|
|
26
|
+
throw new SpawnfileError("validation_error", `Duplicate Moltnet network ${networkId} room ${roomId} declares conflicting ${field}: ${existing} vs ${next}`);
|
|
27
|
+
}
|
|
28
|
+
};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import type { CompilePlan, ResolvedAgentNode } from "./types.js";
|
|
2
|
-
export declare const resolveRuntimeConfig: (plan: CompilePlan, agentNode: ResolvedAgentNode, nodeSlug: string,
|
|
2
|
+
export declare const resolveRuntimeConfig: (plan: CompilePlan, agentNode: ResolvedAgentNode, nodeSlug: string, _networkId: string, _agentId: string) => Record<string, string>;
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { getRuntimeAdapter } from "../runtime/index.js";
|
|
2
2
|
import { SpawnfileError } from "../shared/index.js";
|
|
3
|
-
const DEFAULT_TINYCLAW_PORT = 3777;
|
|
4
3
|
const INSTANCE_ROOT_PLACEHOLDER = "<instance-root>";
|
|
5
4
|
const CONFIG_FILE_PLACEHOLDER = "<config-file>";
|
|
6
5
|
const resolveSequentialRuntimePort = (plan, runtimeName, slug) => {
|
|
@@ -16,7 +15,6 @@ const resolveSequentialRuntimePort = (plan, runtimeName, slug) => {
|
|
|
16
15
|
}
|
|
17
16
|
return basePort + (index * (adapter.container.portStride ?? 1));
|
|
18
17
|
};
|
|
19
|
-
const createTinyClawChannel = (networkId, agentId) => `moltnet:${networkId}:${agentId}`;
|
|
20
18
|
const replaceContainerPathTemplate = (template, instanceRoot, configFileName) => template
|
|
21
19
|
.replaceAll(INSTANCE_ROOT_PLACEHOLDER, instanceRoot)
|
|
22
20
|
.replaceAll(CONFIG_FILE_PLACEHOLDER, configFileName);
|
|
@@ -30,7 +28,7 @@ const resolveRuntimeInstancePaths = (runtimeName, slug) => {
|
|
|
30
28
|
: undefined
|
|
31
29
|
};
|
|
32
30
|
};
|
|
33
|
-
export const resolveRuntimeConfig = (plan, agentNode, nodeSlug,
|
|
31
|
+
export const resolveRuntimeConfig = (plan, agentNode, nodeSlug, _networkId, _agentId) => {
|
|
34
32
|
switch (agentNode.runtime.name) {
|
|
35
33
|
case "openclaw": {
|
|
36
34
|
const port = resolveSequentialRuntimePort(plan, "openclaw", nodeSlug);
|
|
@@ -53,16 +51,6 @@ export const resolveRuntimeConfig = (plan, agentNode, nodeSlug, networkId, agent
|
|
|
53
51
|
kind: "picoclaw"
|
|
54
52
|
};
|
|
55
53
|
}
|
|
56
|
-
case "tinyclaw": {
|
|
57
|
-
const channel = createTinyClawChannel(networkId, agentId);
|
|
58
|
-
return {
|
|
59
|
-
ack_url: `http://127.0.0.1:${DEFAULT_TINYCLAW_PORT}/api/responses`,
|
|
60
|
-
channel,
|
|
61
|
-
inbound_url: `http://127.0.0.1:${DEFAULT_TINYCLAW_PORT}/api/message`,
|
|
62
|
-
kind: "tinyclaw",
|
|
63
|
-
outbound_url: `http://127.0.0.1:${DEFAULT_TINYCLAW_PORT}/api/responses/pending?channel=${encodeURIComponent(channel)}`
|
|
64
|
-
};
|
|
65
|
-
}
|
|
66
54
|
default:
|
|
67
55
|
throw new SpawnfileError("compile_error", `Moltnet does not know how to attach runtime ${agentNode.runtime.name} directly`);
|
|
68
56
|
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/** Uppercases an id and replaces every non-[A-Z0-9] character with `_`. */
|
|
2
|
+
export declare const normalizeNetworkEnvSegment: (id: string) => string;
|
|
3
|
+
export declare const networkUrlEnvName: (networkId: string) => string;
|
|
4
|
+
export declare const networkTokenEnvName: (networkId: string, memberId?: string) => string;
|
|
5
|
+
export interface NetworkBindingInput {
|
|
6
|
+
id: string;
|
|
7
|
+
members: string[];
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Asserts that every generated network binding env name (URL and token vars,
|
|
11
|
+
* across all networks and members) is globally unique after normalization.
|
|
12
|
+
* Collisions are baked into immutable images, so they must fail at compile.
|
|
13
|
+
*/
|
|
14
|
+
export declare const assertNetworkBindingEnvUniqueness: (networks: NetworkBindingInput[]) => void;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { SpawnfileError } from "../shared/index.js";
|
|
2
|
+
const ENV_PREFIX = "SPAWNFILE_NETWORK_";
|
|
3
|
+
/** Uppercases an id and replaces every non-[A-Z0-9] character with `_`. */
|
|
4
|
+
export const normalizeNetworkEnvSegment = (id) => id.toUpperCase().replace(/[^A-Z0-9]+/g, "_");
|
|
5
|
+
export const networkUrlEnvName = (networkId) => `${ENV_PREFIX}${normalizeNetworkEnvSegment(networkId)}_URL`;
|
|
6
|
+
export const networkTokenEnvName = (networkId, memberId) => memberId === undefined
|
|
7
|
+
? `${ENV_PREFIX}${normalizeNetworkEnvSegment(networkId)}_TOKEN`
|
|
8
|
+
: `${ENV_PREFIX}${normalizeNetworkEnvSegment(networkId)}_TOKEN_${normalizeNetworkEnvSegment(memberId)}`;
|
|
9
|
+
/**
|
|
10
|
+
* Asserts that every generated network binding env name (URL and token vars,
|
|
11
|
+
* across all networks and members) is globally unique after normalization.
|
|
12
|
+
* Collisions are baked into immutable images, so they must fail at compile.
|
|
13
|
+
*/
|
|
14
|
+
export const assertNetworkBindingEnvUniqueness = (networks) => {
|
|
15
|
+
const seen = new Map();
|
|
16
|
+
const claim = (envName, owner) => {
|
|
17
|
+
const existing = seen.get(envName);
|
|
18
|
+
if (existing && existing !== owner) {
|
|
19
|
+
throw new SpawnfileError("validation_error", `Network binding env name ${envName} collides between ${existing} and ${owner}. ` +
|
|
20
|
+
"Rename a network or member so their normalized env names stay unique.");
|
|
21
|
+
}
|
|
22
|
+
seen.set(envName, owner);
|
|
23
|
+
};
|
|
24
|
+
for (const network of networks) {
|
|
25
|
+
claim(networkUrlEnvName(network.id), `network ${network.id} url`);
|
|
26
|
+
const members = [...new Set(network.members)];
|
|
27
|
+
if (members.length === 1) {
|
|
28
|
+
claim(networkTokenEnvName(network.id), `network ${network.id} token`);
|
|
29
|
+
}
|
|
30
|
+
for (const member of members) {
|
|
31
|
+
claim(networkTokenEnvName(network.id, member), `network ${network.id} member ${member}`);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type BuildProjectOptions, type BuildProjectResult } from "./buildProject.js";
|
|
2
|
+
export type DockerPushRunner = (command: string, args: string[]) => Promise<string>;
|
|
3
|
+
export interface PublishProjectOptions extends BuildProjectOptions {
|
|
4
|
+
pushRunner?: DockerPushRunner;
|
|
5
|
+
}
|
|
6
|
+
export interface PublishProjectResult extends BuildProjectResult {
|
|
7
|
+
digest: string | null;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Compiles, builds, verifies, and pushes a project image. Pre-push verification
|
|
11
|
+
* refuses to publish a report that leaks creator paths or omits secret markers.
|
|
12
|
+
*/
|
|
13
|
+
export declare const publishProject: (inputPath: string, options?: PublishProjectOptions) => Promise<PublishProjectResult>;
|