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
@@ -1,16 +1,23 @@
1
1
  import { importClaudeCodeAuth, importCodexAuth, importEnvFile, requireAuthProfile } from "../auth/index.js";
2
- import { addAgentProject, addProjectModelFallback, addSubagentProject, addTeamProject, buildCompilePlan, buildProject, clearProjectModelFallbacks, compileProject, initProject, runProject, setProjectPrimaryModel, syncProjectAuth } from "../compiler/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";
3
3
  import { listRuntimeAdapters } from "../runtime/index.js";
4
4
  export interface CliStreams {
5
5
  stderr: (message: string) => void;
6
6
  stdout: (message: string) => void;
7
7
  }
8
+ export interface CliRenderEnvironment {
9
+ ci: boolean;
10
+ noColor: boolean;
11
+ stdoutIsTty: boolean;
12
+ }
8
13
  export interface CliHandlers {
9
14
  buildCompilePlan: typeof buildCompilePlan;
15
+ buildOrganizationView: typeof buildOrganizationView;
10
16
  buildProject: typeof buildProject;
11
17
  compileProject: typeof compileProject;
12
18
  addAgentProject: typeof addAgentProject;
13
19
  addProjectModelFallback: typeof addProjectModelFallback;
20
+ addProjectSurface: typeof addProjectSurface;
14
21
  addSubagentProject: typeof addSubagentProject;
15
22
  addTeamProject: typeof addTeamProject;
16
23
  clearProjectModelFallbacks: typeof clearProjectModelFallbacks;
@@ -19,9 +26,23 @@ export interface CliHandlers {
19
26
  importEnvFile: typeof importEnvFile;
20
27
  initProject: typeof initProject;
21
28
  listRuntimeAdapters: typeof listRuntimeAdapters;
29
+ removeProjectSurface: typeof removeProjectSurface;
22
30
  requireAuthProfile: typeof requireAuthProfile;
23
31
  runProject: typeof runProject;
24
32
  setProjectPrimaryModel: typeof setProjectPrimaryModel;
33
+ setProjectRuntime: typeof setProjectRuntime;
34
+ setProjectSurfaceAccess: typeof setProjectSurfaceAccess;
35
+ showProjectSurfaces: typeof showProjectSurfaces;
25
36
  syncProjectAuth: typeof syncProjectAuth;
26
37
  }
27
- export declare const runCli: (argv: string[], streams?: CliStreams, handlerOverrides?: Partial<CliHandlers>) => Promise<number>;
38
+ export interface RunCliOptions {
39
+ handlers?: Partial<CliHandlers>;
40
+ renderEnvironment?: CliRenderEnvironment;
41
+ streams?: CliStreams;
42
+ }
43
+ type RunCli = {
44
+ (argv: string[], options?: RunCliOptions): Promise<number>;
45
+ (argv: string[], streams?: CliStreams, handlerOverrides?: Partial<CliHandlers>): Promise<number>;
46
+ };
47
+ export declare const runCli: RunCli;
48
+ export {};
@@ -1,31 +1,60 @@
1
1
  import { Command } from "commander";
2
2
  import { importClaudeCodeAuth, importCodexAuth, importEnvFile, requireAuthProfile } from "../auth/index.js";
3
- import { addAgentProject, addProjectModelFallback, addSubagentProject, addTeamProject, buildCompilePlan, buildProject, clearProjectModelFallbacks, compileProject, initProject, runProject, setProjectPrimaryModel, syncProjectAuth } from "../compiler/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";
4
4
  import { isSpawnfileError } from "../shared/index.js";
5
5
  import { listRuntimeAdapters } from "../runtime/index.js";
6
+ import { registerModelCommands } from "./modelCommands.js";
7
+ import { registerRuntimeCommands } from "./runtimeCommands.js";
8
+ import { registerSurfaceCommands } from "./surfaceCommands.js";
9
+ import { registerViewCommand } from "./viewCommand.js";
6
10
  const createDefaultStreams = () => ({
7
11
  stderr: (message) => process.stderr.write(`${message}\n`),
8
12
  stdout: (message) => process.stdout.write(`${message}\n`)
9
13
  });
14
+ const createDefaultRenderEnvironment = () => ({
15
+ ci: process.env.CI !== undefined && process.env.CI !== "" && process.env.CI !== "0",
16
+ noColor: process.env.NO_COLOR !== undefined && process.env.NO_COLOR !== "",
17
+ stdoutIsTty: process.stdout.isTTY === true
18
+ });
10
19
  const createDefaultHandlers = () => ({
11
- buildCompilePlan,
12
- buildProject,
13
- compileProject,
14
- addAgentProject,
15
- addProjectModelFallback,
16
- addSubagentProject,
17
- addTeamProject,
18
- clearProjectModelFallbacks,
19
- importClaudeCodeAuth,
20
- importCodexAuth,
21
- importEnvFile,
22
- initProject,
23
- listRuntimeAdapters,
24
- requireAuthProfile,
25
- runProject,
26
- setProjectPrimaryModel,
27
- syncProjectAuth
20
+ buildCompilePlan, buildOrganizationView, buildProject, compileProject,
21
+ addAgentProject, addProjectModelFallback, addProjectSurface,
22
+ addSubagentProject, addTeamProject, clearProjectModelFallbacks,
23
+ importClaudeCodeAuth, importCodexAuth, importEnvFile,
24
+ initProject, listRuntimeAdapters, removeProjectSurface, requireAuthProfile,
25
+ runProject, setProjectPrimaryModel, setProjectRuntime,
26
+ setProjectSurfaceAccess, showProjectSurfaces, syncProjectAuth
28
27
  });
28
+ const isCliStreams = (value) => {
29
+ const candidate = value;
30
+ return typeof candidate?.stderr === "function" && typeof candidate.stdout === "function";
31
+ };
32
+ const normalizeRunCliOptions = (optionsOrStreams, handlerOverrides = {}) => isCliStreams(optionsOrStreams)
33
+ ? {
34
+ handlers: handlerOverrides,
35
+ renderEnvironment: createDefaultRenderEnvironment(),
36
+ streams: optionsOrStreams
37
+ }
38
+ : {
39
+ handlers: optionsOrStreams?.handlers ?? handlerOverrides,
40
+ renderEnvironment: optionsOrStreams?.renderEnvironment ?? createDefaultRenderEnvironment(),
41
+ streams: optionsOrStreams?.streams ?? createDefaultStreams()
42
+ };
43
+ const writeCommanderOutput = (write, message) => {
44
+ const normalized = message.replace(/\n$/, "");
45
+ if (normalized.length > 0) {
46
+ write(normalized);
47
+ }
48
+ };
49
+ const isCommanderError = (error) => {
50
+ if (typeof error !== "object" || error === null) {
51
+ return false;
52
+ }
53
+ const candidate = error;
54
+ return typeof candidate.code === "string"
55
+ && candidate.code.startsWith("commander.")
56
+ && typeof candidate.exitCode === "number";
57
+ };
29
58
  const formatPlanSummary = (plan) => [
30
59
  `root: ${plan.root}`,
31
60
  `nodes: ${plan.nodes.length}`,
@@ -40,10 +69,20 @@ const formatAuthProfileSummary = (profile) => {
40
69
  `imports: ${importedKinds.length > 0 ? importedKinds.join(", ") : "none"}`
41
70
  ];
42
71
  };
43
- export const runCli = async (argv, streams = createDefaultStreams(), handlerOverrides = {}) => {
44
- const handlers = { ...createDefaultHandlers(), ...handlerOverrides };
72
+ const emitLines = (streams, lines) => lines.forEach((line) => streams.stdout(line));
73
+ const emitFileLines = (streams, label, filePaths) => emitLines(streams, filePaths.map((filePath) => `${label} ${filePath}`));
74
+ export const runCli = async (argv, optionsOrStreams, handlerOverrides = {}) => {
75
+ const cliOptions = normalizeRunCliOptions(optionsOrStreams, handlerOverrides);
76
+ const streams = cliOptions.streams;
77
+ const handlers = { ...createDefaultHandlers(), ...cliOptions.handlers };
45
78
  const program = new Command();
46
79
  program.name("spawnfile").description("Spawnfile v0.1 compiler");
80
+ program.exitOverride();
81
+ program.configureOutput({
82
+ outputError: (message, write) => write(message),
83
+ writeErr: (message) => writeCommanderOutput(streams.stderr, message),
84
+ writeOut: (message) => writeCommanderOutput(streams.stdout, message)
85
+ });
47
86
  program
48
87
  .command("compile")
49
88
  .argument("[path]", "Project directory or Spawnfile path", process.cwd())
@@ -100,9 +139,7 @@ export const runCli = async (argv, streams = createDefaultStreams(), handlerOver
100
139
  team: options.team
101
140
  });
102
141
  streams.stdout(`initialized ${result.directory}`);
103
- for (const filePath of result.createdFiles) {
104
- streams.stdout(`created ${filePath}`);
105
- }
142
+ emitFileLines(streams, "created", result.createdFiles);
106
143
  });
