spawnfile 0.1.11 → 0.1.13

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 (220) hide show
  1. package/README.md +21 -3
  2. package/dist/auth/runtimeCredentials.js +18 -2
  3. package/dist/cli/devCommands.d.ts +3 -0
  4. package/dist/cli/devCommands.js +115 -0
  5. package/dist/cli/lifecycleCommands.js +103 -1
  6. package/dist/cli/modelCommands.js +3 -0
  7. package/dist/cli/resolveCommandInput.d.ts +19 -0
  8. package/dist/cli/resolveCommandInput.js +25 -0
  9. package/dist/cli/runCli.d.ts +10 -1
  10. package/dist/cli/runCli.js +41 -13
  11. package/dist/cli/runtimeCommands.js +1 -0
  12. package/dist/cli/statusCommand.d.ts +43 -0
  13. package/dist/cli/statusCommand.js +428 -0
  14. package/dist/cli/surfaceCommands.js +4 -0
  15. package/dist/compiler/agentSurfaces.js +2 -4
  16. package/dist/compiler/buildProject.d.ts +9 -1
  17. package/dist/compiler/buildProject.js +44 -5
  18. package/dist/compiler/compileProject.d.ts +2 -0
  19. package/dist/compiler/compileProject.js +22 -11
  20. package/dist/compiler/containerArtifacts.d.ts +1 -0
  21. package/dist/compiler/containerArtifacts.js +208 -32
  22. package/dist/compiler/containerArtifactsPlans.js +7 -4
  23. package/dist/compiler/containerArtifactsRender.d.ts +7 -1
  24. package/dist/compiler/containerArtifactsRender.js +31 -69
  25. package/dist/compiler/containerArtifactsTypes.d.ts +9 -0
  26. package/dist/compiler/containerEntrypointRender.js +22 -32
  27. package/dist/compiler/containerPackageRender.d.ts +15 -0
  28. package/dist/compiler/containerPackageRender.js +63 -0
  29. package/dist/compiler/containerTargetResources.js +3 -1
  30. package/dist/compiler/index.d.ts +1 -0
  31. package/dist/compiler/index.js +1 -0
  32. package/dist/compiler/moltnetArtifacts.js +21 -1
  33. package/dist/compiler/moltnetBinaries.d.ts +4 -1
  34. package/dist/compiler/moltnetBinaries.js +24 -3
  35. package/dist/compiler/moltnetClientConfig.d.ts +1 -1
  36. package/dist/compiler/moltnetClientConfig.js +14 -16
  37. package/dist/compiler/moltnetNodeConfig.js +2 -4
  38. package/dist/compiler/moltnetResolution.js +1 -1
  39. package/dist/compiler/moltnetRoomMemberships.js +1 -2
  40. package/dist/compiler/moltnetRuntimeConfig.d.ts +1 -1
  41. package/dist/compiler/moltnetRuntimeConfig.js +9 -10
  42. package/dist/compiler/networkBinding.d.ts +14 -0
  43. package/dist/compiler/networkBinding.js +34 -0
  44. package/dist/compiler/publishProject.d.ts +13 -0
  45. package/dist/compiler/publishProject.js +72 -0
  46. package/dist/compiler/runProject.d.ts +26 -12
  47. package/dist/compiler/runProject.js +109 -126
  48. package/dist/compiler/runProjectAuth.d.ts +5 -0
  49. package/dist/compiler/runProjectAuth.js +98 -0
  50. package/dist/compiler/runProjectDocker.d.ts +19 -0
  51. package/dist/compiler/runProjectDocker.js +202 -0
  52. package/dist/compiler/types.d.ts +1 -2
  53. package/dist/compiler/upProject.d.ts +6 -0
  54. package/dist/compiler/upProject.js +43 -8
  55. package/dist/compiler/view/buildOrganizationView.js +4 -1
  56. package/dist/compiler/view/declarations.d.ts +4 -0
  57. package/dist/compiler/view/declarations.js +104 -0
  58. package/dist/compiler/view/renderNetworks.js +1 -2
  59. package/dist/compiler/view/renderTree.js +6 -2
  60. package/dist/compiler/view/types.d.ts +64 -1
  61. package/dist/deployment/dockerInspect.d.ts +29 -0
  62. package/dist/deployment/dockerInspect.js +130 -0
  63. package/dist/deployment/dockerLabels.d.ts +16 -0
  64. package/dist/deployment/dockerLabels.js +32 -0
  65. package/dist/deployment/dockerLogs.d.ts +24 -0
  66. package/dist/deployment/dockerLogs.js +96 -0
  67. package/dist/deployment/dockerManager.d.ts +59 -0
  68. package/dist/deployment/dockerManager.js +76 -0
  69. package/dist/deployment/dockerProbeGateway.d.ts +16 -0
  70. package/dist/deployment/dockerProbeGateway.js +48 -0
  71. package/dist/deployment/dockerRecover.d.ts +17 -0
  72. package/dist/deployment/dockerRecover.js +129 -0
  73. package/dist/deployment/homeStore.d.ts +19 -0
  74. package/dist/deployment/homeStore.js +130 -0
  75. package/dist/deployment/index.d.ts +10 -0
  76. package/dist/deployment/index.js +10 -0
  77. package/dist/deployment/names.d.ts +3 -0
  78. package/dist/deployment/names.js +12 -0
  79. package/dist/deployment/record.d.ts +76 -0
  80. package/dist/deployment/record.js +174 -0
  81. package/dist/deployment/target.d.ts +35 -0
  82. package/dist/deployment/target.js +96 -0
  83. package/dist/dev/activity.d.ts +14 -0
  84. package/dist/dev/activity.js +48 -0
  85. package/dist/dev/docker.d.ts +16 -0
  86. package/dist/dev/docker.js +71 -0
  87. package/dist/dev/index.d.ts +2 -0
  88. package/dist/dev/index.js +2 -0
  89. package/dist/dev/project.d.ts +35 -0
  90. package/dist/dev/project.js +164 -0
  91. package/dist/distribution/buildDistributionReport.d.ts +22 -0
  92. package/dist/distribution/buildDistributionReport.js +51 -0
  93. package/dist/distribution/consumeImage.d.ts +29 -0
  94. package/dist/distribution/consumeImage.js +254 -0
  95. package/dist/distribution/consumeImageSupport.d.ts +18 -0
  96. package/dist/distribution/consumeImageSupport.js +63 -0
  97. package/dist/distribution/distributionReportSchema.d.ts +84 -0
  98. package/dist/distribution/distributionReportSchema.js +107 -0
  99. package/dist/distribution/dockerRunner.d.ts +5 -0
  100. package/dist/distribution/dockerRunner.js +21 -0
  101. package/dist/distribution/extractImage.d.ts +25 -0
  102. package/dist/distribution/extractImage.js +96 -0
  103. package/dist/distribution/fingerprint.d.ts +2 -0
  104. package/dist/distribution/fingerprint.js +14 -0
  105. package/dist/distribution/imageRef.d.ts +9 -0
  106. package/dist/distribution/imageRef.js +65 -0
  107. package/dist/distribution/imageRuntimeAuth.d.ts +19 -0
  108. package/dist/distribution/imageRuntimeAuth.js +71 -0
  109. package/dist/distribution/index.d.ts +24 -0
  110. package/dist/distribution/index.js +16 -0
  111. package/dist/distribution/preflight.d.ts +11 -0
  112. package/dist/distribution/preflight.js +65 -0
  113. package/dist/distribution/projectImageView.d.ts +8 -0
  114. package/dist/distribution/projectImageView.js +83 -0
  115. package/dist/distribution/projectName.d.ts +1 -0
  116. package/dist/distribution/projectName.js +12 -0
  117. package/dist/distribution/renderImageInterface.d.ts +30 -0
  118. package/dist/distribution/renderImageInterface.js +86 -0
  119. package/dist/distribution/tarReader.d.ts +10 -0
  120. package/dist/distribution/tarReader.js +69 -0
  121. package/dist/distribution/types.d.ts +80 -0
  122. package/dist/distribution/types.js +4 -0
  123. package/dist/distribution/verifyDistributionReport.d.ts +12 -0
  124. package/dist/distribution/verifyDistributionReport.js +29 -0
  125. package/dist/filesystem/paths.d.ts +6 -0
  126. package/dist/filesystem/paths.js +11 -0
  127. package/dist/manifest/loadManifest.js +22 -2
  128. package/dist/manifest/renderSpawnfile.js +2 -4
  129. package/dist/manifest/schemas.d.ts +17 -41
  130. package/dist/manifest/surfaceSchemas.d.ts +19 -47
  131. package/dist/manifest/surfaceSchemas.js +3 -6
  132. package/dist/report/createReport.d.ts +7 -1
  133. package/dist/report/createReport.js +28 -1
  134. package/dist/report/types.d.ts +43 -0
  135. package/dist/runtime/common.d.ts +2 -0
  136. package/dist/runtime/common.js +1 -1
  137. package/dist/runtime/container.d.ts +1 -0
  138. package/dist/runtime/container.js +82 -15
  139. package/dist/runtime/index.d.ts +1 -0
  140. package/dist/runtime/index.js +1 -0
  141. package/dist/runtime/install.d.ts +1 -11
  142. package/dist/runtime/install.js +27 -30
  143. package/dist/runtime/openclaw/adapter.js +9 -1
  144. package/dist/runtime/openclaw/configAuth.d.ts +15 -0
  145. package/dist/runtime/openclaw/configAuth.js +46 -0
  146. package/dist/runtime/openclaw/runAuth.d.ts +6 -0
  147. package/dist/runtime/openclaw/runAuth.js +7 -55
  148. package/dist/runtime/openclaw/statusProbes.d.ts +2 -0
  149. package/dist/runtime/openclaw/statusProbes.js +31 -0
  150. package/dist/runtime/pi/adapter.d.ts +4 -0
  151. package/dist/runtime/pi/adapter.js +198 -0
  152. package/dist/runtime/pi/appActivitySource.d.ts +1 -0
  153. package/dist/runtime/pi/appActivitySource.js +87 -0
  154. package/dist/runtime/pi/appCoreSource.d.ts +1 -0
  155. package/dist/runtime/pi/appCoreSource.js +354 -0
  156. package/dist/runtime/pi/appPreludeSource.d.ts +1 -0
  157. package/dist/runtime/pi/appPreludeSource.js +103 -0
  158. package/dist/runtime/pi/appSource.d.ts +1 -0
  159. package/dist/runtime/pi/appSource.js +8 -0
  160. package/dist/runtime/pi/appTemplate.d.ts +28 -0
  161. package/dist/runtime/pi/appTemplate.js +144 -0
  162. package/dist/runtime/pi/runAuth.d.ts +2 -0
  163. package/dist/runtime/pi/runAuth.js +68 -0
  164. package/dist/runtime/picoclaw/adapter.js +10 -0
  165. package/dist/runtime/picoclaw/runAuth.d.ts +7 -0
  166. package/dist/runtime/picoclaw/runAuth.js +8 -68
  167. package/dist/runtime/picoclaw/statusProbes.d.ts +2 -0
  168. package/dist/runtime/picoclaw/statusProbes.js +100 -0
  169. package/dist/runtime/registry.d.ts +0 -5
  170. package/dist/runtime/registry.js +5 -12
  171. package/dist/runtime/statusProbes.d.ts +16 -0
  172. package/dist/runtime/statusProbes.js +41 -0
  173. package/dist/runtime/types.d.ts +53 -1
  174. package/dist/shared/errors.d.ts +6 -0
  175. package/dist/shared/errors.js +9 -0
  176. package/dist/status/buildStatus.d.ts +13 -0
  177. package/dist/status/buildStatus.js +266 -0
  178. package/dist/status/compileReport.d.ts +96 -0
  179. package/dist/status/compileReport.js +230 -0
  180. package/dist/status/compiledContainerObservations.d.ts +5 -0
  181. package/dist/status/compiledContainerObservations.js +63 -0
  182. package/dist/status/deploymentLogs.d.ts +12 -0
  183. package/dist/status/deploymentLogs.js +45 -0
  184. package/dist/status/deployments.d.ts +14 -0
  185. package/dist/status/deployments.js +121 -0
  186. package/dist/status/imageStatusReport.d.ts +10 -0
  187. package/dist/status/imageStatusReport.js +73 -0
  188. package/dist/status/index.d.ts +14 -0
  189. package/dist/status/index.js +14 -0
  190. package/dist/status/moltnetProbes.d.ts +21 -0
  191. package/dist/status/moltnetProbes.js +240 -0
  192. package/dist/status/registryDrift.d.ts +28 -0
  193. package/dist/status/registryDrift.js +119 -0
  194. package/dist/status/renderStatus.d.ts +2 -0
  195. package/dist/status/renderStatus.js +230 -0
  196. package/dist/status/runtimeProbes.d.ts +13 -0
  197. package/dist/status/runtimeProbes.js +111 -0
  198. package/dist/status/selectionSubjects.d.ts +8 -0
  199. package/dist/status/selectionSubjects.js +77 -0
  200. package/dist/status/selectors.d.ts +14 -0
  201. package/dist/status/selectors.js +90 -0
  202. package/dist/status/traversal.d.ts +6 -0
  203. package/dist/status/traversal.js +15 -0
  204. package/dist/status/types.d.ts +113 -0
  205. package/dist/status/types.js +1 -0
  206. package/package.json +9 -2
  207. package/runtimes.yaml +44 -21
  208. package/dist/runtime/tinyclaw/adapter.d.ts +0 -2
  209. package/dist/runtime/tinyclaw/adapter.js +0 -284
  210. package/dist/runtime/tinyclaw/runAuth.d.ts +0 -2
  211. package/dist/runtime/tinyclaw/runAuth.js +0 -49
  212. package/dist/runtime/tinyclaw/scaffold-assets/AGENTS.md +0 -160
  213. package/dist/runtime/tinyclaw/scaffold-assets/CLAUDE.md +0 -5
  214. package/dist/runtime/tinyclaw/scaffold-assets/SOUL.md +0 -177
  215. package/dist/runtime/tinyclaw/scaffold.d.ts +0 -2
  216. package/dist/runtime/tinyclaw/scaffold.js +0 -24
  217. package/dist/runtime/tinyclaw/schedules.d.ts +0 -9
  218. package/dist/runtime/tinyclaw/schedules.js +0 -62
  219. package/dist/runtime/tinyclaw/surfaces.d.ts +0 -8
  220. package/dist/runtime/tinyclaw/surfaces.js +0 -94
