spawnfile 0.1.4 → 0.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/lifecycleCommands.d.ts +3 -0
- package/dist/cli/lifecycleCommands.js +80 -0
- package/dist/cli/runCli.d.ts +2 -1
- package/dist/cli/runCli.js +4 -48
- package/dist/compiler/buildCompilePlan.js +12 -202
- package/dist/compiler/buildCompilePlanRuntime.d.ts +6 -1
- package/dist/compiler/buildCompilePlanRuntime.js +9 -0
- package/dist/compiler/buildCompilePlanTeams.js +16 -10
- package/dist/compiler/buildCompilePlanTraversal.d.ts +16 -0
- package/dist/compiler/buildCompilePlanTraversal.js +214 -0
- package/dist/compiler/buildCompilePlanTraversalHelpers.d.ts +18 -0
- package/dist/compiler/buildCompilePlanTraversalHelpers.js +22 -0
- package/dist/compiler/compilePlanHelpers.d.ts +3 -1
- package/dist/compiler/compilePlanHelpers.js +37 -1
- package/dist/compiler/compileProject.js +14 -0
- package/dist/compiler/containerArtifacts.js +18 -3
- package/dist/compiler/containerArtifactsPlans.js +32 -0
- package/dist/compiler/containerArtifactsRender.js +86 -3
- package/dist/compiler/containerArtifactsTypes.d.ts +7 -3
- package/dist/compiler/containerEntrypointRender.d.ts +1 -1
- package/dist/compiler/containerEntrypointRender.js +34 -24
- package/dist/compiler/containerTargetResources.d.ts +4 -0
- package/dist/compiler/containerTargetResources.js +54 -0
- package/dist/compiler/containerWorkspaceResourceRender.d.ts +3 -0
- package/dist/compiler/containerWorkspaceResourceRender.js +128 -0
- package/dist/compiler/executionDefaults.js +0 -3
- package/dist/compiler/helpers.d.ts +1 -1
- package/dist/compiler/index.d.ts +1 -0
- package/dist/compiler/index.js +1 -0
- package/dist/compiler/moltnetArtifacts.d.ts +11 -5
- package/dist/compiler/moltnetArtifacts.js +133 -117
- package/dist/compiler/moltnetClientConfig.js +8 -2
- package/dist/compiler/moltnetConfigLowering.d.ts +36 -0
- package/dist/compiler/moltnetConfigLowering.js +125 -0
- package/dist/compiler/moltnetRuntimeConfig.d.ts +2 -0
- package/dist/compiler/moltnetRuntimeConfig.js +69 -0
- package/dist/compiler/surfaces.d.ts +3 -13
- package/dist/compiler/surfaces.js +1 -6
- package/dist/compiler/syncProjectAuth.js +14 -0
- package/dist/compiler/types.d.ts +16 -1
- package/dist/compiler/upProject.d.ts +19 -0
- package/dist/compiler/upProject.js +37 -0
- package/dist/compiler/view/buildOrganizationView.js +22 -2
- package/dist/compiler/view/renderNetworks.js +14 -3
- package/dist/compiler/view/renderTree.js +8 -2
- package/dist/compiler/view/types.d.ts +18 -3
- package/dist/compiler/workspaceResources.d.ts +34 -0
- package/dist/compiler/workspaceResources.js +120 -0
- package/dist/filesystem/paths.js +1 -10
- package/dist/manifest/executionSchemas.d.ts +106 -0
- package/dist/manifest/executionSchemas.js +140 -0
- package/dist/manifest/loadManifest.js +15 -27
- package/dist/manifest/renderSpawnfile.js +44 -52
- package/dist/manifest/renderSpawnfileNetworks.d.ts +2 -0
- package/dist/manifest/renderSpawnfileNetworks.js +63 -0
- package/dist/manifest/renderSpawnfileWorkspace.d.ts +2 -0
- package/dist/manifest/renderSpawnfileWorkspace.js +47 -0
- package/dist/manifest/scaffold.js +12 -6
- package/dist/manifest/scheduleSchemas.d.ts +15 -0
- package/dist/manifest/scheduleSchemas.js +26 -0
- package/dist/manifest/schemas.d.ts +626 -368
- package/dist/manifest/schemas.js +51 -191
- package/dist/manifest/teamNetworkSchemas.d.ts +228 -0
- package/dist/manifest/teamNetworkSchemas.js +295 -0
- package/dist/manifest/workspaceSchemas.d.ts +96 -0
- package/dist/manifest/workspaceSchemas.js +166 -0
- package/dist/report/types.d.ts +10 -0
- package/dist/runtime/common.d.ts +2 -1
- package/dist/runtime/common.js +3 -3
- package/dist/runtime/tinyclaw/adapter.js +9 -2
- package/dist/runtime/tinyclaw/schedules.d.ts +9 -0
- package/dist/runtime/tinyclaw/schedules.js +62 -0
- package/dist/runtime/types.d.ts +1 -0
- package/package.json +2 -1
|
@@ -4,7 +4,7 @@ export interface EntrypointOptions {
|
|
|
4
4
|
hasMoltnet?: boolean;
|
|
5
5
|
hasStagedMoltnetBinaries?: boolean;
|
|
6
6
|
moltnet?: {
|
|
7
|
-
|
|
7
|
+
nodePlans: MoltnetArtifacts["nodePlans"];
|
|
8
8
|
serverPlans: MoltnetArtifacts["serverPlans"];
|
|
9
9
|
};
|
|
10
10
|
moltnetPublishedPorts?: number[];
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
|
+
import { createWorkspaceResourceCommands, createWorkspaceResourceShellFunctions } from "./containerWorkspaceResourceRender.js";
|
|
2
3
|
const MOLTNET_SERVER_DATA_DIRECTORY = "/var/lib/spawnfile/moltnet/servers";
|
|
3
4
|
const shellQuote = (value) => `'${value.replace(/'/g, `'\"'\"'`)}'`;
|
|
4
|
-
const pathSafeSegment = (value) => value.replace(/[^A-Za-z0-9_.-]+/g, "-").replace(/^-+|-+$/g, "") || "server";
|
|
5
|
-
const createMoltnetServerDataPath = (serverId) => `${MOLTNET_SERVER_DATA_DIRECTORY}/${pathSafeSegment(serverId)}.db`;
|
|
6
5
|
const createEnvironmentAssignments = (plan) => {
|
|
7
6
|
const envAssignments = [];
|
|
8
7
|
if (plan.instancePaths.homePath) {
|
|
@@ -114,13 +113,19 @@ export const renderEntrypoint = (runtimePlans, requiredSecrets, options = {}) =>
|
|
|
114
113
|
"",
|
|
115
114
|
"cursor = data",
|
|
116
115
|
"for part in json_path[:-1]:",
|
|
116
|
+
" if isinstance(cursor, list):",
|
|
117
|
+
" cursor = cursor[int(part)]",
|
|
118
|
+
" continue",
|
|
117
119
|
" child = cursor.get(part)",
|
|
118
|
-
" if not isinstance(child, dict):",
|
|
120
|
+
" if not isinstance(child, (dict, list)):",
|
|
119
121
|
" child = {}",
|
|
120
122
|
" cursor[part] = child",
|
|
121
123
|
" cursor = child",
|
|
122
124
|
"",
|
|
123
|
-
"cursor
|
|
125
|
+
"if isinstance(cursor, list):",
|
|
126
|
+
" cursor[int(json_path[-1])] = value",
|
|
127
|
+
"else:",
|
|
128
|
+
" cursor[json_path[-1]] = value",
|
|
124
129
|
"",
|
|
125
130
|
"with open(target_path, 'w', encoding='utf-8') as handle:",
|
|
126
131
|
" json.dump(data, handle, indent=2)",
|
|
@@ -136,7 +141,8 @@ export const renderEntrypoint = (runtimePlans, requiredSecrets, options = {}) =>
|
|
|
136
141
|
' mkdir -p "$home_path/.codex"',
|
|
137
142
|
' printf "%s\\n" "${OPENAI_API_KEY:-}" | HOME="$home_path" CODEX_HOME="$home_path/.codex" codex login --with-api-key >/dev/null',
|
|
138
143
|
"}",
|
|
139
|
-
""
|
|
144
|
+
"",
|
|
145
|
+
...createWorkspaceResourceShellFunctions()
|
|
140
146
|
];
|
|
141
147
|
lines.push('if [ -n "${OPENCLAW_GATEWAY_TOKEN:-}" ] && [ -z "${OPENCLAW_HOOKS_TOKEN:-}" ]; then', ' export OPENCLAW_HOOKS_TOKEN="hooks-${OPENCLAW_GATEWAY_TOKEN}"', "fi", "");
|
|
142
148
|
for (const secretName of requiredSecrets) {
|
|
@@ -146,40 +152,44 @@ export const renderEntrypoint = (runtimePlans, requiredSecrets, options = {}) =>
|
|
|
146
152
|
lines.push("");
|
|
147
153
|
}
|
|
148
154
|
const moltnetServerPlans = options.moltnet?.serverPlans ?? [];
|
|
149
|
-
const
|
|
155
|
+
const moltnetNodePlans = options.moltnet?.nodePlans ?? [];
|
|
150
156
|
if (runtimePlans.length === 1 &&
|
|
151
157
|
moltnetServerPlans.length === 0 &&
|
|
152
|
-
|
|
158
|
+
moltnetNodePlans.length === 0) {
|
|
153
159
|
const plan = runtimePlans[0];
|
|
154
160
|
const commandTokens = resolveStartCommand(plan);
|
|
155
161
|
const envAssignments = createEnvironmentAssignments(plan);
|
|
156
|
-
lines.push(`mkdir -p ${shellQuote(plan.instancePaths.workspacePath)}`, `require_file ${shellQuote(plan.instancePaths.configPath)}`, ...createEnvFileWrites(plan), ...createConfigEnvWrites(plan), ...createAuthSetupCommands(plan), `${envAssignments.join(" ")} exec ${commandTokens.map(shellQuote).join(" ")}`);
|
|
162
|
+
lines.push(`mkdir -p ${shellQuote(plan.instancePaths.workspacePath)}`, ...createWorkspaceResourceCommands(plan), `require_file ${shellQuote(plan.instancePaths.configPath)}`, ...createEnvFileWrites(plan), ...createConfigEnvWrites(plan), ...createAuthSetupCommands(plan), `${envAssignments.join(" ")} exec ${commandTokens.map(shellQuote).join(" ")}`);
|
|
157
163
|
return `${lines.join("\n").trimEnd()}\n`;
|
|
158
164
|
}
|
|
159
165
|
lines.push("PIDS=()", "", "terminate_children() {", ' for pid in "${PIDS[@]:-}"; do', ' kill "$pid" 2>/dev/null || true', " done", "}", "", "trap terminate_children INT TERM EXIT", "");
|
|
160
|
-
|
|
166
|
+
const managedMoltnetServerPlans = moltnetServerPlans.filter((serverPlan) => serverPlan.mode === "managed");
|
|
167
|
+
if (managedMoltnetServerPlans.length > 0) {
|
|
161
168
|
lines.push(`mkdir -p ${shellQuote(MOLTNET_SERVER_DATA_DIRECTORY)}`, "");
|
|
162
169
|
}
|
|
163
|
-
for (const serverPlan of
|
|
164
|
-
|
|
170
|
+
for (const serverPlan of managedMoltnetServerPlans) {
|
|
171
|
+
if (!serverPlan.configPath) {
|
|
172
|
+
continue;
|
|
173
|
+
}
|
|
174
|
+
for (const patch of serverPlan.secretPatches) {
|
|
175
|
+
lines.push(`apply_json_env_value ${shellQuote(serverPlan.configPath)} ${shellQuote(patch.envName)} ${shellQuote(patch.jsonPath)}`);
|
|
176
|
+
}
|
|
177
|
+
lines.push(`MOLTNET_CONFIG=${shellQuote(serverPlan.configPath)} /usr/local/bin/moltnet &`, 'PIDS+=("$!")', "");
|
|
178
|
+
}
|
|
179
|
+
for (const serverPlan of managedMoltnetServerPlans) {
|
|
180
|
+
if (!serverPlan.port) {
|
|
181
|
+
continue;
|
|
182
|
+
}
|
|
183
|
+
lines.push(`until curl -sf ${shellQuote(`http://127.0.0.1:${serverPlan.port}/healthz`)} >/dev/null; do sleep 1; done`);
|
|
184
|
+
lines.push("");
|
|
165
185
|
}
|
|
166
186
|
for (const plan of runtimePlans) {
|
|
167
187
|
const commandTokens = resolveStartCommand(plan);
|
|
168
188
|
const envAssignments = createEnvironmentAssignments(plan);
|
|
169
|
-
lines.push(`mkdir -p ${shellQuote(plan.instancePaths.workspacePath)}`, `require_file ${shellQuote(plan.instancePaths.configPath)}`, ...createEnvFileWrites(plan), ...createConfigEnvWrites(plan), ...createAuthSetupCommands(plan), `${envAssignments.join(" ")} ${commandTokens.map(shellQuote).join(" ")} &`, 'PIDS+=("$!")', "", ...createRuntimeReadinessWait(plan));
|
|
170
|
-
}
|
|
171
|
-
for (const serverPlan of moltnetServerPlans) {
|
|
172
|
-
lines.push(`until curl -sf ${shellQuote(`http://127.0.0.1:${serverPlan.port}/healthz`)} >/dev/null; do sleep 1; done`);
|
|
173
|
-
for (const room of serverPlan.rooms) {
|
|
174
|
-
lines.push(`curl -sf -X POST -H 'Content-Type: application/json' -d ${shellQuote(JSON.stringify({
|
|
175
|
-
id: room.id,
|
|
176
|
-
members: room.members
|
|
177
|
-
}))} ${shellQuote(`http://127.0.0.1:${serverPlan.port}/v1/rooms`)} >/dev/null || true`);
|
|
178
|
-
}
|
|
179
|
-
lines.push("");
|
|
189
|
+
lines.push(`mkdir -p ${shellQuote(plan.instancePaths.workspacePath)}`, ...createWorkspaceResourceCommands(plan), `require_file ${shellQuote(plan.instancePaths.configPath)}`, ...createEnvFileWrites(plan), ...createConfigEnvWrites(plan), ...createAuthSetupCommands(plan), `${envAssignments.join(" ")} ${commandTokens.map(shellQuote).join(" ")} &`, 'PIDS+=("$!")', "", ...createRuntimeReadinessWait(plan));
|
|
180
190
|
}
|
|
181
|
-
for (const
|
|
182
|
-
lines.push(`/usr/local/bin/moltnet
|
|
191
|
+
for (const nodePlan of moltnetNodePlans) {
|
|
192
|
+
lines.push(`/usr/local/bin/moltnet node ${shellQuote(nodePlan.configPath)} &`, 'PIDS+=("$!")', "");
|
|
183
193
|
}
|
|
184
194
|
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"');
|
|
185
195
|
return `${lines.join("\n").trimEnd()}\n`;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { ContainerTarget, ContainerTargetInput, RuntimeContainerMeta } from "../runtime/index.js";
|
|
2
|
+
import type { RuntimeTargetPlan } from "./containerArtifactsTypes.js";
|
|
3
|
+
import { type WorkspaceResourcePlan } from "./workspaceResources.js";
|
|
4
|
+
export declare const resolveTargetResources: (target: ContainerTarget, inputs: ContainerTargetInput[], instancePaths: RuntimeTargetPlan["instancePaths"], meta: RuntimeContainerMeta) => WorkspaceResourcePlan[];
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { SpawnfileError } from "../shared/index.js";
|
|
3
|
+
import { mergeWorkspaceResourcePlans } from "./workspaceResources.js";
|
|
4
|
+
const CONFIG_FILE_PLACEHOLDER = "<config-file>";
|
|
5
|
+
const INSTANCE_ROOT_PLACEHOLDER = "<instance-root>";
|
|
6
|
+
const SOURCE_AGENT_PLACEHOLDER = "<agent-name>";
|
|
7
|
+
const replaceSourceWorkspacePathTemplate = (template, input, instancePaths, meta) => {
|
|
8
|
+
const agentName = input.value.kind === "agent" ? input.value.name : input.slug;
|
|
9
|
+
const instanceRoot = instancePaths.instanceRoot ?? path.posix.dirname(instancePaths.workspacePath);
|
|
10
|
+
return template
|
|
11
|
+
.replaceAll(INSTANCE_ROOT_PLACEHOLDER, instanceRoot)
|
|
12
|
+
.replaceAll(CONFIG_FILE_PLACEHOLDER, meta.configFileName)
|
|
13
|
+
.replaceAll(SOURCE_AGENT_PLACEHOLDER, agentName);
|
|
14
|
+
};
|
|
15
|
+
const resolveSourceWorkspacePath = (input, instancePaths, meta) => meta.instancePaths.sourceWorkspacePathTemplate
|
|
16
|
+
? replaceSourceWorkspacePathTemplate(meta.instancePaths.sourceWorkspacePathTemplate, input, instancePaths, meta)
|
|
17
|
+
: instancePaths.workspacePath;
|
|
18
|
+
const sourceTargetId = (target, input, isMergedTarget) => isMergedTarget ? `${target.id}:${input.id}` : target.id;
|
|
19
|
+
const pathsOverlap = (left, right) => left === right || left.startsWith(`${right}/`) || right.startsWith(`${left}/`);
|
|
20
|
+
const dedupeAndAssertResourcePlans = (target, resources) => {
|
|
21
|
+
const byLinkPath = new Map();
|
|
22
|
+
for (const resource of resources) {
|
|
23
|
+
const existing = byLinkPath.get(resource.linkPath);
|
|
24
|
+
if (existing) {
|
|
25
|
+
if (existing.backingPath !== resource.backingPath || existing.id !== resource.id) {
|
|
26
|
+
throw new SpawnfileError("validation_error", `Container target ${target.id} declares conflicting workspace resources at ${resource.linkPath}`);
|
|
27
|
+
}
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
const overlapping = [...byLinkPath.values()].find((candidate) => pathsOverlap(candidate.linkPath, resource.linkPath));
|
|
31
|
+
if (overlapping) {
|
|
32
|
+
throw new SpawnfileError("validation_error", `Container target ${target.id} declares overlapping workspace resource links ${overlapping.linkPath} and ${resource.linkPath}`);
|
|
33
|
+
}
|
|
34
|
+
byLinkPath.set(resource.linkPath, resource);
|
|
35
|
+
}
|
|
36
|
+
return [...byLinkPath.values()].sort((left, right) => left.linkPath.localeCompare(right.linkPath) || left.id.localeCompare(right.id));
|
|
37
|
+
};
|
|
38
|
+
export const resolveTargetResources = (target, inputs, instancePaths, meta) => {
|
|
39
|
+
const sourceIds = new Set(target.sourceIds ?? []);
|
|
40
|
+
if (sourceIds.size === 0) {
|
|
41
|
+
return [];
|
|
42
|
+
}
|
|
43
|
+
const isMergedTarget = sourceIds.size > 1;
|
|
44
|
+
const resources = inputs.flatMap((input) => {
|
|
45
|
+
if (!sourceIds.has(input.id) || input.value.kind !== "agent") {
|
|
46
|
+
return [];
|
|
47
|
+
}
|
|
48
|
+
return mergeWorkspaceResourcePlans(input.value.workspaceResources ?? [], `${target.id}/${input.id}`, {
|
|
49
|
+
targetId: sourceTargetId(target, input, isMergedTarget),
|
|
50
|
+
workspacePath: resolveSourceWorkspacePath(input, instancePaths, meta)
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
return dedupeAndAssertResourcePlans(target, resources);
|
|
54
|
+
};
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
const shellQuote = (value) => `'${value.replace(/'/g, `'\"'\"'`)}'`;
|
|
2
|
+
export const createWorkspaceResourceCommands = (plan) => (plan.resources ?? []).flatMap((resource) => {
|
|
3
|
+
const readonlyFlag = resource.mode === "readonly" ? "readonly" : "mutable";
|
|
4
|
+
if (resource.kind === "volume") {
|
|
5
|
+
return [
|
|
6
|
+
`prepare_volume_resource ${shellQuote(resource.id)} ${shellQuote(resource.linkPath)} ${shellQuote(resource.backingPath)} ${shellQuote(readonlyFlag)}`
|
|
7
|
+
];
|
|
8
|
+
}
|
|
9
|
+
const selectorKind = resource.branch
|
|
10
|
+
? "branch"
|
|
11
|
+
: resource.tag
|
|
12
|
+
? "tag"
|
|
13
|
+
: resource.ref
|
|
14
|
+
? "ref"
|
|
15
|
+
: "none";
|
|
16
|
+
const selectorValue = resource.branch ?? resource.tag ?? resource.ref ?? "";
|
|
17
|
+
return [
|
|
18
|
+
`prepare_git_resource ${shellQuote(resource.id)} ${shellQuote(resource.linkPath)} ${shellQuote(resource.backingPath)} ${shellQuote(resource.url ?? "")} ${shellQuote(selectorKind)} ${shellQuote(selectorValue)} ${shellQuote(readonlyFlag)}`
|
|
19
|
+
];
|
|
20
|
+
});
|
|
21
|
+
export const createWorkspaceResourceShellFunctions = () => [
|
|
22
|
+
"directory_is_empty() {",
|
|
23
|
+
' local target="$1"',
|
|
24
|
+
' [ -d "$target" ] && [ -z "$(find "$target" -mindepth 1 -maxdepth 1 -print -quit)" ]',
|
|
25
|
+
"}",
|
|
26
|
+
"",
|
|
27
|
+
"prepare_resource_link() {",
|
|
28
|
+
' local id="$1"',
|
|
29
|
+
' local link_path="$2"',
|
|
30
|
+
' local backing_path="$3"',
|
|
31
|
+
' mkdir -p "$(dirname "$link_path")"',
|
|
32
|
+
' if [ -L "$link_path" ]; then',
|
|
33
|
+
' local existing_target',
|
|
34
|
+
' existing_target="$(readlink "$link_path")"',
|
|
35
|
+
' if [ "$existing_target" != "$backing_path" ]; then',
|
|
36
|
+
' echo "Workspace resource $id link points to $existing_target, expected $backing_path" >&2',
|
|
37
|
+
" exit 1",
|
|
38
|
+
" fi",
|
|
39
|
+
" return",
|
|
40
|
+
" fi",
|
|
41
|
+
' if [ -e "$link_path" ]; then',
|
|
42
|
+
' echo "Workspace resource $id mount path already exists and is not a symlink: $link_path" >&2',
|
|
43
|
+
" exit 1",
|
|
44
|
+
" fi",
|
|
45
|
+
' ln -s "$backing_path" "$link_path"',
|
|
46
|
+
"}",
|
|
47
|
+
"",
|
|
48
|
+
"mark_readonly_resource() {",
|
|
49
|
+
' local target="$1"',
|
|
50
|
+
' local mode="$2"',
|
|
51
|
+
' if [ "$mode" = "readonly" ]; then',
|
|
52
|
+
' chmod -R a-w "$target"',
|
|
53
|
+
" fi",
|
|
54
|
+
"}",
|
|
55
|
+
"",
|
|
56
|
+
"prepare_volume_resource() {",
|
|
57
|
+
' local id="$1"',
|
|
58
|
+
' local link_path="$2"',
|
|
59
|
+
' local backing_path="$3"',
|
|
60
|
+
' local mode="$4"',
|
|
61
|
+
' mkdir -p "$backing_path"',
|
|
62
|
+
' if [ ! -d "$backing_path" ]; then',
|
|
63
|
+
' echo "Workspace volume resource $id backing path is not a directory: $backing_path" >&2',
|
|
64
|
+
" exit 1",
|
|
65
|
+
" fi",
|
|
66
|
+
' mark_readonly_resource "$backing_path" "$mode"',
|
|
67
|
+
' prepare_resource_link "$id" "$link_path" "$backing_path"',
|
|
68
|
+
"}",
|
|
69
|
+
"",
|
|
70
|
+
"prepare_git_resource() {",
|
|
71
|
+
' local id="$1"',
|
|
72
|
+
' local link_path="$2"',
|
|
73
|
+
' local backing_path="$3"',
|
|
74
|
+
' local remote="$4"',
|
|
75
|
+
' local selector_kind="$5"',
|
|
76
|
+
' local selector_value="$6"',
|
|
77
|
+
' local mode="$7"',
|
|
78
|
+
' if [ -d "$backing_path/.git" ]; then',
|
|
79
|
+
' local existing_remote',
|
|
80
|
+
' existing_remote="$(git -C "$backing_path" config --get remote.origin.url || true)"',
|
|
81
|
+
' if [ "$existing_remote" != "$remote" ]; then',
|
|
82
|
+
' echo "Workspace git resource $id has remote $existing_remote, expected $remote" >&2',
|
|
83
|
+
" exit 1",
|
|
84
|
+
" fi",
|
|
85
|
+
' if [ "$selector_kind" = "branch" ]; then',
|
|
86
|
+
' local branch',
|
|
87
|
+
' branch="$(git -C "$backing_path" rev-parse --abbrev-ref HEAD)"',
|
|
88
|
+
' if [ "$branch" != "$selector_value" ]; then',
|
|
89
|
+
' echo "Workspace git resource $id is on branch $branch, expected $selector_value" >&2',
|
|
90
|
+
" exit 1",
|
|
91
|
+
" fi",
|
|
92
|
+
' elif [ "$selector_kind" = "tag" ]; then',
|
|
93
|
+
' local tag',
|
|
94
|
+
' tag="$(git -C "$backing_path" describe --tags --exact-match 2>/dev/null || true)"',
|
|
95
|
+
' if [ "$tag" != "$selector_value" ]; then',
|
|
96
|
+
' echo "Workspace git resource $id is on tag $tag, expected $selector_value" >&2',
|
|
97
|
+
" exit 1",
|
|
98
|
+
" fi",
|
|
99
|
+
' elif [ "$selector_kind" = "ref" ]; then',
|
|
100
|
+
' local current_ref',
|
|
101
|
+
' current_ref="$(git -C "$backing_path" rev-parse HEAD)"',
|
|
102
|
+
' if [ "$current_ref" != "$selector_value" ]; then',
|
|
103
|
+
' echo "Workspace git resource $id is on ref $current_ref, expected $selector_value" >&2',
|
|
104
|
+
" exit 1",
|
|
105
|
+
" fi",
|
|
106
|
+
" fi",
|
|
107
|
+
' mark_readonly_resource "$backing_path" "$mode"',
|
|
108
|
+
' prepare_resource_link "$id" "$link_path" "$backing_path"',
|
|
109
|
+
" return",
|
|
110
|
+
" fi",
|
|
111
|
+
' if [ -e "$backing_path" ] && ! directory_is_empty "$backing_path"; then',
|
|
112
|
+
' echo "Workspace git resource $id backing path is not empty: $backing_path" >&2',
|
|
113
|
+
" exit 1",
|
|
114
|
+
" fi",
|
|
115
|
+
' mkdir -p "$(dirname "$backing_path")"',
|
|
116
|
+
' if [ "$selector_kind" = "branch" ]; then',
|
|
117
|
+
' git clone --branch "$selector_value" "$remote" "$backing_path"',
|
|
118
|
+
" else",
|
|
119
|
+
' git clone "$remote" "$backing_path"',
|
|
120
|
+
' if [ "$selector_kind" = "tag" ] || [ "$selector_kind" = "ref" ]; then',
|
|
121
|
+
' git -C "$backing_path" checkout "$selector_value"',
|
|
122
|
+
" fi",
|
|
123
|
+
" fi",
|
|
124
|
+
' mark_readonly_resource "$backing_path" "$mode"',
|
|
125
|
+
' prepare_resource_link "$id" "$link_path" "$backing_path"',
|
|
126
|
+
"}",
|
|
127
|
+
""
|
|
128
|
+
];
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { CompilePlanNode } from "./types.js";
|
|
1
|
+
import type { CompilePlanNode } from "./types.js";
|
|
2
2
|
export declare const createShortHash: (value: string) => string;
|
|
3
3
|
export declare const slugify: (value: string) => string;
|
|
4
4
|
export declare const stableStringify: (value: unknown) => string;
|
package/dist/compiler/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export * from "./addProjectNode.js";
|
|
2
2
|
export * from "./buildCompilePlan.js";
|
|
3
3
|
export * from "./buildProject.js";
|
|
4
|
+
export * from "./upProject.js";
|
|
4
5
|
export * from "./compileProject.js";
|
|
5
6
|
export * from "./initProject.js";
|
|
6
7
|
export * from "./moltnetRoomMemberships.js";
|
package/dist/compiler/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export * from "./addProjectNode.js";
|
|
2
2
|
export * from "./buildCompilePlan.js";
|
|
3
3
|
export * from "./buildProject.js";
|
|
4
|
+
export * from "./upProject.js";
|
|
4
5
|
export * from "./compileProject.js";
|
|
5
6
|
export * from "./initProject.js";
|
|
6
7
|
export * from "./moltnetRoomMemberships.js";
|
|
@@ -1,25 +1,31 @@
|
|
|
1
1
|
import type { EmittedFile } from "../runtime/index.js";
|
|
2
|
+
import type { TeamNetworkServer } from "../manifest/index.js";
|
|
3
|
+
import { type MoltnetSecretPatch } from "./moltnetConfigLowering.js";
|
|
2
4
|
import type { CompilePlan } from "./types.js";
|
|
3
5
|
export interface MoltnetServerPlan {
|
|
6
|
+
baseUrl: string;
|
|
7
|
+
configPath?: string;
|
|
4
8
|
id: string;
|
|
9
|
+
mode: "external" | "managed";
|
|
5
10
|
name: string;
|
|
6
11
|
networkId: string;
|
|
7
|
-
port
|
|
12
|
+
port?: number;
|
|
8
13
|
rooms: Array<{
|
|
9
14
|
id: string;
|
|
10
15
|
members: string[];
|
|
16
|
+
name?: string;
|
|
11
17
|
}>;
|
|
18
|
+
server: TeamNetworkServer;
|
|
19
|
+
secretPatches: MoltnetSecretPatch[];
|
|
12
20
|
teamSource: string;
|
|
13
21
|
}
|
|
14
|
-
export interface
|
|
15
|
-
agentId: string;
|
|
22
|
+
export interface MoltnetNodePlan {
|
|
16
23
|
configPath: string;
|
|
17
24
|
networkId: string;
|
|
18
|
-
runtime: string;
|
|
19
25
|
}
|
|
20
26
|
export interface MoltnetArtifacts {
|
|
21
|
-
bridgePlans: MoltnetBridgePlan[];
|
|
22
27
|
files: EmittedFile[];
|
|
28
|
+
nodePlans: MoltnetNodePlan[];
|
|
23
29
|
ports: number[];
|
|
24
30
|
publishedPorts: number[];
|
|
25
31
|
serverPlans: MoltnetServerPlan[];
|