107
144
  const addCommand = program.command("add").description("Add children to an existing Spawnfile project");
108
145
  addCommand
@@ -116,12 +153,8 @@ export const runCli = async (argv, streams = createDefaultStreams(), handlerOver
116
153
  path: inputPath,
117
154
  runtime: options.runtime
118
155
  });
119
- for (const filePath of result.updatedFiles) {
120
- streams.stdout(`updated ${filePath}`);
121
- }
122
- for (const filePath of result.createdFiles) {
123
- streams.stdout(`created ${filePath}`);
124
- }
156
+ emitFileLines(streams, "updated", result.updatedFiles);
157
+ emitFileLines(streams, "created", result.createdFiles);
125
158
  });
126
159
  addCommand
127
160
  .command("subagent")
@@ -132,12 +165,8 @@ export const runCli = async (argv, streams = createDefaultStreams(), handlerOver
132
165
  id,
133
166
  path: inputPath
134
167
  });
135
- for (const filePath of result.updatedFiles) {
136
- streams.stdout(`updated ${filePath}`);
137
- }
138
- for (const filePath of result.createdFiles) {
139
- streams.stdout(`created ${filePath}`);
140
- }
168
+ emitFileLines(streams, "updated", result.updatedFiles);
169
+ emitFileLines(streams, "created", result.createdFiles);
141
170
  });