@@ -4,6 +4,7 @@ export const registerRuntimeCommands = (program, handlers, streams) => {
4
4
  .description("Edit runtime declarations");
5
5
  runtimeCommand
6
6
  .command("set")
7
+ .description("Set an agent's runtime binding")
7
8
  .argument("<name>", "Runtime name")
8
9
  .argument("[path]", "Project directory or Spawnfile path", process.cwd())
9
10
  .option("--recursive", "Update the target project and its descendants")
@@ -0,0 +1,43 @@
1
+ import { Command } from "commander";
2
+ import { inspectDockerDeployment, recoverDockerDeploymentRecords } from "../deployment/index.js";
3
+ import { collectDeploymentLogObservations, collectMoltnetProbeObservations, collectRuntimeProbeObservations, type StatusCommandResult, type StatusExitCode } from "../status/index.js";
4
+ import type { CliHandlers, CliStreams } from "./runCli.js";
5
+ type StatusCommandHandlers = Pick<CliHandlers, "buildOrganizationView"> & Partial<Pick<CliHandlers, "requireAuthProfile">>;
6
+ type StatusCommandLiveHandlers = {
7
+ collectDeploymentLogObservations?: typeof collectDeploymentLogObservations;
8
+ collectMoltnetProbeObservations?: typeof collectMoltnetProbeObservations;
9
+ collectRuntimeProbeObservations?: typeof collectRuntimeProbeObservations;
10
+ inspectDockerDeployment?: typeof inspectDockerDeployment;
11
+ recoverDockerDeploymentRecords?: typeof recoverDockerDeploymentRecords;
12
+ };
13
+ type StatusCommandHandlersWithLive = StatusCommandHandlers & StatusCommandLiveHandlers;
14
+ export interface StatusCommandOptions {
15
+ agent?: string;
16
+ context?: string;
17
+ deployment?: string;
18
+ dockerCommand?: string;
19
+ image?: boolean;
20
+ json?: boolean;
21
+ live?: boolean;
22
+ logs?: boolean;
23
+ network?: string;
24
+ out?: string;
25
+ pretty?: boolean;
26
+ pull?: boolean;
27
+ pullCheck?: boolean;
28
+ quiet?: boolean;
29
+ recover?: boolean;
30
+ runtime?: string;
31
+ team?: string;
32
+ timeout?: string;
33
+ watch?: boolean;
34
+ }
35
+ export interface StatusWatchOptions {
36
+ intervalMs?: number;
37
+ iterations?: number;
38
+ sleep?: (ms: number) => Promise<void>;
39
+ }
40
+ export declare const executeStatusWatch: (inputPath: string, options: StatusCommandOptions, handlers: StatusCommandHandlersWithLive, streams: CliStreams, setExitCode: (exitCode: StatusExitCode) => void, watchOptions?: StatusWatchOptions) => Promise<void>;
41
+ export declare const executeStatusCommand: (inputPath: string, options: StatusCommandOptions, handlers: StatusCommandHandlersWithLive) => Promise<StatusCommandResult>;
42
+ export declare const registerStatusCommand: (program: Command, handlers: CliHandlers, streams: CliStreams, setExitCode: (exitCode: StatusExitCode) => void) => void;
43
+ export {};
@@ -0,0 +1,428 @@
1
+ import { inspectDockerDeployment, listDeploymentRecords, listHomeDeploymentRecords, readHomeDeploymentRecord, readHomeDeploymentReport, recoverDockerDeploymentRecords } from "../deployment/index.js";
2
+ import { extractImageReport, normalizeProjectLabelSlug, parseDistributionReport, projectImageOrganizationView, renderImageInterface } from "../distribution/index.js";
3
+ import { collectRegistryDriftObservations } from "../status/index.js";
4
+ import { resolveProjectOutputDirectory } from "../filesystem/index.js";
5
+ import { DEFAULT_OUTPUT_DIRECTORY, errorExitCode, SpawnfileError } from "../shared/index.js";
6
+ import { resolveCommandInput } from "./resolveCommandInput.js";
7
+ import { loadedImageCompileReport } from "../status/index.js";
8
+ import { createStaticStatus, createDeploymentSummaries, collectDeploymentLogObservations, collectMoltnetProbeObservations, collectRuntimeProbeObservations, exitCodeForStatus, flattenOrganizationNodes, loadCompileReport, renderStatus, resolveStatusSelector } from "../status/index.js";
9
+ const inputFailure = (message) => ({
10
+ error: message,
11
+ exitCode: 2
12
+ });
13
+ const resolveOutputMode = (options) => {
14
+ const modes = [
15
+ ...(options.json ? ["json"] : []),
16
+ ...(options.pretty ? ["pretty"] : []),
17
+ ...(options.quiet ? ["quiet"] : [])
18
+ ];
19
+ if (modes.length > 1) {
20
+ return inputFailure("Choose only one status output mode: --pretty, --json, or --quiet");
21
+ }
22
+ return modes[0] ?? "pretty";
23
+ };
24
+ const resolveSelectorInput = (options) => {
25
+ const selectors = [
26
+ ...(options.agent ? [{ kind: "agent", value: options.agent }] : []),
27
+ ...(options.team ? [{ kind: "team", value: options.team }] : []),
28
+ ...(options.network ? [{ kind: "network", value: options.network }] : []),
29
+ ...(options.runtime ? [{ kind: "runtime", value: options.runtime }] : [])
30
+ ];
31
+ if (selectors.length > 1) {
32
+ return inputFailure("Choose only one status selector: --agent, --team, --network, or --runtime");
33
+ }
34
+ return selectors[0] ?? null;
35
+ };
36
+ const resolveTimeoutMs = (options) => {
37
+ if (!options.timeout) {
38
+ return undefined;
39
+ }
40
+ const parsed = Number(options.timeout);
41
+ if (!Number.isInteger(parsed) || parsed <= 0) {
42
+ return inputFailure("status --timeout must be a positive integer number of milliseconds");
43
+ }
44
+ return parsed;
45
+ };
46
+ const resolveDeploymentRecords = (records, options) => {
47
+ if (options.deployment) {
48
+ const record = records.find((entry) => entry.record.name === options.deployment);
49
+ return record
50
+ ? [record]
51
+ : inputFailure(`Unknown deployment "${options.deployment}". Valid deployments: ${records.map((entry) => entry.record.name).sort().join(", ") || "none"}`);
52
+ }
53
+ if (options.live && records.length > 1) {
54
+ return inputFailure(`status --live requires --deployment when multiple records exist: ${records.map((entry) => entry.record.name).sort().join(", ")}`);
55
+ }
56
+ return records;
57
+ };
58
+ const inspectDeployments = async (records, handlers, options, timeoutMs) => {
59
+ if (!options.live) {
60
+ return new Map();
61
+ }
62
+ const inspect = handlers.inspectDockerDeployment ?? inspectDockerDeployment;
63
+ const inspections = await Promise.all(records.map(async ({ record }) => [
64
+ record.name,
65
+ await inspect(record, {
66
+ dockerCommand: options.dockerCommand,
67
+ timeoutMs
68
+ })
69
+ ]));
70
+ return new Map(inspections);
71
+ };
72
+ const containsFromView = (view) => flattenOrganizationNodes(view).map((node) => ({ id: node.id, kind: node.kind }));
73
+ const runtimeInstanceIdsFromReport = (loadedReport) => loadedReport.kind === "loaded"
74
+ ? loadedReport.report.runtimeInstances.map((instance) => instance.id).sort()
75
+ : [];
76
+ const recoverContextDeployments = async (input) => {
77
+ const recover = input.handlers.recoverDockerDeploymentRecords ?? recoverDockerDeploymentRecords;
78
+ return recover({
79
+ contains: containsFromView(input.view),
80
+ context: input.options.context,
81
+ dockerCommand: input.options.dockerCommand,
82
+ outputDirectory: input.outputDirectory,
83
+ projectLabel: input.projectLabel,
84
+ runtimeInstanceIds: runtimeInstanceIdsFromReport(input.loadedReport),
85
+ sourceRoot: input.sourceRoot,
86
+ timeoutMs: input.timeoutMs
87
+ });
88
+ };
89
+ const resolveAuthValues = async (records, handlers) => {
90
+ const values = {};
91
+ if (!handlers.requireAuthProfile) {
92
+ return values;
93
+ }
94
+ const profileNames = [...new Set(records
95
+ .map(({ record }) => record.auth_profile)
96
+ .filter((profileName) => typeof profileName === "string" && profileName.length > 0))];
97
+ for (const profileName of profileNames) {
98
+ try {
99
+ const profile = await handlers.requireAuthProfile(profileName);
100
+ Object.assign(values, profile.env);
101
+ }
102
+ catch {
103
+ // Missing profile values are reported by the metadata layer as unknown credentials.
104
+ }
105
+ }
106
+ return values;
107
+ };
108
+ const emitOutput = (streams, output) => {
109
+ for (const line of output.split("\n")) {
110
+ streams.stdout(line);
111
+ }
112
+ };
113
+ const wait = (ms) => new Promise((resolve) => {
114
+ setTimeout(resolve, ms);
115
+ });
116
+ export const executeStatusWatch = async (inputPath, options, handlers, streams, setExitCode, watchOptions = {}) => {
117
+ const intervalMs = watchOptions.intervalMs ?? 5_000;
118
+ const sleep = watchOptions.sleep ?? wait;
119
+ let iteration = 0;
120
+ while (watchOptions.iterations === undefined || iteration < watchOptions.iterations) {
121
+ if (iteration > 0) {
122
+ await sleep(intervalMs);
123
+ streams.stdout("");
124
+ }
125
+ const result = await executeStatusCommand(inputPath, options, handlers);
126
+ setExitCode(result.exitCode);
127
+ if (result.error) {
128
+ streams.stderr(`error: ${result.error}`);
129
+ return;
130
+ }
131
+ if (result.output) {
132
+ emitOutput(streams, result.output);
133
+ }
134
+ iteration += 1;
135
+ }
136
+ };
137
+ /* v8 ignore start -- docker extraction is covered by distribution E2E */
138
+ const runStaticImageStatus = async (imageRef, options, json) => {
139
+ try {
140
+ const inspection = await extractImageReport(imageRef, {
141
+ dockerCommand: options.dockerCommand,
142
+ dockerContext: options.context,
143
+ pull: options.pull
144
+ });
145
+ return {
146
+ exitCode: 0,
147
+ output: renderImageInterface(inspection.report, { imageRef, json })
148
+ };
149
+ }
150
+ catch (error) {
151
+ // Input errors (bad labels, non-JSON report, fingerprint mismatch) exit 2;
152
+ // Docker/runtime failures (daemon down, pull/create failure) exit 1.
153
+ return {
154
+ error: error instanceof Error ? error.message : String(error),
155
+ exitCode: errorExitCode(error)
156
+ };
157
+ }
158
+ };
159
+ /* v8 ignore stop */
160
+ const runHomeDeploymentStatus = async (options, handlers, mode, timeoutMs) => {
161
+ let records;
162
+ try {
163
+ records = await listHomeDeploymentRecords();
164
+ }
165
+ catch (error) {
166
+ return { error: error instanceof Error ? error.message : String(error), exitCode: errorExitCode(error) };
167
+ }
168
+ if (!options.deployment) {
169
+ if (records.length === 0) {
170
+ return inputFailure("No image deployments found in the home store");
171
+ }
172
+ if (records.length > 1) {
173
+ return inputFailure(`status --deployment is required: ${records.map((entry) => entry.record.name).sort().join(", ")}`);
174
+ }
175
+ }
176
+ const targetName = options.deployment ?? records[0].record.name;
177
+ const match = records.find((entry) => entry.record.name === targetName);
178
+ if (!match) {
179
+ return inputFailure(`Unknown deployment "${targetName}". Valid deployments: ${records.map((entry) => entry.record.name).sort().join(", ") || "none"}`);
180
+ }
181
+ let report;
182
+ try {
183
+ const record = await readHomeDeploymentRecord(targetName);
184
+ void record;
185
+ const raw = await readHomeDeploymentReport(targetName);
186
+ let parsed;
187
+ try {
188
+ parsed = JSON.parse(raw);
189
+ }
190
+ catch (error) {
191
+ // A corrupt cached report is bad input, not a runtime failure: exit 2.
192
+ throw new SpawnfileError("validation_error", `Cached report for "${targetName}" is not valid JSON: ${error instanceof Error ? error.message : String(error)}`);
193
+ }
194
+ report = parseDistributionReport(parsed);
195
+ }
196
+ catch (error) {
197
+ return { error: error instanceof Error ? error.message : String(error), exitCode: errorExitCode(error) };
198
+ }
199
+ const view = projectImageOrganizationView(report, match.record.source.kind === "image"
200
+ ? match.record.source.ref
201
+ : targetName);
202
+ const reportPath = match.path.replace(/record\.json$/, "spawnfile-report.json");
203
+ const loadedReport = loadedImageCompileReport(report, reportPath);
204
+ const selectedRecords = [match];
205
+ const deploymentInspections = await inspectDeployments(selectedRecords, handlers, options, timeoutMs);
206
+ const recordValues = selectedRecords.map(({ record }) => record);
207
+ const authValues = options.live ? await resolveAuthValues(selectedRecords, handlers) : {};
208
+ const collectRuntimeProbes = handlers.collectRuntimeProbeObservations ?? collectRuntimeProbeObservations;
209
+ const collectMoltnetProbes = handlers.collectMoltnetProbeObservations ?? collectMoltnetProbeObservations;
210
+ const collectDeploymentLogs = handlers.collectDeploymentLogObservations ?? collectDeploymentLogObservations;
211
+ const liveObservations = options.live && !options.recover
212
+ ? [
213
+ ...await collectRuntimeProbes({
214
+ deployments: recordValues,
215
+ inspections: deploymentInspections,
216
+ loadedReport,
217
+ timeoutMs
218
+ }),
219
+ ...await collectMoltnetProbes({
220
+ authValues,
221
+ deployments: recordValues,
222
+ inspections: deploymentInspections,
223
+ loadedReport,
224
+ timeoutMs
225
+ }),
226
+ ...(options.logs
227
+ ? await collectDeploymentLogs({
228
+ deployments: recordValues,
229
+ dockerCommand: options.dockerCommand,
230
+ loadedReport,
231
+ timeoutMs
232
+ })
233
+ : []),
234
+ ...(options.pullCheck
235
+ ? await collectRegistryDriftObservations({
236
+ deployments: recordValues,
237
+ dockerCommand: options.dockerCommand,
238
+ timeoutMs
239
+ })
240
+ : [])
241
+ ]
242
+ : [];
243
+ const status = createStaticStatus(view, loadedReport, {
244
+ deployments: createDeploymentSummaries(selectedRecords, deploymentInspections),
245
+ inputPath: view.inputPath,
246
+ live: {
247
+ context: null,
248
+ deploymentName: targetName,
249
+ logs: options.logs ?? false,
250
+ recover: false,
251
+ requested: options.live ?? false
252
+ },
253
+ liveObservations,
254
+ outputDirectory: "",
255
+ selection: null
256
+ });
257
+ return { exitCode: exitCodeForStatus(status), output: renderStatus(status, { mode }), status };
258
+ };
259
+ export const executeStatusCommand = async (inputPath, options, handlers) => {
260
+ const mode = resolveOutputMode(options);
261
+ if (typeof mode !== "string") {
262
+ return mode;
263
+ }
264
+ if (options.logs && !options.live) {
265
+ return inputFailure("status --logs requires --live");
266
+ }
267
+ // A positional image reference without --deployment renders the static
268
+ // interface from the embedded report. Image ref with --deployment, or a bare
269
+ // --deployment on the default path, reads the home store.
270
+ // A clear image reference (tag/digest/registry, or forced with --image)
271
+ // without --deployment renders the static interface; any other positional is
272
+ // treated as a project path (the view builder reports a missing path).
273
+ const commandInput = resolveCommandInput(inputPath, { forceImage: options.image });
274
+ const usedDefaultPath = inputPath === process.cwd();
275
+ if (commandInput.kind === "image" && !options.deployment) {
276
+ return runStaticImageStatus(commandInput.ref, options, mode === "json");
277
+ }
278
+ if (options.deployment && !options.context && (commandInput.kind === "image" || usedDefaultPath)) {
279
+ const timeoutForHome = resolveTimeoutMs(options);
280
+ if (typeof timeoutForHome !== "number" && timeoutForHome !== undefined) {
281
+ return timeoutForHome;
282
+ }
283
+ return runHomeDeploymentStatus(options, handlers, mode, timeoutForHome);
284
+ }
285
+ if (options.context && !options.live) {
286
+ return inputFailure("status --context requires --live");
287
+ }
288
+ if (options.logs && !options.live) {
289
+ return inputFailure("status --logs requires --live");
290
+ }
291
+ if (options.recover && !options.context) {
292
+ return inputFailure("status --recover requires --context");
293
+ }
294
+ const timeoutMs = resolveTimeoutMs(options);
295
+ if (typeof timeoutMs !== "number" && timeoutMs !== undefined) {
296
+ return timeoutMs;
297
+ }
298
+ const selectorInput = resolveSelectorInput(options);
299
+ if (selectorInput && "exitCode" in selectorInput) {
300
+ return selectorInput;
301
+ }
302
+ const outputDirectory = resolveProjectOutputDirectory(inputPath, options.out, DEFAULT_OUTPUT_DIRECTORY);
303
+ const view = await handlers.buildOrganizationView(inputPath);
304
+ const selectorResult = resolveStatusSelector(view, selectorInput);
305
+ if (selectorResult?.kind === "failure") {
306
+ return { error: selectorResult.failure.message, exitCode: 2 };
307
+ }
308
+ const loadedReport = await loadCompileReport(outputDirectory);
309
+ if (loadedReport.kind === "failure") {
310
+ return { error: loadedReport.failure.message, exitCode: 2 };
311
+ }
312
+ let deploymentRecords;
313
+ try {
314
+ deploymentRecords = options.context
315
+ ? await recoverContextDeployments({
316
+ handlers,
317
+ loadedReport,
318
+ options,
319
+ outputDirectory,
320
+ projectLabel: normalizeProjectLabelSlug(view.root.name),
321
+ sourceRoot: view.root.source,
322
+ timeoutMs,
323
+ view
324
+ })
325
+ : await listDeploymentRecords(outputDirectory);
326
+ }
327
+ catch (error) {
328
+ return {
329
+ error: error instanceof Error ? error.message : String(error),
330
+ exitCode: errorExitCode(error)
331
+ };
332
+ }
333
+ const selectedDeploymentRecords = resolveDeploymentRecords(deploymentRecords, options);
334
+ if ("exitCode" in selectedDeploymentRecords) {
335
+ return selectedDeploymentRecords;
336
+ }
337
+ const deploymentInspections = await inspectDeployments(selectedDeploymentRecords, handlers, options, timeoutMs);
338
+ const selectedDeploymentRecordValues = selectedDeploymentRecords.map(({ record }) => record);
339
+ const authValues = options.live
340
+ ? await resolveAuthValues(selectedDeploymentRecords, handlers)
341
+ : {};
342
+ const collectRuntimeProbes = handlers.collectRuntimeProbeObservations ?? collectRuntimeProbeObservations;
343
+ const collectMoltnetProbes = handlers.collectMoltnetProbeObservations ?? collectMoltnetProbeObservations;
344
+ const collectDeploymentLogs = handlers.collectDeploymentLogObservations ?? collectDeploymentLogObservations;
345
+ const liveObservations = options.live && !options.recover
346
+ ? [
347
+ ...await collectRuntimeProbes({
348
+ deployments: selectedDeploymentRecordValues,
349
+ inspections: deploymentInspections,
350
+ loadedReport,
351
+ timeoutMs
352
+ }),
353
+ ...await collectMoltnetProbes({
354
+ authValues,
355
+ deployments: selectedDeploymentRecordValues,
356
+ inspections: deploymentInspections,
357
+ loadedReport,
358
+ timeoutMs
359
+ }),
360
+ ...(options.logs
361
+ ? await collectDeploymentLogs({
362
+ deployments: selectedDeploymentRecordValues,
363
+ dockerCommand: options.dockerCommand,
364
+ loadedReport,
365
+ timeoutMs
366
+ })
367
+ : [])
368
+ ]
369
+ : [];
370
+ const status = createStaticStatus(view, loadedReport, {
371
+ deployments: createDeploymentSummaries(selectedDeploymentRecords, deploymentInspections),
372
+ inputPath,
373
+ live: {
374
+ context: options.context ?? null,
375
+ deploymentName: options.deployment ?? null,
376
+ logs: options.logs ?? false,
377
+ recover: options.recover === true || Boolean(options.context),
378
+ requested: options.live ?? false
379
+ },
380
+ liveObservations,
381
+ outputDirectory,
382
+ selection: selectorResult?.selection ?? null
383
+ });
384
+ return {
385
+ exitCode: exitCodeForStatus(status),
386
+ output: renderStatus(status, { mode }),
387
+ status
388
+ };
389
+ };
390
+ export const registerStatusCommand = (program, handlers, streams, setExitCode) => {
391
+ program
392
+ .command("status")
393
+ .description("Show static Spawnfile organization status")
394
+ .argument("[path]", "Project directory or Spawnfile path", process.cwd())
395
+ .option("--out <dir>", "Compile output directory")
396
+ .option("--json", "Render machine-readable JSON")
397
+ .option("--pretty", "Render human output")
398
+ .option("--quiet", "Render only summary and non-ok observations")
399
+ .option("--live", "Inspect the recorded live deployment")
400
+ .option("--deployment <name>", "Deployment record name")
401
+ .option("--image", "Interpret the argument as an image reference")
402
+ .option("--pull", "Pull the image before inspecting (image references only)")
403
+ .option("--pull-check", "Check the registry for a newer image digest (networked)")
404
+ .option("--docker-command <command>", "Docker command")
405
+ .option("--context <name>", "Docker context for live remote deployment recovery")
406
+ .option("--recover", "Recover live status from labels instead of a deployment record")
407
+ .option("--logs", "Include redacted logs when supported")
408
+ .option("--timeout <ms>", "Bound live Docker/runtime checks in milliseconds")
409
+ .option("--watch", "Refresh status every five seconds until interrupted")
410
+ .option("--agent <id>", "Show one agent")
411
+ .option("--team <id>", "Show one team")
412
+ .option("--network <id>", "Show one network")
413
+ .option("--runtime <name>", "Show one runtime")
414
+ .action(async (inputPath, options) => {
415
+ if (options.watch) {
416
+ await executeStatusWatch(inputPath, options, handlers, streams, setExitCode);
417
+ return;
418
+ }
419
+ const result = await executeStatusCommand(inputPath, options, handlers);
420
+ setExitCode(result.exitCode);
421
+ if (result.error) {
422
+ streams.stderr(`error: ${result.error}`);
423
+ }
424
+ if (result.output) {
425
+ emitOutput(streams, result.output);
426
+ }
427
+ });
428
+ };
@@ -22,6 +22,7 @@ export const registerSurfaceCommands = (program, handlers, streams) => {
22
22
  .description("Edit agent surfaces");
23
23
  surfaceCommand
24
24
  .command("add")
25
+ .description("Attach a surface to an agent")
25
26
  .argument("<surface>", "Surface name")
26
27
  .argument("[path]", "Project directory or Spawnfile path", process.cwd())
27
28
  .option("--bot-token-secret <env>", "Override the bot token env var name")
@@ -42,6 +43,7 @@ export const registerSurfaceCommands = (program, handlers, streams) => {
42
43
  });
43
44
  surfaceCommand
44
45
  .command("remove")
46
+ .description("Detach a surface from an agent")
45
47
  .argument("<surface>", "Surface name")
46
48
  .argument("[path]", "Project directory or Spawnfile path", process.cwd())
47
49
  .option("--recursive", "Update the target project and its descendants")
@@ -58,6 +60,7 @@ export const registerSurfaceCommands = (program, handlers, streams) => {
58
60
  });
