spawnfile 0.1.1 → 0.1.3

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.
Files changed (102) hide show
  1. package/README.md +80 -396
  2. package/dist/cli/index.js +0 -0
  3. package/dist/cli/modelCommands.d.ts +3 -0
  4. package/dist/cli/modelCommands.js +68 -0
  5. package/dist/cli/runCli.d.ts +23 -2
  6. package/dist/cli/runCli.js +78 -122
  7. package/dist/cli/runtimeCommands.d.ts +3 -0
  8. package/dist/cli/runtimeCommands.js +20 -0
  9. package/dist/cli/surfaceCommands.d.ts +3 -0
  10. package/dist/cli/surfaceCommands.js +98 -0
  11. package/dist/cli/viewCommand.d.ts +3 -0
  12. package/dist/cli/viewCommand.js +87 -0
  13. package/dist/compiler/agentSurfaces.js +51 -5
  14. package/dist/compiler/buildCompilePlan.js +38 -40
  15. package/dist/compiler/buildCompilePlanRuntime.d.ts +14 -0
  16. package/dist/compiler/buildCompilePlanRuntime.js +39 -0
  17. package/dist/compiler/buildCompilePlanTeams.d.ts +5 -0
  18. package/dist/compiler/buildCompilePlanTeams.js +38 -0
  19. package/dist/compiler/compilePlanHelpers.js +4 -1
  20. package/dist/compiler/compileProject.js +62 -13
  21. package/dist/compiler/compileProjectSupport.d.ts +17 -0
  22. package/dist/compiler/compileProjectSupport.js +136 -0
  23. package/dist/compiler/containerArtifacts.d.ts +6 -1
  24. package/dist/compiler/containerArtifacts.js +26 -4
  25. package/dist/compiler/containerArtifactsPlans.js +16 -1
  26. package/dist/compiler/containerArtifactsRender.d.ts +4 -2
  27. package/dist/compiler/containerArtifactsRender.js +21 -126
  28. package/dist/compiler/containerArtifactsTypes.d.ts +7 -0
  29. package/dist/compiler/containerEntrypointRender.d.ts +12 -0
  30. package/dist/compiler/containerEntrypointRender.js +186 -0
  31. package/dist/compiler/index.d.ts +4 -0
  32. package/dist/compiler/index.js +4 -0
  33. package/dist/compiler/interactiveSurfaceScopes.d.ts +2 -0
  34. package/dist/compiler/interactiveSurfaceScopes.js +21 -0
  35. package/dist/compiler/moltnetArtifacts.d.ts +27 -0
  36. package/dist/compiler/moltnetArtifacts.js +208 -0
  37. package/dist/compiler/moltnetBinaries.d.ts +4 -0
  38. package/dist/compiler/moltnetBinaries.js +103 -0
  39. package/dist/compiler/moltnetClientConfig.d.ts +11 -0
  40. package/dist/compiler/moltnetClientConfig.js +89 -0
  41. package/dist/compiler/moltnetRepresentativeResolution.d.ts +16 -0
  42. package/dist/compiler/moltnetRepresentativeResolution.js +86 -0
  43. package/dist/compiler/moltnetResolution.d.ts +3 -0
  44. package/dist/compiler/moltnetResolution.js +182 -0
  45. package/dist/compiler/moltnetRoomMemberships.d.ts +3 -0
  46. package/dist/compiler/moltnetRoomMemberships.js +140 -0
  47. package/dist/compiler/runProject.js +1 -1
  48. package/dist/compiler/surfaceDefinitions.d.ts +55 -0
  49. package/dist/compiler/surfaceDefinitions.js +204 -0
  50. package/dist/compiler/teamContextHelpers.d.ts +18 -0
  51. package/dist/compiler/teamContextHelpers.js +112 -0
  52. package/dist/compiler/teamContextSupport.d.ts +4 -0
  53. package/dist/compiler/teamContextSupport.js +264 -0
  54. package/dist/compiler/teamContextSupport.testHelpers.d.ts +16 -0
  55. package/dist/compiler/teamContextSupport.testHelpers.js +68 -0
  56. package/dist/compiler/teamContextTypes.d.ts +28 -0
  57. package/dist/compiler/teamContextTypes.js +1 -0
  58. package/dist/compiler/teamRoster.d.ts +12 -0
  59. package/dist/compiler/teamRoster.js +48 -0
  60. package/dist/compiler/teamRosterEntries.d.ts +13 -0
  61. package/dist/compiler/teamRosterEntries.js +230 -0
  62. package/dist/compiler/teamRosterTypes.d.ts +45 -0
  63. package/dist/compiler/teamRosterTypes.js +1 -0
  64. package/dist/compiler/types.d.ts +90 -6
  65. package/dist/compiler/updateProjectRuntime.d.ts +9 -0
  66. package/dist/compiler/updateProjectRuntime.js +67 -0
  67. package/dist/compiler/updateProjectSurfaces.d.ts +8 -0
  68. package/dist/compiler/updateProjectSurfaces.js +106 -0
  69. package/dist/compiler/view/buildOrganizationView.d.ts +2 -0
  70. package/dist/compiler/view/buildOrganizationView.js +180 -0
  71. package/dist/compiler/view/index.d.ts +4 -0
  72. package/dist/compiler/view/index.js +4 -0
  73. package/dist/compiler/view/renderNetworks.d.ts +2 -0
  74. package/dist/compiler/view/renderNetworks.js +93 -0
  75. package/dist/compiler/view/renderTree.d.ts +2 -0
  76. package/dist/compiler/view/renderTree.js +59 -0
  77. package/dist/compiler/view/sourcePaths.d.ts +2 -0
  78. package/dist/compiler/view/sourcePaths.js +19 -0
  79. package/dist/compiler/view/types.d.ts +80 -0
  80. package/dist/compiler/view/types.js +1 -0
  81. package/dist/manifest/loadManifest.js +4 -4
  82. package/dist/manifest/renderSpawnfile.js +74 -8
  83. package/dist/manifest/scaffold.js +1 -3
  84. package/dist/manifest/schemas.d.ts +227 -17
  85. package/dist/manifest/schemas.js +62 -20
  86. package/dist/manifest/surfaceSchemas.d.ts +154 -0
  87. package/dist/manifest/surfaceSchemas.js +77 -5
  88. package/dist/runtime/common.js +3 -0
  89. package/dist/runtime/openclaw/adapter.js +38 -5
  90. package/dist/runtime/openclaw/moltnet.d.ts +12 -0
  91. package/dist/runtime/openclaw/moltnet.js +124 -0
  92. package/dist/runtime/openclaw/surfaces.js +3 -0
  93. package/dist/runtime/picoclaw/adapter.js +27 -8
  94. package/dist/runtime/picoclaw/pico.d.ts +2 -0
  95. package/dist/runtime/picoclaw/pico.js +2 -0
  96. package/dist/runtime/picoclaw/surfaces.js +11 -0
  97. package/dist/runtime/tinyclaw/adapter.js +22 -8
  98. package/dist/runtime/tinyclaw/runAuth.js +28 -1
  99. package/dist/runtime/tinyclaw/surfaces.js +8 -0
  100. package/dist/runtime/types.d.ts +11 -0
  101. package/package.json +5 -3
  102. package/runtimes.yaml +4 -4