142
171
  addCommand
143
172
  .command("team")
@@ -148,79 +177,13 @@ export const runCli = async (argv, streams = createDefaultStreams(), handlerOver
148
177
  id,
149
178
  path: inputPath
150
179
  });
151
- for (const filePath of result.updatedFiles) {
152
- streams.stdout(`updated ${filePath}`);
153
- }
154
- for (const filePath of result.createdFiles) {
155
- streams.stdout(`created ${filePath}`);
156
- }
157
- });
158
- const modelCommand = program
159
- .command("model")
160
- .description("Edit primary and fallback model declarations");
161
- modelCommand
162
- .command("set")
163
- .argument("<provider>", "Model provider")
164
- .argument("<name>", "Model name")
165
- .argument("[path]", "Project directory or Spawnfile path", process.cwd())
166
- .option("--auth <method>", "Model auth method")
167
- .option("--key <env>", "Environment variable for api_key auth")
168
- .option("--compat <compatibility>", "Endpoint compatibility for custom/local models")
169
- .option("--base-url <url>", "Endpoint base URL for custom/local models")
170
- .option("--recursive", "Update the target project and its descendants")
171
- .action(async (provider, name, inputPath, options) => {
172
- const result = await handlers.setProjectPrimaryModel({
173
- authKey: options.key,
174
- authMethod: options.auth,
175
- endpointBaseUrl: options.baseUrl,
176
- endpointCompatibility: options.compat,
177
- name,
178
- path: inputPath,
179
- provider,
180
- recursive: options.recursive
181
- });
182
- for (const filePath of result.updatedFiles) {
183
- streams.stdout(`updated ${filePath}`);
184
- }
185
- });
186
- modelCommand
187
- .command("add-fallback")
188
- .argument("<provider>", "Model provider")
189
- .argument("<name>", "Model name")
190
- .argument("[path]", "Project directory or Spawnfile path", process.cwd())
191
- .option("--auth <method>", "Model auth method")
192
- .option("--key <env>", "Environment variable for api_key auth")
193
- .option("--compat <compatibility>", "Endpoint compatibility for custom/local models")
194
- .option("--base-url <url>", "Endpoint base URL for custom/local models")
195
- .option("--recursive", "Update the target project and its descendants")
196
- .action(async (provider, name, inputPath, options) => {
197
- const result = await handlers.addProjectModelFallback({
198
- authKey: options.key,
199
- authMethod: options.auth,
200
- endpointBaseUrl: options.baseUrl,
201
- endpointCompatibility: options.compat,
202
- name,
203
- path: inputPath,
204
- provider,
205
- recursive: options.recursive
206
- });
207
- for (const filePath of result.updatedFiles) {
208
- streams.stdout(`updated ${filePath}`);
209
- }
210
- });
211
- modelCommand
212
- .command("clear-fallbacks")
213
- .argument("[path]", "Project directory or Spawnfile path", process.cwd())
214
- .option("--recursive", "Update the target project and its descendants")
215
- .action(async (inputPath, options) => {
216
- const result = await handlers.clearProjectModelFallbacks({
217
- path: inputPath,
218
- recursive: options.recursive
219
- });
220
- for (const filePath of result.updatedFiles) {
221
- streams.stdout(`updated ${filePath}`);
222
- }
180
+ emitFileLines(streams, "updated", result.updatedFiles);
181
+ emitFileLines(streams, "created", result.createdFiles);
223
182
  });