59
61
  surfaceCommand
60
62
  .command("set-access")
63
+ .description("Set an agent's access mode for a surface")
61
64
  .argument("<surface>", "Surface name")
62
65
  .argument("[path]", "Project directory or Spawnfile path", process.cwd())
63
66
  .requiredOption("--mode <mode>", "Access mode")
@@ -86,6 +89,7 @@ export const registerSurfaceCommands = (program, handlers, streams) => {
86
89
  });
87
90
  surfaceCommand
88
91
  .command("show")
92
+ .description("Show an agent's resolved surfaces")
89
93
  .argument("[path]", "Project directory or Spawnfile path", process.cwd())
90
94
  .option("--recursive", "Show descendant agent surfaces too")
91
95
  .action(async (inputPath, options) => {
@@ -27,8 +27,7 @@ export const resolveAgentSurfaces = (surfaces) => {
27
27
  ? {
28
28
  dms: {
29
29
  enabled: attachment.dms.enabled,
30
- ...(attachment.dms.read ? { read: attachment.dms.read } : {}),
31
- ...(attachment.dms.reply ? { reply: attachment.dms.reply } : {})
30
+ ...(attachment.dms.wake ? { wake: attachment.dms.wake } : {})
32
31
  }
33
32
  }
34
33
  : {}),
@@ -41,8 +40,7 @@ export const resolveAgentSurfaces = (surfaces) => {
41
40
  .map(([roomId, behavior]) => [
42
41
  roomId,
43
42
  {
44
- ...(behavior.read ? { read: behavior.read } : {}),
45
- ...(behavior.reply ? { reply: behavior.reply } : {})
43
+ ...(behavior.wake ? { wake: behavior.wake } : {})
46
44
  }
47
45
  ]))
48
46
  }
@@ -1,20 +1,28 @@
1
1
  import { type CompileProjectOptions, type CompileProjectResult } from "./compileProject.js";
2
+ import type { MoltnetTargetArchitecture } from "./moltnetBinaries.js";
2
3
  export interface DockerBuildInvocation {
3
4
  args: string[];
4
5
  command: string;
5
6
  cwd: string;
7
+ dockerContext?: string | null;
6
8
  imageTag: string;
7
9
  }
8
10
  export type DockerBuildRunner = (invocation: DockerBuildInvocation) => Promise<void>;
9
11
  export interface BuildProjectOptions extends CompileProjectOptions {
10
12
  buildRunner?: DockerBuildRunner;
11
13
  dockerCommand?: string;
14
+ dockerContext?: string;
12
15
  imageTag?: string;
13
16
  }
14
17
  export interface BuildProjectResult extends CompileProjectResult {
15
18
  imageTag: string;
16
19
  }
17
20
  export declare const createDefaultImageTag: (projectRoot: string) => string;
18
- export declare const createDockerBuildInvocation: (outputDirectory: string, imageTag: string, dockerCommand?: string) => DockerBuildInvocation;
21
+ export declare const createDockerBuildInvocation: (outputDirectory: string, imageTag: string, options?: string | {
22
+ dockerCommand?: string;
23
+ dockerContext?: string;
24
+ }) => DockerBuildInvocation;
25
+ export declare const normalizeDockerArchitecture: (architecture: string) => MoltnetTargetArchitecture;
26
+ export declare const resolveDockerBuildArchitecture: (options: Pick<BuildProjectOptions, "dockerCommand" | "dockerContext">) => Promise<MoltnetTargetArchitecture | undefined>;
19
27
  export declare const runDockerBuild: DockerBuildRunner;
20
28
  export declare const buildProject: (inputPath: string, options?: BuildProjectOptions) => Promise<BuildProjectResult>;
@@ -1,8 +1,10 @@
1
1
  import path from "node:path";
2
- import { spawn } from "node:child_process";
2
+ import { execFile as execFileCallback, spawn } from "node:child_process";
3
+ import { promisify } from "node:util";
3
4
  import { SpawnfileError } from "../shared/index.js";
4
5
  import { compileProject } from "./compileProject.js";
5
6
  import { slugify } from "./helpers.js";
7
+ const execFile = promisify(execFileCallback);
6
8
  export const createDefaultImageTag = (projectRoot) => {
7
9
  const baseName = slugify(path.basename(projectRoot));
8
10
  return `spawnfile-${baseName || "project"}`;
@@ -13,12 +15,44 @@ const resolveImageTagRoot = (inputPath) => {
13
15
  ? path.dirname(resolvedPath)
14
16
  : resolvedPath;
15
17
  };
16
- export const createDockerBuildInvocation = (outputDirectory, imageTag, dockerCommand = "docker") => ({
17
- args: ["build", "-t", imageTag, "."],
18
- command: dockerCommand,
18
+ export const createDockerBuildInvocation = (outputDirectory, imageTag, options = "docker") => ({
19
+ args: typeof options === "string" || !options.dockerContext
20
+ ? ["build", "-t", imageTag, "."]
21
+ : ["--context", options.dockerContext, "build", "-t", imageTag, "."],
22
+ command: typeof options === "string" ? options : options.dockerCommand ?? "docker",
19
23
  cwd: outputDirectory,
24
+ dockerContext: typeof options === "string" ? null : options.dockerContext ?? null,
20
25
  imageTag
21
26
  });
27
+ export const normalizeDockerArchitecture = (architecture) => {
28
+ switch (architecture.trim()) {
29
+ case "amd64":
30
+ case "x64":
31
+ case "x86_64":
32
+ return "amd64";
33
+ case "aarch64":
34
+ case "arm64":
35
+ return "arm64";
36
+ default:
37
+ throw new SpawnfileError("compile_error", `Docker target architecture ${architecture.trim() || "unknown"} is not supported by staged Moltnet binaries`);
38
+ }
39
+ };
40
+ export const resolveDockerBuildArchitecture = async (options) => {
41
+ if (!options.dockerContext) {
42
+ return undefined;
43
+ }
44
+ try {
45
+ const { stdout } = await execFile(options.dockerCommand ?? "docker", ["--context", options.dockerContext, "info", "--format", "{{.Architecture}}"], { timeout: 10_000 });
46
+ return normalizeDockerArchitecture(stdout);
47
+ }
48
+ catch (error) {
49
+ if (error instanceof SpawnfileError) {
50
+ throw error;
51
+ }
52
+ const reason = error instanceof Error ? error.message : String(error);
53
+ throw new SpawnfileError("compile_error", `Unable to resolve Docker context ${options.dockerContext} architecture: ${reason}`);
54
+ }
55
+ };
22
56
  export const runDockerBuild = async (invocation) => new Promise((resolve, reject) => {
23
57
  const child = spawn(invocation.command, invocation.args, {
24
58
  cwd: invocation.cwd,
@@ -38,12 +72,17 @@ export const runDockerBuild = async (invocation) => new Promise((resolve, reject
38
72
  });
39
73
  });
40
74
  export const buildProject = async (inputPath, options = {}) => {
75
+ const targetArchitecture = options.containerArchitecture ?? await resolveDockerBuildArchitecture(options);
41
76
  const compileResult = await compileProject(inputPath, {
42
77
  clean: options.clean,
78
+ containerArchitecture: targetArchitecture,
43
79
  outputDirectory: options.outputDirectory
44
80
  });
45
81
  const imageTag = options.imageTag ?? createDefaultImageTag(resolveImageTagRoot(inputPath));
46
- const invocation = createDockerBuildInvocation(compileResult.outputDirectory, imageTag, options.dockerCommand);
82
+ const invocation = createDockerBuildInvocation(compileResult.outputDirectory, imageTag, {
83
+ dockerCommand: options.dockerCommand,
84
+ dockerContext: options.dockerContext
85
+ });
47
86
  await (options.buildRunner ?? runDockerBuild)(invocation);
48
87
  return {
49
88
  ...compileResult,
@@ -1,6 +1,8 @@
1
1
  import { CompileReport } from "../report/index.js";
2
+ import { type MoltnetTargetArchitecture } from "./moltnetBinaries.js";
2
3
  export interface CompileProjectOptions {
3
4
  clean?: boolean;
5
+ containerArchitecture?: MoltnetTargetArchitecture;
4
6
  outputDirectory?: string;
5
7
  }
6
8
  export interface CompileProjectResult {