spawnfile 0.1.3 → 0.1.5
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 +2 -0
- 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 +5 -47
- 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 +37 -27
- 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/runProject.d.ts +2 -0
- package/dist/compiler/runProject.js +20 -6
- package/dist/compiler/surfaces.d.ts +3 -13
- package/dist/compiler/surfaces.js +1 -6
- package/dist/compiler/syncProjectAuth.js +67 -19
- 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/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/picoclaw/adapter.js +7 -0
- package/dist/runtime/picoclaw/runAuth.js +5 -41
- 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
package/README.md
CHANGED
|
@@ -43,6 +43,8 @@ spawnfile run --tag my-agent --auth-profile dev
|
|
|
43
43
|
|
|
44
44
|
Compiled output lands under `.spawn/` by default, including a `Dockerfile`, `entrypoint.sh`, `.env.example`, and a prebuilt `container/rootfs/` tree. `spawnfile build` uses the pinned runtime artifacts from `runtimes.yaml`; it does not rebuild runtimes from source.
|
|
45
45
|
|
|
46
|
+
Declare external credentials in `secrets:` and provide values through an ignored env file or the shell environment. `spawnfile auth sync --env-file .env` stores declared model auth and project secrets in a local auth profile; `spawnfile run --env-file .env` can inject the same values directly for a single run. This is the intended pattern for credentials like `GH_TOKEN`, MCP tokens, and provider API keys.
|
|
47
|
+
|
|
46
48
|
## Project structure
|
|
47
49
|
|
|
48
50
|
A Spawnfile project is either an `agent` or a `team`.
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
export const registerLifecycleCommands = (program, handlers, streams) => {
|
|
2
|
+
program
|
|
3
|
+
.command("compile")
|
|
4
|
+
.argument("[path]", "Project directory or Spawnfile path", process.cwd())
|
|
5
|
+
.option("-o, --out <directory>", "Output directory")
|
|
6
|
+
.action(async (inputPath, options) => {
|
|
7
|
+
const result = await handlers.compileProject(inputPath, { outputDirectory: options.out });
|
|
8
|
+
streams.stdout(`compiled to ${result.outputDirectory}`);
|
|
9
|
+
streams.stdout(`report: ${result.reportPath}`);
|
|
10
|
+
});
|
|
11
|
+
program
|
|
12
|
+
.command("build")
|
|
13
|
+
.argument("[path]", "Project directory or Spawnfile path", process.cwd())
|
|
14
|
+
.option("--docker-command <command>", "Docker command")
|
|
15
|
+
.option("-o, --out <directory>", "Output directory")
|
|
16
|
+
.option("-t, --tag <image>", "Docker image tag")
|
|
17
|
+
.action(async (inputPath, options) => {
|
|
18
|
+
const result = await handlers.buildProject(inputPath, {
|
|
19
|
+
dockerCommand: options.dockerCommand,
|
|
20
|
+
imageTag: options.tag,
|
|
21
|
+
outputDirectory: options.out
|
|
22
|
+
});
|
|
23
|
+
streams.stdout(`built image ${result.imageTag}`);
|
|
24
|
+
streams.stdout(`compiled to ${result.outputDirectory}`);
|
|
25
|
+
streams.stdout(`report: ${result.reportPath}`);
|
|
26
|
+
});
|
|
27
|
+
program
|
|
28
|
+
.command("run")
|
|
29
|
+
.argument("[path]", "Project directory or Spawnfile path", process.cwd())
|
|
30
|
+
.option("-o, --out <directory>", "Output directory")
|
|
31
|
+
.option("-t, --tag <image>", "Docker image tag")
|
|
32
|
+
.option("--auth-profile <name>", "Local Spawnfile auth profile")
|
|
33
|
+
.option("--docker-command <command>", "Docker command")
|
|
34
|
+
.option("--name <container>", "Docker container name")
|
|
35
|
+
.option("--env-file <file>", "Path to an env file for runtime secrets")
|
|
36
|
+
.option("-d, --detach", "Run the container in detached mode")
|
|
37
|
+
.action(async (inputPath, options) => {
|
|
38
|
+
const result = await handlers.runProject(inputPath, {
|
|
39
|
+
authProfile: options.authProfile,
|
|
40
|
+
containerName: options.name,
|
|
41
|
+
detach: options.detach,
|
|
42
|
+
dockerCommand: options.dockerCommand,
|
|
43
|
+
envFilePath: options.envFile,
|
|
44
|
+
imageTag: options.tag,
|
|
45
|
+
outputDirectory: options.out
|
|
46
|
+
});
|
|
47
|
+
if (options.detach) {
|
|
48
|
+
streams.stdout(`running container ${result.containerName ?? "unknown"}`);
|
|
49
|
+
streams.stdout(`image: ${result.imageTag}`);
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
program
|
|
53
|
+
.command("up")
|
|
54
|
+
.argument("[path]", "Project directory or Spawnfile path", process.cwd())
|
|
55
|
+
.option("-o, --out <directory>", "Output directory")
|
|
56
|
+
.option("-t, --tag <image>", "Docker image tag")
|
|
57
|
+
.option("--auth-profile <name>", "Local Spawnfile auth profile")
|
|
58
|
+
.option("--docker-command <command>", "Docker command")
|
|
59
|
+
.option("--name <container>", "Docker container name")
|
|
60
|
+
.option("--env-file <file>", "Path to an env file for runtime secrets")
|
|
61
|
+
.option("-d, --detach", "Run the container in detached mode")
|
|
62
|
+
.action(async (inputPath, options) => {
|
|
63
|
+
const result = await handlers.upProject(inputPath, {
|
|
64
|
+
authProfile: options.authProfile,
|
|
65
|
+
containerName: options.name,
|
|
66
|
+
detach: options.detach,
|
|
67
|
+
dockerCommand: options.dockerCommand,
|
|
68
|
+
envFilePath: options.envFile,
|
|
69
|
+
imageTag: options.tag,
|
|
70
|
+
outputDirectory: options.out
|
|
71
|
+
});
|
|
72
|
+
streams.stdout(`built image ${result.imageTag}`);
|
|
73
|
+
streams.stdout(`compiled to ${result.outputDirectory}`);
|
|
74
|
+
streams.stdout(`report: ${result.reportPath}`);
|
|
75
|
+
if (options.detach) {
|
|
76
|
+
streams.stdout(`running container ${result.containerName ?? "unknown"}`);
|
|
77
|
+
streams.stdout(`image: ${result.imageTag}`);
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
};
|
package/dist/cli/runCli.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { importClaudeCodeAuth, importCodexAuth, importEnvFile, requireAuthProfile } from "../auth/index.js";
|
|
2
|
-
import { addAgentProject, addProjectSurface, addProjectModelFallback, addSubagentProject, addTeamProject, buildOrganizationView, buildCompilePlan, buildProject, clearProjectModelFallbacks, compileProject, initProject, removeProjectSurface, runProject, setProjectPrimaryModel, setProjectRuntime, setProjectSurfaceAccess, showProjectSurfaces, syncProjectAuth } from "../compiler/index.js";
|
|
2
|
+
import { addAgentProject, addProjectSurface, addProjectModelFallback, addSubagentProject, addTeamProject, buildOrganizationView, buildCompilePlan, buildProject, clearProjectModelFallbacks, compileProject, initProject, upProject, removeProjectSurface, runProject, setProjectPrimaryModel, setProjectRuntime, setProjectSurfaceAccess, showProjectSurfaces, syncProjectAuth } from "../compiler/index.js";
|
|
3
3
|
import { listRuntimeAdapters } from "../runtime/index.js";
|
|
4
4
|
export interface CliStreams {
|
|
5
5
|
stderr: (message: string) => void;
|
|
@@ -29,6 +29,7 @@ export interface CliHandlers {
|
|
|
29
29
|
removeProjectSurface: typeof removeProjectSurface;
|
|
30
30
|
requireAuthProfile: typeof requireAuthProfile;
|
|
31
31
|
runProject: typeof runProject;
|
|
32
|
+
upProject: typeof upProject;
|
|
32
33
|
setProjectPrimaryModel: typeof setProjectPrimaryModel;
|
|
33
34
|
setProjectRuntime: typeof setProjectRuntime;
|
|
34
35
|
setProjectSurfaceAccess: typeof setProjectSurfaceAccess;
|
package/dist/cli/runCli.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { Command } from "commander";
|
|
2
2
|
import { importClaudeCodeAuth, importCodexAuth, importEnvFile, requireAuthProfile } from "../auth/index.js";
|
|
3
|
-
import { addAgentProject, addProjectSurface, addProjectModelFallback, addSubagentProject, addTeamProject, buildOrganizationView, buildCompilePlan, buildProject, clearProjectModelFallbacks, compileProject, initProject, removeProjectSurface, runProject, setProjectPrimaryModel, setProjectRuntime, setProjectSurfaceAccess, showProjectSurfaces, syncProjectAuth } from "../compiler/index.js";
|
|
3
|
+
import { addAgentProject, addProjectSurface, addProjectModelFallback, addSubagentProject, addTeamProject, buildOrganizationView, buildCompilePlan, buildProject, clearProjectModelFallbacks, compileProject, initProject, upProject, removeProjectSurface, runProject, setProjectPrimaryModel, setProjectRuntime, setProjectSurfaceAccess, showProjectSurfaces, syncProjectAuth } from "../compiler/index.js";
|
|
4
4
|
import { isSpawnfileError } from "../shared/index.js";
|
|
5
5
|
import { listRuntimeAdapters } from "../runtime/index.js";
|
|
6
|
+
import { registerLifecycleCommands } from "./lifecycleCommands.js";
|
|
6
7
|
import { registerModelCommands } from "./modelCommands.js";
|
|
7
8
|
import { registerRuntimeCommands } from "./runtimeCommands.js";
|
|
8
9
|
import { registerSurfaceCommands } from "./surfaceCommands.js";
|
|
@@ -22,7 +23,7 @@ const createDefaultHandlers = () => ({
|
|
|
22
23
|
addSubagentProject, addTeamProject, clearProjectModelFallbacks,
|
|
23
24
|
importClaudeCodeAuth, importCodexAuth, importEnvFile,
|
|
24
25
|
initProject, listRuntimeAdapters, removeProjectSurface, requireAuthProfile,
|
|
25
|
-
runProject, setProjectPrimaryModel, setProjectRuntime,
|
|
26
|
+
runProject, setProjectPrimaryModel, setProjectRuntime, upProject,
|
|
26
27
|
setProjectSurfaceAccess, showProjectSurfaces, syncProjectAuth
|
|
27
28
|
});
|
|
28
29
|
const isCliStreams = (value) => {
|
|
@@ -83,50 +84,7 @@ export const runCli = async (argv, optionsOrStreams, handlerOverrides = {}) => {
|
|
|
83
84
|
writeErr: (message) => writeCommanderOutput(streams.stderr, message),
|
|
84
85
|
writeOut: (message) => writeCommanderOutput(streams.stdout, message)
|
|
85
86
|
});
|
|
86
|
-
program
|
|
87
|
-
.command("compile")
|
|
88
|
-
.argument("[path]", "Project directory or Spawnfile path", process.cwd())
|
|
89
|
-
.option("-o, --out <directory>", "Output directory")
|
|
90
|
-
.action(async (inputPath, options) => {
|
|
91
|
-
const result = await handlers.compileProject(inputPath, { outputDirectory: options.out });
|
|
92
|
-
streams.stdout(`compiled to ${result.outputDirectory}`);
|
|
93
|
-
streams.stdout(`report: ${result.reportPath}`);
|
|
94
|
-
});
|
|
95
|
-
program
|
|
96
|
-
.command("build")
|
|
97
|
-
.argument("[path]", "Project directory or Spawnfile path", process.cwd())
|
|
98
|
-
.option("-o, --out <directory>", "Output directory")
|
|
99
|
-
.option("-t, --tag <image>", "Docker image tag")
|
|
100
|
-
.action(async (inputPath, options) => {
|
|
101
|
-
const result = await handlers.buildProject(inputPath, {
|
|
102
|
-
imageTag: options.tag,
|
|
103
|
-
outputDirectory: options.out
|
|
104
|
-
});
|
|
105
|
-
streams.stdout(`built image ${result.imageTag}`);
|
|
106
|
-
streams.stdout(`compiled to ${result.outputDirectory}`);
|
|
107
|
-
streams.stdout(`report: ${result.reportPath}`);
|
|
108
|
-
});
|
|
109
|
-
program
|
|
110
|
-
.command("run")
|
|
111
|
-
.argument("[path]", "Project directory or Spawnfile path", process.cwd())
|
|
112
|
-
.option("-o, --out <directory>", "Output directory")
|
|
113
|
-
.option("-t, --tag <image>", "Docker image tag")
|
|
114
|
-
.option("--auth-profile <name>", "Local Spawnfile auth profile")
|
|
115
|
-
.option("--name <container>", "Docker container name")
|
|
116
|
-
.option("-d, --detach", "Run the container in detached mode")
|
|
117
|
-
.action(async (inputPath, options) => {
|
|
118
|
-
const result = await handlers.runProject(inputPath, {
|
|
119
|
-
authProfile: options.authProfile,
|
|
120
|
-
containerName: options.name,
|
|
121
|
-
detach: options.detach,
|
|
122
|
-
imageTag: options.tag,
|
|
123
|
-
outputDirectory: options.out
|
|
124
|
-
});
|
|
125
|
-
if (options.detach) {
|
|
126
|
-
streams.stdout(`running container ${result.containerName ?? "unknown"}`);
|
|
127
|
-
streams.stdout(`image: ${result.imageTag}`);
|
|
128
|
-
}
|
|
129
|
-
});
|
|
87
|
+
registerLifecycleCommands(program, handlers, streams);
|
|
130
88
|
program
|
|
131
89
|
.command("init")
|
|
132
90
|
.argument("[path]", "Directory to initialize", process.cwd())
|
|
@@ -232,7 +190,7 @@ export const runCli = async (argv, optionsOrStreams, handlerOverrides = {}) => {
|
|
|
232
190
|
.command("sync")
|
|
233
191
|
.argument("[path]", "Project directory or Spawnfile path", process.cwd())
|
|
234
192
|
.option("-p, --profile <name>", "Auth profile name", "default")
|
|
235
|
-
.option("--env-file <file>", "Path to an env file with model
|
|
193
|
+
.option("--env-file <file>", "Path to an env file with model keys and runtime secrets")
|
|
236
194
|
.option("--claude-from <directory>", "Source Claude Code config directory")
|
|
237
195
|
.option("--codex-from <directory>", "Source Codex config directory")
|
|
238
196
|
.action(async (inputPath, options) => {
|
|
@@ -1,17 +1,10 @@
|
|
|
1
|
-
import { getCanonicalManifestPath, getManifestPath
|
|
2
|
-
import {
|
|
3
|
-
import { SpawnfileError } from "../shared/index.js";
|
|
4
|
-
import { getAgentFingerprint, getMcpNames, getTeamFingerprint, validateEffectiveSkillRequirements } from "./compilePlanHelpers.js";
|
|
5
|
-
import { resolveAgentSurfaces } from "./agentSurfaces.js";
|
|
1
|
+
import { getCanonicalManifestPath, getManifestPath } from "../filesystem/index.js";
|
|
2
|
+
import { loadManifest, isAgentManifest } from "../manifest/index.js";
|
|
6
3
|
import { assignStableNodeIds } from "./helpers.js";
|
|
7
|
-
import { loadResolvedDocuments, mergeResolvedSkills, loadResolvedSkills, mergeSharedSurface } from "./surfaces.js";
|
|
8
|
-
import { assertRuntimeSupportsExecutionModelAuth } from "./modelAuth.js";
|
|
9
|
-
import { assertRuntimeSupportsAgentSurfaces } from "./surfaceSupport.js";
|
|
10
|
-
import { applyExecutionDefaults } from "./executionDefaults.js";
|
|
11
4
|
import { resolvePlanMoltnetAttachments } from "./moltnetResolution.js";
|
|
12
5
|
import { resolveMoltnetRoomMemberships } from "./moltnetRoomMemberships.js";
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
6
|
+
import { createRuntimeGroups } from "./buildCompilePlanRuntime.js";
|
|
7
|
+
import { createCompilePlanTraversal } from "./buildCompilePlanTraversal.js";
|
|
15
8
|
export const buildCompilePlan = async (inputPath) => {
|
|
16
9
|
const rootManifestPath = getCanonicalManifestPath(getManifestPath(inputPath));
|
|
17
10
|
const loadCache = new Map();
|
|
@@ -19,7 +12,6 @@ export const buildCompilePlan = async (inputPath) => {
|
|
|
19
12
|
const fingerprintCache = new Map();
|
|
20
13
|
const edges = [];
|
|
21
14
|
const memberships = new Map();
|
|
22
|
-
const visitStack = [];
|
|
23
15
|
const getLoadedManifest = (manifestPath) => {
|
|
24
16
|
const canonicalPath = getCanonicalManifestPath(manifestPath);
|
|
25
17
|
const cached = loadCache.get(canonicalPath);
|
|
@@ -30,186 +22,13 @@ export const buildCompilePlan = async (inputPath) => {
|
|
|
30
22
|
loadCache.set(canonicalPath, promise);
|
|
31
23
|
return promise;
|
|
32
24
|
};
|
|
33
|
-
const visitAgent =
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
throw new SpawnfileError("compile_error", `Expected agent manifest, got ${loadedManifest.manifest.kind} at ${canonicalPath}`);
|
|
41
|
-
}
|
|
42
|
-
const runtime = await resolveRuntime(loadedManifest.manifest, context);
|
|
43
|
-
const execution = applyExecutionDefaults(context.isSubagent
|
|
44
|
-
? mergeExecution(context.inheritedExecution, loadedManifest.manifest.execution)
|
|
45
|
-
: loadedManifest.manifest.execution);
|
|
46
|
-
assertRuntimeSupportsExecutionModelAuth(runtime.name, execution, loadedManifest.manifest.name);
|
|
47
|
-
const sharedSurface = mergeSharedSurface(context.inheritedShared?.surface, {
|
|
48
|
-
env: loadedManifest.manifest.env,
|
|
49
|
-
mcpServers: loadedManifest.manifest.mcp_servers,
|
|
50
|
-
secrets: loadedManifest.manifest.secrets,
|
|
51
|
-
skills: loadedManifest.manifest.skills
|
|
52
|
-
});
|
|
53
|
-
const inheritedSkills = context.inheritedShared
|
|
54
|
-
? await loadResolvedSkills(context.inheritedShared.manifestPath, context.inheritedShared.surface?.skills)
|
|
55
|
-
: [];
|
|
56
|
-
const localSkills = await loadResolvedSkills(canonicalPath, loadedManifest.manifest.skills);
|
|
57
|
-
const skills = mergeResolvedSkills(inheritedSkills, localSkills);
|
|
58
|
-
validateEffectiveSkillRequirements(loadedManifest.manifest.name, getMcpNames(sharedSurface.mcpServers), skills);
|
|
59
|
-
const docs = await loadResolvedDocuments(canonicalPath, loadedManifest.manifest.docs);
|
|
60
|
-
const candidate = {
|
|
61
|
-
description: resolveDescription(loadedManifest.manifest.description, docs),
|
|
62
|
-
docs,
|
|
63
|
-
env: sharedSurface.env,
|
|
64
|
-
execution,
|
|
65
|
-
expose: loadedManifest.manifest.expose ?? false,
|
|
66
|
-
kind: "agent",
|
|
67
|
-
mcpServers: sharedSurface.mcpServers,
|
|
68
|
-
name: loadedManifest.manifest.name,
|
|
69
|
-
policyMode: loadedManifest.manifest.policy?.mode ?? null,
|
|
70
|
-
policyOnDegrade: loadedManifest.manifest.policy?.on_degrade ?? null,
|
|
71
|
-
runtime,
|
|
72
|
-
secrets: sharedSurface.secrets,
|
|
73
|
-
skills,
|
|
74
|
-
source: canonicalPath,
|
|
75
|
-
surfaces: resolveAgentSurfaces(loadedManifest.manifest.surfaces),
|
|
76
|
-
subagents: []
|
|
77
|
-
};
|
|
78
|
-
assertRuntimeSupportsAgentSurfaces(runtime.name, candidate.surfaces, loadedManifest.manifest.name);
|
|
79
|
-
const fingerprint = getAgentFingerprint(candidate);
|
|
80
|
-
const existingFingerprint = fingerprintCache.get(canonicalPath);
|
|
81
|
-
if (existingFingerprint && existingFingerprint !== fingerprint) {
|
|
82
|
-
throw new SpawnfileError("compile_error", `Manifest ${canonicalPath} resolves differently across compile contexts`);
|
|
83
|
-
}
|
|
84
|
-
const cachedNode = nodeCache.get(canonicalPath);
|
|
85
|
-
if (cachedNode) {
|
|
86
|
-
return cachedNode.value;
|
|
87
|
-
}
|
|
88
|
-
fingerprintCache.set(canonicalPath, fingerprint);
|
|
89
|
-
nodeCache.set(canonicalPath, {
|
|
90
|
-
runtimeName: runtime.name,
|
|
91
|
-
source: canonicalPath,
|
|
92
|
-
value: candidate
|
|
93
|
-
});
|
|
94
|
-
visitStack.push(canonicalPath);
|
|
95
|
-
for (const subagent of loadedManifest.manifest.subagents ?? []) {
|
|
96
|
-
const childManifestPath = getManifestPath(resolveProjectPath(canonicalPath, subagent.ref));
|
|
97
|
-
const resolvedSubagent = await visitAgent(childManifestPath, {
|
|
98
|
-
inheritedExecution: execution,
|
|
99
|
-
inheritedRuntime: runtime,
|
|
100
|
-
isSubagent: true
|
|
101
|
-
});
|
|
102
|
-
candidate.subagents.push({
|
|
103
|
-
id: subagent.id,
|
|
104
|
-
nodeSource: resolvedSubagent.source
|
|
105
|
-
});
|
|
106
|
-
edges.push({
|
|
107
|
-
from: canonicalPath,
|
|
108
|
-
kind: "subagent",
|
|
109
|
-
label: subagent.id,
|
|
110
|
-
to: resolvedSubagent.source
|
|
111
|
-
});
|
|
112
|
-
}
|
|
113
|
-
visitStack.pop();
|
|
114
|
-
return candidate;
|
|
115
|
-
};
|
|
116
|
-
const visitTeam = async (manifestPath) => {
|
|
117
|
-
const canonicalPath = getCanonicalManifestPath(manifestPath);
|
|
118
|
-
if (visitStack.includes(canonicalPath)) {
|
|
119
|
-
throw new SpawnfileError("compile_error", `Cycle detected while visiting ${canonicalPath}`);
|
|
120
|
-
}
|
|
121
|
-
const loadedManifest = await getLoadedManifest(canonicalPath);
|
|
122
|
-
if (!isTeamManifest(loadedManifest.manifest)) {
|
|
123
|
-
throw new SpawnfileError("compile_error", `Expected team manifest, got ${loadedManifest.manifest.kind} at ${canonicalPath}`);
|
|
124
|
-
}
|
|
125
|
-
const sharedSkills = await loadResolvedSkills(canonicalPath, loadedManifest.manifest.shared?.skills);
|
|
126
|
-
validateEffectiveSkillRequirements(loadedManifest.manifest.name, getMcpNames(loadedManifest.manifest.shared?.mcp_servers ?? []), sharedSkills);
|
|
127
|
-
const manifest = loadedManifest.manifest;
|
|
128
|
-
const resolvedExternal = resolveTeamExternalIds(manifest);
|
|
129
|
-
const docs = await loadResolvedDocuments(canonicalPath, manifest.docs);
|
|
130
|
-
const candidate = {
|
|
131
|
-
description: manifest.description ? normalizeDescription(manifest.description) : "",
|
|
132
|
-
docs,
|
|
133
|
-
external: resolvedExternal,
|
|
134
|
-
externalExplicit: manifest.external !== undefined,
|
|
135
|
-
kind: "team",
|
|
136
|
-
lead: manifest.lead ?? null,
|
|
137
|
-
members: [],
|
|
138
|
-
mode: manifest.mode,
|
|
139
|
-
name: manifest.name,
|
|
140
|
-
networks: resolveTeamNetworks(manifest),
|
|
141
|
-
policyMode: manifest.policy?.mode ?? null,
|
|
142
|
-
policyOnDegrade: manifest.policy?.on_degrade ?? null,
|
|
143
|
-
shared: {
|
|
144
|
-
env: manifest.shared?.env ?? {},
|
|
145
|
-
mcpServers: manifest.shared?.mcp_servers ?? [],
|
|
146
|
-
secrets: manifest.shared?.secrets ?? [],
|
|
147
|
-
skills: sharedSkills
|
|
148
|
-
},
|
|
149
|
-
source: canonicalPath,
|
|
150
|
-
};
|
|
151
|
-
const fingerprint = getTeamFingerprint(candidate);
|
|
152
|
-
const existingFingerprint = fingerprintCache.get(canonicalPath);
|
|
153
|
-
if (existingFingerprint && existingFingerprint !== fingerprint) {
|
|
154
|
-
throw new SpawnfileError("compile_error", `Team manifest ${canonicalPath} resolves differently across compile contexts`);
|
|
155
|
-
}
|
|
156
|
-
const cachedNode = nodeCache.get(canonicalPath);
|
|
157
|
-
if (cachedNode) {
|
|
158
|
-
return cachedNode.value;
|
|
159
|
-
}
|
|
160
|
-
fingerprintCache.set(canonicalPath, fingerprint);
|
|
161
|
-
nodeCache.set(canonicalPath, {
|
|
162
|
-
runtimeName: null,
|
|
163
|
-
source: canonicalPath,
|
|
164
|
-
value: candidate
|
|
165
|
-
});
|
|
166
|
-
visitStack.push(canonicalPath);
|
|
167
|
-
for (const member of loadedManifest.manifest.members) {
|
|
168
|
-
const childManifestPath = getManifestPath(resolveProjectPath(canonicalPath, member.ref));
|
|
169
|
-
const childManifest = await getLoadedManifest(childManifestPath);
|
|
170
|
-
let resolvedMember;
|
|
171
|
-
if (isAgentManifest(childManifest.manifest)) {
|
|
172
|
-
const resolvedAgent = await visitAgent(childManifestPath, {
|
|
173
|
-
inheritedShared: {
|
|
174
|
-
manifestPath: canonicalPath,
|
|
175
|
-
surface: loadedManifest.manifest.shared
|
|
176
|
-
},
|
|
177
|
-
isSubagent: false
|
|
178
|
-
});
|
|
179
|
-
resolvedMember = {
|
|
180
|
-
id: member.id,
|
|
181
|
-
kind: "agent",
|
|
182
|
-
nodeSource: resolvedAgent.source,
|
|
183
|
-
runtimeName: resolvedAgent.runtime.name
|
|
184
|
-
};
|
|
185
|
-
memberships.set(`${canonicalPath}::${member.id}::${resolvedAgent.source}`, {
|
|
186
|
-
agentSource: resolvedAgent.source,
|
|
187
|
-
memberId: member.id,
|
|
188
|
-
teamName: candidate.name,
|
|
189
|
-
teamSource: canonicalPath
|
|
190
|
-
});
|
|
191
|
-
}
|
|
192
|
-
else {
|
|
193
|
-
const resolvedTeam = await visitTeam(childManifestPath);
|
|
194
|
-
resolvedMember = {
|
|
195
|
-
id: member.id,
|
|
196
|
-
kind: "team",
|
|
197
|
-
nodeSource: resolvedTeam.source,
|
|
198
|
-
runtimeName: null
|
|
199
|
-
};
|
|
200
|
-
}
|
|
201
|
-
candidate.members.push(resolvedMember);
|
|
202
|
-
edges.push({
|
|
203
|
-
from: canonicalPath,
|
|
204
|
-
kind: "team_member",
|
|
205
|
-
label: member.id,
|
|
206
|
-
to: resolvedMember.nodeSource
|
|
207
|
-
});
|
|
208
|
-
}
|
|
209
|
-
validateTeamNetworkRooms(candidate);
|
|
210
|
-
visitStack.pop();
|
|
211
|
-
return candidate;
|
|
212
|
-
};
|
|
25
|
+
const { visitAgent, visitTeam } = createCompilePlanTraversal({
|
|
26
|
+
getLoadedManifest,
|
|
27
|
+
nodeCache,
|
|
28
|
+
edges,
|
|
29
|
+
fingerprintCache,
|
|
30
|
+
memberships
|
|
31
|
+
});
|
|
213
32
|
const rootLoadedManifest = await getLoadedManifest(rootManifestPath);
|
|
214
33
|
if (isAgentManifest(rootLoadedManifest.manifest)) {
|
|
215
34
|
await visitAgent(rootManifestPath, { isSubagent: false });
|
|
@@ -234,21 +53,12 @@ export const buildCompilePlan = async (inputPath) => {
|
|
|
234
53
|
from: idBySource.get(edge.from) ?? edge.from,
|
|
235
54
|
to: idBySource.get(edge.to) ?? edge.to
|
|
236
55
|
}));
|
|
237
|
-
const runtimes = compilePlanNodes.reduce((groups, node) => {
|
|
238
|
-
if (!node.runtimeName) {
|
|
239
|
-
return groups;
|
|
240
|
-
}
|
|
241
|
-
const group = groups[node.runtimeName] ?? { nodeIds: [] };
|
|
242
|
-
group.nodeIds.push(node.id);
|
|
243
|
-
groups[node.runtimeName] = group;
|
|
244
|
-
return groups;
|
|
245
|
-
}, {});
|
|
246
56
|
const compilePlan = {
|
|
247
57
|
edges: compilePlanEdges,
|
|
248
58
|
memberships: [...memberships.values()].sort((left, right) => `${left.agentSource}:${left.teamSource}:${left.memberId}`.localeCompare(`${right.agentSource}:${right.teamSource}:${right.memberId}`)),
|
|
249
59
|
nodes: compilePlanNodes,
|
|
250
60
|
root: rootManifestPath,
|
|
251
|
-
runtimes
|
|
61
|
+
runtimes: createRuntimeGroups(compilePlanNodes)
|
|
252
62
|
};
|
|
253
63
|
compilePlan.moltnetRoomMemberships = resolveMoltnetRoomMemberships(compilePlan);
|
|
254
64
|
resolvePlanMoltnetAttachments(compilePlan);
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { type AgentManifest, type ExecutionBlock, type SharedSurface } from "../manifest/index.js";
|
|
2
|
-
import type { ResolvedDocument, ResolvedRuntime } from "./types.js";
|
|
2
|
+
import type { CompilePlanNode, ResolvedDocument, ResolvedRuntime } from "./types.js";
|
|
3
|
+
import type { ResolvedWorkspaceResource } from "./workspaceResources.js";
|
|
3
4
|
export interface AgentVisitContext {
|
|
4
5
|
inheritedExecution?: ExecutionBlock;
|
|
6
|
+
inheritedResources?: ResolvedWorkspaceResource[];
|
|
5
7
|
inheritedShared?: {
|
|
6
8
|
manifestPath: string;
|
|
7
9
|
surface: SharedSurface | undefined;
|
|
@@ -12,3 +14,6 @@ export interface AgentVisitContext {
|
|
|
12
14
|
export declare const resolveRuntime: (manifest: AgentManifest, context: AgentVisitContext) => Promise<ResolvedRuntime>;
|
|
13
15
|
export declare const normalizeDescription: (description: string) => string;
|
|
14
16
|
export declare const resolveDescription: (description: string | undefined, docs: ResolvedDocument[]) => string;
|
|
17
|
+
export declare const createRuntimeGroups: (nodes: CompilePlanNode[]) => Record<string, {
|
|
18
|
+
nodeIds: string[];
|
|
19
|
+
}>;
|
|
@@ -37,3 +37,12 @@ const deriveDescriptionFromDocs = (docs) => {
|
|
|
37
37
|
export const resolveDescription = (description, docs) => description !== undefined
|
|
38
38
|
? normalizeDescription(description)
|
|
39
39
|
: deriveDescriptionFromDocs(docs);
|
|
40
|
+
export const createRuntimeGroups = (nodes) => nodes.reduce((groups, node) => {
|
|
41
|
+
if (!node.runtimeName) {
|
|
42
|
+
return groups;
|
|
43
|
+
}
|
|
44
|
+
const group = groups[node.runtimeName] ?? { nodeIds: [] };
|
|
45
|
+
group.nodeIds.push(node.id);
|
|
46
|
+
groups[node.runtimeName] = group;
|
|
47
|
+
return groups;
|
|
48
|
+
}, {});
|
|
@@ -14,16 +14,22 @@ export const resolveTeamExternalIds = (manifest) => {
|
|
|
14
14
|
? [manifest.lead]
|
|
15
15
|
: memberIds);
|
|
16
16
|
};
|
|
17
|
-
export const resolveTeamNetworks = (manifest) => (manifest.networks ?? []).map((network) =>
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
}))
|
|
17
|
+
export const resolveTeamNetworks = (manifest) => (manifest.networks ?? []).map((network) => {
|
|
18
|
+
const resolved = {
|
|
19
|
+
id: network.id,
|
|
20
|
+
name: network.name ?? network.id,
|
|
21
|
+
provider: network.provider,
|
|
22
|
+
rooms: network.rooms.map((room) => ({
|
|
23
|
+
id: room.id,
|
|
24
|
+
members: [...room.members],
|
|
25
|
+
...(room.name ? { name: room.name } : {})
|
|
26
|
+
}))
|
|
27
|
+
};
|
|
28
|
+
if (network.server) {
|
|
29
|
+
resolved.server = network.server;
|
|
30
|
+
}
|
|
31
|
+
return resolved;
|
|
32
|
+
});
|
|
27
33
|
export const validateTeamNetworkRooms = (teamNode) => {
|
|
28
34
|
for (const network of teamNode.networks ?? []) {
|
|
29
35
|
for (const room of network.rooms) {
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { LoadedManifest } from "../manifest/index.js";
|
|
2
|
+
import { CompilePlanEdge, ResolvedAgentNode, ResolvedTeamMembershipContext, ResolvedTeamNode } from "./types.js";
|
|
3
|
+
import { type AgentVisitContext } from "./buildCompilePlanRuntime.js";
|
|
4
|
+
import { type InternalNode } from "./buildCompilePlanTraversalHelpers.js";
|
|
5
|
+
type BuildCompilePlanTraversalDeps = {
|
|
6
|
+
getLoadedManifest: (manifestPath: string) => Promise<LoadedManifest>;
|
|
7
|
+
nodeCache: Map<string, InternalNode>;
|
|
8
|
+
fingerprintCache: Map<string, string>;
|
|
9
|
+
edges: CompilePlanEdge[];
|
|
10
|
+
memberships: Map<string, ResolvedTeamMembershipContext>;
|
|
11
|
+
};
|
|
12
|
+
export declare const createCompilePlanTraversal: ({ getLoadedManifest, nodeCache, fingerprintCache, edges, memberships }: BuildCompilePlanTraversalDeps) => {
|
|
13
|
+
visitAgent: (manifestPath: string, context: AgentVisitContext) => Promise<ResolvedAgentNode>;
|
|
14
|
+
visitTeam: (manifestPath: string, inheritedResources?: ResolvedAgentNode["workspaceResources"]) => Promise<ResolvedTeamNode>;
|
|
15
|
+
};
|
|
16
|
+
export type { InternalNode };
|