183
+ registerModelCommands(program, handlers, streams);
184
+ registerRuntimeCommands(program, handlers, streams);
185
+ registerSurfaceCommands(program, handlers, streams);
186
+ registerViewCommand(program, handlers, streams, cliOptions.renderEnvironment);
224
187
  program
225
188
  .command("validate")
226
189
  .argument("[path]", "Project directory or Spawnfile path", process.cwd())
@@ -247,9 +210,7 @@ export const runCli = async (argv, streams = createDefaultStreams(), handlerOver
247
210
  .option("-p, --profile <name>", "Auth profile name", "default")
248
211
  .action(async (filePath, options) => {
249
212
  const profile = await handlers.importEnvFile(options.profile, filePath);
250
- for (const line of formatAuthProfileSummary(profile)) {
251
- streams.stdout(line);
252
- }
213
+ emitLines(streams, formatAuthProfileSummary(profile));
253
214
  });
254
215
  authImportCommand
255
216
  .command("claude-code")
@@ -257,9 +218,7 @@ export const runCli = async (argv, streams = createDefaultStreams(), handlerOver
257
218
  .option("--from <directory>", "Source Claude Code config directory")
258
219
  .action(async (options) => {
259
220
  const profile = await handlers.importClaudeCodeAuth(options.profile, options.from);
260
- for (const line of formatAuthProfileSummary(profile)) {
261
- streams.stdout(line);
262
- }
221
+ emitLines(streams, formatAuthProfileSummary(profile));
263
222
  });
264
223
  authImportCommand
265
224
  .command("codex")
@@ -267,9 +226,7 @@ export const runCli = async (argv, streams = createDefaultStreams(), handlerOver
267
226
  .option("--from <directory>", "Source Codex config directory")
268
227
  .action(async (options) => {
269
228
  const profile = await handlers.importCodexAuth(options.profile, options.from);
270
- for (const line of formatAuthProfileSummary(profile)) {
271
- streams.stdout(line);
272
- }
229
+ emitLines(streams, formatAuthProfileSummary(profile));
273
230
  });
274
231
  authCommand
275
232
  .command("sync")
@@ -285,24 +242,23 @@ export const runCli = async (argv, streams = createDefaultStreams(), handlerOver
285
242
  envFilePath: options.envFile,
286
243
  profileName: options.profile
287
244
  });
288
- for (const line of formatAuthProfileSummary(profile)) {
289
- streams.stdout(line);
290
- }
245
+ emitLines(streams, formatAuthProfileSummary(profile));
291
246
  });
