spawnfile 0.1.11 → 0.1.12

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 (182) hide show
  1. package/README.md +13 -2
  2. package/dist/cli/lifecycleCommands.js +101 -1
  3. package/dist/cli/modelCommands.js +3 -0
  4. package/dist/cli/resolveCommandInput.d.ts +19 -0
  5. package/dist/cli/resolveCommandInput.js +25 -0
  6. package/dist/cli/runCli.d.ts +4 -1
  7. package/dist/cli/runCli.js +37 -13
  8. package/dist/cli/runtimeCommands.js +1 -0
  9. package/dist/cli/statusCommand.d.ts +42 -0
  10. package/dist/cli/statusCommand.js +394 -0
  11. package/dist/cli/surfaceCommands.js +4 -0
  12. package/dist/compiler/agentSurfaces.js +2 -4
  13. package/dist/compiler/compileProject.js +19 -10
  14. package/dist/compiler/containerArtifacts.d.ts +1 -0
  15. package/dist/compiler/containerArtifacts.js +208 -32
  16. package/dist/compiler/containerArtifactsPlans.js +7 -4
  17. package/dist/compiler/containerArtifactsRender.d.ts +7 -1
  18. package/dist/compiler/containerArtifactsRender.js +6 -0
  19. package/dist/compiler/containerArtifactsTypes.d.ts +9 -0
  20. package/dist/compiler/containerEntrypointRender.js +18 -31
  21. package/dist/compiler/index.d.ts +1 -0
  22. package/dist/compiler/index.js +1 -0
  23. package/dist/compiler/moltnetArtifacts.js +5 -0
  24. package/dist/compiler/moltnetClientConfig.d.ts +1 -1
  25. package/dist/compiler/moltnetClientConfig.js +3 -16
  26. package/dist/compiler/moltnetNodeConfig.js +2 -4
  27. package/dist/compiler/moltnetResolution.js +1 -1
  28. package/dist/compiler/moltnetRoomMemberships.js +1 -2
  29. package/dist/compiler/moltnetRuntimeConfig.d.ts +1 -1
  30. package/dist/compiler/moltnetRuntimeConfig.js +1 -13
  31. package/dist/compiler/networkBinding.d.ts +14 -0
  32. package/dist/compiler/networkBinding.js +34 -0
  33. package/dist/compiler/publishProject.d.ts +13 -0
  34. package/dist/compiler/publishProject.js +72 -0
  35. package/dist/compiler/runProject.d.ts +26 -12
  36. package/dist/compiler/runProject.js +102 -125
  37. package/dist/compiler/runProjectAuth.d.ts +5 -0
  38. package/dist/compiler/runProjectAuth.js +98 -0
  39. package/dist/compiler/runProjectDocker.d.ts +19 -0
  40. package/dist/compiler/runProjectDocker.js +57 -0
  41. package/dist/compiler/types.d.ts +1 -2
  42. package/dist/compiler/upProject.d.ts +6 -0
  43. package/dist/compiler/upProject.js +42 -8
  44. package/dist/compiler/view/buildOrganizationView.js +4 -1
  45. package/dist/compiler/view/declarations.d.ts +4 -0
  46. package/dist/compiler/view/declarations.js +104 -0
  47. package/dist/compiler/view/renderNetworks.js +1 -2
  48. package/dist/compiler/view/renderTree.js +6 -2
  49. package/dist/compiler/view/types.d.ts +64 -1
  50. package/dist/deployment/dockerInspect.d.ts +29 -0
  51. package/dist/deployment/dockerInspect.js +130 -0
  52. package/dist/deployment/dockerLabels.d.ts +16 -0
  53. package/dist/deployment/dockerLabels.js +32 -0
  54. package/dist/deployment/dockerLogs.d.ts +24 -0
  55. package/dist/deployment/dockerLogs.js +96 -0
  56. package/dist/deployment/dockerManager.d.ts +59 -0
  57. package/dist/deployment/dockerManager.js +76 -0
  58. package/dist/deployment/dockerProbeGateway.d.ts +16 -0
  59. package/dist/deployment/dockerProbeGateway.js +48 -0
  60. package/dist/deployment/homeStore.d.ts +19 -0
  61. package/dist/deployment/homeStore.js +130 -0
  62. package/dist/deployment/index.d.ts +9 -0
  63. package/dist/deployment/index.js +9 -0
  64. package/dist/deployment/names.d.ts +3 -0
  65. package/dist/deployment/names.js +12 -0
  66. package/dist/deployment/record.d.ts +76 -0
  67. package/dist/deployment/record.js +174 -0
  68. package/dist/deployment/target.d.ts +35 -0
  69. package/dist/deployment/target.js +96 -0
  70. package/dist/distribution/buildDistributionReport.d.ts +22 -0
  71. package/dist/distribution/buildDistributionReport.js +51 -0
  72. package/dist/distribution/consumeImage.d.ts +29 -0
  73. package/dist/distribution/consumeImage.js +254 -0
  74. package/dist/distribution/consumeImageSupport.d.ts +18 -0
  75. package/dist/distribution/consumeImageSupport.js +63 -0
  76. package/dist/distribution/distributionReportSchema.d.ts +84 -0
  77. package/dist/distribution/distributionReportSchema.js +107 -0
  78. package/dist/distribution/dockerRunner.d.ts +5 -0
  79. package/dist/distribution/dockerRunner.js +21 -0
  80. package/dist/distribution/extractImage.d.ts +25 -0
  81. package/dist/distribution/extractImage.js +96 -0
  82. package/dist/distribution/fingerprint.d.ts +2 -0
  83. package/dist/distribution/fingerprint.js +14 -0
  84. package/dist/distribution/imageRef.d.ts +9 -0
  85. package/dist/distribution/imageRef.js +65 -0
  86. package/dist/distribution/imageRuntimeAuth.d.ts +19 -0
  87. package/dist/distribution/imageRuntimeAuth.js +71 -0
  88. package/dist/distribution/index.d.ts +24 -0
  89. package/dist/distribution/index.js +16 -0
  90. package/dist/distribution/preflight.d.ts +11 -0
  91. package/dist/distribution/preflight.js +65 -0
  92. package/dist/distribution/projectImageView.d.ts +8 -0
  93. package/dist/distribution/projectImageView.js +83 -0
  94. package/dist/distribution/projectName.d.ts +1 -0
  95. package/dist/distribution/projectName.js +12 -0
  96. package/dist/distribution/renderImageInterface.d.ts +30 -0
  97. package/dist/distribution/renderImageInterface.js +86 -0
  98. package/dist/distribution/tarReader.d.ts +10 -0
  99. package/dist/distribution/tarReader.js +69 -0
  100. package/dist/distribution/types.d.ts +80 -0
  101. package/dist/distribution/types.js +4 -0
  102. package/dist/distribution/verifyDistributionReport.d.ts +12 -0
  103. package/dist/distribution/verifyDistributionReport.js +29 -0
  104. package/dist/filesystem/paths.d.ts +6 -0
  105. package/dist/filesystem/paths.js +11 -0
  106. package/dist/manifest/loadManifest.js +22 -2
  107. package/dist/manifest/renderSpawnfile.js +2 -4
  108. package/dist/manifest/schemas.d.ts +17 -41
  109. package/dist/manifest/surfaceSchemas.d.ts +19 -47
  110. package/dist/manifest/surfaceSchemas.js +3 -6
  111. package/dist/report/createReport.d.ts +7 -1
  112. package/dist/report/createReport.js +28 -1
  113. package/dist/report/types.d.ts +43 -0
  114. package/dist/runtime/container.js +0 -16
  115. package/dist/runtime/index.d.ts +1 -0
  116. package/dist/runtime/index.js +1 -0
  117. package/dist/runtime/install.d.ts +0 -10
  118. package/dist/runtime/install.js +0 -45
  119. package/dist/runtime/openclaw/adapter.js +9 -1
  120. package/dist/runtime/openclaw/configAuth.d.ts +15 -0
  121. package/dist/runtime/openclaw/configAuth.js +46 -0
  122. package/dist/runtime/openclaw/runAuth.d.ts +6 -0
  123. package/dist/runtime/openclaw/runAuth.js +7 -55
  124. package/dist/runtime/openclaw/statusProbes.d.ts +2 -0
  125. package/dist/runtime/openclaw/statusProbes.js +31 -0
  126. package/dist/runtime/picoclaw/adapter.js +10 -0
  127. package/dist/runtime/picoclaw/runAuth.d.ts +7 -0
  128. package/dist/runtime/picoclaw/runAuth.js +8 -68
  129. package/dist/runtime/picoclaw/statusProbes.d.ts +2 -0
  130. package/dist/runtime/picoclaw/statusProbes.js +100 -0
  131. package/dist/runtime/registry.d.ts +0 -5
  132. package/dist/runtime/registry.js +2 -12
  133. package/dist/runtime/statusProbes.d.ts +16 -0
  134. package/dist/runtime/statusProbes.js +41 -0
  135. package/dist/runtime/types.d.ts +52 -1
  136. package/dist/shared/errors.d.ts +6 -0
  137. package/dist/shared/errors.js +9 -0
  138. package/dist/status/buildStatus.d.ts +13 -0
  139. package/dist/status/buildStatus.js +266 -0
  140. package/dist/status/compileReport.d.ts +96 -0
  141. package/dist/status/compileReport.js +230 -0
  142. package/dist/status/compiledContainerObservations.d.ts +5 -0
  143. package/dist/status/compiledContainerObservations.js +63 -0
  144. package/dist/status/deploymentLogs.d.ts +12 -0
  145. package/dist/status/deploymentLogs.js +45 -0
  146. package/dist/status/deployments.d.ts +14 -0
  147. package/dist/status/deployments.js +128 -0
  148. package/dist/status/imageStatusReport.d.ts +10 -0
  149. package/dist/status/imageStatusReport.js +73 -0
  150. package/dist/status/index.d.ts +14 -0
  151. package/dist/status/index.js +14 -0
  152. package/dist/status/moltnetProbes.d.ts +21 -0
  153. package/dist/status/moltnetProbes.js +240 -0
  154. package/dist/status/registryDrift.d.ts +28 -0
  155. package/dist/status/registryDrift.js +119 -0
  156. package/dist/status/renderStatus.d.ts +2 -0
  157. package/dist/status/renderStatus.js +230 -0
  158. package/dist/status/runtimeProbes.d.ts +13 -0
  159. package/dist/status/runtimeProbes.js +111 -0
  160. package/dist/status/selectionSubjects.d.ts +8 -0
  161. package/dist/status/selectionSubjects.js +77 -0
  162. package/dist/status/selectors.d.ts +14 -0
  163. package/dist/status/selectors.js +90 -0
  164. package/dist/status/traversal.d.ts +6 -0
  165. package/dist/status/traversal.js +15 -0
  166. package/dist/status/types.d.ts +113 -0
  167. package/dist/status/types.js +1 -0
  168. package/package.json +4 -2
  169. package/runtimes.yaml +22 -15
  170. package/dist/runtime/tinyclaw/adapter.d.ts +0 -2
  171. package/dist/runtime/tinyclaw/adapter.js +0 -284
  172. package/dist/runtime/tinyclaw/runAuth.d.ts +0 -2
  173. package/dist/runtime/tinyclaw/runAuth.js +0 -49
  174. package/dist/runtime/tinyclaw/scaffold-assets/AGENTS.md +0 -160
  175. package/dist/runtime/tinyclaw/scaffold-assets/CLAUDE.md +0 -5
  176. package/dist/runtime/tinyclaw/scaffold-assets/SOUL.md +0 -177
  177. package/dist/runtime/tinyclaw/scaffold.d.ts +0 -2
  178. package/dist/runtime/tinyclaw/scaffold.js +0 -24
  179. package/dist/runtime/tinyclaw/schedules.d.ts +0 -9
  180. package/dist/runtime/tinyclaw/schedules.js +0 -62
  181. package/dist/runtime/tinyclaw/surfaces.d.ts +0 -8
  182. package/dist/runtime/tinyclaw/surfaces.js +0 -94
