@tiangong-ai/cli 0.0.61 → 0.0.63
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/AGENTS.md +17 -6
- package/CONTRIBUTING.md +5 -5
- package/README.md +417 -36
- package/dist/cli.js +2 -2
- package/dist/data/builtins.js +33 -5
- package/dist/data/builtins.js.map +1 -1
- package/dist/data/catalog.js +46 -0
- package/dist/data/catalog.js.map +1 -1
- package/dist/data/commands.js +15 -1
- package/dist/data/commands.js.map +1 -1
- package/dist/data/connectors/airnow-hourly-observations.js +60 -10
- package/dist/data/connectors/airnow-hourly-observations.js.map +1 -1
- package/dist/data/connectors/epa-eis-records.js +16 -2
- package/dist/data/connectors/epa-eis-records.js.map +1 -1
- package/dist/data/connectors/gdelt-doc-search.js +54 -18
- package/dist/data/connectors/gdelt-doc-search.js.map +1 -1
- package/dist/data/connectors/gdelt-file-feeds.js +20 -11
- package/dist/data/connectors/gdelt-file-feeds.js.map +1 -1
- package/dist/data/connectors/gdelt-web-ngrams.d.ts +2 -0
- package/dist/data/connectors/gdelt-web-ngrams.js +350 -0
- package/dist/data/connectors/gdelt-web-ngrams.js.map +1 -0
- package/dist/data/connectors/gdelt-web-ngrams.schemas.d.ts +188 -0
- package/dist/data/connectors/gdelt-web-ngrams.schemas.js +138 -0
- package/dist/data/connectors/gdelt-web-ngrams.schemas.js.map +1 -0
- package/dist/data/connectors/nasa-firms-fire.js +4 -0
- package/dist/data/connectors/nasa-firms-fire.js.map +1 -1
- package/dist/data/connectors/open-meteo-air-quality.js +27 -22
- package/dist/data/connectors/open-meteo-air-quality.js.map +1 -1
- package/dist/data/connectors/open-meteo-air-quality.schemas.d.ts +4 -1
- package/dist/data/connectors/open-meteo-air-quality.schemas.js +21 -1
- package/dist/data/connectors/open-meteo-air-quality.schemas.js.map +1 -1
- package/dist/data/connectors/open-meteo-flood.js +28 -23
- package/dist/data/connectors/open-meteo-flood.js.map +1 -1
- package/dist/data/connectors/open-meteo-flood.schemas.d.ts +4 -1
- package/dist/data/connectors/open-meteo-flood.schemas.js +21 -1
- package/dist/data/connectors/open-meteo-flood.schemas.js.map +1 -1
- package/dist/data/connectors/open-meteo-historical-weather.js +26 -21
- package/dist/data/connectors/open-meteo-historical-weather.js.map +1 -1
- package/dist/data/connectors/open-meteo-historical-weather.schemas.d.ts +4 -1
- package/dist/data/connectors/open-meteo-historical-weather.schemas.js +21 -1
- package/dist/data/connectors/open-meteo-historical-weather.schemas.js.map +1 -1
- package/dist/data/connectors/openaq-air-quality.js +50 -12
- package/dist/data/connectors/openaq-air-quality.js.map +1 -1
- package/dist/data/connectors/openaq-air-quality.schemas.d.ts +0 -4
- package/dist/data/connectors/openaq-air-quality.schemas.js +2 -2
- package/dist/data/connectors/openaq-air-quality.schemas.js.map +1 -1
- package/dist/data/connectors/youtube-public-content.js +76 -6
- package/dist/data/connectors/youtube-public-content.js.map +1 -1
- package/dist/data/connectors/youtube-public-content.schemas.d.ts +63 -3
- package/dist/data/connectors/youtube-public-content.schemas.js +56 -2
- package/dist/data/connectors/youtube-public-content.schemas.js.map +1 -1
- package/dist/data/contracts.d.ts +22 -1
- package/dist/data/runtime/bounded-http.d.ts +2 -0
- package/dist/data/runtime/bounded-http.js +221 -59
- package/dist/data/runtime/bounded-http.js.map +1 -1
- package/dist/data/runtime/execute.d.ts +2 -0
- package/dist/data/runtime/execute.js +82 -60
- package/dist/data/runtime/execute.js.map +1 -1
- package/dist/data/runtime/http-timing.d.ts +15 -0
- package/dist/data/runtime/http-timing.js +59 -0
- package/dist/data/runtime/http-timing.js.map +1 -0
- package/dist/data/runtime/http-transport.d.ts +1 -0
- package/dist/data/runtime/http-transport.js +27 -0
- package/dist/data/runtime/http-transport.js.map +1 -0
- package/dist/data/schemas/catalog.v1.json +46 -0
- package/dist/data/schemas/discovery.v1.json +12 -0
- package/dist/data/schemas/error.v1.json +1 -0
- package/dist/data/schemas/manifest.v1.json +19 -1
- package/dist/research/orchestration.js +233 -10
- package/dist/research/orchestration.js.map +1 -1
- package/dist/research/setup-command.js +37 -6
- package/dist/research/setup-command.js.map +1 -1
- package/dist/research/workspace/audit-bundle.js +28 -8
- package/dist/research/workspace/audit-bundle.js.map +1 -1
- package/dist/research/workspace/broker.js +25 -4
- package/dist/research/workspace/broker.js.map +1 -1
- package/dist/research/workspace/constants.d.ts +1 -0
- package/dist/research/workspace/constants.js +1 -0
- package/dist/research/workspace/constants.js.map +1 -1
- package/dist/research/workspace/content-evidence.d.ts +1 -0
- package/dist/research/workspace/content-evidence.js +1 -1
- package/dist/research/workspace/content-evidence.js.map +1 -1
- package/dist/research/workspace/credentials.js +2 -1
- package/dist/research/workspace/credentials.js.map +1 -1
- package/dist/research/workspace/data-evidence-adapter.d.ts +71 -0
- package/dist/research/workspace/data-evidence-adapter.js +269 -59
- package/dist/research/workspace/data-evidence-adapter.js.map +1 -1
- package/dist/research/workspace/data-evidence-view.d.ts +58 -0
- package/dist/research/workspace/data-evidence-view.js +411 -0
- package/dist/research/workspace/data-evidence-view.js.map +1 -0
- package/dist/research/workspace/evidence-ledger.js +32 -29
- package/dist/research/workspace/evidence-ledger.js.map +1 -1
- package/dist/research/workspace/evidence.d.ts +28 -0
- package/dist/research/workspace/evidence.js +48 -0
- package/dist/research/workspace/evidence.js.map +1 -1
- package/dist/research/workspace/executor.d.ts +27 -1
- package/dist/research/workspace/executor.js +180 -20
- package/dist/research/workspace/executor.js.map +1 -1
- package/dist/research/workspace/external-skills.d.ts +1 -0
- package/dist/research/workspace/external-skills.js +4 -2
- package/dist/research/workspace/external-skills.js.map +1 -1
- package/dist/research/workspace/investigation-attempt.d.ts +159 -0
- package/dist/research/workspace/investigation-attempt.js +619 -0
- package/dist/research/workspace/investigation-attempt.js.map +1 -0
- package/dist/research/workspace/investigation-audit.d.ts +20 -0
- package/dist/research/workspace/investigation-audit.js +306 -0
- package/dist/research/workspace/investigation-audit.js.map +1 -0
- package/dist/research/workspace/investigation-candidate.d.ts +84 -0
- package/dist/research/workspace/investigation-candidate.js +156 -0
- package/dist/research/workspace/investigation-candidate.js.map +1 -0
- package/dist/research/workspace/investigation-certification.d.ts +39 -0
- package/dist/research/workspace/investigation-certification.js +152 -0
- package/dist/research/workspace/investigation-certification.js.map +1 -0
- package/dist/research/workspace/investigation-close.d.ts +47 -0
- package/dist/research/workspace/investigation-close.js +153 -0
- package/dist/research/workspace/investigation-close.js.map +1 -0
- package/dist/research/workspace/investigation-lineage.d.ts +8 -0
- package/dist/research/workspace/investigation-lineage.js +10 -0
- package/dist/research/workspace/investigation-lineage.js.map +1 -0
- package/dist/research/workspace/investigation-observer.d.ts +22 -0
- package/dist/research/workspace/investigation-observer.js +122 -0
- package/dist/research/workspace/investigation-observer.js.map +1 -0
- package/dist/research/workspace/investigation-promotion.d.ts +129 -0
- package/dist/research/workspace/investigation-promotion.js +316 -0
- package/dist/research/workspace/investigation-promotion.js.map +1 -0
- package/dist/research/workspace/investigation-requirements.d.ts +5 -0
- package/dist/research/workspace/investigation-requirements.js +32 -0
- package/dist/research/workspace/investigation-requirements.js.map +1 -0
- package/dist/research/workspace/investigation-resources.d.ts +12 -0
- package/dist/research/workspace/investigation-resources.js +78 -0
- package/dist/research/workspace/investigation-resources.js.map +1 -0
- package/dist/research/workspace/investigation-source-export.d.ts +6 -0
- package/dist/research/workspace/investigation-source-export.js +68 -0
- package/dist/research/workspace/investigation-source-export.js.map +1 -0
- package/dist/research/workspace/investigation-store.d.ts +9 -0
- package/dist/research/workspace/investigation-store.js +55 -0
- package/dist/research/workspace/investigation-store.js.map +1 -0
- package/dist/research/workspace/investigation.d.ts +424 -0
- package/dist/research/workspace/investigation.js +716 -0
- package/dist/research/workspace/investigation.js.map +1 -0
- package/dist/research/workspace/native-process-supervisor.d.ts +1 -0
- package/dist/research/workspace/native-process-supervisor.js +97 -0
- package/dist/research/workspace/native-process-supervisor.js.map +1 -0
- package/dist/research/workspace/native-run.d.ts +79 -6
- package/dist/research/workspace/native-run.js +293 -51
- package/dist/research/workspace/native-run.js.map +1 -1
- package/dist/research/workspace/preflight.d.ts +3 -0
- package/dist/research/workspace/preflight.js +11 -6
- package/dist/research/workspace/preflight.js.map +1 -1
- package/dist/research/workspace/project-authority.js +2 -0
- package/dist/research/workspace/project-authority.js.map +1 -1
- package/dist/research/workspace/project-budget.d.ts +41 -0
- package/dist/research/workspace/project-budget.js +265 -0
- package/dist/research/workspace/project-budget.js.map +1 -0
- package/dist/research/workspace/project-mutations.d.ts +1 -1
- package/dist/research/workspace/project-mutations.js +27 -3
- package/dist/research/workspace/project-mutations.js.map +1 -1
- package/dist/research/workspace/projects.d.ts +66 -0
- package/dist/research/workspace/projects.js +181 -3
- package/dist/research/workspace/projects.js.map +1 -1
- package/dist/research/workspace/provider-budget.d.ts +3 -0
- package/dist/research/workspace/provider-budget.js +45 -0
- package/dist/research/workspace/provider-budget.js.map +1 -0
- package/dist/research/workspace/provider-state.d.ts +1 -0
- package/dist/research/workspace/provider-state.js +20 -0
- package/dist/research/workspace/provider-state.js.map +1 -0
- package/dist/research/workspace/publication-lineage.d.ts +34 -0
- package/dist/research/workspace/publication-lineage.js +165 -0
- package/dist/research/workspace/publication-lineage.js.map +1 -0
- package/dist/research/workspace/publication-workflow.d.ts +24 -0
- package/dist/research/workspace/publication-workflow.js +118 -14
- package/dist/research/workspace/publication-workflow.js.map +1 -1
- package/dist/research/workspace/review-executor.d.ts +6 -1
- package/dist/research/workspace/review-executor.js +17 -3
- package/dist/research/workspace/review-executor.js.map +1 -1
- package/dist/research/workspace/runtime.d.ts +12 -1
- package/dist/research/workspace/runtime.js +143 -19
- package/dist/research/workspace/runtime.js.map +1 -1
- package/dist/research/workspace/scientific-amendment.d.ts +103 -0
- package/dist/research/workspace/scientific-amendment.js +537 -0
- package/dist/research/workspace/scientific-amendment.js.map +1 -0
- package/dist/research/workspace/scientific-fulfillment-audit.d.ts +20 -2
- package/dist/research/workspace/scientific-fulfillment-audit.js +87 -7
- package/dist/research/workspace/scientific-fulfillment-audit.js.map +1 -1
- package/dist/research/workspace/scientific-fulfillment.d.ts +10 -1
- package/dist/research/workspace/scientific-fulfillment.js +20 -6
- package/dist/research/workspace/scientific-fulfillment.js.map +1 -1
- package/dist/research/workspace/scientific-review-execution.js +162 -22
- package/dist/research/workspace/scientific-review-execution.js.map +1 -1
- package/dist/research/workspace/scientific-review.d.ts +2 -1
- package/dist/research/workspace/scientific-review.js +33 -2
- package/dist/research/workspace/scientific-review.js.map +1 -1
- package/dist/research/workspace/setup-catalog.js +13 -13
- package/dist/research/workspace/setup-catalog.js.map +1 -1
- package/dist/research/workspace/setup-release.d.ts +22 -0
- package/dist/research/workspace/setup-release.js +426 -0
- package/dist/research/workspace/setup-release.js.map +1 -0
- package/dist/research/workspace/setup-runtime-integrity.d.ts +2 -0
- package/dist/research/workspace/setup-runtime-integrity.js +31 -0
- package/dist/research/workspace/setup-runtime-integrity.js.map +1 -0
- package/dist/research/workspace/setup-upgrade.d.ts +17 -0
- package/dist/research/workspace/setup-upgrade.js +784 -0
- package/dist/research/workspace/setup-upgrade.js.map +1 -0
- package/dist/research/workspace/setup.d.ts +31 -39
- package/dist/research/workspace/setup.js +228 -19
- package/dist/research/workspace/setup.js.map +1 -1
- package/dist/research/workspace/task-acceptance.d.ts +8 -1
- package/dist/research/workspace/task-acceptance.js +37 -5
- package/dist/research/workspace/task-acceptance.js.map +1 -1
- package/dist/research/workspace/task-audit.d.ts +5 -1
- package/dist/research/workspace/task-audit.js +33 -18
- package/dist/research/workspace/task-audit.js.map +1 -1
- package/dist/research/workspace/types.d.ts +44 -0
- package/dist/research/workspace/workspace.js +34 -4
- package/dist/research/workspace/workspace.js.map +1 -1
- package/package.json +5 -4
|
@@ -1,5 +1,12 @@
|
|
|
1
|
+
import { investigationObserverRoute, inspectInvestigationObserver, } from "./investigation-observer.js";
|
|
2
|
+
import { investigationWallReservations } from "./investigation-resources.js";
|
|
3
|
+
import { createCalculationSandboxInvocation } from "./executor.js";
|
|
4
|
+
import { assertInvestigationCertificationRequired, prepareInvestigationCertification, frozenPromotionView, certificationAssessment, } from "./investigation-certification.js";
|
|
5
|
+
import { beginProjectMutation, prepareProjectMutation, projectMutationBinding, settleProjectMutation, } from "./project-mutations.js";
|
|
6
|
+
import { settleProjectCost } from "./project-budget.js";
|
|
1
7
|
import { Ajv2020 } from "ajv/dist/2020.js";
|
|
2
|
-
import { spawn } from "node:child_process";
|
|
8
|
+
import { fork, spawn } from "node:child_process";
|
|
9
|
+
import { fileURLToPath } from "node:url";
|
|
3
10
|
import { createHash } from "node:crypto";
|
|
4
11
|
import { constants } from "node:fs";
|
|
5
12
|
import { chmod, copyFile, lstat, mkdir, mkdtemp, readFile, realpath } from "node:fs/promises";
|
|
@@ -21,6 +28,7 @@ const statuses = [
|
|
|
21
28
|
"succeeded",
|
|
22
29
|
"failed",
|
|
23
30
|
"timed-out",
|
|
31
|
+
"output-limit-exceeded",
|
|
24
32
|
"cancelled",
|
|
25
33
|
"invalid-output",
|
|
26
34
|
"inputs-changed",
|
|
@@ -91,6 +99,7 @@ const inputSchema = {
|
|
|
91
99
|
},
|
|
92
100
|
arguments: { type: "array", maxItems: 256, items: { type: "string", maxLength: 4000 } },
|
|
93
101
|
timeoutSeconds: { type: "integer", minimum: 1, maximum: 172800 },
|
|
102
|
+
investigationPromotionSha256: { type: "string", pattern: HASH.source },
|
|
94
103
|
},
|
|
95
104
|
};
|
|
96
105
|
const validateInput = new Ajv2020({ strict: false, allErrors: true }).compile(inputSchema);
|
|
@@ -155,9 +164,11 @@ export async function observeNativeRun(root, projectId, value, confirm) {
|
|
|
155
164
|
stagingDirectoryName: String(started.payload.stagingDirectoryName ?? ""),
|
|
156
165
|
};
|
|
157
166
|
}
|
|
167
|
+
await assertInvestigationCertificationRequired(root, projectId, input, events);
|
|
158
168
|
await assertRunWindow(root, project, input);
|
|
159
169
|
const config = await loadWorkspaceConfig(root);
|
|
160
|
-
const
|
|
170
|
+
const { wallSeconds: reservedWall } = await investigationWallReservations(root, projectId, events);
|
|
171
|
+
const timeoutSeconds = Math.min(input.timeoutSeconds, config.budget.packageMaxWallSeconds.analyze, config.budget.maxWallSeconds - project.usage.wallSeconds - reservedWall);
|
|
161
172
|
if (timeoutSeconds < input.timeoutSeconds)
|
|
162
173
|
throw error("The declared calculation timeout exceeds the remaining finite workspace time budget.");
|
|
163
174
|
const working = await exactDirectory(input.workingDirectory);
|
|
@@ -169,11 +180,15 @@ export async function observeNativeRun(root, projectId, value, confirm) {
|
|
|
169
180
|
if (!(await lstat(runtimePath)).isFile())
|
|
170
181
|
throw error("The selected interpreter is not a regular executable file.");
|
|
171
182
|
const binarySha256 = await sha256File(runtimePath);
|
|
172
|
-
const
|
|
173
|
-
|
|
174
|
-
if (
|
|
175
|
-
|
|
176
|
-
|
|
183
|
+
const certification = await prepareInvestigationCertification(root, project, input, binarySha256, events);
|
|
184
|
+
let reportedVersion = "";
|
|
185
|
+
if (!certification) {
|
|
186
|
+
const version = await captureProcess(input.runtime.path, ["--version"], working, { PATH: dirname(input.runtime.path) }, 5);
|
|
187
|
+
reportedVersion = version.stdout.trim() || version.stderr.trim();
|
|
188
|
+
if (version.exitCode !== 0 ||
|
|
189
|
+
!(input.runtime.kind === "node" ? /^v\d+\.\d+\.\d+$/u : /^Python \d+\.\d+\.\d+$/u).test(reportedVersion))
|
|
190
|
+
throw error("The selected executable is not the declared ordinary Node/Python runtime. Agent CLI launchers are not supported.");
|
|
191
|
+
}
|
|
177
192
|
const acquisition = await loadCurrentEvidenceSnapshot(root, projectId);
|
|
178
193
|
const selected = input.inputs.map((item) => {
|
|
179
194
|
const artifact = acquisition.artifacts.find((artifact) => artifact.artifactId === item.artifactId && artifact.sha256 === item.sha256);
|
|
@@ -196,7 +211,11 @@ export async function observeNativeRun(root, projectId, value, confirm) {
|
|
|
196
211
|
const staging = await mkdtemp(join(working, `.tiangong-run-${input.runId}-`));
|
|
197
212
|
const privateHome = join(staging, "home");
|
|
198
213
|
await mkdir(privateHome, { mode: 0o700 });
|
|
199
|
-
const scriptFile = join(staging,
|
|
214
|
+
const scriptFile = join(staging, certification
|
|
215
|
+
? input.runtime.kind === "node"
|
|
216
|
+
? "program.mjs"
|
|
217
|
+
: "program.py"
|
|
218
|
+
: basename(input.scriptPath));
|
|
200
219
|
await copyExact(resolveContained(workspacePaths(root).control, script.objectLocator), scriptFile, script.sha256);
|
|
201
220
|
const runInputs = [];
|
|
202
221
|
for (const item of selected) {
|
|
@@ -225,6 +244,26 @@ export async function observeNativeRun(root, projectId, value, confirm) {
|
|
|
225
244
|
const nativePacketSha256 = await nativePacketBinding(root, project, input.nativeSessionId);
|
|
226
245
|
const sourceScript = await storeRunObject(root, projectId, scriptFile);
|
|
227
246
|
const environmentLock = await storeRunObject(root, projectId, resolveContained(workspacePaths(root).control, environment.objectLocator));
|
|
247
|
+
if (certification &&
|
|
248
|
+
(sourceScript.sha256 !== certification.promotion.plan.recipe.script.sha256 ||
|
|
249
|
+
environmentLock.sha256 !== certification.promotion.plan.recipe.environmentLock.sha256))
|
|
250
|
+
throw error("The staged certification bytes changed after promotion scope validation.", "RESEARCH_INVESTIGATION_CERTIFICATION_INVALID");
|
|
251
|
+
const invocation = certification
|
|
252
|
+
? await createCalculationSandboxInvocation({
|
|
253
|
+
binary: runtimePath,
|
|
254
|
+
args: [scriptFile, ...args],
|
|
255
|
+
capsuleRoot: staging,
|
|
256
|
+
workspaceRoot: root,
|
|
257
|
+
})
|
|
258
|
+
: null;
|
|
259
|
+
const versionInvocation = certification
|
|
260
|
+
? await createCalculationSandboxInvocation({
|
|
261
|
+
binary: runtimePath,
|
|
262
|
+
args: ["--version"],
|
|
263
|
+
capsuleRoot: staging,
|
|
264
|
+
workspaceRoot: root,
|
|
265
|
+
})
|
|
266
|
+
: null;
|
|
228
267
|
await appendJournalEvent(workspacePaths(root).journal, "project.task.run.started", projectId, {
|
|
229
268
|
runId: input.runId,
|
|
230
269
|
requestSha256,
|
|
@@ -235,9 +274,18 @@ export async function observeNativeRun(root, projectId, value, confirm) {
|
|
|
235
274
|
runtimeBinarySha256: binarySha256,
|
|
236
275
|
nativePacketSha256,
|
|
237
276
|
stagingDirectoryName: basename(staging),
|
|
277
|
+
...(certification
|
|
278
|
+
? {
|
|
279
|
+
investigationPromotionSha256: certification.promotion.recordSha256,
|
|
280
|
+
certificationReservedWallSeconds: timeoutSeconds,
|
|
281
|
+
}
|
|
282
|
+
: {}),
|
|
238
283
|
});
|
|
239
284
|
return {
|
|
240
285
|
project,
|
|
286
|
+
certification,
|
|
287
|
+
invocation,
|
|
288
|
+
versionInvocation,
|
|
241
289
|
runtimePath,
|
|
242
290
|
binarySha256,
|
|
243
291
|
reportedVersion,
|
|
@@ -259,8 +307,9 @@ export async function observeNativeRun(root, projectId, value, confirm) {
|
|
|
259
307
|
replayed: true,
|
|
260
308
|
stagingDirectoryName: prepared.stagingDirectoryName,
|
|
261
309
|
};
|
|
262
|
-
// No workspace lease is held during the
|
|
263
|
-
|
|
310
|
+
// No workspace lease is held during either the certification runtime probe
|
|
311
|
+
// or the calculation. Its one-use start is durable before either process.
|
|
312
|
+
const environment = {
|
|
264
313
|
PATH: dirname(input.runtime.path),
|
|
265
314
|
HOME: prepared.privateHome,
|
|
266
315
|
TMPDIR: prepared.staging,
|
|
@@ -268,7 +317,35 @@ export async function observeNativeRun(root, projectId, value, confirm) {
|
|
|
268
317
|
TZ: "UTC",
|
|
269
318
|
PYTHONDONTWRITEBYTECODE: "1",
|
|
270
319
|
PYTHONNOUSERSITE: "1",
|
|
271
|
-
}
|
|
320
|
+
};
|
|
321
|
+
const probe = prepared.versionInvocation
|
|
322
|
+
? await captureProcess(prepared.versionInvocation.binary, prepared.versionInvocation.args, prepared.staging, environment, Math.min(5, prepared.timeoutSeconds), { maxBytes: prepared.certification.promotion.plan.certification.maxOutputBytes }, investigationObserverRoute(root, projectId, requestSha256, "runtime-probe", prepared.staging))
|
|
323
|
+
: null;
|
|
324
|
+
const probeVersion = probe
|
|
325
|
+
? probe.stdout.trim() || probe.stderr.trim()
|
|
326
|
+
: prepared.reportedVersion;
|
|
327
|
+
const runtimeValid = !probe ||
|
|
328
|
+
(probe.exitCode === 0 &&
|
|
329
|
+
!probe.outputLimitExceeded &&
|
|
330
|
+
!probe.timedOut &&
|
|
331
|
+
!probe.cancelled &&
|
|
332
|
+
probeVersion === prepared.certification.promotion.plan.recipe.runtime.version);
|
|
333
|
+
const availableSeconds = prepared.timeoutSeconds - (probe?.wallSeconds ?? 0);
|
|
334
|
+
const availableOutput = prepared.certification
|
|
335
|
+
? prepared.certification.promotion.plan.certification.maxOutputBytes -
|
|
336
|
+
(probe?.observedOutputBytes ?? 0)
|
|
337
|
+
: Number.POSITIVE_INFINITY;
|
|
338
|
+
const observed = probe && (!runtimeValid || availableSeconds <= 0 || availableOutput <= 0)
|
|
339
|
+
? probe
|
|
340
|
+
: await captureProcess(prepared.invocation?.binary ?? input.runtime.path, prepared.invocation?.args ?? [prepared.scriptFile, ...prepared.args], prepared.staging, environment, availableSeconds, prepared.certification
|
|
341
|
+
? { maxBytes: availableOutput, paths: [...prepared.outputPaths.values()] }
|
|
342
|
+
: undefined, prepared.certification
|
|
343
|
+
? investigationObserverRoute(root, projectId, requestSha256, "calculation", prepared.staging)
|
|
344
|
+
: undefined);
|
|
345
|
+
const wallSeconds = observed.wallSeconds + (probe && observed !== probe ? probe.wallSeconds : 0);
|
|
346
|
+
const outputLimitExceeded = Boolean(probe?.outputLimitExceeded || observed.outputLimitExceeded || availableOutput <= 0);
|
|
347
|
+
const observedOutputBytes = (observed.observedOutputBytes ?? 0) +
|
|
348
|
+
(probe && probe !== observed ? (probe.observedOutputBytes ?? 0) : 0);
|
|
272
349
|
return await withWorkspaceLock(root, "research.task.run.commit", async () => {
|
|
273
350
|
const project = await loadProject(root, projectId);
|
|
274
351
|
let status = observed.cancelled
|
|
@@ -278,8 +355,15 @@ export async function observeNativeRun(root, projectId, value, confirm) {
|
|
|
278
355
|
: observed.exitCode === 0
|
|
279
356
|
? "succeeded"
|
|
280
357
|
: "failed";
|
|
358
|
+
if (!runtimeValid)
|
|
359
|
+
status = "failed";
|
|
360
|
+
if (outputLimitExceeded)
|
|
361
|
+
status = "output-limit-exceeded";
|
|
281
362
|
try {
|
|
282
363
|
await assertRunWindow(root, project, input);
|
|
364
|
+
if (prepared.certification &&
|
|
365
|
+
(await frozenPromotionView(root, project, prepared.certification.promotion, await readVerifiedJournal(workspacePaths(root).journal))) !== prepared.certification.effectiveDesignSha256)
|
|
366
|
+
status = "stale";
|
|
283
367
|
if ((await nativePacketBinding(root, project, input.nativeSessionId)) !==
|
|
284
368
|
prepared.nativePacketSha256 ||
|
|
285
369
|
project.scientificDesign?.designSha256 !==
|
|
@@ -302,12 +386,15 @@ export async function observeNativeRun(root, projectId, value, confirm) {
|
|
|
302
386
|
if (!stable || (await realpath(input.runtime.path)) !== prepared.runtimePath)
|
|
303
387
|
status = "inputs-changed";
|
|
304
388
|
const outputs = [];
|
|
305
|
-
for (const output of input.outputs) {
|
|
389
|
+
for (const output of outputLimitExceeded ? [] : input.outputs) {
|
|
306
390
|
const path = prepared.outputPaths.get(output.id);
|
|
307
391
|
try {
|
|
308
392
|
const info = await lstat(path);
|
|
309
|
-
if (!info.isFile() ||
|
|
310
|
-
|
|
393
|
+
if (!info.isFile() ||
|
|
394
|
+
info.isSymbolicLink() ||
|
|
395
|
+
(prepared.certification &&
|
|
396
|
+
info.size > prepared.certification.promotion.plan.certification.maxOutputBytes))
|
|
397
|
+
throw error("Calculation output is not a regular file within its approved byte bound.");
|
|
311
398
|
if (output.mediaType === "application/json")
|
|
312
399
|
JSON.parse(await readFile(path, "utf8"));
|
|
313
400
|
outputs.push({
|
|
@@ -321,6 +408,9 @@ export async function observeNativeRun(root, projectId, value, confirm) {
|
|
|
321
408
|
status = "invalid-output";
|
|
322
409
|
}
|
|
323
410
|
}
|
|
411
|
+
const investigationCertification = prepared.certification
|
|
412
|
+
? await certificationAssessment(root, projectId, prepared.certification, status, outputs, probe, prepared.invocation.isolation, prepared.versionInvocation.isolation, { observedOutputBytes, outputLimitExceeded })
|
|
413
|
+
: undefined;
|
|
324
414
|
const core = {
|
|
325
415
|
schemaVersion: 1,
|
|
326
416
|
kind: "tiangong-native-run",
|
|
@@ -338,7 +428,7 @@ export async function observeNativeRun(root, projectId, value, confirm) {
|
|
|
338
428
|
environmentVerification: "declared-lock-not-attested",
|
|
339
429
|
runtime: {
|
|
340
430
|
kind: input.runtime.kind,
|
|
341
|
-
version:
|
|
431
|
+
version: runtimeValid ? probeVersion : "unverified",
|
|
342
432
|
binarySha256: prepared.binarySha256,
|
|
343
433
|
platform: platform(),
|
|
344
434
|
architecture: arch(),
|
|
@@ -352,19 +442,45 @@ export async function observeNativeRun(root, projectId, value, confirm) {
|
|
|
352
442
|
process: {
|
|
353
443
|
exitCode: observed.exitCode,
|
|
354
444
|
signal: observed.signal,
|
|
355
|
-
startedAt: observed.startedAt,
|
|
445
|
+
startedAt: probe?.startedAt ?? observed.startedAt,
|
|
356
446
|
finishedAt: observed.finishedAt,
|
|
357
|
-
wallSeconds
|
|
447
|
+
wallSeconds,
|
|
358
448
|
stdoutSha256: observed.stdoutSha256,
|
|
359
449
|
stderrSha256: observed.stderrSha256,
|
|
360
450
|
stdoutBytes: observed.stdoutBytes,
|
|
361
451
|
stderrBytes: observed.stderrBytes,
|
|
362
452
|
diagnostic: safeDiagnostic(observed.stderr, observed.truncated),
|
|
453
|
+
...(prepared.certification ? { observedOutputBytes, outputLimitExceeded } : {}),
|
|
363
454
|
},
|
|
455
|
+
...(investigationCertification ? { investigationCertification } : {}),
|
|
364
456
|
};
|
|
365
457
|
const record = { ...core, recordSha256: sha256Text(canonicalJson(core)) };
|
|
366
458
|
await writeTaskObject(root, projectId, "runs", record.recordSha256, record);
|
|
367
|
-
|
|
459
|
+
if (prepared.certification) {
|
|
460
|
+
let mutation = await beginProjectMutation(root, "investigation-certification", project, record.recordSha256);
|
|
461
|
+
try {
|
|
462
|
+
settleProjectCost(project, `investigation-certification-${prepared.certification.promotion.recordSha256}`, prepared.certification.promotion.plan.certification.maxCostUsd, "allocated-upper-bound");
|
|
463
|
+
project.usage.wallSeconds += wallSeconds;
|
|
464
|
+
project.updatedAt = new Date().toISOString();
|
|
465
|
+
mutation = await prepareProjectMutation(root, mutation, project);
|
|
466
|
+
await appendJournalEvent(workspacePaths(root).journal, "project.task.run.completed", projectId, {
|
|
467
|
+
projectId,
|
|
468
|
+
runId: input.runId,
|
|
469
|
+
requestSha256,
|
|
470
|
+
recordSha256: record.recordSha256,
|
|
471
|
+
status,
|
|
472
|
+
mutation: projectMutationBinding(mutation),
|
|
473
|
+
});
|
|
474
|
+
await settleProjectMutation(root, mutation);
|
|
475
|
+
}
|
|
476
|
+
catch (error) {
|
|
477
|
+
await settleProjectMutation(root, mutation);
|
|
478
|
+
throw error;
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
else {
|
|
482
|
+
await appendJournalEvent(workspacePaths(root).journal, "project.task.run.completed", projectId, { runId: input.runId, requestSha256, recordSha256: record.recordSha256, status });
|
|
483
|
+
}
|
|
368
484
|
return { record, replayed: false, stagingDirectoryName: basename(prepared.staging) };
|
|
369
485
|
});
|
|
370
486
|
}
|
|
@@ -387,7 +503,7 @@ async function assertRunWindow(root, project, input) {
|
|
|
387
503
|
throw error("An observed calculation needs an active computational requirement, frozen acquisition, and an actionable project before completed review.");
|
|
388
504
|
await nativePacketBinding(root, project, input.nativeSessionId);
|
|
389
505
|
}
|
|
390
|
-
async function nativePacketBinding(root, project, sessionId) {
|
|
506
|
+
export async function nativePacketBinding(root, project, sessionId) {
|
|
391
507
|
const active = await pathExists(join(workspacePaths(root).projects, project.id, "native/active.json"));
|
|
392
508
|
if (!active) {
|
|
393
509
|
if (sessionId !== null)
|
|
@@ -408,7 +524,7 @@ async function exactDirectory(path) {
|
|
|
408
524
|
// Canonicalize parent aliases such as macOS /var before containment checks.
|
|
409
525
|
return realpath(path);
|
|
410
526
|
}
|
|
411
|
-
async function copyExact(source, target, sha256) {
|
|
527
|
+
export async function copyExact(source, target, sha256) {
|
|
412
528
|
const info = await lstat(source);
|
|
413
529
|
if (!info.isFile() || info.isSymbolicLink() || (await sha256File(source)) !== sha256)
|
|
414
530
|
throw error("A bound calculation file is missing, linked or changed.");
|
|
@@ -417,7 +533,7 @@ async function copyExact(source, target, sha256) {
|
|
|
417
533
|
if ((await sha256File(target)) !== sha256)
|
|
418
534
|
throw error("Calculation bytes changed during staging.");
|
|
419
535
|
}
|
|
420
|
-
async function storeRunObject(root, projectId, source) {
|
|
536
|
+
export async function storeRunObject(root, projectId, source) {
|
|
421
537
|
const info = await lstat(source);
|
|
422
538
|
if (!info.isFile() || info.isSymbolicLink())
|
|
423
539
|
throw error("Run objects must be exact regular files.");
|
|
@@ -452,34 +568,59 @@ export async function inspectNativeRun(root, projectId, runId) {
|
|
|
452
568
|
const completed = completedRunEvent(events, projectId, runId);
|
|
453
569
|
if (completed)
|
|
454
570
|
return { record: await readNativeRun(root, projectId, String(completed.payload.recordSha256)) };
|
|
571
|
+
const started = events.find((event) => event.scope === projectId &&
|
|
572
|
+
event.type === "project.task.run.started" &&
|
|
573
|
+
event.payload.runId === runId);
|
|
455
574
|
return {
|
|
456
575
|
projectId,
|
|
457
576
|
runId,
|
|
458
|
-
status:
|
|
459
|
-
event.type === "project.task.run.started" &&
|
|
460
|
-
event.payload.runId === runId)
|
|
461
|
-
? "incomplete"
|
|
462
|
-
: "not-found",
|
|
577
|
+
status: started ? "incomplete" : "not-found",
|
|
463
578
|
automaticRetry: false,
|
|
579
|
+
...(started?.payload.investigationPromotionSha256
|
|
580
|
+
? {
|
|
581
|
+
observer: await inspectInvestigationObserver(root, projectId, String(started.payload.requestSha256)),
|
|
582
|
+
}
|
|
583
|
+
: {}),
|
|
464
584
|
};
|
|
465
585
|
}
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
const
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
586
|
+
/** Shared by live inspection and portable audit, including ordinary histories
|
|
587
|
+
* that contain no investigation records to trigger a separate verifier. */
|
|
588
|
+
export function assertNativeRunJournalBinding(record, started, completed) {
|
|
589
|
+
const certification = record.investigationCertification;
|
|
590
|
+
if (!started ||
|
|
591
|
+
!completed ||
|
|
592
|
+
started.scope !== record.projectId ||
|
|
593
|
+
completed.scope !== record.projectId ||
|
|
594
|
+
started.type !== "project.task.run.started" ||
|
|
595
|
+
completed.type !== "project.task.run.completed" ||
|
|
596
|
+
started.payload.runId !== record.runId ||
|
|
597
|
+
completed.payload.runId !== record.runId ||
|
|
598
|
+
completed.payload.recordSha256 !== record.recordSha256 ||
|
|
474
599
|
completed.payload.requestSha256 !== record.requestSha256 ||
|
|
475
|
-
started
|
|
600
|
+
started.payload.requestSha256 !== record.requestSha256 ||
|
|
601
|
+
started.payload.requirementId !== record.requirementId ||
|
|
602
|
+
started.payload.requirementSha256 !== record.requirementSha256 ||
|
|
476
603
|
started.payload.scriptSha256 !== record.script.sha256 ||
|
|
477
604
|
started.payload.runtimeBinarySha256 !== record.runtime.binarySha256 ||
|
|
478
605
|
started.payload.environmentLockSha256 !== record.environmentLock.sha256 ||
|
|
479
606
|
started.payload.nativePacketSha256 !== record.nativePacketSha256 ||
|
|
607
|
+
(certification !== undefined &&
|
|
608
|
+
(!isObject(certification) ||
|
|
609
|
+
typeof certification.promotionSha256 !== "string" ||
|
|
610
|
+
!HASH.test(certification.promotionSha256))) ||
|
|
611
|
+
started.payload.investigationPromotionSha256 !== certification?.promotionSha256 ||
|
|
480
612
|
completed.payload.status !== record.status ||
|
|
481
613
|
started.sequence >= completed.sequence)
|
|
482
614
|
throw error("Native run does not match its committed start and completion.", "RESEARCH_NATIVE_RUN_BINDING_INVALID");
|
|
615
|
+
}
|
|
616
|
+
export async function readNativeRun(root, projectId, hash, knownEvents) {
|
|
617
|
+
const record = validateNativeRunRecord(await readTaskObject(root, projectId, "runs", hash, "recordSha256"), projectId);
|
|
618
|
+
const events = knownEvents ?? (await readVerifiedJournal(workspacePaths(root).journal));
|
|
619
|
+
const completed = completedRunEvent(events, projectId, record.runId);
|
|
620
|
+
const started = events.find((event) => event.scope === projectId &&
|
|
621
|
+
event.type === "project.task.run.started" &&
|
|
622
|
+
event.payload.runId === record.runId);
|
|
623
|
+
assertNativeRunJournalBinding(record, started, completed);
|
|
483
624
|
await taskDirectory(root, projectId, "run-objects", false);
|
|
484
625
|
for (const object of [
|
|
485
626
|
record.script,
|
|
@@ -555,22 +696,85 @@ function safeDiagnostic(text, truncated) {
|
|
|
555
696
|
.replace(/[A-Za-z]:\\[^\s"']+/gu, "[host-path]")
|
|
556
697
|
.slice(0, 2000);
|
|
557
698
|
}
|
|
558
|
-
async function captureProcess(binary, args, cwd, env, timeoutSeconds) {
|
|
699
|
+
export async function captureProcess(binary, args, cwd, env, timeoutSeconds, outputLimit, observation) {
|
|
700
|
+
if (outputLimit && (!Number.isSafeInteger(outputLimit.maxBytes) || outputLimit.maxBytes < 1))
|
|
701
|
+
throw error("Observed output budget must be a positive finite byte count.");
|
|
559
702
|
const startedAt = new Date().toISOString();
|
|
560
703
|
const start = process.hrtime.bigint();
|
|
561
704
|
return new Promise((resolvePromise) => {
|
|
562
|
-
const
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
705
|
+
const supervised = Boolean(outputLimit);
|
|
706
|
+
const sourceRuntime = import.meta.url.endsWith(".ts");
|
|
707
|
+
const supervisorPath = fileURLToPath(new URL(sourceRuntime ? "./native-process-supervisor.ts" : "./native-process-supervisor.js", import.meta.url));
|
|
708
|
+
const child = supervised
|
|
709
|
+
? fork(supervisorPath, [], {
|
|
710
|
+
cwd,
|
|
711
|
+
env,
|
|
712
|
+
detached: platform() !== "win32",
|
|
713
|
+
execArgv: [
|
|
714
|
+
...(sourceRuntime ? ["--import", import.meta.resolve("tsx")] : []),
|
|
715
|
+
...(observation ? [`--title=${observation.title}`] : []),
|
|
716
|
+
],
|
|
717
|
+
stdio: ["ignore", "pipe", "pipe", "ipc"],
|
|
718
|
+
})
|
|
719
|
+
: spawn(binary, args, {
|
|
720
|
+
cwd,
|
|
721
|
+
env,
|
|
722
|
+
shell: false,
|
|
723
|
+
detached: platform() !== "win32",
|
|
724
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
725
|
+
});
|
|
726
|
+
let supervisorResult = null;
|
|
727
|
+
if (supervised) {
|
|
728
|
+
child.on("message", (value) => {
|
|
729
|
+
if (isObject(value) &&
|
|
730
|
+
value.kind === "result" &&
|
|
731
|
+
(value.exitCode === null || Number.isInteger(value.exitCode)) &&
|
|
732
|
+
(value.signal === null || typeof value.signal === "string") &&
|
|
733
|
+
typeof value.timedOut === "boolean")
|
|
734
|
+
supervisorResult = {
|
|
735
|
+
exitCode: value.exitCode,
|
|
736
|
+
signal: value.signal,
|
|
737
|
+
timedOut: value.timedOut,
|
|
738
|
+
};
|
|
739
|
+
});
|
|
740
|
+
void (async () => {
|
|
741
|
+
if (observation) {
|
|
742
|
+
if (!child.pid)
|
|
743
|
+
throw new Error("Observer was not spawned");
|
|
744
|
+
await observation.onSpawn(child.pid);
|
|
745
|
+
}
|
|
746
|
+
child.send({
|
|
747
|
+
kind: "start",
|
|
748
|
+
binary,
|
|
749
|
+
args,
|
|
750
|
+
env,
|
|
751
|
+
deadlineNs: (start + BigInt(Math.ceil(timeoutSeconds * 1e9))).toString(),
|
|
752
|
+
}, (error) => {
|
|
753
|
+
if (error)
|
|
754
|
+
child.kill("SIGTERM");
|
|
755
|
+
});
|
|
756
|
+
})().catch(() => {
|
|
757
|
+
spawnFailed = true;
|
|
758
|
+
child.kill("SIGTERM");
|
|
759
|
+
});
|
|
760
|
+
}
|
|
569
761
|
const out = createHash("sha256"), err = createHash("sha256");
|
|
570
762
|
const stdout = [], stderr = [];
|
|
571
763
|
let stdoutBytes = 0, stderrBytes = 0, truncated = false, timedOut = false, cancelled = false, spawnFailed = false;
|
|
572
764
|
const terminate = (signal) => {
|
|
573
|
-
if (!child.pid
|
|
765
|
+
if (!child.pid)
|
|
766
|
+
return;
|
|
767
|
+
if (supervised) {
|
|
768
|
+
if (child.connected)
|
|
769
|
+
child.send({ kind: "stop", reason: timedOut ? "timeout" : cancelled ? "cancel" : "output-limit" }, (error) => {
|
|
770
|
+
if (error && child.exitCode === null)
|
|
771
|
+
child.kill("SIGTERM");
|
|
772
|
+
});
|
|
773
|
+
else if (child.exitCode === null)
|
|
774
|
+
child.kill("SIGTERM");
|
|
775
|
+
return;
|
|
776
|
+
}
|
|
777
|
+
if (!outputLimit && (child.exitCode !== null || child.signalCode !== null))
|
|
574
778
|
return;
|
|
575
779
|
try {
|
|
576
780
|
if (platform() === "win32")
|
|
@@ -579,9 +783,39 @@ async function captureProcess(binary, args, cwd, env, timeoutSeconds) {
|
|
|
579
783
|
process.kill(-child.pid, signal);
|
|
580
784
|
}
|
|
581
785
|
catch {
|
|
582
|
-
child.
|
|
786
|
+
if (child.exitCode === null && child.signalCode === null)
|
|
787
|
+
child.kill(signal);
|
|
583
788
|
}
|
|
584
789
|
};
|
|
790
|
+
let outputLimitExceeded = false;
|
|
791
|
+
const filePeaks = new Map();
|
|
792
|
+
let pendingScan = null;
|
|
793
|
+
const outputBytes = () => stdoutBytes + stderrBytes + [...filePeaks.values()].reduce((sum, n) => sum + n, 0);
|
|
794
|
+
const checkOutput = () => {
|
|
795
|
+
if (outputLimit && outputBytes() > outputLimit.maxBytes) {
|
|
796
|
+
outputLimitExceeded = true;
|
|
797
|
+
terminate("SIGKILL");
|
|
798
|
+
}
|
|
799
|
+
};
|
|
800
|
+
const scanOutputFiles = async () => {
|
|
801
|
+
if (!outputLimit)
|
|
802
|
+
return;
|
|
803
|
+
await Promise.all((outputLimit.paths ?? []).map(async (path) => {
|
|
804
|
+
const info = await lstat(path).catch(() => null);
|
|
805
|
+
if (info?.isFile() && !info.isSymbolicLink())
|
|
806
|
+
filePeaks.set(path, Math.max(filePeaks.get(path) ?? 0, info.size));
|
|
807
|
+
}));
|
|
808
|
+
checkOutput();
|
|
809
|
+
};
|
|
810
|
+
const outputTimer = outputLimit?.paths?.length
|
|
811
|
+
? setInterval(() => {
|
|
812
|
+
if (pendingScan)
|
|
813
|
+
return;
|
|
814
|
+
pendingScan = scanOutputFiles().finally(() => {
|
|
815
|
+
pendingScan = null;
|
|
816
|
+
});
|
|
817
|
+
}, 250)
|
|
818
|
+
: null;
|
|
585
819
|
const cancel = () => {
|
|
586
820
|
cancelled = true;
|
|
587
821
|
terminate("SIGKILL");
|
|
@@ -595,29 +829,36 @@ async function captureProcess(binary, args, cwd, env, timeoutSeconds) {
|
|
|
595
829
|
child.stdout.on("data", (chunk) => {
|
|
596
830
|
out.update(chunk);
|
|
597
831
|
stdoutBytes += chunk.length;
|
|
598
|
-
if (stdoutBytes <= 1024 * 1024)
|
|
832
|
+
if (outputLimit ? stdoutBytes + stderrBytes <= outputLimit.maxBytes : stdoutBytes <= 1024 * 1024)
|
|
599
833
|
stdout.push(chunk);
|
|
600
834
|
else
|
|
601
835
|
truncated = true;
|
|
836
|
+
checkOutput();
|
|
602
837
|
});
|
|
603
838
|
child.stderr.on("data", (chunk) => {
|
|
604
839
|
err.update(chunk);
|
|
605
840
|
stderrBytes += chunk.length;
|
|
606
|
-
if (stderrBytes <= 1024 * 1024)
|
|
841
|
+
if (outputLimit ? stdoutBytes + stderrBytes <= outputLimit.maxBytes : stderrBytes <= 1024 * 1024)
|
|
607
842
|
stderr.push(chunk);
|
|
608
843
|
else
|
|
609
844
|
truncated = true;
|
|
845
|
+
checkOutput();
|
|
610
846
|
});
|
|
611
847
|
child.on("error", () => {
|
|
612
848
|
spawnFailed = true;
|
|
613
849
|
});
|
|
614
|
-
child.on("close", (exitCode, signal) => {
|
|
850
|
+
child.on("close", async (exitCode, signal) => {
|
|
615
851
|
clearTimeout(timer);
|
|
852
|
+
if (outputTimer)
|
|
853
|
+
clearInterval(outputTimer);
|
|
854
|
+
if (pendingScan)
|
|
855
|
+
await pendingScan;
|
|
856
|
+
await scanOutputFiles();
|
|
616
857
|
process.off("SIGINT", cancel);
|
|
617
858
|
process.off("SIGTERM", cancel);
|
|
618
859
|
resolvePromise({
|
|
619
|
-
exitCode: spawnFailed ? null : exitCode,
|
|
620
|
-
signal,
|
|
860
|
+
exitCode: supervised ? (supervisorResult?.exitCode ?? null) : spawnFailed ? null : exitCode,
|
|
861
|
+
signal: supervised ? (supervisorResult?.signal ?? signal) : signal,
|
|
621
862
|
startedAt,
|
|
622
863
|
finishedAt: new Date().toISOString(),
|
|
623
864
|
wallSeconds: Number(process.hrtime.bigint() - start) / 1e9,
|
|
@@ -628,8 +869,9 @@ async function captureProcess(binary, args, cwd, env, timeoutSeconds) {
|
|
|
628
869
|
stdoutBytes,
|
|
629
870
|
stderrBytes,
|
|
630
871
|
truncated,
|
|
631
|
-
timedOut,
|
|
872
|
+
timedOut: timedOut || Boolean(supervisorResult?.timedOut),
|
|
632
873
|
cancelled,
|
|
874
|
+
...(outputLimit ? { outputLimitExceeded, observedOutputBytes: outputBytes() } : {}),
|
|
633
875
|
});
|
|
634
876
|
});
|
|
635
877
|
});
|