@@ -0,0 +1,230 @@
1
+ import { resolveTeamRepresentatives } from "./moltnetResolution.js";
2
+ const SURFACE_ORDER = ["moltnet", "slack", "discord", "telegram", "whatsapp"];
3
+ const findNode = (plan, source) => plan.nodes.find((node) => node.value.source === source)?.value ?? null;
4
+ const findAgent = (plan, source) => {
5
+ const node = findNode(plan, source);
6
+ return node?.kind === "agent" ? node : null;
7
+ };
8
+ const findTeam = (plan, source) => {
9
+ const node = findNode(plan, source);
10
+ return node?.kind === "team" ? node : null;
11
+ };
12
+ const lookupDescription = (source, plan) => findNode(plan, source)?.description ?? "";
13
+ const getContextRoomIds = (contextTeamSource, attachment) => {
14
+ const contextRooms = attachment.contextRooms?.[contextTeamSource];
15
+ if (contextRooms) {
16
+ return [...contextRooms].sort();
17
+ }
18
+ if (attachment.teamSource === contextTeamSource) {
19
+ return Object.keys(attachment.rooms ?? {}).sort();
20
+ }
21
+ return [];
22
+ };
23
+ const createMoltnetAddresses = (agent, contextTeamSource, memberId) => {
24
+ const addresses = {};
25
+ for (const attachment of agent.surfaces?.moltnet ?? []) {
26
+ if (attachment.memberId !== memberId) {
27
+ continue;
28
+ }
29
+ const rooms = getContextRoomIds(contextTeamSource, attachment);
30
+ if (rooms.length === 0 && attachment.teamSource !== contextTeamSource) {
31
+ continue;
32
+ }
33
+ addresses[attachment.network] = {
34
+ fqid: `molt://${attachment.network}/agents/${memberId}`,
35
+ rooms
36
+ };
37
+ }
38
+ return addresses;
39
+ };
40
+ const createIdentityAddresses = (surfaces) => ({
41
+ ...(surfaces?.slack?.identity
42
+ ? { slack: { user_id: surfaces.slack.identity.userId } }
43
+ : {}),
44
+ ...(surfaces?.discord?.identity
45
+ ? { discord: { user_id: surfaces.discord.identity.userId } }
46
+ : {}),
47
+ ...(surfaces?.telegram?.identity
48
+ ? {
49
+ telegram: {
50
+ ...(surfaces.telegram.identity.userId
51
+ ? { user_id: surfaces.telegram.identity.userId }
52
+ : {}),
53
+ ...(surfaces.telegram.identity.username
54
+ ? { username: surfaces.telegram.identity.username }
55
+ : {})
56
+ }
57
+ }
58
+ : {}),
59
+ ...(surfaces?.whatsapp?.identity
60
+ ? { whatsapp: { phone: surfaces.whatsapp.identity.phone } }
61
+ : {})
62
+ });
63
+ const createConcreteEntry = (plan, agentSource, memberId, role, contextTeamSource, delegateRole) => {
64
+ const agent = findAgent(plan, agentSource);
65
+ const moltnet = agent
66
+ ? createMoltnetAddresses(agent, contextTeamSource, memberId)
67
+ : {};
68
+ const identity = createIdentityAddresses(agent?.surfaces);
69
+ const addresses = {
70
+ ...identity,
71
+ ...(Object.keys(moltnet).length > 0 ? { moltnet } : {})
72
+ };
73
+ const surfaces = SURFACE_ORDER.filter((surface) => {
74
+ if (surface === "moltnet") {
75
+ return Object.keys(moltnet).length > 0;
76
+ }
77
+ return Boolean(agent?.surfaces?.[surface]);
78
+ });
79
+ return {
80
+ addresses,
81
+ ...(delegateRole ? { delegate_role: delegateRole } : {}),
82
+ description: agent?.description ?? "",
83
+ role,
84
+ surfaces
85
+ };
86
+ };
87
+ const createCardPath = (contextKey, memberId) => `.spawnfile/team-cards/${contextKey}/${memberId}.md`;
88
+ const createTeamEntry = (plan, teamNode, member, contextKey, contextTeamSource) => {
89
+ const childTeam = findTeam(plan, member.nodeSource);
90
+ const representatives = childTeam
91
+ ? resolveTeamRepresentatives(plan, childTeam)
92
+ : [];
93
+ const isLead = member.id === teamNode.lead;
94
+ const delegateRole = isLead ? "lead" : "representative";
95
+ return {
96
+ addresses: {},
97
+ card: {
98
+ path: createCardPath(contextKey, member.id),
99
+ summary: lookupDescription(member.nodeSource, plan)
100
+ },
101
+ description: lookupDescription(member.nodeSource, plan),
102
+ ...(isLead ? { is_lead: true } : {}),
103
+ representatives: Object.fromEntries(representatives.map((representative) => {
104
+ const entry = createConcreteEntry(plan, representative.agentSource, representative.memberId, delegateRole === "lead" ? "lead" : "member", contextTeamSource, delegateRole);
105
+ const { role: _role, ...representativeEntry } = entry;
106
+ return [representative.memberId, representativeEntry];
107
+ })),
108
+ role: "team",
109
+ surfaces: []
110
+ };
111
+ };
112
+ export const getVisibleTeamMembers = (teamNode, selfMemberId, delegateRole, representedSlotId) => {
113
+ const excluded = representedSlotId ?? selfMemberId;
114
+ if (teamNode.mode === "swarm") {
115
+ return teamNode.members.filter((member) => member.id !== excluded);
116
+ }
117
+ const hasLeadVisibility = selfMemberId === teamNode.lead || delegateRole === "lead";
118
+ if (hasLeadVisibility) {
119
+ return teamNode.members.filter((member) => member.id !== excluded);
120
+ }
121
+ const lead = teamNode.lead
122
+ ? teamNode.members.find((member) => member.id === teamNode.lead)
123
+ : undefined;
124
+ return lead && lead.id !== excluded ? [lead] : [];
125
+ };
126
+ export const createRosterEntry = (plan, teamNode, member, options) => {
127
+ if (member.kind === "team") {
128
+ return createTeamEntry(plan, teamNode, member, options.contextKey, options.teamSource);
129
+ }
130
+ return createConcreteEntry(plan, member.nodeSource, member.id, member.id === teamNode.lead ? "lead" : "member", options.teamSource);
131
+ };
132
+ export const collectConcreteParticipants = (plan, teamNode, selfMemberId, visibleMembers, representedSlotId) => {
133
+ const selfMember = representedSlotId
134
+ ? null
135
+ : teamNode.members.find((member) => member.id === selfMemberId && member.kind === "agent");
136
+ const participants = selfMember
137
+ ? [{ agentSource: selfMember.nodeSource, id: selfMember.id }]
138
+ : [];
139
+ if (representedSlotId) {
140
+ const representedMember = teamNode.members.find((member) => member.id === representedSlotId);
141
+ if (representedMember?.kind === "team") {
142
+ const childTeam = findTeam(plan, representedMember.nodeSource);
143
+ const representative = childTeam
144
+ ? resolveTeamRepresentatives(plan, childTeam).find((entry) => entry.memberId === selfMemberId)
145
+ : undefined;
146
+ if (representative) {
147
+ participants.push({
148
+ agentSource: representative.agentSource,
149
+ id: representative.memberId
150
+ });
151
+ }
152
+ }
153
+ }
154
+ for (const member of visibleMembers) {
155
+ if (member.kind === "agent") {
156
+ participants.push({ agentSource: member.nodeSource, id: member.id });
157
+ continue;
158
+ }
159
+ const childTeam = findTeam(plan, member.nodeSource);
160
+ if (!childTeam) {
161
+ continue;
162
+ }
163
+ for (const representative of resolveTeamRepresentatives(plan, childTeam)) {
164
+ participants.push({
165
+ agentSource: representative.agentSource,
166
+ id: representative.memberId
167
+ });
168
+ }
169
+ }
170
+ return participants;
171
+ };
172
+ const getCoordinationBindings = (plan, participant, contextTeamSource) => {
173
+ const agent = findAgent(plan, participant.agentSource);
174
+ if (!agent) {
175
+ return [];
176
+ }
177
+ const bindings = new Set();
178
+ for (const surface of ["slack", "discord", "telegram", "whatsapp"]) {
179
+ if (agent.surfaces?.[surface]) {
180
+ bindings.add(surface);
181
+ }
182
+ }
183
+ for (const attachment of agent.surfaces?.moltnet ?? []) {
184
+ if (attachment.memberId !== participant.id) {
185
+ continue;
186
+ }
187
+ for (const roomId of getContextRoomIds(contextTeamSource, attachment)) {
188
+ bindings.add(`moltnet:${attachment.network}:${roomId}`);
189
+ }
190
+ }
191
+ return [...bindings].sort();
192
+ };
193
+ export const createCoordinationDiagnostics = (plan, teamNode, participants, contextTeamSource) => {
194
+ if (participants.length <= 1) {
195
+ return [];
196
+ }
197
+ const bindingsByParticipant = new Map(participants.map((participant) => [
198
+ participant.id,
199
+ getCoordinationBindings(plan, participant, contextTeamSource)
200
+ ]));
201
+ const connected = new Set();
202
+ let edgeCount = 0;
203
+ for (let index = 0; index < participants.length; index += 1) {
204
+ for (let other = index + 1; other < participants.length; other += 1) {
205
+ const left = participants[index];
206
+ const right = participants[other];
207
+ const leftBindings = new Set(bindingsByParticipant.get(left.id) ?? []);
208
+ const hasSharedBinding = (bindingsByParticipant.get(right.id) ?? []).some((binding) => leftBindings.has(binding));
209
+ if (hasSharedBinding) {
210
+ edgeCount += 1;
211
+ connected.add(left.id);
212
+ connected.add(right.id);
213
+ }
214
+ }
215
+ }
216
+ return [
217
+ ...(edgeCount === 0
218
+ ? [{
219
+ level: "warn",
220
+ message: `Team ${teamNode.name} context has no shared coordination surface between visible participants`
221
+ }]
222
+ : []),
223
+ ...participants
224
+ .filter((participant) => !connected.has(participant.id))
225
+ .map((participant) => ({
226
+ level: "warn",
227
+ message: `Team ${teamNode.name} member ${participant.id} has no shared coordination surface with any visible teammate`
228
+ }))
229
+ ];
230
+ };
@@ -0,0 +1,45 @@
1
+ import type { DiagnosticReport } from "../report/index.js";
2
+ import type { ResolvedMemberRef } from "./types.js";
3
+ export interface RosterRepresentativeEntry {
4
+ addresses: Record<string, unknown>;
5
+ delegate_role?: "lead" | "representative";
6
+ description: string;
7
+ surfaces: string[];
8
+ }
9
+ export interface RosterEntry {
10
+ addresses: Record<string, unknown>;
11
+ card?: {
12
+ path: string;
13
+ summary: string;
14
+ };
15
+ description: string;
16
+ is_lead?: boolean;
17
+ representatives?: Record<string, RosterRepresentativeEntry>;
18
+ role: "lead" | "member" | "team";
19
+ surfaces: string[];
20
+ }
21
+ export interface Roster {
22
+ context_kind?: "direct" | "representative";
23
+ lead: string | null;
24
+ members: Record<string, RosterEntry>;
25
+ mode: "hierarchical" | "swarm";
26
+ represents?: {
27
+ delegate_role: "lead" | "representative";
28
+ representative: string;
29
+ slot: string;
30
+ };
31
+ self: string;
32
+ team: string;
33
+ }
34
+ export interface GenerateTeamRosterOptions {
35
+ contextKey: string;
36
+ delegateRole?: "lead" | "representative";
37
+ representedSlotId?: string;
38
+ selfMemberId: string;
39
+ teamSource: string;
40
+ }
41
+ export interface GeneratedTeamRoster {
42
+ diagnostics: DiagnosticReport[];
43
+ roster: string;
44
+ visibleMembers: ResolvedMemberRef[];
45
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -24,6 +24,9 @@ export interface ResolvedDiscordSurface {
24
24
  users: string[];
25
25
  };
26
26
  botTokenSecret: string;
27
+ identity?: {
28
+ userId: string;
29
+ };
27
30
  }