@@ -0,0 +1,266 @@
1
+ import path from "node:path";
2
+ import { createCompiledContainerObservations } from "./compiledContainerObservations.js";
3
+ import { createDeploymentObservations } from "./deployments.js";
4
+ import { expandStatusSelectionSubjects } from "./selectionSubjects.js";
5
+ import { countNodesByKind, flattenOrganizationNodes } from "./traversal.js";
6
+ export const countObservations = (observations) => ({
7
+ error: observations.filter((observation) => observation.severity === "error").length,
8
+ ok: observations.filter((observation) => observation.severity === "ok").length,
9
+ unknown: observations.filter((observation) => observation.severity === "unknown").length,
10
+ warn: observations.filter((observation) => observation.severity === "warn").length
11
+ });
12
+ export const getVisibleObservations = (status) => {
13
+ if (!status.selection) {
14
+ return status.observations;
15
+ }
16
+ const subjects = new Set(["compile", "status", ...status.selection.subjectKeys]);
17
+ return status.observations.filter((observation) => subjects.has(observation.subject));
18
+ };
19
+ export const exitCodeForStatus = (status) => getVisibleObservations(status).some((observation) => observation.severity === "error")
20
+ ? 1
21
+ : 0;
22
+ const severityForDiagnostic = (diagnostic) => diagnostic.level === "error" ? "error" : diagnostic.level === "warn" ? "warn" : "ok";
23
+ const severityForCapability = (capability) => capability.outcome === "unsupported"
24
+ ? "error"
25
+ : capability.outcome === "degraded"
26
+ ? "warn"
27
+ : "ok";
28
+ const createNodeReportObservations = (node) => {
29
+ const observations = [];
30
+ for (const diagnostic of node.diagnostics) {
31
+ observations.push({
32
+ key: `diagnostic.${diagnostic.level}`,
33
+ label: node.id,
34
+ message: diagnostic.message,
35
+ severity: severityForDiagnostic(diagnostic),
36
+ source: "compile_report",
37
+ subject: node.id
38
+ });
39
+ }
40
+ for (const capability of node.capabilities) {
41
+ const severity = severityForCapability(capability);
42
+ if (severity === "ok") {
43
+ continue;
44
+ }
45
+ observations.push({
46
+ key: `capability.${capability.key}`,
47
+ label: node.id,
48
+ message: capability.message,
49
+ severity,
50
+ source: "compile_report",
51
+ subject: node.id
52
+ });
53
+ }
54
+ return observations;
55
+ };
56
+ const createObservation = (input) => ({
57
+ ...input,
58
+ label: `${input.severity.toUpperCase()} ${input.key}`
59
+ });
60
+ const compileInfoFor = (loaded) => {
61
+ if (loaded.kind !== "loaded") {
62
+ return {
63
+ compileFingerprint: null,
64
+ generatedAt: null,
65
+ outputDirectory: null,
66
+ path: loaded.reportPath,
67
+ present: false,
68
+ root: null
69
+ };
70
+ }
71
+ return {
72
+ compileFingerprint: loaded.report.compileFingerprint,
73
+ generatedAt: loaded.report.generatedAt,
74
+ outputDirectory: loaded.report.outputDirectory,
75
+ path: loaded.reportPath,
76
+ present: true,
77
+ root: loaded.report.root
78
+ };
79
+ };
80
+ const addDeclaredObservations = (observations, view, nodes) => {
81
+ observations.push(createObservation({
82
+ key: "source.valid",
83
+ message: `Loaded organization graph from ${view.root.source}`,
84
+ severity: "ok",
85
+ source: "declared",
86
+ subject: "status"
87
+ }));
88
+ for (const node of nodes) {
89
+ observations.push(createObservation({
90
+ key: `${node.kind}.declared`,
91
+ message: `${node.displayName} is declared`,
92
+ severity: "ok",
93
+ source: "declared",
94
+ subject: node.id
95
+ }));
96
+ }
97
+ for (const network of view.networks) {
98
+ observations.push(createObservation({
99
+ key: "network.declared",
100
+ message: `${network.id} declares ${network.rooms.length} room(s)`,
101
+ severity: "ok",
102
+ source: "declared",
103
+ subject: `network:${network.id}`
104
+ }));
105
+ }
106
+ for (const runtime of view.runtimes) {
107
+ observations.push(createObservation({
108
+ key: "runtime.declared",
109
+ message: `${runtime.name} serves ${runtime.nodeIds.length} node(s)`,
110
+ severity: "ok",
111
+ source: "declared",
112
+ subject: `runtime:${runtime.name}`
113
+ }));
114
+ }
115
+ };
116
+ const addCompiledObservations = (observations, loaded, view, nodes) => {
117
+ if (loaded.kind === "missing") {
118
+ observations.push(createObservation({
119
+ key: "compile.report",
120
+ message: `Compile report not found at ${loaded.reportPath}`,
121
+ severity: "unknown",
122
+ source: "compile_report",
123
+ subject: "compile"
124
+ }));
125
+ return;
126
+ }
127
+ if (loaded.kind === "failure") {
128
+ observations.push(createObservation({
129
+ key: "compile.report",
130
+ message: loaded.failure.message,
131
+ severity: "error",
132
+ source: "input",
133
+ subject: "compile"
134
+ }));
135
+ return;
136
+ }
137
+ observations.push(createObservation({
138
+ key: "compile.report",
139
+ message: `Loaded compile report ${loaded.report.reportPath}`,
140
+ severity: "ok",
141
+ source: "compile_report",
142
+ subject: "compile"
143
+ }));
144
+ observations.push(createObservation({
145
+ key: "compile.fingerprint",
146
+ message: loaded.report.compileFingerprint
147
+ ? `Compile fingerprint ${loaded.report.compileFingerprint}`
148
+ : "Compile report has no compile_fingerprint yet",
149
+ severity: loaded.report.compileFingerprint ? "ok" : "unknown",
150
+ source: "compile_report",
151
+ subject: "compile"
152
+ }));
153
+ observations.push(...createCompiledContainerObservations(loaded));
154
+ if (loaded.report.root && path.resolve(loaded.report.root) !== path.resolve(view.root.source)) {
155
+ observations.push(createObservation({
156
+ key: "compile.root",
157
+ message: `Compile report root ${loaded.report.root} differs from source ${view.root.source}`,
158
+ severity: "warn",
159
+ source: "compile_report",
160
+ subject: "compile"
161
+ }));
162
+ }
163
+ const reportNodes = new Map(loaded.report.nodes.map((node) => [node.id, node]));
164
+ const declaredIds = new Set(nodes.map((node) => node.id));
165
+ for (const node of nodes) {
166
+ const reportNode = reportNodes.get(node.id);
167
+ observations.push(createObservation({
168
+ key: `${node.kind}.compiled`,
169
+ message: reportNode
170
+ ? `${node.displayName} is present in the compile report`
171
+ : `${node.displayName} is missing from the compile report`,
172
+ severity: reportNode ? "ok" : "warn",
173
+ source: "compile_report",
174
+ subject: node.id
175
+ }));
176
+ if (reportNode) {
177
+ observations.push(...createNodeReportObservations(reportNode));
178
+ }
179
+ }
180
+ for (const reportNode of loaded.report.nodes) {
181
+ if (!declaredIds.has(reportNode.id)) {
182
+ observations.push(createObservation({
183
+ key: "compile.extra_node",
184
+ message: `${reportNode.id} appears in the compile report but not in source`,
185
+ severity: "warn",
186
+ source: "compile_report",
187
+ subject: reportNode.id
188
+ }));
189
+ }
190
+ }
191
+ };
192
+ const defaultLiveRequest = () => ({
193
+ context: null,
194
+ deploymentName: null,
195
+ logs: false,
196
+ recover: false,
197
+ requested: false
198
+ });
199
+ const addLivePlaceholderObservations = (observations, view, live, providedLiveObservations) => {
200
+ if (!live.requested) {
201
+ return;
202
+ }
203
+ if (!providedLiveObservations.some((observation) => observation.source === "runtime")) {
204
+ for (const runtime of view.runtimes) {
205
+ observations.push(createObservation({
206
+ key: "runtime.probe",
207
+ message: `${runtime.name} live runtime probe is not available for this status request`,
208
+ severity: "unknown",
209
+ source: "runtime",
210
+ subject: `runtime:${runtime.name}`
211
+ }));
212
+ }
213
+ }
214
+ if (!providedLiveObservations.some((observation) => observation.source === "network")) {
215
+ for (const network of view.networks) {
216
+ observations.push(createObservation({
217
+ key: "network.probe",
218
+ message: `${network.id} live network probe is not available for this status request`,
219
+ severity: "unknown",
220
+ source: "network",
221
+ subject: `network:${network.id}`
222
+ }));
223
+ }
224
+ }
225
+ };
226
+ export const createStaticStatus = (view, loadedReport, input) => {
227
+ const nodes = flattenOrganizationNodes(view);
228
+ const observations = [];
229
+ const nodeCounts = countNodesByKind(nodes);
230
+ const deployments = input.deployments ?? [];
231
+ const live = input.live ?? defaultLiveRequest();
232
+ const liveObservations = input.liveObservations ?? [];
233
+ const selection = expandStatusSelectionSubjects(input.selection, {
234
+ deployments,
235
+ loadedReport,
236
+ view
237
+ });
238
+ addDeclaredObservations(observations, view, nodes);
239
+ addCompiledObservations(observations, loadedReport, view, nodes);
240
+ observations.push(...createDeploymentObservations(deployments, {
241
+ compileFingerprint: compileInfoFor(loadedReport).compileFingerprint,
242
+ liveRequested: live.requested,
243
+ outputDirectory: input.outputDirectory,
244
+ recover: live.recover
245
+ }));
246
+ observations.push(...liveObservations);
247
+ addLivePlaceholderObservations(observations, view, live, liveObservations);
248
+ return {
249
+ compile: compileInfoFor(loadedReport),
250
+ deployments,
251
+ inputPath: input.inputPath,
252
+ live,
253
+ observations,
254
+ outputDirectory: input.outputDirectory,
255
+ projectRoot: view.projectRoot ?? null,
256
+ selection,
257
+ summary: {
258
+ ...nodeCounts,
259
+ deployments: deployments.length,
260
+ networks: view.networks.length,
261
+ runtimes: view.runtimes.length
262
+ },
263
+ view,
264
+ version: "spawnfile.status.v1"
265
+ };
266
+ };
@@ -0,0 +1,96 @@
1
+ import type { StatusInputFailure } from "./types.js";
2
+ export interface StatusReportCapability {
3
+ key: string;
4
+ message: string;
5
+ outcome: "degraded" | "supported" | "unsupported";
6
+ }
7
+ export interface StatusReportDiagnostic {
8
+ level: "error" | "info" | "warn";
9
+ message: string;
10
+ }
11
+ export interface StatusReportNode {
12
+ capabilities: StatusReportCapability[];
13
+ diagnostics: StatusReportDiagnostic[];
14
+ id: string;
15
+ kind: "agent" | "team";
16
+ outputDir: string | null;
17
+ runtime: string | null;
18
+ }
19
+ export interface StatusReportRuntimeInstance {
20
+ configPath: string | null;
21
+ homePath: string | null;
22
+ id: string;
23
+ internalPort: number | null;
24
+ nodeIds: string[];
25
+ publishedPort: number | null;
26
+ runtime: string;
27
+ workspacePath: string | null;
28
+ }
29
+ export interface StatusReportMoltnetRoom {
30
+ id: string;
31
+ members: string[];
32
+ visibility: string | null;
33
+ writePolicy: string | null;
34
+ }
35
+ export interface StatusReportMoltnetServerPlan {
36
+ authMode: string | null;
37
+ baseUrl: string;
38
+ directMessages: boolean | null;
39
+ id: string;
40
+ mode: "external" | "managed";
41
+ networkId: string;
42
+ operatorTokenSecret: string | null;
43
+ port: number | null;
44
+ publicRead: boolean | null;
45
+ rooms: StatusReportMoltnetRoom[];
46
+ storeKind: string | null;
47
+ }
48
+ export interface StatusReportContainerPortMapping {
49
+ internalPort: number;
50
+ publishedPort: number;
51
+ }
52
+ export interface StatusReportPersistentMount {
53
+ id: string;
54
+ mountPath: string;
55
+ reason: string;
56
+ volumeName: string;
57
+ }
58
+ export interface StatusReportWorkspaceResource {
59
+ backingPath: string;
60
+ id: string;
61
+ kind: string;
62
+ linkPath: string;
63
+ mode: string;
64
+ mount: string;
65
+ sharing: string;
66
+ }
67
+ export interface StatusReport {
68
+ compileFingerprint: string | null;
69
+ generatedAt: string | null;
70
+ internalPorts?: number[];
71
+ moltnetServers?: StatusReportMoltnetServerPlan[];
72
+ nodes: StatusReportNode[];
73
+ outputDirectory: string | null;
74
+ persistentMounts?: StatusReportPersistentMount[];
75
+ portMappings?: StatusReportContainerPortMapping[];
76
+ publishedPorts?: number[];
77
+ reportPath: string;
78
+ root: string | null;
79
+ runtimeInstances: StatusReportRuntimeInstance[];
80
+ secretsRequired?: string[];
81
+ workspaceResources?: StatusReportWorkspaceResource[];
82
+ }
83
+ export type LoadedCompileReport = {
84
+ kind: "failure";
85
+ failure: StatusInputFailure;
86
+ reportPath: string;
87
+ } | {
88
+ kind: "loaded";
89
+ report: StatusReport;
90
+ reportPath: string;
91
+ } | {
92
+ kind: "missing";
93
+ reportPath: string;
94
+ };
95
+ export declare const resolveCompileReportPath: (outputDirectory: string) => string;
96
+ export declare const loadCompileReport: (outputDirectory: string) => Promise<LoadedCompileReport>;
@@ -0,0 +1,230 @@
1
+ import { readFile, stat } from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { REPORT_FILENAME } from "../shared/index.js";
4
+ const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
5
+ const toStringOrNull = (value) => typeof value === "string" ? value : null;
6
+ const toStringArray = (value) => Array.isArray(value)
7
+ ? value.filter((entry) => typeof entry === "string")
8
+ : [];
9
+ const toNumberOrNull = (value) => typeof value === "number" && Number.isFinite(value) ? value : null;
10
+ const toBooleanOrNull = (value) => typeof value === "boolean" ? value : null;
11
+ const toNumberArray = (value) => Array.isArray(value)
12
+ ? value.filter((entry) => typeof entry === "number" && Number.isFinite(entry))
13
+ : [];
14
+ const normalizeCapability = (value) => {
15
+ if (!isRecord(value)) {
16
+ return null;
17
+ }
18
+ const key = toStringOrNull(value.key);
19
+ const message = toStringOrNull(value.message);
20
+ const outcome = toStringOrNull(value.outcome);
21
+ if (!key || !message || !["degraded", "supported", "unsupported"].includes(outcome ?? "")) {
22
+ return null;
23
+ }
24
+ return { key, message, outcome: outcome };
25
+ };
26
+ const normalizeDiagnostic = (value) => {
27
+ if (!isRecord(value)) {
28
+ return null;
29
+ }
30
+ const level = toStringOrNull(value.level);
31
+ const message = toStringOrNull(value.message);
32
+ if (!message || !["error", "info", "warn"].includes(level ?? "")) {
33
+ return null;
34
+ }
35
+ return { level: level, message };
36
+ };
37
+ const normalizeNode = (value) => {
38
+ if (!isRecord(value)) {
39
+ return null;
40
+ }
41
+ const id = toStringOrNull(value.id);
42
+ const kind = toStringOrNull(value.kind);
43
+ if (!id || !["agent", "team"].includes(kind ?? "")) {
44
+ return null;
45
+ }
46
+ return {
47
+ capabilities: (Array.isArray(value.capabilities) ? value.capabilities : [])
48
+ .map(normalizeCapability)
49
+ .filter((entry) => entry !== null),
50
+ diagnostics: (Array.isArray(value.diagnostics) ? value.diagnostics : [])
51
+ .map(normalizeDiagnostic)
52
+ .filter((entry) => entry !== null),
53
+ id,
54
+ kind: kind,
55
+ outputDir: toStringOrNull(value.output_dir),
56
+ runtime: toStringOrNull(value.runtime)
57
+ };
58
+ };
59
+ const normalizeRuntimeInstance = (value) => {
60
+ if (!isRecord(value)) {
61
+ return null;
62
+ }
63
+ const id = toStringOrNull(value.id);
64
+ const runtime = toStringOrNull(value.runtime);
65
+ if (!id || !runtime) {
66
+ return null;
67
+ }
68
+ return {
69
+ configPath: toStringOrNull(value.config_path),
70
+ homePath: toStringOrNull(value.home_path),
71
+ id,
72
+ internalPort: toNumberOrNull(value.internal_port),
73
+ nodeIds: toStringArray(value.node_ids),
74
+ publishedPort: toNumberOrNull(value.published_port),
75
+ runtime,
76
+ workspacePath: toStringOrNull(value.workspace_path)
77
+ };
78
+ };
79
+ const normalizeMoltnetRoom = (value) => {
80
+ if (!isRecord(value)) {
81
+ return null;
82
+ }
83
+ const id = toStringOrNull(value.id);
84
+ if (!id) {
85
+ return null;
86
+ }
87
+ return {
88
+ id,
89
+ members: toStringArray(value.members),
90
+ visibility: toStringOrNull(value.visibility),
91
+ writePolicy: toStringOrNull(value.write_policy)
92
+ };
93
+ };
94
+ const normalizeMoltnetServer = (value) => {
95
+ if (!isRecord(value)) {
96
+ return null;
97
+ }
98
+ const id = toStringOrNull(value.id);
99
+ const mode = toStringOrNull(value.mode);
100
+ const networkId = toStringOrNull(value.network_id);
101
+ const baseUrl = toStringOrNull(value.base_url);
102
+ if (!id || !baseUrl || !networkId || (mode !== "managed" && mode !== "external")) {
103
+ return null;
104
+ }
105
+ return {
106
+ authMode: toStringOrNull(value.auth_mode),
107
+ baseUrl,
108
+ directMessages: toBooleanOrNull(value.direct_messages),
109
+ id,
110
+ mode,
111
+ networkId,
112
+ operatorTokenSecret: toStringOrNull(value.operator_token_secret),
113
+ port: toNumberOrNull(value.port),
114
+ publicRead: toBooleanOrNull(value.public_read),
115
+ rooms: (Array.isArray(value.rooms) ? value.rooms : [])
116
+ .map(normalizeMoltnetRoom)
117
+ .filter((entry) => entry !== null),
118
+ storeKind: toStringOrNull(value.store_kind)
119
+ };
120
+ };
121
+ const normalizePortMapping = (value) => {
122
+ if (!isRecord(value)) {
123
+ return null;
124
+ }
125
+ const internalPort = toNumberOrNull(value.internal_port);
126
+ const publishedPort = toNumberOrNull(value.published_port);
127
+ return internalPort && publishedPort ? { internalPort, publishedPort } : null;
128
+ };
129
+ const normalizePersistentMount = (value) => {
130
+ if (!isRecord(value)) {
131
+ return null;
132
+ }
133
+ const id = toStringOrNull(value.id);
134
+ const mountPath = toStringOrNull(value.mount_path);
135
+ const reason = toStringOrNull(value.reason);
136
+ const volumeName = toStringOrNull(value.volume_name);
137
+ return id && mountPath && reason && volumeName
138
+ ? { id, mountPath, reason, volumeName }
139
+ : null;
140
+ };
141
+ const normalizeWorkspaceResource = (value) => {
142
+ if (!isRecord(value)) {
143
+ return null;
144
+ }
145
+ const backingPath = toStringOrNull(value.backing_path);
146
+ const id = toStringOrNull(value.id);
147
+ const kind = toStringOrNull(value.kind);
148
+ const linkPath = toStringOrNull(value.link_path);
149
+ const mode = toStringOrNull(value.mode);
150
+ const mount = toStringOrNull(value.mount);
151
+ const sharing = toStringOrNull(value.sharing);
152
+ return backingPath && id && kind && linkPath && mode && mount && sharing
153
+ ? { backingPath, id, kind, linkPath, mode, mount, sharing }
154
+ : null;
155
+ };
156
+ const normalizeReport = (value, reportPath) => {
157
+ if (!isRecord(value) || !Array.isArray(value.nodes)) {
158
+ return null;
159
+ }
160
+ const container = isRecord(value.container) ? value.container : {};
161
+ const runtimeInstances = Array.isArray(container.runtime_instances)
162
+ ? container.runtime_instances
163
+ : [];
164
+ const moltnet = isRecord(container.moltnet) ? container.moltnet : {};
165
+ const moltnetServers = Array.isArray(moltnet.server_plans) ? moltnet.server_plans : [];
166
+ return {
167
+ compileFingerprint: toStringOrNull(value.compile_fingerprint),
168
+ generatedAt: toStringOrNull(value.generated_at),
169
+ internalPorts: toNumberArray(container.internal_ports),
170
+ moltnetServers: moltnetServers
171
+ .map(normalizeMoltnetServer)
172
+ .filter((entry) => entry !== null),
173
+ nodes: value.nodes
174
+ .map(normalizeNode)
175
+ .filter((entry) => entry !== null),
176
+ outputDirectory: toStringOrNull(value.output_directory),
177
+ persistentMounts: (Array.isArray(container.persistent_mounts) ? container.persistent_mounts : [])
178
+ .map(normalizePersistentMount)
179
+ .filter((entry) => entry !== null),
180
+ portMappings: (Array.isArray(container.port_mappings) ? container.port_mappings : [])
181
+ .map(normalizePortMapping)
182
+ .filter((entry) => entry !== null),
183
+ publishedPorts: toNumberArray(container.published_ports ?? container.ports),
184
+ reportPath,
185
+ root: toStringOrNull(value.root),
186
+ runtimeInstances: runtimeInstances
187
+ .map(normalizeRuntimeInstance)
188
+ .filter((entry) => entry !== null),
189
+ secretsRequired: toStringArray(container.secrets_required),
190
+ workspaceResources: (Array.isArray(container.workspace_resources) ? container.workspace_resources : [])
191
+ .map(normalizeWorkspaceResource)
192
+ .filter((entry) => entry !== null)
193
+ };
194
+ };
195
+ export const resolveCompileReportPath = (outputDirectory) => path.join(outputDirectory, REPORT_FILENAME);
196
+ export const loadCompileReport = async (outputDirectory) => {
197
+ const reportPath = resolveCompileReportPath(outputDirectory);
198
+ try {
199
+ await stat(reportPath);
200
+ }
201
+ catch (error) {
202
+ if (error.code === "ENOENT") {
203
+ return { kind: "missing", reportPath };
204
+ }
205
+ return {
206
+ failure: { exitCode: 2, message: `Unable to stat compile report ${reportPath}` },
207
+ kind: "failure",
208
+ reportPath
209
+ };
210
+ }
211
+ let parsed;
212
+ try {
213
+ parsed = JSON.parse(await readFile(reportPath, "utf8"));
214
+ }
215
+ catch {
216
+ return {
217
+ failure: { exitCode: 2, message: `Unable to read compile report ${reportPath}` },
218
+ kind: "failure",
219
+ reportPath
220
+ };
221
+ }
222
+ const report = normalizeReport(parsed, reportPath);
223
+ return report
224
+ ? { kind: "loaded", report, reportPath }
225
+ : {
226
+ failure: { exitCode: 2, message: `Malformed compile report ${reportPath}` },
227
+ kind: "failure",
228
+ reportPath
229
+ };
230
+ };
@@ -0,0 +1,5 @@
1
+ import type { LoadedCompileReport } from "./compileReport.js";
2
+ import type { StatusObservation } from "./types.js";
3
+ export declare const createCompiledContainerObservations: (loaded: Extract<LoadedCompileReport, {
4
+ kind: "loaded";
5
+ }>) => StatusObservation[];
@@ -0,0 +1,63 @@
1
+ const createObservation = (input) => ({
2
+ ...input,
3
+ label: `${input.severity.toUpperCase()} ${input.key}`
4
+ });
5
+ export const createCompiledContainerObservations = (loaded) => {
6
+ const observations = [];
7
+ const report = loaded.report;
8
+ for (const instance of report.runtimeInstances) {
9
+ observations.push(createObservation({
10
+ key: "runtime.instance",
11
+ message: `${instance.id} emits ${instance.runtime} workspace ${instance.workspacePath ?? "unknown"}`,
12
+ severity: "ok",
13
+ source: "compile_report",
14
+ subject: `runtime-instance:${instance.id}`
15
+ }));
16
+ }
17
+ for (const server of report.moltnetServers ?? []) {
18
+ observations.push(createObservation({
19
+ key: "network.compiled",
20
+ message: `${server.networkId} Moltnet ${server.mode} server at ${server.baseUrl}`,
21
+ severity: "ok",
22
+ source: "compile_report",
23
+ subject: `network:${server.networkId}`
24
+ }));
25
+ for (const room of server.rooms) {
26
+ observations.push(createObservation({
27
+ key: "network.room.compiled",
28
+ message: `${server.networkId}/${room.id} expects ${room.members.length} member(s)`,
29
+ severity: "ok",
30
+ source: "compile_report",
31
+ subject: `room:${server.networkId}:${room.id}`
32
+ }));
33
+ }
34
+ }
35
+ for (const mount of report.persistentMounts ?? []) {
36
+ observations.push(createObservation({
37
+ key: "container.mount",
38
+ message: `${mount.id} mounted at ${mount.mountPath} using volume ${mount.volumeName}`,
39
+ severity: "ok",
40
+ source: "compile_report",
41
+ subject: "compile"
42
+ }));
43
+ }
44
+ for (const resource of report.workspaceResources ?? []) {
45
+ observations.push(createObservation({
46
+ key: "workspace.resource",
47
+ message: `${resource.id} linked at ${resource.linkPath} from ${resource.backingPath}`,
48
+ severity: "ok",
49
+ source: "compile_report",
50
+ subject: "compile"
51
+ }));
52
+ }
53
+ if ((report.internalPorts?.length ?? 0) > 0 || (report.publishedPorts?.length ?? 0) > 0) {
54
+ observations.push(createObservation({
55
+ key: "container.ports",
56
+ message: `internal ports: ${(report.internalPorts ?? []).join(", ") || "none"}; published ports: ${(report.publishedPorts ?? []).join(", ") || "none"}`,
57
+ severity: "ok",
58
+ source: "compile_report",
59
+ subject: "compile"
60
+ }));
61
+ }
62
+ return observations;
63
+ };
@@ -0,0 +1,12 @@
1
+ import { type DeploymentRecord, type DockerLogsExecFile } from "../deployment/index.js";
2
+ import type { LoadedCompileReport } from "./compileReport.js";
3
+ import type { StatusObservation } from "./types.js";
4
+ export interface CollectDeploymentLogOptions {
5
+ deployments: DeploymentRecord[];
6
+ dockerCommand?: string;
7
+ execFile?: DockerLogsExecFile;
8
+ loadedReport: LoadedCompileReport;
9
+ tail?: number;
10
+ timeoutMs?: number;
11
+ }
12
+ export declare const collectDeploymentLogObservations: (options: CollectDeploymentLogOptions) => Promise<StatusObservation[]>;