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
@@ -0,0 +1,45 @@
1
+ import { readDockerDeploymentLogs } from "../deployment/index.js";
2
+ const createObservation = (input) => ({
3
+ ...input,
4
+ label: `${input.severity.toUpperCase()} ${input.key}`,
5
+ source: "deployment"
6
+ });
7
+ const secretValuesFor = (loadedReport) => {
8
+ if (loadedReport.kind !== "loaded") {
9
+ return [];
10
+ }
11
+ return (loadedReport.report.secretsRequired ?? [])
12
+ .map((secretName) => process.env[secretName])
13
+ .filter((value) => typeof value === "string" && value.length > 0);
14
+ };
15
+ const normalizeFailureSeverity = (severity) => severity === "error" ? "unknown" : severity;
16
+ export const collectDeploymentLogObservations = async (options) => {
17
+ const secretValues = secretValuesFor(options.loadedReport);
18
+ const observations = [];
19
+ for (const deployment of options.deployments) {
20
+ const logs = await readDockerDeploymentLogs(deployment, {
21
+ dockerCommand: options.dockerCommand,
22
+ execFile: options.execFile,
23
+ secretValues,
24
+ tail: options.tail,
25
+ timeoutMs: options.timeoutMs
26
+ });
27
+ for (const unit of deployment.units) {
28
+ const unitLogs = logs.get(unit.id);
29
+ if (!unitLogs) {
30
+ continue;
31
+ }
32
+ observations.push(createObservation({
33
+ details: {
34
+ container_ref: unitLogs.containerRef,
35
+ log_tail: unitLogs.text
36
+ },
37
+ key: "deployment.logs",
38
+ message: `${deployment.name}/${unit.id}: ${unitLogs.message}`,
39
+ severity: normalizeFailureSeverity(unitLogs.severity),
40
+ subject: `deployment-unit:${deployment.name}:${unit.id}`
41
+ }));
42
+ }
43
+ }
44
+ return observations;
45
+ };
@@ -0,0 +1,14 @@
1
+ import type { DeploymentRecord, DockerInspectionResult } from "../deployment/index.js";
2
+ import type { StatusDeploymentSummary, StatusObservation } from "./types.js";
3
+ export interface LoadedDeploymentRecord {
4
+ path: string;
5
+ record: DeploymentRecord;
6
+ }
7
+ export type StatusDeploymentInspections = Map<string, DockerInspectionResult>;
8
+ export declare const createDeploymentSummaries: (records: LoadedDeploymentRecord[], inspections?: StatusDeploymentInspections) => StatusDeploymentSummary[];
9
+ export declare const createDeploymentObservations: (deployments: StatusDeploymentSummary[], options: {
10
+ compileFingerprint: string | null;
11
+ liveRequested: boolean;
12
+ outputDirectory: string;
13
+ recover: boolean;
14
+ }) => StatusObservation[];
@@ -0,0 +1,121 @@
1
+ const createObservation = (input) => ({
2
+ ...input,
3
+ label: `${input.severity.toUpperCase()} ${input.key}`
4
+ });
5
+ const targetLabelFor = (record) => record.target.kind === "context"
6
+ ? `docker context ${record.target.name}`
7
+ : record.target.kind === "docker-context"
8
+ ? `docker context ${record.target.context}`
9
+ : "docker host";
10
+ const liveForInspection = (inspection) => {
11
+ if (!inspection) {
12
+ return null;
13
+ }
14
+ return {
15
+ checked: true,
16
+ containerId: inspection.containerId,
17
+ drift: [...inspection.drift],
18
+ exists: inspection.exists,
19
+ exitCode: inspection.exitCode,
20
+ finishedAt: inspection.finishedAt,
21
+ imageId: inspection.imageId,
22
+ message: inspection.message,
23
+ restartCount: inspection.restartCount,
24
+ running: inspection.running,
25
+ severity: inspection.severity,
26
+ startedAt: inspection.startedAt,
27
+ status: inspection.status
28
+ };
29
+ };
30
+ const unitSeverity = (live) => {
31
+ if (!live) {
32
+ return "ok";
33
+ }
34
+ if (live.severity !== "ok") {
35
+ return live.severity;
36
+ }
37
+ if (live.running === true) {
38
+ return "ok";
39
+ }
40
+ if (live.exists === false) {
41
+ return "warn";
42
+ }
43
+ if (live.running === false) {
44
+ return "error";
45
+ }
46
+ return "unknown";
47
+ };
48
+ const summarizeUnit = (unit, live) => ({
49
+ containerId: unit.container_id,
50
+ containerName: unit.container_name,
51
+ contains: unit.contains.map((entry) => ({ id: entry.id, kind: entry.kind })),
52
+ id: unit.id,
53
+ imageId: unit.image_id,
54
+ imageTag: unit.image_tag,
55
+ kind: unit.kind,
56
+ live,
57
+ runtimeInstances: [...unit.runtime_instances]
58
+ });
59
+ export const createDeploymentSummaries = (records, inspections = new Map()) => records.map(({ path, record }) => ({
60
+ authProfile: record.auth_profile,
61
+ compileFingerprint: record.compile_fingerprint,
62
+ createdAt: record.created_at,
63
+ manager: record.manager,
64
+ name: record.name,
65
+ recordPath: path,
66
+ target: targetLabelFor(record),
67
+ units: record.units.map((unit) => summarizeUnit(unit, liveForInspection(inspections.get(record.name)?.get(unit.id))))
68
+ }));
69
+ export const createDeploymentObservations = (deployments, options) => {
70
+ const observations = [];
71
+ if (deployments.length === 0 && options.liveRequested) {
72
+ observations.push(createObservation({
73
+ key: options.recover ? "deployment.recover" : "deployment.record",
74
+ message: options.recover
75
+ ? `No recoverable deployment labels found for ${options.outputDirectory}`
76
+ : `No deployment records found under ${options.outputDirectory}`,
77
+ severity: "warn",
78
+ source: "deployment",
79
+ subject: "deployment"
80
+ }));
81
+ }
82
+ for (const deployment of deployments) {
83
+ observations.push(createObservation({
84
+ key: "deployment.record",
85
+ message: `${deployment.name} record exists at ${deployment.recordPath}`,
86
+ severity: "ok",
87
+ source: "deployment",
88
+ subject: `deployment:${deployment.name}`
89
+ }));
90
+ if (options.compileFingerprint && deployment.compileFingerprint !== options.compileFingerprint) {
91
+ observations.push(createObservation({
92
+ key: "deployment.compile_fingerprint",
93
+ message: `${deployment.name} was deployed from ${deployment.compileFingerprint}, current compile is ${options.compileFingerprint}`,
94
+ severity: "warn",
95
+ source: "deployment",
96
+ subject: `deployment:${deployment.name}`
97
+ }));
98
+ }
99
+ for (const unit of deployment.units) {
100
+ const severity = unitSeverity(unit.live);
101
+ const unitSubject = `deployment-unit:${deployment.name}:${unit.id}`;
102
+ observations.push(createObservation({
103
+ key: "deployment.unit",
104
+ message: unit.live?.message ?? `${unit.id} recorded for ${deployment.target}`,
105
+ severity,
106
+ source: "deployment",
107
+ subject: unitSubject
108
+ }));
109
+ for (const entry of unit.contains) {
110
+ observations.push(createObservation({
111
+ key: "deployment.hosting",
112
+ message: `${entry.id} is hosted by ${deployment.name}/${unit.id}`,
113
+ severity,
114
+ source: "deployment",
115
+ subject: entry.id
116
+ }));
117
+ }
118
+ }
119
+ }
120
+ return observations;
121
+ };
@@ -0,0 +1,10 @@
1
+ import type { DistributionReport } from "../distribution/index.js";
2
+ import type { LoadedCompileReport, StatusReport } from "./compileReport.js";
3
+ /**
4
+ * Maps a cached distribution report (from a sourceless image deployment) into
5
+ * the StatusReport shape so live status can render the compiled, deployment,
6
+ * and runtime layers without project source. Moltnet server plans are not part
7
+ * of the distribution report, so the network layer falls back to `unknown`.
8
+ */
9
+ export declare const distributionReportToStatusReport: (report: DistributionReport, reportPath: string) => StatusReport;
10
+ export declare const loadedImageCompileReport: (report: DistributionReport, reportPath: string) => LoadedCompileReport;
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Maps a cached distribution report (from a sourceless image deployment) into
3
+ * the StatusReport shape so live status can render the compiled, deployment,
4
+ * and runtime layers without project source. Moltnet server plans are not part
5
+ * of the distribution report, so the network layer falls back to `unknown`.
6
+ */
7
+ export const distributionReportToStatusReport = (report, reportPath) => ({
8
+ compileFingerprint: report.compile_fingerprint,
9
+ generatedAt: report.generated_at,
10
+ internalPorts: report.internal_ports,
11
+ moltnetServers: [],
12
+ nodes: [
13
+ ...report.organization.agents.map((agent) => ({
14
+ capabilities: [],
15
+ diagnostics: [],
16
+ id: agent.id,
17
+ kind: "agent",
18
+ outputDir: null,
19
+ runtime: agent.runtime
20
+ })),
21
+ ...report.organization.teams.map((team) => ({
22
+ capabilities: [],
23
+ diagnostics: [],
24
+ id: team.id,
25
+ kind: "team",
26
+ outputDir: null,
27
+ runtime: null
28
+ }))
29
+ ],
30
+ outputDirectory: null,
31
+ persistentMounts: report.persistent_mounts.map((mount) => ({
32
+ id: mount.id,
33
+ mountPath: mount.target,
34
+ reason: "image persistent mount",
35
+ volumeName: ""
36
+ })),
37
+ portMappings: report.port_mappings.map((mapping) => ({
38
+ internalPort: mapping.internal_port,
39
+ publishedPort: mapping.published_port
40
+ })),
41
+ publishedPorts: report.ports,
42
+ reportPath,
43
+ root: null,
44
+ runtimeInstances: report.runtime_instances.map((instance) => ({
45
+ configPath: instance.config_path,
46
+ homePath: instance.home_path,
47
+ id: instance.id,
48
+ internalPort: instance.internal_port,
49
+ nodeIds: instance.node_ids,
50
+ publishedPort: instance.published_port,
51
+ runtime: instance.runtime,
52
+ workspacePath: instance.workspace_path
53
+ })),
54
+ secretsRequired: [
55
+ ...new Set(["model", "project", "runtime", "surface"].flatMap((category) => report.secrets[category]
56
+ .filter((entry) => entry.required && !entry.generated)
57
+ .map((entry) => entry.name)))
58
+ ].sort(),
59
+ workspaceResources: report.resources.map((resource) => ({
60
+ backingPath: "",
61
+ id: resource.id,
62
+ kind: resource.kind,
63
+ linkPath: resource.link_path,
64
+ mode: resource.mode,
65
+ mount: resource.mount,
66
+ sharing: resource.sharing
67
+ }))
68
+ });
69
+ export const loadedImageCompileReport = (report, reportPath) => ({
70
+ kind: "loaded",
71
+ report: distributionReportToStatusReport(report, reportPath),
72
+ reportPath
73
+ });
@@ -0,0 +1,14 @@
1
+ export * from "./buildStatus.js";
2
+ export * from "./compiledContainerObservations.js";
3
+ export * from "./compileReport.js";
4
+ export * from "./deploymentLogs.js";
5
+ export * from "./deployments.js";
6
+ export * from "./moltnetProbes.js";
7
+ export * from "./renderStatus.js";
8
+ export * from "./runtimeProbes.js";
9
+ export * from "./selectionSubjects.js";
10
+ export * from "./selectors.js";
11
+ export * from "./traversal.js";
12
+ export * from "./types.js";
13
+ export * from "./imageStatusReport.js";
14
+ export * from "./registryDrift.js";
@@ -0,0 +1,14 @@
1
+ export * from "./buildStatus.js";
2
+ export * from "./compiledContainerObservations.js";
3
+ export * from "./compileReport.js";
4
+ export * from "./deploymentLogs.js";
5
+ export * from "./deployments.js";
6
+ export * from "./moltnetProbes.js";
7
+ export * from "./renderStatus.js";
8
+ export * from "./runtimeProbes.js";
9
+ export * from "./selectionSubjects.js";
10
+ export * from "./selectors.js";
11
+ export * from "./traversal.js";
12
+ export * from "./types.js";
13
+ export * from "./imageStatusReport.js";
14
+ export * from "./registryDrift.js";
@@ -0,0 +1,21 @@
1
+ import type { DeploymentRecord, DockerInspectionResult, DockerProbeExecFile } from "../deployment/index.js";
2
+ import type { LoadedCompileReport } from "./compileReport.js";
3
+ import type { StatusObservation } from "./types.js";
4
+ export type StatusNetworkInspections = Map<string, DockerInspectionResult>;
5
+ export interface CollectMoltnetProbeOptions {
6
+ authValues?: Record<string, string>;
7
+ deployments: DeploymentRecord[];
8
+ execFile?: DockerProbeExecFile;
9
+ fetchJson?: MoltnetFetchJson;
10
+ inspections: StatusNetworkInspections;
11
+ loadedReport: LoadedCompileReport;
12
+ timeoutMs?: number;
13
+ }
14
+ export type MoltnetFetchJson = (url: string, headers: Record<string, string>, timeoutMs: number) => Promise<MoltnetProbeResponse>;
15
+ interface MoltnetProbeResponse {
16
+ error?: string;
17
+ json: unknown;
18
+ ok: boolean;
19
+ }
20
+ export declare const collectMoltnetProbeObservations: (options: CollectMoltnetProbeOptions) => Promise<StatusObservation[]>;
21
+ export {};
@@ -0,0 +1,240 @@
1
+ import { createDockerProbeGateway } from "../deployment/index.js";
2
+ const createObservation = (input) => ({
3
+ ...input,
4
+ label: `${input.severity.toUpperCase()} ${input.key}`,
5
+ source: "network"
6
+ });
7
+ const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
8
+ const toString = (value) => typeof value === "string" ? value : null;
9
+ const toStringArray = (value) => Array.isArray(value)
10
+ ? value.filter((entry) => typeof entry === "string")
11
+ : [];
12
+ const parseRooms = (value) => {
13
+ const entries = isRecord(value) && Array.isArray(value.rooms) ? value.rooms : [];
14
+ return entries.flatMap((entry) => {
15
+ if (!isRecord(entry))
16
+ return [];
17
+ const id = toString(entry.id);
18
+ return id ? [{ id, members: toStringArray(entry.members) }] : [];
19
+ });
20
+ };
21
+ const parseAgents = (value) => {
22
+ const entries = isRecord(value) && Array.isArray(value.agents) ? value.agents : [];
23
+ return entries.flatMap((entry) => {
24
+ if (!isRecord(entry))
25
+ return [];
26
+ const id = toString(entry.id);
27
+ return id
28
+ ? [{ connected: entry.connected === true, id, rooms: toStringArray(entry.rooms) }]
29
+ : [];
30
+ });
31
+ };
32
+ const parseNetwork = (value) => ({
33
+ directMessages: isRecord(value) && isRecord(value.capabilities) && typeof value.capabilities.direct_messages === "boolean"
34
+ ? value.capabilities.direct_messages
35
+ : null,
36
+ networkId: isRecord(value) ? toString(value.id) : null
37
+ });
38
+ const defaultFetchJson = async (url, headers, timeoutMs) => {
39
+ const controller = new AbortController();
40
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
41
+ try {
42
+ const response = await fetch(url, { headers, signal: controller.signal });
43
+ if (!response.ok) {
44
+ return { error: `HTTP ${response.status}`, json: null, ok: false };
45
+ }
46
+ return { json: await response.json(), ok: true };
47
+ }
48
+ catch (error) {
49
+ return { error: error instanceof Error ? error.message : String(error), json: null, ok: false };
50
+ }
51
+ finally {
52
+ clearTimeout(timer);
53
+ }
54
+ };
55
+ const authHeadersFor = (server, authValues = {}) => {
56
+ if (!server.operatorTokenSecret) {
57
+ return {};
58
+ }
59
+ const token = authValues[server.operatorTokenSecret] ?? process.env[server.operatorTokenSecret];
60
+ return token ? { Authorization: `Bearer ${token}` } : null;
61
+ };
62
+ const readManagedJson = async (gateway, server, path, headers) => {
63
+ if (!server.port) {
64
+ return { error: "managed Moltnet server has no internal port", json: null, ok: false };
65
+ }
66
+ const response = await gateway.httpGet(server.port, path, headers);
67
+ if (!response.ok) {
68
+ return { error: response.error, json: null, ok: false };
69
+ }
70
+ try {
71
+ return { json: JSON.parse(response.body), ok: true };
72
+ }
73
+ catch (error) {
74
+ return { error: error instanceof Error ? error.message : String(error), json: null, ok: false };
75
+ }
76
+ };
77
+ const readExternalJson = async (fetchJson, server, path, headers, timeoutMs) => fetchJson(`${server.baseUrl.replace(/\/$/u, "")}${path}`, headers, timeoutMs);
78
+ const createManagedGateway = (deployments, inspections, options) => {
79
+ for (const deployment of deployments) {
80
+ const inspectionMap = inspections.get(deployment.name);
81
+ const unit = deployment.units[0];
82
+ if (!unit)
83
+ continue;
84
+ const inspection = inspectionMap?.get(unit.id);
85
+ if (inspection?.running === true) {
86
+ return createDockerProbeGateway(deployment, unit, {
87
+ execFile: options.execFile,
88
+ inspection,
89
+ timeoutMs: options.timeoutMs
90
+ });
91
+ }
92
+ }
93
+ return null;
94
+ };
95
+ const readSnapshot = async (server, options, headers) => {
96
+ const timeoutMs = options.timeoutMs ?? 10_000;
97
+ const gateway = server.mode === "managed"
98
+ ? createManagedGateway(options.deployments, options.inspections, options)
99
+ : null;
100
+ if (server.mode === "managed" && !gateway) {
101
+ return { error: "no running deployment unit hosts the managed Moltnet server", json: null, ok: false };
102
+ }
103
+ const readJson = (path) => gateway
104
+ ? readManagedJson(gateway, server, path, headers)
105
+ : readExternalJson(options.fetchJson ?? defaultFetchJson, server, path, headers, timeoutMs);
106
+ const health = await readJson("/healthz");
107
+ if (!health.ok)
108
+ return health;
109
+ const network = await readJson("/v1/network");
110
+ if (!network.ok)
111
+ return network;
112
+ const rooms = await readJson("/v1/rooms");
113
+ if (!rooms.ok)
114
+ return rooms;
115
+ const agents = await readJson("/v1/agents");
116
+ if (!agents.ok)
117
+ return agents;
118
+ const parsedNetwork = parseNetwork(network.json);
119
+ return {
120
+ json: null,
121
+ ok: true,
122
+ snapshot: {
123
+ agents: parseAgents(agents.json),
124
+ directMessages: parsedNetwork.directMessages,
125
+ networkId: parsedNetwork.networkId,
126
+ rooms: parseRooms(rooms.json)
127
+ }
128
+ };
129
+ };
130
+ const compareSnapshot = (server, snapshot) => {
131
+ const observations = [];
132
+ observations.push(createObservation({
133
+ key: "network.reachable",
134
+ message: `${server.networkId} Moltnet server is reachable`,
135
+ severity: "ok",
136
+ subject: `network:${server.networkId}`
137
+ }));
138
+ if (snapshot.networkId && snapshot.networkId !== server.networkId) {
139
+ observations.push(createObservation({
140
+ key: "network.id",
141
+ message: `expected network ${server.networkId}, live network is ${snapshot.networkId}`,
142
+ severity: "error",
143
+ subject: `network:${server.networkId}`
144
+ }));
145
+ }
146
+ const liveRooms = new Map(snapshot.rooms.map((room) => [room.id, room]));
147
+ const liveAgents = new Map(snapshot.agents.map((agent) => [agent.id, agent]));
148
+ for (const room of server.rooms) {
149
+ const liveRoom = liveRooms.get(room.id);
150
+ if (!liveRoom) {
151
+ observations.push(createObservation({
152
+ key: "network.room",
153
+ message: `${server.networkId}/${room.id} is missing from live Moltnet`,
154
+ severity: "error",
155
+ subject: `room:${server.networkId}:${room.id}`
156
+ }));
157
+ continue;
158
+ }
159
+ observations.push(createObservation({
160
+ key: "network.room",
161
+ message: `${server.networkId}/${room.id} exists with ${liveRoom.members.length} member(s)`,
162
+ severity: "ok",
163
+ subject: `room:${server.networkId}:${room.id}`
164
+ }));
165
+ for (const member of room.members) {
166
+ const liveAgent = liveAgents.get(member);
167
+ if (!liveAgent) {
168
+ observations.push(createObservation({
169
+ key: "network.member",
170
+ message: `${member} is expected in ${room.id} but is not registered`,
171
+ severity: "warn",
172
+ subject: `agent:${member}`
173
+ }));
174
+ }
175
+ else if (!liveAgent.rooms.includes(room.id)) {
176
+ observations.push(createObservation({
177
+ key: "network.member",
178
+ message: `${member} is registered but not attached to ${room.id}`,
179
+ severity: "warn",
180
+ subject: `agent:${member}`
181
+ }));
182
+ }
183
+ else if (!liveAgent.connected) {
184
+ observations.push(createObservation({
185
+ key: "network.agent.connected",
186
+ message: `${member} is attached to ${room.id} but disconnected`,
187
+ severity: "warn",
188
+ subject: `agent:${member}`
189
+ }));
190
+ }
191
+ else {
192
+ observations.push(createObservation({
193
+ key: "network.agent.connected",
194
+ message: `${member} is connected to ${room.id}`,
195
+ severity: "ok",
196
+ subject: `agent:${member}`
197
+ }));
198
+ }
199
+ }
200
+ }
201
+ if (snapshot.directMessages !== null && server.directMessages !== null && snapshot.directMessages !== server.directMessages) {
202
+ observations.push(createObservation({
203
+ key: "network.direct_messages",
204
+ message: `direct messages expected ${server.directMessages}, live value is ${snapshot.directMessages}`,
205
+ severity: "warn",
206
+ subject: `network:${server.networkId}`
207
+ }));
208
+ }
209
+ return observations;
210
+ };
211
+ export const collectMoltnetProbeObservations = async (options) => {
212
+ if (options.loadedReport.kind !== "loaded") {
213
+ return [];
214
+ }
215
+ const observations = [];
216
+ for (const server of options.loadedReport.report.moltnetServers ?? []) {
217
+ const headers = authHeadersFor(server, options.authValues);
218
+ if (headers === null) {
219
+ observations.push(createObservation({
220
+ key: "network.auth",
221
+ message: `${server.networkId} requires operator token ${server.operatorTokenSecret}, but no value is available`,
222
+ severity: "unknown",
223
+ subject: `network:${server.networkId}`
224
+ }));
225
+ continue;
226
+ }
227
+ const response = await readSnapshot(server, options, headers);
228
+ if (!response.ok || !response.snapshot) {
229
+ observations.push(createObservation({
230
+ key: "network.reachable",
231
+ message: `${server.networkId} Moltnet metadata probe failed: ${response.error ?? "unknown failure"}`,
232
+ severity: "unknown",
233
+ subject: `network:${server.networkId}`
234
+ }));
235
+ continue;
236
+ }
237
+ observations.push(...compareSnapshot(server, response.snapshot));
238
+ }
239
+ return observations;
240
+ };
@@ -0,0 +1,28 @@
1
+ import { type DeploymentRecord } from "../deployment/index.js";
2
+ import type { StatusObservation } from "./types.js";
3
+ export type RegistryDigestResolver = (imageRef: string, baseArgs: string[]) => Promise<string | null>;
4
+ export interface RegistryDriftInput {
5
+ deployments: DeploymentRecord[];
6
+ dockerCommand?: string;
7
+ resolveDigest?: RegistryDigestResolver;
8
+ timeoutMs?: number;
9
+ }
10
+ /**
11
+ * Extracts the comparable digest from `docker manifest inspect --verbose` output.
12
+ *
13
+ * A single-arch tag resolves to one manifest object whose `Descriptor.digest`
14
+ * equals the digest RepoDigests records at deploy time. A multi-arch tag resolves
15
+ * to a JSON ARRAY of per-platform manifests; each `Descriptor.digest` is a CHILD
16
+ * digest, never the manifest-list (index) digest that was recorded — comparing one
17
+ * would report drift on every check. We cannot derive the index digest from this
18
+ * command, so multi-arch (and any unparseable output) yields null → "unknown"
19
+ * rather than a false positive.
20
+ */
21
+ export declare const parseManifestInspectDigest: (output: string) => string | null;
22
+ /**
23
+ * Compares each image deployment's recorded source.digest against the digest
24
+ * the registry tag currently resolves to. Networked: runs only behind the
25
+ * explicit --pull-check flag. A digest-pinned ref needs no lookup; a null
26
+ * recorded digest renders unknown.
27
+ */
28
+ export declare const collectRegistryDriftObservations: (input: RegistryDriftInput) => Promise<StatusObservation[]>;