28
31
  export interface ResolvedTelegramSurface {
29
32
  access?: {
@@ -32,6 +35,10 @@ export interface ResolvedTelegramSurface {
32
35
  users: string[];
33
36
  };
34
37
  botTokenSecret: string;
38
+ identity?: {
39
+ userId?: string;
40
+ username?: string;
41
+ };
35
42
  }
36
43
  export interface ResolvedWhatsAppSurface {
37
44
  access?: {
@@ -39,6 +46,9 @@ export interface ResolvedWhatsAppSurface {
39
46
  mode: "allowlist" | "open" | "pairing";
40
47
  users: string[];
41
48
  };
49
+ identity?: {
50
+ phone: string;
51
+ };
42
52
  }
43
53
  export interface ResolvedSlackSurface {
44
54
  access?: {
@@ -48,13 +58,60 @@ export interface ResolvedSlackSurface {
48
58
  };
49
59
  appTokenSecret: string;
50
60
  botTokenSecret: string;
61
+ identity?: {
62
+ userId: string;
63
+ };
64
+ }
65
+ export interface ResolvedHttpSurface {
66
+ access?: {
67
+ mode: "open";
68
+ };
69
+ auth?: {
70
+ mode: "bearer";
71
+ tokenSecret?: string;
72
+ };
73
+ pathPrefix: string;
74
+ port?: number;
75
+ }
76
+ export interface ResolvedMoltnetRoomPolicy {
77
+ read?: "all" | "mentions" | "thread_only";
78
+ reply?: "auto" | "never";
79
+ }
80
+ export interface ResolvedMoltnetDMConfig extends ResolvedMoltnetRoomPolicy {
81
+ enabled: boolean;
82
+ }
83
+ export interface ResolvedMoltnetAttachment {
84
+ contextRooms?: Record<string, string[]>;
85
+ dms?: ResolvedMoltnetDMConfig;
86
+ memberId: string | null;
87
+ network: string;
88
+ rooms?: Record<string, ResolvedMoltnetRoomPolicy>;
89
+ teamSource: string | null;
90
+ }
91
+ export interface ResolvedWebhookSurface {
92
+ signingSecret?: string;
93
+ url: string;
51
94
  }
52
95
  export interface ResolvedAgentSurfaces {
53
96
  discord?: ResolvedDiscordSurface;
97
+ http?: ResolvedHttpSurface;
98
+ moltnet?: ResolvedMoltnetAttachment[];
54
99
  slack?: ResolvedSlackSurface;
55
100
  telegram?: ResolvedTelegramSurface;
101
+ webhook?: ResolvedWebhookSurface;
56
102
  whatsapp?: ResolvedWhatsAppSurface;
57
103
  }
104
+ export interface ResolvedTeamNetworkRoom {
105
+ id: string;
106
+ members: string[];
107
+ }
108
+ export interface ResolvedTeamNetwork {
109
+ expose?: boolean;
110
+ id: string;
111
+ name: string;
112
+ provider: "moltnet";
113
+ rooms: ResolvedTeamNetworkRoom[];
114
+ }
58
115
  export interface EffectiveModelTarget {
59
116
  auth: {
60
117
  key?: string;
@@ -75,9 +132,11 @@ export interface ResolvedMemberRef {
75
132
  runtimeName: string | null;
76
133
  }
77
134
  export interface ResolvedAgentNode {
135
+ description: string;
78
136
  docs: ResolvedDocument[];
79
137
  env: StringMap;
80
138
  execution: ExecutionBlock | undefined;
139
+ expose?: boolean;
81
140
  kind: "agent";
82
141
  mcpServers: McpServer[];
83
142
  name: string;
@@ -90,16 +149,17 @@ export interface ResolvedAgentNode {
90
149
  surfaces?: ResolvedAgentSurfaces;
91
150
  subagents: ResolvedSubagentRef[];
92
151
  }
93
- export interface ResolvedTeamStructure {
94
- external: string[];
95
- leader: string | null;
96
- mode: "hierarchical" | "swarm";
97
- }
98
152
  export interface ResolvedTeamNode {
153
+ description: string;
99
154
  docs: ResolvedDocument[];
155
+ external: string[];
156
+ externalExplicit?: boolean;
100
157
  kind: "team";
158
+ lead: string | null;
101
159
  members: ResolvedMemberRef[];
160
+ mode: "hierarchical" | "swarm";
102
161
  name: string;
162
+ networks?: ResolvedTeamNetwork[];
103
163
  policyMode: string | null;
104
164
  policyOnDegrade: string | null;
105
165
  shared: {
@@ -109,7 +169,6 @@ export interface ResolvedTeamNode {
109
169
  skills: ResolvedSkill[];
110
170
  };
111
171
  source: string;
112
- structure: ResolvedTeamStructure;
113
172
  }
114
173
  export interface CompilePlanEdge {
115
174
  from: string;
@@ -124,8 +183,33 @@ export interface CompilePlanNode {
124
183
  slug: string;
125
184
  value: ResolvedAgentNode | ResolvedTeamNode;
126
185
  }
186
+ export interface ResolvedTeamMembershipContext {
187
+ agentSource: string;
188
+ memberId: string;
189
+ teamName: string;
190
+ teamSource: string;
191
+ }
192
+ export interface ResolvedMoltnetRoomMembership {
193
+ agentName: string;
194
+ agentSource: string;
195
+ concreteMemberId: string;
196
+ declaredSlot: string;
197
+ declaringTeamName: string;
198
+ declaringTeamSource: string;
199
+ directTeamName: string;
200
+ directTeamSource: string;
201
+ networkId: string;
202
+ policy?: ResolvedMoltnetRoomPolicy;
203
+ representedSlot?: string;
204
+ representedTeamName?: string;
205
+ representedTeamSource?: string;
206
+ representativePath?: string[];
207
+ roomId: string;
208
+ }
127
209
  export interface CompilePlan {
128
210
  edges: CompilePlanEdge[];
211
+ memberships?: ResolvedTeamMembershipContext[];
212
+ moltnetRoomMemberships?: ResolvedMoltnetRoomMembership[];
129
213
  nodes: CompilePlanNode[];
130
214
  root: string;
131
215
  runtimes: Record<string, {
@@ -0,0 +1,9 @@
1
+ export interface ProjectRuntimeOptions {
2
+ path?: string;
3
+ recursive?: boolean;
4
+ runtime: string;
5
+ }
6
+ export interface UpdateProjectRuntimeResult {
7
+ updatedFiles: string[];
8
+ }
9
+ export declare const setProjectRuntime: (options: ProjectRuntimeOptions) => Promise<UpdateProjectRuntimeResult>;
@@ -0,0 +1,67 @@
1
+ import path from "node:path";
2
+ import { getCanonicalManifestPath, getManifestPath, getProjectRoot, writeUtf8File } from "../filesystem/index.js";
3
+ import { loadManifest, renderSpawnfile } from "../manifest/index.js";
4
+ import { assertRuntimeCanCompile } from "../runtime/index.js";
5
+ import { SpawnfileError } from "../shared/index.js";
6
+ import { assertRuntimeSupportsExecutionModelAuth } from "./modelAuth.js";
7
+ import { validateAgentSurfaceSupport } from "./surfaceDefinitions.js";
8
+ const TEAM_RUNTIME_COMMAND_ERROR = "spawnfile runtime commands only write agent manifests; use --recursive to update descendant agents of a team project";
9
+ const resolveTargetManifestPath = (inputPath) => getManifestPath(path.resolve(inputPath ?? process.cwd()));
10
+ const collectManifestPaths = async (manifestPath, recursive, visited = new Set()) => {
11
+ const canonicalPath = getCanonicalManifestPath(manifestPath);
12
+ if (visited.has(canonicalPath)) {
13
+ return [];
14
+ }
15
+ visited.add(canonicalPath);
16
+ if (!recursive) {
17
+ return [canonicalPath];
18
+ }
19
+ const loadedManifest = await loadManifest(canonicalPath);
20
+ const childRefs = loadedManifest.manifest.kind === "team"
21
+ ? loadedManifest.manifest.members.map((member) => member.ref)
22
+ : (loadedManifest.manifest.subagents ?? []).map((subagent) => subagent.ref);
23
+ const nestedPaths = await Promise.all(childRefs.map((ref) => collectManifestPaths(getManifestPath(path.resolve(getProjectRoot(canonicalPath), ref)), true, visited)));
24
+ return [canonicalPath, ...nestedPaths.flat()];
25
+ };
26
+ const manifestChanged = (current, next) => JSON.stringify(current) !== JSON.stringify(next);
27
+ const assertRuntimeMutationAllowed = (manifest, recursive) => {
28
+ if (manifest.kind === "agent") {
29
+ return true;
30
+ }
31
+ if (recursive) {
32
+ return false;
33
+ }
34
+ throw new SpawnfileError("validation_error", TEAM_RUNTIME_COMMAND_ERROR);
35
+ };
36
+ const validateAgentRuntimeMutation = (manifest) => {
37
+ validateAgentSurfaceSupport(manifest);
38
+ const runtimeName = typeof manifest.runtime === "string" ? manifest.runtime : manifest.runtime?.name;
39
+ if (!runtimeName) {
40
+ return;
41
+ }
42
+ assertRuntimeSupportsExecutionModelAuth(runtimeName, manifest.execution, manifest.name);
43
+ };
44
+ export const setProjectRuntime = async (options) => {
45
+ await assertRuntimeCanCompile(options.runtime);
46
+ const recursive = options.recursive ?? false;
47
+ const manifestPaths = await collectManifestPaths(resolveTargetManifestPath(options.path), recursive);
48
+ const updatedFiles = [];
49
+ for (const manifestPath of manifestPaths) {
50
+ const loadedManifest = await loadManifest(manifestPath);
51
+ const manifest = loadedManifest.manifest;
52
+ if (!assertRuntimeMutationAllowed(manifest, recursive)) {
53
+ continue;
54
+ }
55
+ const nextManifest = {
56
+ ...manifest,
57
+ runtime: options.runtime
58
+ };
59
+ validateAgentRuntimeMutation(nextManifest);
60
+ if (!manifestChanged(manifest, nextManifest)) {
61
+ continue;
62
+ }
63
+ await writeUtf8File(manifestPath, renderSpawnfile(nextManifest));
64
+ updatedFiles.push(manifestPath);
65
+ }
66
+ return { updatedFiles };
67
+ };
@@ -0,0 +1,8 @@
1
+ import { type AddProjectSurfaceOptions, type ProjectSurfaceSummariesResult, type RemoveProjectSurfaceOptions, type ShowProjectSurfacesOptions, type UpdateProjectSurfacesResult } from "./surfaceDefinitions.js";
2
+ import type { ProjectSurfaceAccessOptions } from "./surfaceDefinitions.js";
3
+ export { type AddProjectSurfaceOptions, type ProjectSurfaceAccessOptions, type ProjectSurfaceSummariesResult, type RemoveProjectSurfaceOptions, type ShowProjectSurfacesOptions, type UpdateProjectSurfacesResult, resolvePortableSurfaceName } from "./surfaceDefinitions.js";
4
+ export type { ProjectSurfaceSummary, SurfaceAccessMode, SurfaceName } from "./surfaceDefinitions.js";
5
+ export declare const addProjectSurface: (options: AddProjectSurfaceOptions) => Promise<UpdateProjectSurfacesResult>;
6
+ export declare const setProjectSurfaceAccess: (options: ProjectSurfaceAccessOptions) => Promise<UpdateProjectSurfacesResult>;
7
+ export declare const removeProjectSurface: (options: RemoveProjectSurfaceOptions) => Promise<UpdateProjectSurfacesResult>;
8
+ export declare const showProjectSurfaces: (options?: ShowProjectSurfacesOptions) => Promise<ProjectSurfaceSummariesResult>;
@@ -0,0 +1,106 @@
1
+ import path from "node:path";
2
+ import { getCanonicalManifestPath, getManifestPath, getProjectRoot, writeUtf8File } from "../filesystem/index.js";
3
+ import { loadManifest, renderSpawnfile } from "../manifest/index.js";
4
+ import { assertSurfaceMutationAllowed, removeSurface, updateSurfaceAccess, upsertSurface, validateAgentSurfaceSupport } from "./surfaceDefinitions.js";
5
+ const resolveTargetManifestPath = (inputPath) => getManifestPath(path.resolve(inputPath ?? process.cwd()));
6
+ const collectManifestPaths = async (manifestPath, recursive, visited = new Set()) => {
7
+ const canonicalPath = getCanonicalManifestPath(manifestPath);
8
+ if (visited.has(canonicalPath)) {
9
+ return [];
10
+ }
11
+ visited.add(canonicalPath);
12
+ if (!recursive) {
13
+ return [canonicalPath];
14
+ }
15
+ const loadedManifest = await loadManifest(canonicalPath);
16
+ const childRefs = loadedManifest.manifest.kind === "team"
17
+ ? loadedManifest.manifest.members.map((member) => member.ref)
18
+ : (loadedManifest.manifest.subagents ?? []).map((subagent) => subagent.ref);
19
+ const nestedPaths = await Promise.all(childRefs.map((ref) => collectManifestPaths(getManifestPath(path.resolve(getProjectRoot(canonicalPath), ref)), true, visited)));
20
+ return [canonicalPath, ...nestedPaths.flat()];
21
+ };
22
+ const manifestChanged = (current, next) => JSON.stringify(current) !== JSON.stringify(next);
23
+ const rewriteTouchedManifests = async (manifestPaths, mutate) => {
24
+ const rewrites = [];
25
+ for (const manifestPath of manifestPaths) {
26
+ const loadedManifest = await loadManifest(manifestPath);
27
+ const nextManifest = mutate(loadedManifest.manifest, manifestPath);
28
+ if (!nextManifest || !manifestChanged(loadedManifest.manifest, nextManifest)) {
29
+ continue;
30
+ }
31
+ if (nextManifest.kind === "agent") {
32
+ validateAgentSurfaceSupport(nextManifest);
33
+ }
34
+ rewrites.push({
35
+ manifest: nextManifest,
36
+ manifestPath
37
+ });
38
+ }
39
+ for (const rewrite of rewrites) {
40
+ await writeUtf8File(rewrite.manifestPath, renderSpawnfile(rewrite.manifest));
41
+ }
42
+ return {
43
+ updatedFiles: rewrites.map((rewrite) => rewrite.manifestPath)
44
+ };
45
+ };
46
+ export { resolvePortableSurfaceName } from "./surfaceDefinitions.js";
47
+ export const addProjectSurface = async (options) => {
48
+ const recursive = options.recursive ?? false;
49
+ const manifestPaths = await collectManifestPaths(resolveTargetManifestPath(options.path), recursive);
50
+ return rewriteTouchedManifests(manifestPaths, (manifest) => {
51
+ if (!assertSurfaceMutationAllowed(manifest, recursive)) {
52
+ return null;
53
+ }
54
+ return {
55
+ ...manifest,
56
+ surfaces: upsertSurface(manifest.surfaces, options)
57
+ };
58
+ });
59
+ };
60
+ export const setProjectSurfaceAccess = async (options) => {
61
+ const recursive = options.recursive ?? false;
62
+ const manifestPaths = await collectManifestPaths(resolveTargetManifestPath(options.path), recursive);
63
+ return rewriteTouchedManifests(manifestPaths, (manifest, manifestPath) => {
64
+ if (!assertSurfaceMutationAllowed(manifest, recursive)) {
65
+ return null;
66
+ }
67
+ const nextSurfaces = updateSurfaceAccess(manifest.surfaces, options, manifestPath, recursive);
68
+ if (!nextSurfaces) {
69
+ return null;
70
+ }
71
+ return {
72
+ ...manifest,
73
+ surfaces: nextSurfaces
74
+ };
75
+ });
76
+ };
77
+ export const removeProjectSurface = async (options) => {
78
+ const recursive = options.recursive ?? false;
79
+ const manifestPaths = await collectManifestPaths(resolveTargetManifestPath(options.path), recursive);
80
+ return rewriteTouchedManifests(manifestPaths, (manifest) => {
81
+ if (!assertSurfaceMutationAllowed(manifest, recursive)) {
82
+ return null;
83
+ }
84
+ return {
85
+ ...manifest,
86
+ surfaces: removeSurface(manifest.surfaces, options.surface)
87
+ };
88
+ });
89
+ };
90
+ export const showProjectSurfaces = async (options = {}) => {
91
+ const manifestPaths = await collectManifestPaths(resolveTargetManifestPath(options.path), options.recursive ?? false);
92
+ const entries = [];
93
+ for (const manifestPath of manifestPaths) {
94
+ const loadedManifest = await loadManifest(manifestPath);
95
+ if (options.recursive && loadedManifest.manifest.kind !== "agent") {
96
+ continue;
97
+ }
98
+ entries.push({
99
+ kind: loadedManifest.manifest.kind,
100
+ manifestPath,
101
+ name: loadedManifest.manifest.name,
102
+ surfaces: loadedManifest.manifest.surfaces
103
+ });
104
+ }
105
+ return { entries };
106
+ };
@@ -0,0 +1,2 @@
1
+ import type { OrganizationView } from "./types.js";
2
+ export declare const buildOrganizationView: (inputPath: string) => Promise<OrganizationView>;