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.
- package/README.md +13 -2
- package/dist/cli/lifecycleCommands.js +101 -1
- package/dist/cli/modelCommands.js +3 -0
- package/dist/cli/resolveCommandInput.d.ts +19 -0
- package/dist/cli/resolveCommandInput.js +25 -0
- package/dist/cli/runCli.d.ts +4 -1
- package/dist/cli/runCli.js +37 -13
- package/dist/cli/runtimeCommands.js +1 -0
- package/dist/cli/statusCommand.d.ts +42 -0
- package/dist/cli/statusCommand.js +394 -0
- package/dist/cli/surfaceCommands.js +4 -0
- package/dist/compiler/agentSurfaces.js +2 -4
- package/dist/compiler/compileProject.js +19 -10
- package/dist/compiler/containerArtifacts.d.ts +1 -0
- package/dist/compiler/containerArtifacts.js +208 -32
- package/dist/compiler/containerArtifactsPlans.js +7 -4
- package/dist/compiler/containerArtifactsRender.d.ts +7 -1
- package/dist/compiler/containerArtifactsRender.js +6 -0
- package/dist/compiler/containerArtifactsTypes.d.ts +9 -0
- package/dist/compiler/containerEntrypointRender.js +18 -31
- package/dist/compiler/index.d.ts +1 -0
- package/dist/compiler/index.js +1 -0
- package/dist/compiler/moltnetArtifacts.js +5 -0
- package/dist/compiler/moltnetClientConfig.d.ts +1 -1
- package/dist/compiler/moltnetClientConfig.js +3 -16
- package/dist/compiler/moltnetNodeConfig.js +2 -4
- package/dist/compiler/moltnetResolution.js +1 -1
- package/dist/compiler/moltnetRoomMemberships.js +1 -2
- package/dist/compiler/moltnetRuntimeConfig.d.ts +1 -1
- package/dist/compiler/moltnetRuntimeConfig.js +1 -13
- package/dist/compiler/networkBinding.d.ts +14 -0
- package/dist/compiler/networkBinding.js +34 -0
- package/dist/compiler/publishProject.d.ts +13 -0
- package/dist/compiler/publishProject.js +72 -0
- package/dist/compiler/runProject.d.ts +26 -12
- package/dist/compiler/runProject.js +102 -125
- package/dist/compiler/runProjectAuth.d.ts +5 -0
- package/dist/compiler/runProjectAuth.js +98 -0
- package/dist/compiler/runProjectDocker.d.ts +19 -0
- package/dist/compiler/runProjectDocker.js +57 -0
- package/dist/compiler/types.d.ts +1 -2
- package/dist/compiler/upProject.d.ts +6 -0
- package/dist/compiler/upProject.js +42 -8
- package/dist/compiler/view/buildOrganizationView.js +4 -1
- package/dist/compiler/view/declarations.d.ts +4 -0
- package/dist/compiler/view/declarations.js +104 -0
- package/dist/compiler/view/renderNetworks.js +1 -2
- package/dist/compiler/view/renderTree.js +6 -2
- package/dist/compiler/view/types.d.ts +64 -1
- package/dist/deployment/dockerInspect.d.ts +29 -0
- package/dist/deployment/dockerInspect.js +130 -0
- package/dist/deployment/dockerLabels.d.ts +16 -0
- package/dist/deployment/dockerLabels.js +32 -0
- package/dist/deployment/dockerLogs.d.ts +24 -0
- package/dist/deployment/dockerLogs.js +96 -0
- package/dist/deployment/dockerManager.d.ts +59 -0
- package/dist/deployment/dockerManager.js +76 -0
- package/dist/deployment/dockerProbeGateway.d.ts +16 -0
- package/dist/deployment/dockerProbeGateway.js +48 -0
- package/dist/deployment/homeStore.d.ts +19 -0
- package/dist/deployment/homeStore.js +130 -0
- package/dist/deployment/index.d.ts +9 -0
- package/dist/deployment/index.js +9 -0
- package/dist/deployment/names.d.ts +3 -0
- package/dist/deployment/names.js +12 -0
- package/dist/deployment/record.d.ts +76 -0
- package/dist/deployment/record.js +174 -0
- package/dist/deployment/target.d.ts +35 -0
- package/dist/deployment/target.js +96 -0
- package/dist/distribution/buildDistributionReport.d.ts +22 -0
- package/dist/distribution/buildDistributionReport.js +51 -0
- package/dist/distribution/consumeImage.d.ts +29 -0
- package/dist/distribution/consumeImage.js +254 -0
- package/dist/distribution/consumeImageSupport.d.ts +18 -0
- package/dist/distribution/consumeImageSupport.js +63 -0
- package/dist/distribution/distributionReportSchema.d.ts +84 -0
- package/dist/distribution/distributionReportSchema.js +107 -0
- package/dist/distribution/dockerRunner.d.ts +5 -0
- package/dist/distribution/dockerRunner.js +21 -0
- package/dist/distribution/extractImage.d.ts +25 -0
- package/dist/distribution/extractImage.js +96 -0
- package/dist/distribution/fingerprint.d.ts +2 -0
- package/dist/distribution/fingerprint.js +14 -0
- package/dist/distribution/imageRef.d.ts +9 -0
- package/dist/distribution/imageRef.js +65 -0
- package/dist/distribution/imageRuntimeAuth.d.ts +19 -0
- package/dist/distribution/imageRuntimeAuth.js +71 -0
- package/dist/distribution/index.d.ts +24 -0
- package/dist/distribution/index.js +16 -0
- package/dist/distribution/preflight.d.ts +11 -0
- package/dist/distribution/preflight.js +65 -0
- package/dist/distribution/projectImageView.d.ts +8 -0
- package/dist/distribution/projectImageView.js +83 -0
- package/dist/distribution/projectName.d.ts +1 -0
- package/dist/distribution/projectName.js +12 -0
- package/dist/distribution/renderImageInterface.d.ts +30 -0
- package/dist/distribution/renderImageInterface.js +86 -0
- package/dist/distribution/tarReader.d.ts +10 -0
- package/dist/distribution/tarReader.js +69 -0
- package/dist/distribution/types.d.ts +80 -0
- package/dist/distribution/types.js +4 -0
- package/dist/distribution/verifyDistributionReport.d.ts +12 -0
- package/dist/distribution/verifyDistributionReport.js +29 -0
- package/dist/filesystem/paths.d.ts +6 -0
- package/dist/filesystem/paths.js +11 -0
- package/dist/manifest/loadManifest.js +22 -2
- package/dist/manifest/renderSpawnfile.js +2 -4
- package/dist/manifest/schemas.d.ts +17 -41
- package/dist/manifest/surfaceSchemas.d.ts +19 -47
- package/dist/manifest/surfaceSchemas.js +3 -6
- package/dist/report/createReport.d.ts +7 -1
- package/dist/report/createReport.js +28 -1
- package/dist/report/types.d.ts +43 -0
- package/dist/runtime/container.js +0 -16
- package/dist/runtime/index.d.ts +1 -0
- package/dist/runtime/index.js +1 -0
- package/dist/runtime/install.d.ts +0 -10
- package/dist/runtime/install.js +0 -45
- package/dist/runtime/openclaw/adapter.js +9 -1
- package/dist/runtime/openclaw/configAuth.d.ts +15 -0
- package/dist/runtime/openclaw/configAuth.js +46 -0
- package/dist/runtime/openclaw/runAuth.d.ts +6 -0
- package/dist/runtime/openclaw/runAuth.js +7 -55
- package/dist/runtime/openclaw/statusProbes.d.ts +2 -0
- package/dist/runtime/openclaw/statusProbes.js +31 -0
- package/dist/runtime/picoclaw/adapter.js +10 -0
- package/dist/runtime/picoclaw/runAuth.d.ts +7 -0
- package/dist/runtime/picoclaw/runAuth.js +8 -68
- package/dist/runtime/picoclaw/statusProbes.d.ts +2 -0
- package/dist/runtime/picoclaw/statusProbes.js +100 -0
- package/dist/runtime/registry.d.ts +0 -5
- package/dist/runtime/registry.js +2 -12
- package/dist/runtime/statusProbes.d.ts +16 -0
- package/dist/runtime/statusProbes.js +41 -0
- package/dist/runtime/types.d.ts +52 -1
- package/dist/shared/errors.d.ts +6 -0
- package/dist/shared/errors.js +9 -0
- package/dist/status/buildStatus.d.ts +13 -0
- package/dist/status/buildStatus.js +266 -0
- package/dist/status/compileReport.d.ts +96 -0
- package/dist/status/compileReport.js +230 -0
- package/dist/status/compiledContainerObservations.d.ts +5 -0
- package/dist/status/compiledContainerObservations.js +63 -0
- package/dist/status/deploymentLogs.d.ts +12 -0
- package/dist/status/deploymentLogs.js +45 -0
- package/dist/status/deployments.d.ts +14 -0
- package/dist/status/deployments.js +128 -0
- package/dist/status/imageStatusReport.d.ts +10 -0
- package/dist/status/imageStatusReport.js +73 -0
- package/dist/status/index.d.ts +14 -0
- package/dist/status/index.js +14 -0
- package/dist/status/moltnetProbes.d.ts +21 -0
- package/dist/status/moltnetProbes.js +240 -0
- package/dist/status/registryDrift.d.ts +28 -0
- package/dist/status/registryDrift.js +119 -0
- package/dist/status/renderStatus.d.ts +2 -0
- package/dist/status/renderStatus.js +230 -0
- package/dist/status/runtimeProbes.d.ts +13 -0
- package/dist/status/runtimeProbes.js +111 -0
- package/dist/status/selectionSubjects.d.ts +8 -0
- package/dist/status/selectionSubjects.js +77 -0
- package/dist/status/selectors.d.ts +14 -0
- package/dist/status/selectors.js +90 -0
- package/dist/status/traversal.d.ts +6 -0
- package/dist/status/traversal.js +15 -0
- package/dist/status/types.d.ts +113 -0
- package/dist/status/types.js +1 -0
- package/package.json +4 -2
- package/runtimes.yaml +22 -15
- package/dist/runtime/tinyclaw/adapter.d.ts +0 -2
- package/dist/runtime/tinyclaw/adapter.js +0 -284
- package/dist/runtime/tinyclaw/runAuth.d.ts +0 -2
- package/dist/runtime/tinyclaw/runAuth.js +0 -49
- package/dist/runtime/tinyclaw/scaffold-assets/AGENTS.md +0 -160
- package/dist/runtime/tinyclaw/scaffold-assets/CLAUDE.md +0 -5
- package/dist/runtime/tinyclaw/scaffold-assets/SOUL.md +0 -177
- package/dist/runtime/tinyclaw/scaffold.d.ts +0 -2
- package/dist/runtime/tinyclaw/scaffold.js +0 -24
- package/dist/runtime/tinyclaw/schedules.d.ts +0 -9
- package/dist/runtime/tinyclaw/schedules.js +0 -62
- package/dist/runtime/tinyclaw/surfaces.d.ts +0 -8
- package/dist/runtime/tinyclaw/surfaces.js +0 -94
|
@@ -0,0 +1,394 @@
|
|
|
1
|
+
import { inspectDockerDeployment, listDeploymentRecords, listHomeDeploymentRecords, readHomeDeploymentRecord, readHomeDeploymentReport } from "../deployment/index.js";
|
|
2
|
+
import { extractImageReport, 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, 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 || options.recover) {
|
|
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, { timeoutMs })
|
|
66
|
+
]));
|
|
67
|
+
return new Map(inspections);
|
|
68
|
+
};
|
|
69
|
+
const resolveAuthValues = async (records, handlers) => {
|
|
70
|
+
const values = {};
|
|
71
|
+
if (!handlers.requireAuthProfile) {
|
|
72
|
+
return values;
|
|
73
|
+
}
|
|
74
|
+
const profileNames = [...new Set(records
|
|
75
|
+
.map(({ record }) => record.auth_profile)
|
|
76
|
+
.filter((profileName) => typeof profileName === "string" && profileName.length > 0))];
|
|
77
|
+
for (const profileName of profileNames) {
|
|
78
|
+
try {
|
|
79
|
+
const profile = await handlers.requireAuthProfile(profileName);
|
|
80
|
+
Object.assign(values, profile.env);
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
// Missing profile values are reported by the metadata layer as unknown credentials.
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return values;
|
|
87
|
+
};
|
|
88
|
+
const emitOutput = (streams, output) => {
|
|
89
|
+
for (const line of output.split("\n")) {
|
|
90
|
+
streams.stdout(line);
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
const wait = (ms) => new Promise((resolve) => {
|
|
94
|
+
setTimeout(resolve, ms);
|
|
95
|
+
});
|
|
96
|
+
export const executeStatusWatch = async (inputPath, options, handlers, streams, setExitCode, watchOptions = {}) => {
|
|
97
|
+
const intervalMs = watchOptions.intervalMs ?? 5_000;
|
|
98
|
+
const sleep = watchOptions.sleep ?? wait;
|
|
99
|
+
let iteration = 0;
|
|
100
|
+
while (watchOptions.iterations === undefined || iteration < watchOptions.iterations) {
|
|
101
|
+
if (iteration > 0) {
|
|
102
|
+
await sleep(intervalMs);
|
|
103
|
+
streams.stdout("");
|
|
104
|
+
}
|
|
105
|
+
const result = await executeStatusCommand(inputPath, options, handlers);
|
|
106
|
+
setExitCode(result.exitCode);
|
|
107
|
+
if (result.error) {
|
|
108
|
+
streams.stderr(`error: ${result.error}`);
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
if (result.output) {
|
|
112
|
+
emitOutput(streams, result.output);
|
|
113
|
+
}
|
|
114
|
+
iteration += 1;
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
/* v8 ignore start -- docker extraction is covered by distribution E2E */
|
|
118
|
+
const runStaticImageStatus = async (imageRef, options, json) => {
|
|
119
|
+
try {
|
|
120
|
+
const inspection = await extractImageReport(imageRef, {
|
|
121
|
+
dockerCommand: options.dockerCommand,
|
|
122
|
+
dockerContext: options.context,
|
|
123
|
+
pull: options.pull
|
|
124
|
+
});
|
|
125
|
+
return {
|
|
126
|
+
exitCode: 0,
|
|
127
|
+
output: renderImageInterface(inspection.report, { imageRef, json })
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
catch (error) {
|
|
131
|
+
// Input errors (bad labels, non-JSON report, fingerprint mismatch) exit 2;
|
|
132
|
+
// Docker/runtime failures (daemon down, pull/create failure) exit 1.
|
|
133
|
+
return {
|
|
134
|
+
error: error instanceof Error ? error.message : String(error),
|
|
135
|
+
exitCode: errorExitCode(error)
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
/* v8 ignore stop */
|
|
140
|
+
const runHomeDeploymentStatus = async (options, handlers, mode, timeoutMs) => {
|
|
141
|
+
let records;
|
|
142
|
+
try {
|
|
143
|
+
records = await listHomeDeploymentRecords();
|
|
144
|
+
}
|
|
145
|
+
catch (error) {
|
|
146
|
+
return { error: error instanceof Error ? error.message : String(error), exitCode: errorExitCode(error) };
|
|
147
|
+
}
|
|
148
|
+
if (!options.deployment) {
|
|
149
|
+
if (records.length === 0) {
|
|
150
|
+
return inputFailure("No image deployments found in the home store");
|
|
151
|
+
}
|
|
152
|
+
if (records.length > 1) {
|
|
153
|
+
return inputFailure(`status --deployment is required: ${records.map((entry) => entry.record.name).sort().join(", ")}`);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
const targetName = options.deployment ?? records[0].record.name;
|
|
157
|
+
const match = records.find((entry) => entry.record.name === targetName);
|
|
158
|
+
if (!match) {
|
|
159
|
+
return inputFailure(`Unknown deployment "${targetName}". Valid deployments: ${records.map((entry) => entry.record.name).sort().join(", ") || "none"}`);
|
|
160
|
+
}
|
|
161
|
+
let report;
|
|
162
|
+
try {
|
|
163
|
+
const record = await readHomeDeploymentRecord(targetName);
|
|
164
|
+
void record;
|
|
165
|
+
const raw = await readHomeDeploymentReport(targetName);
|
|
166
|
+
let parsed;
|
|
167
|
+
try {
|
|
168
|
+
parsed = JSON.parse(raw);
|
|
169
|
+
}
|
|
170
|
+
catch (error) {
|
|
171
|
+
// A corrupt cached report is bad input, not a runtime failure: exit 2.
|
|
172
|
+
throw new SpawnfileError("validation_error", `Cached report for "${targetName}" is not valid JSON: ${error instanceof Error ? error.message : String(error)}`);
|
|
173
|
+
}
|
|
174
|
+
report = parseDistributionReport(parsed);
|
|
175
|
+
}
|
|
176
|
+
catch (error) {
|
|
177
|
+
return { error: error instanceof Error ? error.message : String(error), exitCode: errorExitCode(error) };
|
|
178
|
+
}
|
|
179
|
+
const view = projectImageOrganizationView(report, match.record.source.kind === "image"
|
|
180
|
+
? match.record.source.ref
|
|
181
|
+
: targetName);
|
|
182
|
+
const reportPath = match.path.replace(/record\.json$/, "spawnfile-report.json");
|
|
183
|
+
const loadedReport = loadedImageCompileReport(report, reportPath);
|
|
184
|
+
const selectedRecords = [match];
|
|
185
|
+
const deploymentInspections = await inspectDeployments(selectedRecords, handlers, options, timeoutMs);
|
|
186
|
+
const recordValues = selectedRecords.map(({ record }) => record);
|
|
187
|
+
const authValues = options.live ? await resolveAuthValues(selectedRecords, handlers) : {};
|
|
188
|
+
const collectRuntimeProbes = handlers.collectRuntimeProbeObservations ?? collectRuntimeProbeObservations;
|
|
189
|
+
const collectMoltnetProbes = handlers.collectMoltnetProbeObservations ?? collectMoltnetProbeObservations;
|
|
190
|
+
const collectDeploymentLogs = handlers.collectDeploymentLogObservations ?? collectDeploymentLogObservations;
|
|
191
|
+
const liveObservations = options.live && !options.recover
|
|
192
|
+
? [
|
|
193
|
+
...await collectRuntimeProbes({
|
|
194
|
+
deployments: recordValues,
|
|
195
|
+
inspections: deploymentInspections,
|
|
196
|
+
loadedReport,
|
|
197
|
+
timeoutMs
|
|
198
|
+
}),
|
|
199
|
+
...await collectMoltnetProbes({
|
|
200
|
+
authValues,
|
|
201
|
+
deployments: recordValues,
|
|
202
|
+
inspections: deploymentInspections,
|
|
203
|
+
loadedReport,
|
|
204
|
+
timeoutMs
|
|
205
|
+
}),
|
|
206
|
+
...(options.logs
|
|
207
|
+
? await collectDeploymentLogs({ deployments: recordValues, loadedReport, timeoutMs })
|
|
208
|
+
: []),
|
|
209
|
+
...(options.pullCheck
|
|
210
|
+
? await collectRegistryDriftObservations({
|
|
211
|
+
deployments: recordValues,
|
|
212
|
+
dockerCommand: options.dockerCommand,
|
|
213
|
+
timeoutMs
|
|
214
|
+
})
|
|
215
|
+
: [])
|
|
216
|
+
]
|
|
217
|
+
: [];
|
|
218
|
+
const status = createStaticStatus(view, loadedReport, {
|
|
219
|
+
deployments: createDeploymentSummaries(selectedRecords, deploymentInspections),
|
|
220
|
+
inputPath: view.inputPath,
|
|
221
|
+
live: {
|
|
222
|
+
context: null,
|
|
223
|
+
deploymentName: targetName,
|
|
224
|
+
logs: options.logs ?? false,
|
|
225
|
+
recover: false,
|
|
226
|
+
requested: options.live ?? false
|
|
227
|
+
},
|
|
228
|
+
liveObservations,
|
|
229
|
+
outputDirectory: "",
|
|
230
|
+
selection: null
|
|
231
|
+
});
|
|
232
|
+
return { exitCode: exitCodeForStatus(status), output: renderStatus(status, { mode }), status };
|
|
233
|
+
};
|
|
234
|
+
export const executeStatusCommand = async (inputPath, options, handlers) => {
|
|
235
|
+
const mode = resolveOutputMode(options);
|
|
236
|
+
if (typeof mode !== "string") {
|
|
237
|
+
return mode;
|
|
238
|
+
}
|
|
239
|
+
if (options.logs && !options.live) {
|
|
240
|
+
return inputFailure("status --logs requires --live");
|
|
241
|
+
}
|
|
242
|
+
// A positional image reference without --deployment renders the static
|
|
243
|
+
// interface from the embedded report. Image ref with --deployment, or a bare
|
|
244
|
+
// --deployment on the default path, reads the home store.
|
|
245
|
+
// A clear image reference (tag/digest/registry, or forced with --image)
|
|
246
|
+
// without --deployment renders the static interface; any other positional is
|
|
247
|
+
// treated as a project path (the view builder reports a missing path).
|
|
248
|
+
const commandInput = resolveCommandInput(inputPath, { forceImage: options.image });
|
|
249
|
+
const usedDefaultPath = inputPath === process.cwd();
|
|
250
|
+
if (commandInput.kind === "image" && !options.deployment) {
|
|
251
|
+
return runStaticImageStatus(commandInput.ref, options, mode === "json");
|
|
252
|
+
}
|
|
253
|
+
if (options.deployment && (commandInput.kind === "image" || usedDefaultPath)) {
|
|
254
|
+
const timeoutForHome = resolveTimeoutMs(options);
|
|
255
|
+
if (typeof timeoutForHome !== "number" && timeoutForHome !== undefined) {
|
|
256
|
+
return timeoutForHome;
|
|
257
|
+
}
|
|
258
|
+
return runHomeDeploymentStatus(options, handlers, mode, timeoutForHome);
|
|
259
|
+
}
|
|
260
|
+
if (options.context && !options.recover) {
|
|
261
|
+
return inputFailure("status accepts --context only with --recover");
|
|
262
|
+
}
|
|
263
|
+
if (options.logs && !options.live) {
|
|
264
|
+
return inputFailure("status --logs requires --live");
|
|
265
|
+
}
|
|
266
|
+
if (options.logs && options.recover) {
|
|
267
|
+
return inputFailure("status --logs is not available with --recover");
|
|
268
|
+
}
|
|
269
|
+
if (options.recover && !options.context) {
|
|
270
|
+
return inputFailure("status --recover requires --context");
|
|
271
|
+
}
|
|
272
|
+
const timeoutMs = resolveTimeoutMs(options);
|
|
273
|
+
if (typeof timeoutMs !== "number" && timeoutMs !== undefined) {
|
|
274
|
+
return timeoutMs;
|
|
275
|
+
}
|
|
276
|
+
const selectorInput = resolveSelectorInput(options);
|
|
277
|
+
if (selectorInput && "exitCode" in selectorInput) {
|
|
278
|
+
return selectorInput;
|
|
279
|
+
}
|
|
280
|
+
const outputDirectory = resolveProjectOutputDirectory(inputPath, options.out, DEFAULT_OUTPUT_DIRECTORY);
|
|
281
|
+
const view = await handlers.buildOrganizationView(inputPath);
|
|
282
|
+
const selectorResult = resolveStatusSelector(view, selectorInput);
|
|
283
|
+
if (selectorResult?.kind === "failure") {
|
|
284
|
+
return { error: selectorResult.failure.message, exitCode: 2 };
|
|
285
|
+
}
|
|
286
|
+
const loadedReport = await loadCompileReport(outputDirectory);
|
|
287
|
+
if (loadedReport.kind === "failure") {
|
|
288
|
+
return { error: loadedReport.failure.message, exitCode: 2 };
|
|
289
|
+
}
|
|
290
|
+
let deploymentRecords;
|
|
291
|
+
try {
|
|
292
|
+
deploymentRecords = await listDeploymentRecords(outputDirectory);
|
|
293
|
+
}
|
|
294
|
+
catch (error) {
|
|
295
|
+
return {
|
|
296
|
+
error: error instanceof Error ? error.message : String(error),
|
|
297
|
+
exitCode: 2
|
|
298
|
+
};
|
|
299
|
+
}
|
|
300
|
+
const selectedDeploymentRecords = resolveDeploymentRecords(deploymentRecords, options);
|
|
301
|
+
if ("exitCode" in selectedDeploymentRecords) {
|
|
302
|
+
return selectedDeploymentRecords;
|
|
303
|
+
}
|
|
304
|
+
const deploymentInspections = await inspectDeployments(selectedDeploymentRecords, handlers, options, timeoutMs);
|
|
305
|
+
const selectedDeploymentRecordValues = selectedDeploymentRecords.map(({ record }) => record);
|
|
306
|
+
const authValues = options.live
|
|
307
|
+
? await resolveAuthValues(selectedDeploymentRecords, handlers)
|
|
308
|
+
: {};
|
|
309
|
+
const collectRuntimeProbes = handlers.collectRuntimeProbeObservations ?? collectRuntimeProbeObservations;
|
|
310
|
+
const collectMoltnetProbes = handlers.collectMoltnetProbeObservations ?? collectMoltnetProbeObservations;
|
|
311
|
+
const collectDeploymentLogs = handlers.collectDeploymentLogObservations ?? collectDeploymentLogObservations;
|
|
312
|
+
const liveObservations = options.live && !options.recover
|
|
313
|
+
? [
|
|
314
|
+
...await collectRuntimeProbes({
|
|
315
|
+
deployments: selectedDeploymentRecordValues,
|
|
316
|
+
inspections: deploymentInspections,
|
|
317
|
+
loadedReport,
|
|
318
|
+
timeoutMs
|
|
319
|
+
}),
|
|
320
|
+
...await collectMoltnetProbes({
|
|
321
|
+
authValues,
|
|
322
|
+
deployments: selectedDeploymentRecordValues,
|
|
323
|
+
inspections: deploymentInspections,
|
|
324
|
+
loadedReport,
|
|
325
|
+
timeoutMs
|
|
326
|
+
}),
|
|
327
|
+
...(options.logs
|
|
328
|
+
? await collectDeploymentLogs({
|
|
329
|
+
deployments: selectedDeploymentRecordValues,
|
|
330
|
+
loadedReport,
|
|
331
|
+
timeoutMs
|
|
332
|
+
})
|
|
333
|
+
: [])
|
|
334
|
+
]
|
|
335
|
+
: [];
|
|
336
|
+
const status = createStaticStatus(view, loadedReport, {
|
|
337
|
+
deployments: createDeploymentSummaries(selectedDeploymentRecords, deploymentInspections),
|
|
338
|
+
inputPath,
|
|
339
|
+
live: {
|
|
340
|
+
context: options.context ?? null,
|
|
341
|
+
deploymentName: options.deployment ?? null,
|
|
342
|
+
logs: options.logs ?? false,
|
|
343
|
+
recover: options.recover ?? false,
|
|
344
|
+
requested: options.live ?? false
|
|
345
|
+
},
|
|
346
|
+
liveObservations,
|
|
347
|
+
outputDirectory,
|
|
348
|
+
selection: selectorResult?.selection ?? null
|
|
349
|
+
});
|
|
350
|
+
return {
|
|
351
|
+
exitCode: exitCodeForStatus(status),
|
|
352
|
+
output: renderStatus(status, { mode }),
|
|
353
|
+
status
|
|
354
|
+
};
|
|
355
|
+
};
|
|
356
|
+
export const registerStatusCommand = (program, handlers, streams, setExitCode) => {
|
|
357
|
+
program
|
|
358
|
+
.command("status")
|
|
359
|
+
.description("Show static Spawnfile organization status")
|
|
360
|
+
.argument("[path]", "Project directory or Spawnfile path", process.cwd())
|
|
361
|
+
.option("--out <dir>", "Compile output directory")
|
|
362
|
+
.option("--json", "Render machine-readable JSON")
|
|
363
|
+
.option("--pretty", "Render human output")
|
|
364
|
+
.option("--quiet", "Render only summary and non-ok observations")
|
|
365
|
+
.option("--live", "Inspect the recorded live deployment")
|
|
366
|
+
.option("--deployment <name>", "Deployment record name")
|
|
367
|
+
.option("--image", "Interpret the argument as an image reference")
|
|
368
|
+
.option("--pull", "Pull the image before inspecting (image references only)")
|
|
369
|
+
.option("--pull-check", "Check the registry for a newer image digest (networked)")
|
|
370
|
+
.option("--docker-command <command>", "Docker command")
|
|
371
|
+
.option("--context <name>", "Docker context for label recovery only")
|
|
372
|
+
.option("--recover", "Recover live status from labels instead of a deployment record")
|
|
373
|
+
.option("--logs", "Include redacted logs when supported")
|
|
374
|
+
.option("--timeout <ms>", "Bound live Docker/runtime checks in milliseconds")
|
|
375
|
+
.option("--watch", "Refresh status every five seconds until interrupted")
|
|
376
|
+
.option("--agent <id>", "Show one agent")
|
|
377
|
+
.option("--team <id>", "Show one team")
|
|
378
|
+
.option("--network <id>", "Show one network")
|
|
379
|
+
.option("--runtime <name>", "Show one runtime")
|
|
380
|
+
.action(async (inputPath, options) => {
|
|
381
|
+
if (options.watch) {
|
|
382
|
+
await executeStatusWatch(inputPath, options, handlers, streams, setExitCode);
|
|
383
|
+
return;
|
|
384
|
+
}
|
|
385
|
+
const result = await executeStatusCommand(inputPath, options, handlers);
|
|
386
|
+
setExitCode(result.exitCode);
|
|
387
|
+
if (result.error) {
|
|
388
|
+
streams.stderr(`error: ${result.error}`);
|
|
389
|
+
}
|
|
390
|
+
if (result.output) {
|
|
391
|
+
emitOutput(streams, result.output);
|
|
392
|
+
}
|
|
393
|
+
});
|
|
394
|
+
};
|
|
@@ -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.
|
|
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.
|
|
45
|
-
...(behavior.reply ? { reply: behavior.reply } : {})
|
|
43
|
+
...(behavior.wake ? { wake: behavior.wake } : {})
|
|
46
44
|
}
|
|
47
45
|
]))
|
|
48
46
|
}
|
|
@@ -22,9 +22,7 @@ const createTeamOutputDirectory = (baseDirectory, runtimeName, node) => path.joi
|
|
|
22
22
|
const compileAgentNode = async (baseDirectory, node) => {
|
|
23
23
|
const runtime = await assertRuntimeCanCompile(node.runtimeName ?? node.value.runtime.name);
|
|
24
24
|
const adapter = getRuntimeAdapter(runtime.name);
|
|
25
|
-
const diagnostics = [
|
|
26
|
-
...createRuntimeLifecycleDiagnostics(runtime)
|
|
27
|
-
];
|
|
25
|
+
const diagnostics = [...createRuntimeLifecycleDiagnostics(runtime)];
|
|
28
26
|
for (const diagnostic of adapter.validateRuntimeOptions?.(node.value.runtime.options) ?? []) {
|
|
29
27
|
diagnostics.push(diagnostic);
|
|
30
28
|
}
|
|
@@ -37,6 +35,7 @@ const compileAgentNode = async (baseDirectory, node) => {
|
|
|
37
35
|
await writeEmittedFiles(outputDirectory, result.files);
|
|
38
36
|
return {
|
|
39
37
|
emittedFiles: result.files,
|
|
38
|
+
id: node.id,
|
|
40
39
|
kind: node.kind,
|
|
41
40
|
report: {
|
|
42
41
|
capabilities: result.capabilities,
|
|
@@ -63,6 +62,7 @@ const compileTeamNode = async (baseDirectory, node) => {
|
|
|
63
62
|
if (!runtimeName) {
|
|
64
63
|
return {
|
|
65
64
|
emittedFiles: [],
|
|
65
|
+
id: node.id,
|
|
66
66
|
kind: node.kind,
|
|
67
67
|
report: {
|
|
68
68
|
capabilities: createTeamCapabilities("degraded", "Team spans multiple runtimes and cannot lower to one native team artifact in v0.1"),
|
|
@@ -88,6 +88,7 @@ const compileTeamNode = async (baseDirectory, node) => {
|
|
|
88
88
|
if (!adapter.compileTeam) {
|
|
89
89
|
return {
|
|
90
90
|
emittedFiles: [],
|
|
91
|
+
id: node.id,
|
|
91
92
|
kind: node.kind,
|
|
92
93
|
report: {
|
|
93
94
|
capabilities: createTeamCapabilities("degraded", `Runtime ${runtime.name} does not provide native team compilation in v0.1`),
|
|
@@ -113,6 +114,7 @@ const compileTeamNode = async (baseDirectory, node) => {
|
|
|
113
114
|
await writeEmittedFiles(outputDirectory, result.files);
|
|
114
115
|
return {
|
|
115
116
|
emittedFiles: result.files,
|
|
117
|
+
id: node.id,
|
|
116
118
|
kind: node.kind,
|
|
117
119
|
report: {
|
|
118
120
|
capabilities: result.capabilities,
|
|
@@ -200,7 +202,11 @@ const augmentNodeReports = (compiledNodes, support) => {
|
|
|
200
202
|
};
|
|
201
203
|
export const compileProject = async (inputPath, options = {}) => {
|
|
202
204
|
const plan = await buildCompilePlan(inputPath);
|
|
203
|
-
|
|
205
|
+
// The default output directory lives under the resolved project root, not the
|
|
206
|
+
// process working directory, so `spawnfile compile ./org` writes ./org/.spawn.
|
|
207
|
+
const outputDirectory = options.outputDirectory
|
|
208
|
+
? path.resolve(options.outputDirectory)
|
|
209
|
+
: path.join(path.dirname(plan.root), DEFAULT_OUTPUT_DIRECTORY);
|
|
204
210
|
if (options.clean ?? true) {
|
|
205
211
|
await removeDirectory(outputDirectory);
|
|
206
212
|
}
|
|
@@ -229,17 +235,20 @@ export const compileProject = async (inputPath, options = {}) => {
|
|
|
229
235
|
? await stageMoltnetBinaries(outputDirectory)
|
|
230
236
|
: false;
|
|
231
237
|
await injectMoltnetWorkspaceFiles(outputDirectory, compiledNodes, moltnetArtifacts);
|
|
238
|
+
const generatedAt = new Date().toISOString();
|
|
232
239
|
const containerArtifacts = await createContainerArtifacts(plan, compiledNodes, {
|
|
240
|
+
generatedAt,
|
|
233
241
|
hasStagedMoltnetBinaries,
|
|
234
242
|
moltnet: moltnetArtifacts
|
|
235
243
|
});
|
|
236
244
|
await writeEmittedFiles(outputDirectory, containerArtifacts.files);
|
|
237
245
|
await Promise.all(containerArtifacts.executablePaths.map((filePath) => chmod(path.join(outputDirectory, filePath), 0o755)));
|
|
238
|
-
const report = createCompileReport(plan.root, nodeReports, [], containerArtifacts.report
|
|
239
|
-
|
|
240
|
-
|
|
246
|
+
const report = createCompileReport(plan.root, nodeReports, [], containerArtifacts.report, {
|
|
247
|
+
compileFingerprint: containerArtifacts.distribution.fingerprint,
|
|
248
|
+
generatedAt,
|
|
241
249
|
outputDirectory,
|
|
242
|
-
report
|
|
243
|
-
|
|
244
|
-
|
|
250
|
+
projectName: containerArtifacts.distribution.report.organization.project
|
|
251
|
+
});
|
|
252
|
+
const reportPath = await writeCompileReport(outputDirectory, report);
|
|
253
|
+
return { outputDirectory, report, reportPath };
|
|
245
254
|
};
|
|
@@ -3,6 +3,7 @@ import type { CompiledNodeArtifact, GeneratedContainerArtifacts } from "./contai
|
|
|
3
3
|
import type { CompilePlan } from "./types.js";
|
|
4
4
|
export type { CompiledNodeArtifact, GeneratedContainerArtifacts } from "./containerArtifactsTypes.js";
|
|
5
5
|
export interface ContainerArtifactOptions {
|
|
6
|
+
generatedAt?: string;
|
|
6
7
|
hasStagedMoltnetBinaries?: boolean;
|
|
7
8
|
moltnet?: MoltnetArtifacts | null;
|
|
8
9
|
}
|