292
247
  authCommand
293
248
  .command("show")
294
249
  .option("-p, --profile <name>", "Auth profile name", "default")
295
250
  .action(async (options) => {
296
251
  const profile = await handlers.requireAuthProfile(options.profile);
297
- for (const line of formatAuthProfileSummary(profile)) {
298
- streams.stdout(line);
299
- }
252
+ emitLines(streams, formatAuthProfileSummary(profile));
300
253
  });
301
254
  try {
302
255
  await program.parseAsync(argv, { from: "user" });
303
256
  return 0;
304
257
  }
305
258
  catch (error) {
259
+ if (isCommanderError(error)) {
260
+ return error.exitCode === 0 ? 0 : 1;
261
+ }
306
262
  const message = isSpawnfileError(error)
307
263
  ? `${error.code}: ${error.message}`
308
264
  : error instanceof Error
@@ -0,0 +1,3 @@
1
+ import { Command } from "commander";
2
+ import type { CliHandlers, CliStreams } from "./runCli.js";
3
+ export declare const registerRuntimeCommands: (program: Command, handlers: CliHandlers, streams: CliStreams) => void;
@@ -0,0 +1,20 @@
1
+ export const registerRuntimeCommands = (program, handlers, streams) => {
2
+ const runtimeCommand = program
3
+ .command("runtime")
4
+ .description("Edit runtime declarations");
5
+ runtimeCommand
6
+ .command("set")
7
+ .argument("<name>", "Runtime name")
8
+ .argument("[path]", "Project directory or Spawnfile path", process.cwd())
9
+ .option("--recursive", "Update the target project and its descendants")
10
+ .action(async (runtime, inputPath, options) => {
11
+ const result = await handlers.setProjectRuntime({
12
+ path: inputPath,
13
+ recursive: options.recursive,
14
+ runtime
15
+ });
16
+ for (const filePath of result.updatedFiles) {
17
+ streams.stdout(`updated ${filePath}`);
18
+ }
19
+ });
20
+ };
@@ -0,0 +1,3 @@
1
+ import { Command } from "commander";
2
+ import type { CliHandlers, CliStreams } from "./runCli.js";
3
+ export declare const registerSurfaceCommands: (program: Command, handlers: CliHandlers, streams: CliStreams) => void;
@@ -0,0 +1,98 @@
1
+ import YAML from "yaml";
2
+ import { resolvePortableSurfaceName } from "../compiler/index.js";
3
+ const collectStringOption = (value, previous) => [...previous, value];
4
+ const emitSurfaceSummaries = (streams, entries) => {
5
+ entries.forEach((entry, index) => {
6
+ if (index > 0) {
7
+ streams.stdout("");
8
+ }
9
+ streams.stdout(`path: ${entry.manifestPath}`);
10
+ streams.stdout(`kind: ${entry.kind}`);
11
+ streams.stdout(`name: ${entry.name}`);
12
+ if (!entry.surfaces) {
13
+ streams.stdout("surfaces: none");
14
+ return;
15
+ }
16
+ streams.stdout(YAML.stringify({ surfaces: entry.surfaces }).trimEnd());
17
+ });
18
+ };
19
+ export const registerSurfaceCommands = (program, handlers, streams) => {
20
+ const surfaceCommand = program
21
+ .command("surface")
22
+ .description("Edit agent surfaces");
23
+ surfaceCommand
24
+ .command("add")
25
+ .argument("<surface>", "Surface name")
26
+ .argument("[path]", "Project directory or Spawnfile path", process.cwd())
27
+ .option("--bot-token-secret <env>", "Override the bot token env var name")
28
+ .option("--app-token-secret <env>", "Override the Slack app token env var name")
29
+ .option("--recursive", "Update the target project and its descendants")
30
+ .action(async (surface, inputPath, options) => {
31
+ const surfaceName = resolvePortableSurfaceName(surface);
32
+ const result = await handlers.addProjectSurface({
33
+ appTokenSecret: options.appTokenSecret,
34
+ botTokenSecret: options.botTokenSecret,
35
+ path: inputPath,
36
+ recursive: options.recursive,
37
+ surface: surfaceName
38
+ });
39
+ for (const filePath of result.updatedFiles) {
40
+ streams.stdout(`updated ${filePath}`);
41
+ }
42
+ });
43
+ surfaceCommand
44
+ .command("remove")
45
+ .argument("<surface>", "Surface name")
46
+ .argument("[path]", "Project directory or Spawnfile path", process.cwd())
47
+ .option("--recursive", "Update the target project and its descendants")
48
+ .action(async (surface, inputPath, options) => {
49
+ const surfaceName = resolvePortableSurfaceName(surface);
50
+ const result = await handlers.removeProjectSurface({
51
+ path: inputPath,
52
+ recursive: options.recursive,
53
+ surface: surfaceName
54
+ });
55
+ for (const filePath of result.updatedFiles) {
56
+ streams.stdout(`updated ${filePath}`);
57
+ }
58
+ });
59
+ surfaceCommand
60
+ .command("set-access")
61
+ .argument("<surface>", "Surface name")
62
+ .argument("[path]", "Project directory or Spawnfile path", process.cwd())
63
+ .requiredOption("--mode <mode>", "Access mode")
64
+ .option("--user <id>", "Allowlisted user id", collectStringOption, [])
65
+ .option("--channel <id>", "Allowlisted channel id", collectStringOption, [])
66
+ .option("--guild <id>", "Allowlisted guild id", collectStringOption, [])
67
+ .option("--chat <id>", "Allowlisted chat id", collectStringOption, [])
68
+ .option("--group <id>", "Allowlisted group id", collectStringOption, [])
69
+ .option("--recursive", "Update the target project and its descendants")
70
+ .action(async (surface, inputPath, options) => {
71
+ const surfaceName = resolvePortableSurfaceName(surface);
72
+ const result = await handlers.setProjectSurfaceAccess({
73
+ channels: options.channel,
74
+ chats: options.chat,
75
+ groups: options.group,
76
+ guilds: options.guild,
77
+ mode: options.mode,
78
+ path: inputPath,
79
+ recursive: options.recursive,
80
+ surface: surfaceName,
81
+ users: options.user
82
+ });
83
+ for (const filePath of result.updatedFiles) {
84
+ streams.stdout(`updated ${filePath}`);
85
+ }
86
+ });
87
+ surfaceCommand
88
+ .command("show")
89
+ .argument("[path]", "Project directory or Spawnfile path", process.cwd())
90
+ .option("--recursive", "Show descendant agent surfaces too")
91
+ .action(async (inputPath, options) => {
92
+ const result = await handlers.showProjectSurfaces({
93
+ path: inputPath,
94
+ recursive: options.recursive
95
+ });
96
+ emitSurfaceSummaries(streams, result.entries);
97
+ });
98
+ };
@@ -0,0 +1,3 @@
1
+ import { Command } from "commander";
2
+ import type { CliHandlers, CliRenderEnvironment, CliStreams } from "./runCli.js";
3
+ export declare const registerViewCommand: (program: Command, handlers: CliHandlers, streams: CliStreams, renderEnvironment: CliRenderEnvironment) => void;
@@ -0,0 +1,87 @@
1
+ import { stat } from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { Option } from "commander";
4
+ import { renderOrganizationNetworks, renderOrganizationTree } from "../compiler/index.js";
5
+ import { SpawnfileError } from "../shared/index.js";
6
+ const VIEW_MODES = ["tree", "networks"];
7
+ const VIEW_SHOW_OPTIONS = ["paths", "declared"];
8
+ const VIEW_COLOR_OPTIONS = ["auto", "always", "never"];
9
+ const isViewMode = (value) => VIEW_MODES.includes(value);
10
+ const isViewShow = (value) => VIEW_SHOW_OPTIONS.includes(value);
11
+ const manifestPathFor = (inputPath) => path.basename(inputPath) === "Spawnfile"
12
+ ? path.resolve(inputPath)
13
+ : path.resolve(inputPath, "Spawnfile");
14
+ const hasResolvedSpawnfile = async (inputPath) => {
15
+ try {
16
+ return (await stat(manifestPathFor(inputPath))).isFile();
17
+ }
18
+ catch {
19
+ return false;
20
+ }
21
+ };
22
+ const suggestModeOptionForPathToken = async (inputPath) => {
23
+ if (!inputPath || !isViewMode(inputPath) || await hasResolvedSpawnfile(inputPath)) {
24
+ return;
25
+ }
26
+ throw new SpawnfileError("validation_error", `No Spawnfile found for path "${inputPath}". Did you mean "spawnfile view --mode ${inputPath}"?`);
27
+ };
28
+ const resolveColor = (color, environment) => {
29
+ if (color === "always") {
30
+ return true;
31
+ }
32
+ if (color === "never") {
33
+ return false;
34
+ }
35
+ return environment.stdoutIsTty && !environment.ci && !environment.noColor;
36
+ };
37
+ const parseShowLayers = (value) => {
38
+ const layers = new Set();
39
+ if (!value) {
40
+ return layers;
41
+ }
42
+ for (const layer of value.split(",")) {
43
+ const normalized = layer.trim();
44
+ if (!isViewShow(normalized)) {
45
+ throw new SpawnfileError("validation_error", `Unsupported view detail layer "${normalized}". Supported layers: paths, declared.`);
46
+ }
47
+ layers.add(normalized);
48
+ }
49
+ return layers;
50
+ };
51
+ const toRenderOptions = (options, environment) => {
52
+ const showLayers = parseShowLayers(options.show);
53
+ if (options.paths) {
54
+ showLayers.add("paths");
55
+ }
56
+ return {
57
+ ascii: options.ascii,
58
+ color: resolveColor(options.color, environment),
59
+ declared: showLayers.has("declared"),
60
+ paths: showLayers.has("paths")
61
+ };
62
+ };
63
+ const emitRenderedView = (streams, output) => {
64
+ for (const line of output.split("\n")) {
65
+ streams.stdout(line);
66
+ }
67
+ };
68
+ export const registerViewCommand = (program, handlers, streams, renderEnvironment) => {
69
+ program
70
+ .command("view")
71
+ .description("Render a read-only organization view")
72
+ .argument("[path]", "Project directory or Spawnfile path")
73
+ .addOption(new Option("--mode <mode>", "View mode").choices(VIEW_MODES).default("tree"))
74
+ .option("--show <show>", "Comma-separated additional details")
75
+ .option("--ascii", "Use ASCII tree connectors")
76
+ .addOption(new Option("--color <when>", "Color output").choices(VIEW_COLOR_OPTIONS).default("auto"))
77
+ .option("--paths", "Show source paths")
78
+ .action(async (inputPath, options) => {
79
+ await suggestModeOptionForPathToken(inputPath);
80
+ const renderOptions = toRenderOptions(options, renderEnvironment);
81
+ const view = await handlers.buildOrganizationView(inputPath ?? process.cwd());
82
+ const output = options.mode === "networks"
83
+ ? renderOrganizationNetworks(view, renderOptions)
84
+ : renderOrganizationTree(view, renderOptions);
85
+ emitRenderedView(streams, output);
86
+ });
87
+ };
@@ -5,6 +5,7 @@ export const resolveAgentSurfaces = (surfaces) => {
5
5
  }
6
6
  const resolved = {};
7
7
  if (surfaces.discord) {
8
+ const identity = surfaces.discord.identity;
8
9
  resolved.discord = {
9
10
  ...(surfaces.discord.access
10
11
  ? {
@@ -16,10 +17,41 @@ export const resolveAgentSurfaces = (surfaces) => {
16
17
  }
17
18
  }
18
19
  : {}),
19
- botTokenSecret: surfaces.discord.bot_token_secret ?? DEFAULT_DISCORD_BOT_TOKEN_SECRET
20
+ botTokenSecret: surfaces.discord.bot_token_secret ?? DEFAULT_DISCORD_BOT_TOKEN_SECRET,
21
+ ...(identity ? { identity: { userId: identity.user_id } } : {})
20
22
  };
21
23
  }
24
+ if (surfaces.moltnet) {
25
+ resolved.moltnet = surfaces.moltnet.map((attachment) => ({
26
+ ...(attachment.dms
27
+ ? {
28
+ dms: {
29
+ enabled: attachment.dms.enabled,
30
+ ...(attachment.dms.read ? { read: attachment.dms.read } : {}),
31
+ ...(attachment.dms.reply ? { reply: attachment.dms.reply } : {})
32
+ }
33
+ }
34
+ : {}),
35
+ memberId: null,
36
+ network: attachment.network,
37
+ ...(attachment.rooms
38
+ ? {
39
+ rooms: Object.fromEntries(Object.entries(attachment.rooms)
40
+ .sort(([left], [right]) => left.localeCompare(right))
41
+ .map(([roomId, behavior]) => [
42
+ roomId,
43
+ {
44
+ ...(behavior.read ? { read: behavior.read } : {}),
45
+ ...(behavior.reply ? { reply: behavior.reply } : {})
46
+ }
47
+ ]))
48
+ }
49
+ : {}),
50
+ teamSource: null
51
+ }));
52
+ }
22
53
  if (surfaces.telegram) {
54
+ const identity = surfaces.telegram.identity;
23
55
  resolved.telegram = {
24
56
  ...(surfaces.telegram.access
25
57
  ? {
@@ -30,21 +62,34 @@ export const resolveAgentSurfaces = (surfaces) => {
30
62
  }
31
63
  }
32
64
  : {}),
33
- botTokenSecret: surfaces.telegram.bot_token_secret ?? DEFAULT_TELEGRAM_BOT_TOKEN_SECRET
65
+ botTokenSecret: surfaces.telegram.bot_token_secret ?? DEFAULT_TELEGRAM_BOT_TOKEN_SECRET,
66
+ ...(identity
67
+ ? {
68
+ identity: {
69
+ ...(identity.user_id ? { userId: identity.user_id } : {}),
70
+ ...(identity.username ? { username: identity.username } : {})
71
+ }
72
+ }
73
+ : {})
34
74
  };
35
75
  }
36
76
  if (surfaces.whatsapp) {
77
+ const identity = surfaces.whatsapp.identity;
37
78
  resolved.whatsapp = surfaces.whatsapp.access
38
79
  ? {
39
80
  access: {
40
81
  groups: [...(surfaces.whatsapp.access.groups ?? [])],
41
82
  mode: surfaces.whatsapp.access.mode ?? "allowlist",
42
83
  users: [...(surfaces.whatsapp.access.users ?? [])]
43
- }
84
+ },
85
+ ...(identity ? { identity: { phone: identity.phone } } : {})
44
86
  }
45
- : {};
87
+ : {
88
+ ...(identity ? { identity: { phone: identity.phone } } : {})
89
+ };
46
90
  }
47
91
  if (surfaces.slack) {
92
+ const identity = surfaces.slack.identity;
48
93
  resolved.slack = {
49
94
  ...(surfaces.slack.access
50
95
  ? {
@@ -56,7 +101,8 @@ export const resolveAgentSurfaces = (surfaces) => {
56
101
  }
57
102
  : {}),
58
103
  appTokenSecret: surfaces.slack.app_token_secret ?? DEFAULT_SLACK_APP_TOKEN_SECRET,
59
- botTokenSecret: surfaces.slack.bot_token_secret ?? DEFAULT_SLACK_BOT_TOKEN_SECRET
104
+ botTokenSecret: surfaces.slack.bot_token_secret ?? DEFAULT_SLACK_BOT_TOKEN_SECRET,
105
+ ...(identity ? { identity: { userId: identity.user_id } } : {})
60
106
  };
61
107
  }
62
108
  return Object.keys(resolved).length > 0 ? resolved : undefined;