deepline 0.3.200 → 0.3.202
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/dist/bundling-sources/sdk/src/client.ts +62 -1
- package/dist/bundling-sources/sdk/src/http.ts +55 -6
- package/dist/bundling-sources/sdk/src/index.ts +1 -0
- package/dist/bundling-sources/sdk/src/release.ts +1 -1
- package/dist/bundling-sources/sdk/src/types.ts +10 -2
- package/dist/bundling-sources/shared_libs/play-runtime/app-runtime-api.ts +4 -2
- package/dist/bundling-sources/shared_libs/play-runtime/context.ts +460 -96
- package/dist/bundling-sources/shared_libs/play-runtime/ctx-types.ts +11 -1
- package/dist/bundling-sources/shared_libs/play-runtime/execution-gateway-invocation-fence.ts +6 -2
- package/dist/bundling-sources/shared_libs/play-runtime/fixture-behavior.ts +401 -2
- package/dist/bundling-sources/shared_libs/play-runtime/output-size-limits.ts +458 -0
- package/dist/bundling-sources/shared_libs/play-runtime/provider-no-progress.ts +40 -0
- package/dist/bundling-sources/shared_libs/play-runtime/receipt-sql.ts +7 -0
- package/dist/bundling-sources/shared_libs/play-runtime/run-ledger.ts +25 -3
- package/dist/bundling-sources/shared_libs/play-runtime/runner-app/index.ts +1 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-api.ts +119 -171
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-work-counters.ts +37 -0
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-deadline-reconciliation.ts +160 -58
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-runtime-worker.ts +111 -6
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd.ts +51 -46
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/postgres-rate-state.ts +16 -7
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/postgres.ts +304 -33
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/receipt-gateway.ts +21 -0
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/runtime-receipt-value-storage.ts +64 -15
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/runtime-sandbox-capacity.ts +133 -5
- package/dist/bundling-sources/shared_libs/play-runtime/sheet-attempt-sql.ts +5 -5
- package/dist/bundling-sources/shared_libs/play-runtime/tool-call/index.ts +1 -0
- package/dist/bundling-sources/shared_libs/play-runtime/tool-call/result-receipt-policy.ts +46 -0
- package/dist/bundling-sources/shared_libs/play-runtime/tool-execute-retry-policy.ts +14 -5
- package/dist/bundling-sources/shared_libs/play-runtime/tool-http-errors.ts +5 -1
- package/dist/bundling-sources/shared_libs/play-runtime/work-receipt-state-machine.ts +3 -9
- package/dist/cli/index.js +364 -39
- package/dist/cli/index.mjs +367 -41
- package/dist/index.d.mts +131 -3
- package/dist/index.d.ts +131 -3
- package/dist/index.js +64 -7
- package/dist/index.mjs +64 -7
- package/dist/install-integrity.json +3 -0
- package/dist/release.d.mts +1 -1
- package/dist/release.d.ts +1 -1
- package/dist/release.js +1 -1
- package/dist/release.mjs +1 -1
- package/package.json +1 -1
package/dist/cli/index.mjs
CHANGED
|
@@ -3046,7 +3046,7 @@ var SDK_RELEASE = {
|
|
|
3046
3046
|
// getters keep their established compatibility behavior.
|
|
3047
3047
|
// 0.3.1 deprecated the legacy `deepline enrich` command in favor of Plays.
|
|
3048
3048
|
// 0.3.90 is the first deliberately versioned SDK release for API v3.
|
|
3049
|
-
version: "0.3.
|
|
3049
|
+
version: "0.3.202",
|
|
3050
3050
|
updateSummary: "Play grep now returns concise results with the matched fields and terms. Automatic CLI updates are enabled by default; use `deepline settings autoupdate off` to opt out, `deepline settings autoupdate on` to re-enable updates, or `deepline settings autoupdate pin <version>` to hold an exact release.",
|
|
3051
3051
|
packageCapabilities: {
|
|
3052
3052
|
updatePreferences: 1
|
|
@@ -3637,6 +3637,11 @@ var MAX_DIAGNOSTIC_HEADER_LENGTH = 120;
|
|
|
3637
3637
|
var COWORK_NETWORK_HINT = "Claude Cowork appears to be running Deepline in a network-restricted sandbox. In Claude Desktop, open Settings > Capabilities, turn on Allow network egress, and set Domain allowlist to All domains for the Cowork session.";
|
|
3638
3638
|
var REQUEST_TIMEOUT_MARKER = Symbol("deeplineRequestTimeout");
|
|
3639
3639
|
var REQUEST_ABORT_MARKER = Symbol("deeplineRequestAbort");
|
|
3640
|
+
function requestCancelledError(signal) {
|
|
3641
|
+
const error = withErrorCause(new Error("Request aborted"), signal.reason);
|
|
3642
|
+
error[REQUEST_ABORT_MARKER] = true;
|
|
3643
|
+
return error;
|
|
3644
|
+
}
|
|
3640
3645
|
function normalizeRequestAbortError(error, input2) {
|
|
3641
3646
|
const normalized = error instanceof Error ? error : new Error(String(error));
|
|
3642
3647
|
const tagged = normalized;
|
|
@@ -3815,14 +3820,27 @@ var HttpClient = class {
|
|
|
3815
3820
|
const candidateUrls = options?.exactUrlOnly ? [url] : buildCandidateUrls(url);
|
|
3816
3821
|
let retryAfterDelayMs = null;
|
|
3817
3822
|
const maxRetries = options?.maxRetries ?? this.config.maxRetries;
|
|
3818
|
-
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
3823
|
+
requestAttempts: for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
3824
|
+
if (options?.signal?.aborted) {
|
|
3825
|
+
lastError = requestCancelledError(options.signal);
|
|
3826
|
+
break;
|
|
3827
|
+
}
|
|
3819
3828
|
if (attempt > 0) {
|
|
3820
3829
|
const backoffMs = Math.min(1e3 * Math.pow(2, attempt - 1), 3e4);
|
|
3821
3830
|
const delayMs = retryAfterDelayMs === null ? backoffMs : Math.max(backoffMs, retryAfterDelayMs);
|
|
3822
3831
|
retryAfterDelayMs = null;
|
|
3823
|
-
|
|
3832
|
+
try {
|
|
3833
|
+
await sleep(delayMs, options?.signal);
|
|
3834
|
+
} catch (error) {
|
|
3835
|
+
lastError = error instanceof Error ? error : new Error(String(error));
|
|
3836
|
+
break;
|
|
3837
|
+
}
|
|
3824
3838
|
}
|
|
3825
3839
|
for (const candidateUrl of candidateUrls) {
|
|
3840
|
+
if (options?.signal?.aborted) {
|
|
3841
|
+
lastError = requestCancelledError(options.signal);
|
|
3842
|
+
break requestAttempts;
|
|
3843
|
+
}
|
|
3826
3844
|
const controller = new AbortController();
|
|
3827
3845
|
const timeoutMs = options?.timeout ?? this.config.timeout;
|
|
3828
3846
|
let requestTimedOut = false;
|
|
@@ -3830,6 +3848,10 @@ var HttpClient = class {
|
|
|
3830
3848
|
requestTimedOut = true;
|
|
3831
3849
|
controller.abort();
|
|
3832
3850
|
}, timeoutMs);
|
|
3851
|
+
const abortRequest = () => controller.abort();
|
|
3852
|
+
options?.signal?.addEventListener("abort", abortRequest, {
|
|
3853
|
+
once: true
|
|
3854
|
+
});
|
|
3833
3855
|
try {
|
|
3834
3856
|
const response = await fetch(candidateUrl, {
|
|
3835
3857
|
method,
|
|
@@ -3842,8 +3864,8 @@ var HttpClient = class {
|
|
|
3842
3864
|
clearTimeout(timeoutId);
|
|
3843
3865
|
return null;
|
|
3844
3866
|
}
|
|
3845
|
-
clearTimeout(timeoutId);
|
|
3846
3867
|
const body = await response.text();
|
|
3868
|
+
clearTimeout(timeoutId);
|
|
3847
3869
|
const parsed = parseResponseBody(body);
|
|
3848
3870
|
const structuredToolError = options?.toolId && !response.ok ? deserializeToolExecutionFailure(
|
|
3849
3871
|
apiErrorMessage(parsed, response.status),
|
|
@@ -3938,6 +3960,10 @@ var HttpClient = class {
|
|
|
3938
3960
|
return parsed;
|
|
3939
3961
|
} catch (error) {
|
|
3940
3962
|
clearTimeout(timeoutId);
|
|
3963
|
+
if (options?.signal?.aborted) {
|
|
3964
|
+
lastError = requestCancelledError(options.signal);
|
|
3965
|
+
break requestAttempts;
|
|
3966
|
+
}
|
|
3941
3967
|
if (error instanceof AuthError || error instanceof DeeplineError) {
|
|
3942
3968
|
throw error;
|
|
3943
3969
|
}
|
|
@@ -3949,6 +3975,9 @@ var HttpClient = class {
|
|
|
3949
3975
|
timeoutMs,
|
|
3950
3976
|
timedOut: requestTimedOut
|
|
3951
3977
|
});
|
|
3978
|
+
} finally {
|
|
3979
|
+
clearTimeout(timeoutId);
|
|
3980
|
+
options?.signal?.removeEventListener("abort", abortRequest);
|
|
3952
3981
|
}
|
|
3953
3982
|
}
|
|
3954
3983
|
if (attempt < maxRetries) continue;
|
|
@@ -4277,8 +4306,23 @@ function decodeSseFrame(frame) {
|
|
|
4277
4306
|
}
|
|
4278
4307
|
return parsed;
|
|
4279
4308
|
}
|
|
4280
|
-
function sleep(ms) {
|
|
4281
|
-
return new Promise((resolve22) =>
|
|
4309
|
+
function sleep(ms, signal) {
|
|
4310
|
+
return new Promise((resolve22, reject) => {
|
|
4311
|
+
if (signal?.aborted) {
|
|
4312
|
+
reject(requestCancelledError(signal));
|
|
4313
|
+
return;
|
|
4314
|
+
}
|
|
4315
|
+
const timeoutId = setTimeout(() => {
|
|
4316
|
+
signal?.removeEventListener("abort", abort);
|
|
4317
|
+
resolve22();
|
|
4318
|
+
}, ms);
|
|
4319
|
+
const abort = () => {
|
|
4320
|
+
clearTimeout(timeoutId);
|
|
4321
|
+
signal?.removeEventListener("abort", abort);
|
|
4322
|
+
reject(requestCancelledError(signal));
|
|
4323
|
+
};
|
|
4324
|
+
signal?.addEventListener("abort", abort, { once: true });
|
|
4325
|
+
});
|
|
4282
4326
|
}
|
|
4283
4327
|
function withCoworkNetworkHint(message) {
|
|
4284
4328
|
if (!isCoworkLikeSandbox2() || message.includes(COWORK_NETWORK_HINT)) {
|
|
@@ -5465,9 +5509,13 @@ function normalizePlayRunLedgerSnapshot(value, fallback) {
|
|
|
5465
5509
|
tableNamespace: optionalString(rawDataset.tableNamespace) ?? datasetId,
|
|
5466
5510
|
phase,
|
|
5467
5511
|
persistedRows: Math.max(0, finiteNumber(rawDataset.persistedRows) ?? 0),
|
|
5512
|
+
persistedRowsObserved: rawDataset.persistedRowsObserved === true,
|
|
5468
5513
|
succeededRows: Math.max(0, finiteNumber(rawDataset.succeededRows) ?? 0),
|
|
5514
|
+
succeededRowsObserved: rawDataset.succeededRowsObserved === true,
|
|
5469
5515
|
failedRows: Math.max(0, finiteNumber(rawDataset.failedRows) ?? 0),
|
|
5516
|
+
failedRowsObserved: rawDataset.failedRowsObserved === true,
|
|
5470
5517
|
complete: rawDataset.complete === true,
|
|
5518
|
+
completeObserved: rawDataset.completeObserved === true,
|
|
5471
5519
|
// ADR 0019 birth survives the snapshot round trip. A partial record is
|
|
5472
5520
|
// dropped rather than half-admitted, so a dataset either states where its
|
|
5473
5521
|
// rows came from or says nothing.
|
|
@@ -7207,6 +7255,7 @@ var DeeplineClient = class _DeeplineClient {
|
|
|
7207
7255
|
this.http = new HttpClient(this.config);
|
|
7208
7256
|
this.runs = {
|
|
7209
7257
|
get: (runId, options2) => this.getRunStatus(runId, options2),
|
|
7258
|
+
status: (runId) => this.getRunLifecycleStatus(runId),
|
|
7210
7259
|
list: (options2) => this.listRuns(options2),
|
|
7211
7260
|
listPage: (options2) => this.listRunsPage(options2),
|
|
7212
7261
|
tail: (runId, options2) => this.tailRun(runId, options2),
|
|
@@ -8619,6 +8668,13 @@ var DeeplineClient = class _DeeplineClient {
|
|
|
8619
8668
|
}
|
|
8620
8669
|
};
|
|
8621
8670
|
}
|
|
8671
|
+
/** Read only the bounded scalar projection; does not hydrate the run package. */
|
|
8672
|
+
async getRunLifecycleStatus(runId) {
|
|
8673
|
+
const response = await this.http.get(
|
|
8674
|
+
`/api/v2/runs/${encodeURIComponent(runId)}/status`
|
|
8675
|
+
);
|
|
8676
|
+
return response;
|
|
8677
|
+
}
|
|
8622
8678
|
/**
|
|
8623
8679
|
* List play runs using the public runs resource model.
|
|
8624
8680
|
*
|
|
@@ -9012,7 +9068,8 @@ var DeeplineClient = class _DeeplineClient {
|
|
|
9012
9068
|
params.set("rowMode", "all");
|
|
9013
9069
|
}
|
|
9014
9070
|
const result = await this.http.get(
|
|
9015
|
-
`/api/v2/plays/${encodeURIComponent(input2.playName)}/sheet?${params.toString()}
|
|
9071
|
+
`/api/v2/plays/${encodeURIComponent(input2.playName)}/sheet?${params.toString()}`,
|
|
9072
|
+
{ signal: input2.signal }
|
|
9016
9073
|
);
|
|
9017
9074
|
const requestedRunId = input2.runId?.trim() || "";
|
|
9018
9075
|
if (requestedRunId) {
|
|
@@ -15808,7 +15865,7 @@ import {
|
|
|
15808
15865
|
mkdtemp as mkdtemp3,
|
|
15809
15866
|
readFile as readFile4,
|
|
15810
15867
|
realpath as realpath4,
|
|
15811
|
-
rename,
|
|
15868
|
+
rename as rename2,
|
|
15812
15869
|
rm as rm3,
|
|
15813
15870
|
stat as stat4,
|
|
15814
15871
|
writeFile as writeFile4
|
|
@@ -15833,6 +15890,7 @@ import {
|
|
|
15833
15890
|
link,
|
|
15834
15891
|
open,
|
|
15835
15892
|
readFile as readFileAsync,
|
|
15893
|
+
rename,
|
|
15836
15894
|
unlink
|
|
15837
15895
|
} from "fs/promises";
|
|
15838
15896
|
import {
|
|
@@ -20734,6 +20792,12 @@ var FIXTURE_BEHAVIOR_REPLAY_VERSION = 3;
|
|
|
20734
20792
|
var MAX_FIXTURE_RESPONSE_DELAY_SAMPLES = 256;
|
|
20735
20793
|
var MAX_FIXTURE_RESPONSE_DELAY_MS = 8 * 6e4;
|
|
20736
20794
|
var MAX_FIXTURE_RESPONSE_ERROR_MESSAGE_LENGTH = 500;
|
|
20795
|
+
var MAX_FIXTURE_RETRY_AFTER_MS = 60 * 6e4;
|
|
20796
|
+
var FIXTURE_RATE_WINDOWS = [
|
|
20797
|
+
{ field: "requestsPerSecond", name: "rps", windowMs: 1e3 },
|
|
20798
|
+
{ field: "requestsPerMinute", name: "rpm", windowMs: 6e4 },
|
|
20799
|
+
{ field: "requestsPerHour", name: "rph", windowMs: 36e5 }
|
|
20800
|
+
];
|
|
20737
20801
|
function validateFixtureBehavior(value) {
|
|
20738
20802
|
if (value === void 0 || value === null) {
|
|
20739
20803
|
return { ok: true, behavior: null };
|
|
@@ -20745,6 +20809,8 @@ function validateFixtureBehavior(value) {
|
|
|
20745
20809
|
const supportedKeys = record3.version === FIXTURE_BEHAVIOR_RESPONSE_VERSION || record3.version === FIXTURE_BEHAVIOR_REPLAY_VERSION ? /* @__PURE__ */ new Set([
|
|
20746
20810
|
"version",
|
|
20747
20811
|
"responseSamples",
|
|
20812
|
+
"transient429",
|
|
20813
|
+
"sharedRateLimit",
|
|
20748
20814
|
...record3.version === FIXTURE_BEHAVIOR_REPLAY_VERSION ? ["replayBundle"] : []
|
|
20749
20815
|
]) : /* @__PURE__ */ new Set(["version", "responseDelaySamplesMs"]);
|
|
20750
20816
|
const unknownKeys = Object.keys(record3).filter(
|
|
@@ -20841,7 +20907,7 @@ function validateFixtureBehavior(value) {
|
|
|
20841
20907
|
}
|
|
20842
20908
|
const error = sample.httpError;
|
|
20843
20909
|
const errorUnknownKeys = Object.keys(error).filter(
|
|
20844
|
-
(key) => key !== "status" && key !== "message"
|
|
20910
|
+
(key) => key !== "status" && key !== "message" && key !== "retryAfterMs" && key !== "retryAfterFormat" && key !== "failuresBeforeSuccess"
|
|
20845
20911
|
);
|
|
20846
20912
|
if (errorUnknownKeys.length > 0) {
|
|
20847
20913
|
return {
|
|
@@ -20861,7 +20927,33 @@ function validateFixtureBehavior(value) {
|
|
|
20861
20927
|
error: `fixtureBehavior.responseSamples[${index}].httpError.message must contain 1-${MAX_FIXTURE_RESPONSE_ERROR_MESSAGE_LENGTH} characters.`
|
|
20862
20928
|
};
|
|
20863
20929
|
}
|
|
20864
|
-
|
|
20930
|
+
if (error.retryAfterMs !== void 0 && (error.status !== 429 || typeof error.retryAfterMs !== "number" || !Number.isSafeInteger(error.retryAfterMs) || error.retryAfterMs < 1 || error.retryAfterMs > MAX_FIXTURE_RETRY_AFTER_MS)) {
|
|
20931
|
+
return {
|
|
20932
|
+
ok: false,
|
|
20933
|
+
error: `fixtureBehavior.responseSamples[${index}].httpError.retryAfterMs requires status 429 and an integer from 1 through ${MAX_FIXTURE_RETRY_AFTER_MS}.`
|
|
20934
|
+
};
|
|
20935
|
+
}
|
|
20936
|
+
if (error.retryAfterFormat !== void 0 && (error.status !== 429 || error.retryAfterFormat !== "delta_seconds" && error.retryAfterFormat !== "http_date")) {
|
|
20937
|
+
return {
|
|
20938
|
+
ok: false,
|
|
20939
|
+
error: `fixtureBehavior.responseSamples[${index}].httpError.retryAfterFormat requires status 429 and delta_seconds or http_date.`
|
|
20940
|
+
};
|
|
20941
|
+
}
|
|
20942
|
+
if (error.failuresBeforeSuccess !== void 0 && (error.status !== 429 || typeof error.failuresBeforeSuccess !== "number" || !Number.isSafeInteger(error.failuresBeforeSuccess) || error.failuresBeforeSuccess < 1 || error.failuresBeforeSuccess > 20)) {
|
|
20943
|
+
return {
|
|
20944
|
+
ok: false,
|
|
20945
|
+
error: `fixtureBehavior.responseSamples[${index}].httpError.failuresBeforeSuccess requires status 429 and an integer from 1 through 20.`
|
|
20946
|
+
};
|
|
20947
|
+
}
|
|
20948
|
+
httpError = {
|
|
20949
|
+
status: error.status,
|
|
20950
|
+
message: error.message.trim(),
|
|
20951
|
+
...error.retryAfterMs !== void 0 ? { retryAfterMs: error.retryAfterMs } : {},
|
|
20952
|
+
...error.retryAfterFormat !== void 0 ? {
|
|
20953
|
+
retryAfterFormat: error.retryAfterFormat
|
|
20954
|
+
} : {},
|
|
20955
|
+
...error.failuresBeforeSuccess !== void 0 ? { failuresBeforeSuccess: error.failuresBeforeSuccess } : {}
|
|
20956
|
+
};
|
|
20865
20957
|
}
|
|
20866
20958
|
samples2.push({
|
|
20867
20959
|
delayMs: sample.delayMs,
|
|
@@ -20869,6 +20961,106 @@ function validateFixtureBehavior(value) {
|
|
|
20869
20961
|
...httpError ? { httpError } : {}
|
|
20870
20962
|
});
|
|
20871
20963
|
}
|
|
20964
|
+
let sharedRateLimit;
|
|
20965
|
+
if (record3.sharedRateLimit !== void 0) {
|
|
20966
|
+
const plan = record3.sharedRateLimit;
|
|
20967
|
+
if (!plan || typeof plan !== "object" || Array.isArray(plan)) {
|
|
20968
|
+
return {
|
|
20969
|
+
ok: false,
|
|
20970
|
+
error: "fixtureBehavior.sharedRateLimit must be an object."
|
|
20971
|
+
};
|
|
20972
|
+
}
|
|
20973
|
+
const planRecord = plan;
|
|
20974
|
+
const entries = Object.entries(planRecord);
|
|
20975
|
+
const boundaryAfterMs = planRecord.requestsPerHourBoundaryAfterMs;
|
|
20976
|
+
const quotaEntries = entries.filter(
|
|
20977
|
+
([name]) => name !== "requestsPerHourBoundaryAfterMs"
|
|
20978
|
+
);
|
|
20979
|
+
if (quotaEntries.length === 0 || quotaEntries.some(
|
|
20980
|
+
([name, limit]) => !FIXTURE_RATE_WINDOWS.some((window) => window.field === name) || typeof limit !== "number" || !Number.isSafeInteger(limit) || limit < 1
|
|
20981
|
+
)) {
|
|
20982
|
+
return {
|
|
20983
|
+
ok: false,
|
|
20984
|
+
error: "fixtureBehavior.sharedRateLimit requires positive integer requestsPerSecond, requestsPerMinute, or requestsPerHour quotas."
|
|
20985
|
+
};
|
|
20986
|
+
}
|
|
20987
|
+
if (boundaryAfterMs !== void 0 && (planRecord.requestsPerHour === void 0 || typeof boundaryAfterMs !== "number" || !Number.isSafeInteger(boundaryAfterMs) || boundaryAfterMs < 1e3 || boundaryAfterMs > 3e5)) {
|
|
20988
|
+
return {
|
|
20989
|
+
ok: false,
|
|
20990
|
+
error: "fixtureBehavior.sharedRateLimit.requestsPerHourBoundaryAfterMs requires requestsPerHour and an integer from 1000 through 300000."
|
|
20991
|
+
};
|
|
20992
|
+
}
|
|
20993
|
+
sharedRateLimit = Object.fromEntries(entries);
|
|
20994
|
+
}
|
|
20995
|
+
let transient429;
|
|
20996
|
+
if (record3.transient429 !== void 0) {
|
|
20997
|
+
const selected = record3.transient429;
|
|
20998
|
+
if (!selected || typeof selected !== "object" || Array.isArray(selected)) {
|
|
20999
|
+
return {
|
|
21000
|
+
ok: false,
|
|
21001
|
+
error: "fixtureBehavior.transient429 must be an object."
|
|
21002
|
+
};
|
|
21003
|
+
}
|
|
21004
|
+
const fault = selected;
|
|
21005
|
+
const unknownFaultKeys = Object.keys(fault).filter(
|
|
21006
|
+
(key) => key !== "everyNthCall" && key !== "retryAfterMs" && key !== "failuresBeforeSuccess" && key !== "when"
|
|
21007
|
+
);
|
|
21008
|
+
if (unknownFaultKeys.length > 0) {
|
|
21009
|
+
return {
|
|
21010
|
+
ok: false,
|
|
21011
|
+
error: `Unsupported fixtureBehavior.transient429 field "${unknownFaultKeys[0]}".`
|
|
21012
|
+
};
|
|
21013
|
+
}
|
|
21014
|
+
for (const [name, value2, max] of [
|
|
21015
|
+
["everyNthCall", fault.everyNthCall, 1e4],
|
|
21016
|
+
["retryAfterMs", fault.retryAfterMs, MAX_FIXTURE_RETRY_AFTER_MS],
|
|
21017
|
+
["failuresBeforeSuccess", fault.failuresBeforeSuccess, 20]
|
|
21018
|
+
]) {
|
|
21019
|
+
if (typeof value2 !== "number" || !Number.isSafeInteger(value2) || value2 < 1 || value2 > max) {
|
|
21020
|
+
return {
|
|
21021
|
+
ok: false,
|
|
21022
|
+
error: `fixtureBehavior.transient429.${name} must be an integer from 1 through ${max}.`
|
|
21023
|
+
};
|
|
21024
|
+
}
|
|
21025
|
+
}
|
|
21026
|
+
let when;
|
|
21027
|
+
if (fault.when !== void 0) {
|
|
21028
|
+
if (!fault.when || typeof fault.when !== "object" || Array.isArray(fault.when)) {
|
|
21029
|
+
return {
|
|
21030
|
+
ok: false,
|
|
21031
|
+
error: "fixtureBehavior.transient429.when must be an object."
|
|
21032
|
+
};
|
|
21033
|
+
}
|
|
21034
|
+
const condition = fault.when;
|
|
21035
|
+
const unknownConditionKeys = Object.keys(condition).filter(
|
|
21036
|
+
(key) => key !== "provider" && key !== "operation"
|
|
21037
|
+
);
|
|
21038
|
+
if (unknownConditionKeys.length > 0) {
|
|
21039
|
+
return {
|
|
21040
|
+
ok: false,
|
|
21041
|
+
error: `Unsupported fixtureBehavior.transient429.when field "${unknownConditionKeys[0]}".`
|
|
21042
|
+
};
|
|
21043
|
+
}
|
|
21044
|
+
const provider = normalizeFixtureScopeValue(condition.provider, 100);
|
|
21045
|
+
const operation = normalizeFixtureScopeValue(condition.operation, 200);
|
|
21046
|
+
if (provider.error || operation.error || !provider.value && !operation.value) {
|
|
21047
|
+
return {
|
|
21048
|
+
ok: false,
|
|
21049
|
+
error: "fixtureBehavior.transient429.when must select a valid provider or operation."
|
|
21050
|
+
};
|
|
21051
|
+
}
|
|
21052
|
+
when = {
|
|
21053
|
+
...provider.value ? { provider: provider.value } : {},
|
|
21054
|
+
...operation.value ? { operation: operation.value } : {}
|
|
21055
|
+
};
|
|
21056
|
+
}
|
|
21057
|
+
transient429 = {
|
|
21058
|
+
everyNthCall: fault.everyNthCall,
|
|
21059
|
+
retryAfterMs: fault.retryAfterMs,
|
|
21060
|
+
failuresBeforeSuccess: fault.failuresBeforeSuccess,
|
|
21061
|
+
...when ? { when } : {}
|
|
21062
|
+
};
|
|
21063
|
+
}
|
|
20872
21064
|
let replayBundle;
|
|
20873
21065
|
if (record3.version === FIXTURE_BEHAVIOR_REPLAY_VERSION) {
|
|
20874
21066
|
if (!record3.replayBundle || typeof record3.replayBundle !== "object" || Array.isArray(record3.replayBundle)) {
|
|
@@ -20931,6 +21123,8 @@ function validateFixtureBehavior(value) {
|
|
|
20931
21123
|
behavior: {
|
|
20932
21124
|
version: FIXTURE_BEHAVIOR_REPLAY_VERSION,
|
|
20933
21125
|
responseSamples: samples2,
|
|
21126
|
+
...transient429 ? { transient429 } : {},
|
|
21127
|
+
...sharedRateLimit ? { sharedRateLimit } : {},
|
|
20934
21128
|
replayBundle
|
|
20935
21129
|
}
|
|
20936
21130
|
};
|
|
@@ -20939,7 +21133,9 @@ function validateFixtureBehavior(value) {
|
|
|
20939
21133
|
ok: true,
|
|
20940
21134
|
behavior: {
|
|
20941
21135
|
version: FIXTURE_BEHAVIOR_RESPONSE_VERSION,
|
|
20942
|
-
responseSamples: samples2
|
|
21136
|
+
responseSamples: samples2,
|
|
21137
|
+
...transient429 ? { transient429 } : {},
|
|
21138
|
+
...sharedRateLimit ? { sharedRateLimit } : {}
|
|
20943
21139
|
}
|
|
20944
21140
|
};
|
|
20945
21141
|
}
|
|
@@ -22823,43 +23019,52 @@ async function readRunIdFile(destination) {
|
|
|
22823
23019
|
}
|
|
22824
23020
|
return parsed;
|
|
22825
23021
|
}
|
|
22826
|
-
async function writePlayRunIdFile(destination, runId) {
|
|
23022
|
+
async function writePlayRunIdFile(destination, runId, options = {}) {
|
|
22827
23023
|
const existing = await readRunIdFile(destination);
|
|
22828
23024
|
if (existing) {
|
|
22829
|
-
if (existing.runId
|
|
22830
|
-
|
|
22831
|
-
|
|
22832
|
-
|
|
23025
|
+
if (existing.runId !== runId) {
|
|
23026
|
+
throw new Error(
|
|
23027
|
+
`--run-id-file destination already records run ${existing.runId}; refusing to replace it with ${runId}: ${destination}`
|
|
23028
|
+
);
|
|
23029
|
+
}
|
|
23030
|
+
if (!options.launchConfirmed || existing.launchConfirmed) return;
|
|
22833
23031
|
}
|
|
22834
23032
|
const tempPath = runIdFileTempPath(destination);
|
|
22835
23033
|
let handle = null;
|
|
22836
23034
|
try {
|
|
22837
23035
|
handle = await open(tempPath, "wx", 384);
|
|
22838
23036
|
await handle.writeFile(
|
|
22839
|
-
`${JSON.stringify({ version: 1, runId })}
|
|
23037
|
+
`${JSON.stringify({ version: 1, runId, ...options })}
|
|
22840
23038
|
`,
|
|
22841
23039
|
"utf8"
|
|
22842
23040
|
);
|
|
22843
23041
|
await handle.sync();
|
|
22844
23042
|
await handle.close();
|
|
22845
23043
|
handle = null;
|
|
22846
|
-
|
|
22847
|
-
await
|
|
22848
|
-
|
|
22849
|
-
|
|
22850
|
-
|
|
22851
|
-
|
|
22852
|
-
|
|
22853
|
-
|
|
23044
|
+
if (existing) {
|
|
23045
|
+
await rename(tempPath, destination);
|
|
23046
|
+
} else {
|
|
23047
|
+
try {
|
|
23048
|
+
await link(tempPath, destination);
|
|
23049
|
+
} catch (error) {
|
|
23050
|
+
if (error.code !== "EEXIST") throw error;
|
|
23051
|
+
const raced = await readRunIdFile(destination);
|
|
23052
|
+
if (raced?.runId !== runId) {
|
|
23053
|
+
throw new Error(
|
|
23054
|
+
`--run-id-file destination already records run ${raced?.runId ?? "<invalid>"}; refusing to replace it with ${runId}: ${destination}`
|
|
23055
|
+
);
|
|
22854
23056
|
}
|
|
23057
|
+
if (!options.launchConfirmed || raced.launchConfirmed) return;
|
|
23058
|
+
await rename(tempPath, destination);
|
|
23059
|
+
}
|
|
23060
|
+
}
|
|
23061
|
+
if (process.platform !== "win32") {
|
|
23062
|
+
const directory = await open(dirname10(destination), "r");
|
|
23063
|
+
try {
|
|
23064
|
+
await directory.sync();
|
|
23065
|
+
} finally {
|
|
23066
|
+
await directory.close();
|
|
22855
23067
|
}
|
|
22856
|
-
} catch (error) {
|
|
22857
|
-
if (error.code !== "EEXIST") throw error;
|
|
22858
|
-
const raced = await readRunIdFile(destination);
|
|
22859
|
-
if (raced?.runId === runId) return;
|
|
22860
|
-
throw new Error(
|
|
22861
|
-
`--run-id-file destination already records run ${raced?.runId ?? "<invalid>"}; refusing to replace it with ${runId}: ${destination}`
|
|
22862
|
-
);
|
|
22863
23068
|
}
|
|
22864
23069
|
} finally {
|
|
22865
23070
|
await handle?.close();
|
|
@@ -23916,6 +24121,16 @@ function getRunIdFromLiveEvent(event) {
|
|
|
23916
24121
|
function eventConfirmsPlayRunLaunch(event) {
|
|
23917
24122
|
return event.type === "play.run.status" && getEventPayload(event).launchConfirmed === true;
|
|
23918
24123
|
}
|
|
24124
|
+
function statusProvesPlayRunExecution(status) {
|
|
24125
|
+
return status === "waiting" || status === "completed";
|
|
24126
|
+
}
|
|
24127
|
+
function eventProvesPlayRunExecution(event) {
|
|
24128
|
+
if (statusProvesPlayRunExecution(getStatusFromLiveEvent(event))) return true;
|
|
24129
|
+
const payload = getEventPayload(event);
|
|
24130
|
+
return Boolean(getStringField(payload, "stepId")) && (event.type === "play.step.progress" || event.type === "play.step.status" && ["running", "completed", "failed", "skipped"].includes(
|
|
24131
|
+
getStringField(payload, "status") ?? ""
|
|
24132
|
+
));
|
|
24133
|
+
}
|
|
23919
24134
|
function getStatusFromLiveEvent(event) {
|
|
23920
24135
|
if (event.type !== "play.run.status" && event.type !== "play.run.snapshot" && event.type !== "play.run.final_status") {
|
|
23921
24136
|
return null;
|
|
@@ -24392,6 +24607,12 @@ async function waitForPlayCompletionByStream(input2) {
|
|
|
24392
24607
|
const durableStatusProbeIntervalMs = input2.durableStatusProbeIntervalMs ?? PLAY_DURABLE_STATUS_PROBE_INTERVAL_MS;
|
|
24393
24608
|
let nextDurableProbeAt = Date.now() + durableStatusProbeIntervalMs;
|
|
24394
24609
|
let durableStatusProbe = null;
|
|
24610
|
+
let admissionConfirmed = false;
|
|
24611
|
+
const confirmAdmission = async () => {
|
|
24612
|
+
if (admissionConfirmed) return;
|
|
24613
|
+
admissionConfirmed = true;
|
|
24614
|
+
await input2.onRunAdmitted?.(input2.workflowId);
|
|
24615
|
+
};
|
|
24395
24616
|
const withDashboardUrl = (status) => input2.dashboardUrl ? { ...status, dashboardUrl: input2.dashboardUrl } : status;
|
|
24396
24617
|
const remainingWaitMs = () => input2.waitTimeoutMs === null ? null : input2.waitTimeoutMs - (Date.now() - input2.startedAt);
|
|
24397
24618
|
const fetchTerminalStatus = async () => {
|
|
@@ -24408,6 +24629,9 @@ async function waitForPlayCompletionByStream(input2) {
|
|
|
24408
24629
|
}
|
|
24409
24630
|
throw error;
|
|
24410
24631
|
}
|
|
24632
|
+
if (refreshed.runId === input2.workflowId && statusProvesPlayRunExecution(refreshed.status)) {
|
|
24633
|
+
await confirmAdmission();
|
|
24634
|
+
}
|
|
24411
24635
|
return TERMINAL_PLAY_STATUSES2.has(refreshed.status) ? withDashboardUrl(refreshed) : null;
|
|
24412
24636
|
})();
|
|
24413
24637
|
durableStatusProbe = probe;
|
|
@@ -24419,6 +24643,9 @@ async function waitForPlayCompletionByStream(input2) {
|
|
|
24419
24643
|
};
|
|
24420
24644
|
const handleLiveEvent = async (event, probeDurableStatus) => {
|
|
24421
24645
|
assertPlayWaitNotTimedOut({ ...input2, lastPhase });
|
|
24646
|
+
if (getRunIdFromLiveEvent(event) === input2.workflowId && (eventConfirmsPlayRunLaunch(event) || eventProvesPlayRunExecution(event))) {
|
|
24647
|
+
await confirmAdmission();
|
|
24648
|
+
}
|
|
24422
24649
|
const now = Date.now();
|
|
24423
24650
|
if (now >= nextDurableProbeAt) {
|
|
24424
24651
|
nextDurableProbeAt = now + durableStatusProbeIntervalMs;
|
|
@@ -24668,6 +24895,11 @@ async function startAndWaitForPlayCompletionByStreamOnce(input2) {
|
|
|
24668
24895
|
let eventCount = 0;
|
|
24669
24896
|
let firstRunIdMs = null;
|
|
24670
24897
|
let launchConfirmed = false;
|
|
24898
|
+
const confirmAdmission = async (runId) => {
|
|
24899
|
+
if (launchConfirmed || !runId || runId === "pending") return;
|
|
24900
|
+
launchConfirmed = true;
|
|
24901
|
+
await input2.onRunAdmitted?.(runId);
|
|
24902
|
+
};
|
|
24671
24903
|
let lastPhase = null;
|
|
24672
24904
|
const timeout = input2.waitTimeoutMs === null ? null : setTimeout(
|
|
24673
24905
|
() => {
|
|
@@ -24691,6 +24923,9 @@ async function startAndWaitForPlayCompletionByStreamOnce(input2) {
|
|
|
24691
24923
|
}
|
|
24692
24924
|
throw error;
|
|
24693
24925
|
}
|
|
24926
|
+
if (refreshed.runId === lastKnownWorkflowId && statusProvesPlayRunExecution(refreshed.status)) {
|
|
24927
|
+
await confirmAdmission(lastKnownWorkflowId);
|
|
24928
|
+
}
|
|
24694
24929
|
return TERMINAL_PLAY_STATUSES2.has(refreshed.status) ? {
|
|
24695
24930
|
...refreshed,
|
|
24696
24931
|
dashboardUrl,
|
|
@@ -24718,8 +24953,8 @@ async function startAndWaitForPlayCompletionByStreamOnce(input2) {
|
|
|
24718
24953
|
await input2.onRunStarted?.(eventRunId);
|
|
24719
24954
|
}
|
|
24720
24955
|
}
|
|
24721
|
-
if (eventConfirmsPlayRunLaunch(event) && eventRunId === lastKnownWorkflowId) {
|
|
24722
|
-
|
|
24956
|
+
if (!launchConfirmed && eventConfirmsPlayRunLaunch(event) && eventRunId === lastKnownWorkflowId) {
|
|
24957
|
+
await confirmAdmission(lastKnownWorkflowId);
|
|
24723
24958
|
}
|
|
24724
24959
|
const workflowId = lastKnownWorkflowId || "pending";
|
|
24725
24960
|
if (workflowId !== "pending" && !emittedDashboardUrl) {
|
|
@@ -24834,6 +25069,9 @@ async function startAndWaitForPlayCompletionByStreamOnce(input2) {
|
|
|
24834
25069
|
firstRunIdMs,
|
|
24835
25070
|
lastPhase
|
|
24836
25071
|
});
|
|
25072
|
+
if (statusProvesPlayRunExecution(canonicalTerminal.status)) {
|
|
25073
|
+
await confirmAdmission(lastKnownWorkflowId);
|
|
25074
|
+
}
|
|
24837
25075
|
return canonicalTerminal;
|
|
24838
25076
|
}
|
|
24839
25077
|
if (lastKnownWorkflowId && launchConfirmed) {
|
|
@@ -24861,7 +25099,8 @@ async function startAndWaitForPlayCompletionByStreamOnce(input2) {
|
|
|
24861
25099
|
waitTimeoutMs: input2.waitTimeoutMs,
|
|
24862
25100
|
startedAt,
|
|
24863
25101
|
state,
|
|
24864
|
-
progress: input2.progress
|
|
25102
|
+
progress: input2.progress,
|
|
25103
|
+
onRunAdmitted: confirmAdmission
|
|
24865
25104
|
});
|
|
24866
25105
|
}
|
|
24867
25106
|
}
|
|
@@ -24921,7 +25160,8 @@ async function startAndWaitForPlayCompletionByStreamOnce(input2) {
|
|
|
24921
25160
|
waitTimeoutMs: input2.waitTimeoutMs,
|
|
24922
25161
|
startedAt,
|
|
24923
25162
|
state,
|
|
24924
|
-
progress: input2.progress
|
|
25163
|
+
progress: input2.progress,
|
|
25164
|
+
onRunAdmitted: confirmAdmission
|
|
24925
25165
|
});
|
|
24926
25166
|
}
|
|
24927
25167
|
if (!lastKnownWorkflowId && isTransientPlayStreamError(error)) {
|
|
@@ -24974,7 +25214,8 @@ async function startAndWaitForPlayCompletionByStreamOnce(input2) {
|
|
|
24974
25214
|
waitTimeoutMs: input2.waitTimeoutMs,
|
|
24975
25215
|
startedAt,
|
|
24976
25216
|
state,
|
|
24977
|
-
progress: input2.progress
|
|
25217
|
+
progress: input2.progress,
|
|
25218
|
+
onRunAdmitted: confirmAdmission
|
|
24978
25219
|
});
|
|
24979
25220
|
}
|
|
24980
25221
|
const phaseSuffix = lastPhase && lastPhase.trim() ? ` (last observed phase: ${lastPhase.trim()})` : "";
|
|
@@ -25917,8 +26158,15 @@ function formatPackageDatasetActionLines(packaged, options) {
|
|
|
25917
26158
|
const isReturned = datasetId && returned.datasetIds.has(datasetId) || returned.paths.has(path);
|
|
25918
26159
|
const category = isReturned ? "returned" : dataset.recovered === true ? "recovered" : "persisted";
|
|
25919
26160
|
const rowCount = typeof dataset.rowCount === "number" && Number.isFinite(dataset.rowCount) ? Math.max(0, Math.trunc(dataset.rowCount)) : null;
|
|
26161
|
+
const lifecycle = readRecord(dataset.lifecycle);
|
|
26162
|
+
const countUnconfirmed = lifecycle?.complete === false;
|
|
26163
|
+
const persistedLowerBound = typeof lifecycle?.persistedRowsAtLeast === "number" && Number.isFinite(lifecycle.persistedRowsAtLeast) ? Math.max(0, Math.trunc(lifecycle.persistedRowsAtLeast)) : 0;
|
|
25920
26164
|
const actions = readRecord(dataset.actions) ?? {};
|
|
25921
|
-
if (
|
|
26165
|
+
if (countUnconfirmed) {
|
|
26166
|
+
lines.push(
|
|
26167
|
+
` dataset ${path}: row count unconfirmed (at least ${formatInteger(persistedLowerBound)} persisted); export this run to inspect saved rows`
|
|
26168
|
+
);
|
|
26169
|
+
} else if (includeSummary) {
|
|
25922
26170
|
if (category === "recovered" && Object.keys(actions).length === 0) {
|
|
25923
26171
|
lines.push(
|
|
25924
26172
|
` dataset ${path}: available, ${rowCount === null ? "persisted" : formatInteger(rowCount)} rows persisted; re-running reuses completed work`
|
|
@@ -28266,7 +28514,8 @@ async function handleFileBackedRun(options, hooks) {
|
|
|
28266
28514
|
waitTimeoutMs: options.waitTimeoutMs,
|
|
28267
28515
|
open: options.open,
|
|
28268
28516
|
progress,
|
|
28269
|
-
onRunStarted: hooks?.onRunStarted
|
|
28517
|
+
onRunStarted: hooks?.onRunStarted,
|
|
28518
|
+
onRunAdmitted: hooks?.onRunAdmitted
|
|
28270
28519
|
}).catch(async (error) => {
|
|
28271
28520
|
throw await normalizePlayStartError(client2, error, playName);
|
|
28272
28521
|
})
|
|
@@ -28307,6 +28556,7 @@ async function handleFileBackedRun(options, hooks) {
|
|
|
28307
28556
|
})
|
|
28308
28557
|
);
|
|
28309
28558
|
await hooks?.onRunStarted?.(started.workflowId);
|
|
28559
|
+
await hooks?.onRunAdmitted?.(started.workflowId);
|
|
28310
28560
|
const resolvedDashboardUrl = buildPlayDashboardUrl(client2.baseUrl, playName);
|
|
28311
28561
|
openPlayDashboard(resolvedDashboardUrl, options.open);
|
|
28312
28562
|
progress.phase("started run");
|
|
@@ -28449,7 +28699,8 @@ async function handleNamedRun(options, hooks) {
|
|
|
28449
28699
|
waitTimeoutMs: options.waitTimeoutMs,
|
|
28450
28700
|
open: options.open,
|
|
28451
28701
|
progress,
|
|
28452
|
-
onRunStarted: hooks?.onRunStarted
|
|
28702
|
+
onRunStarted: hooks?.onRunStarted,
|
|
28703
|
+
onRunAdmitted: hooks?.onRunAdmitted
|
|
28453
28704
|
}).catch(async (error) => {
|
|
28454
28705
|
throw await normalizePlayStartError(client2, error, playName, {
|
|
28455
28706
|
suggestMissingPlay: true
|
|
@@ -28495,6 +28746,7 @@ async function handleNamedRun(options, hooks) {
|
|
|
28495
28746
|
})
|
|
28496
28747
|
);
|
|
28497
28748
|
await hooks?.onRunStarted?.(started.workflowId);
|
|
28749
|
+
await hooks?.onRunAdmitted?.(started.workflowId);
|
|
28498
28750
|
const resolvedDashboardUrl = buildPlayDashboardUrl(client2.baseUrl, playName);
|
|
28499
28751
|
openPlayDashboard(resolvedDashboardUrl, options.open);
|
|
28500
28752
|
progress.phase("started run");
|
|
@@ -28532,6 +28784,19 @@ async function handlePlayRun(args, hooks) {
|
|
|
28532
28784
|
);
|
|
28533
28785
|
}
|
|
28534
28786
|
await hooks?.onRunStarted?.(runId);
|
|
28787
|
+
},
|
|
28788
|
+
onRunAdmitted: async (runId) => {
|
|
28789
|
+
try {
|
|
28790
|
+
await writePlayRunIdFile(options.runIdFile, runId, {
|
|
28791
|
+
launchConfirmed: true
|
|
28792
|
+
});
|
|
28793
|
+
} catch (error) {
|
|
28794
|
+
throw new Error(
|
|
28795
|
+
`Run ${runId} was admitted, but its confirmation could not be persisted to ${options.runIdFile}: ${error instanceof Error ? error.message : String(error)}. Inspect it with 'deepline runs get ${runId} --json'; do not submit a replacement run.`,
|
|
28796
|
+
{ cause: error }
|
|
28797
|
+
);
|
|
28798
|
+
}
|
|
28799
|
+
await hooks?.onRunAdmitted?.(runId);
|
|
28535
28800
|
}
|
|
28536
28801
|
} : hooks;
|
|
28537
28802
|
if (options.target.kind === "file") {
|
|
@@ -28604,6 +28869,36 @@ async function handleRunGet(args) {
|
|
|
28604
28869
|
});
|
|
28605
28870
|
return 0;
|
|
28606
28871
|
}
|
|
28872
|
+
async function handleRunLifecycleStatus(args) {
|
|
28873
|
+
const usage = "Usage: deepline runs status <run-id> [--json]";
|
|
28874
|
+
let runId;
|
|
28875
|
+
try {
|
|
28876
|
+
runId = parseRunIdPositional(args, usage);
|
|
28877
|
+
} catch (error) {
|
|
28878
|
+
console.error(error instanceof Error ? error.message : usage);
|
|
28879
|
+
return 1;
|
|
28880
|
+
}
|
|
28881
|
+
const status = await new DeeplineClient().runs.status(runId);
|
|
28882
|
+
if (argsWantJson(args)) {
|
|
28883
|
+
printCommandEnvelope(status, { json: true });
|
|
28884
|
+
return 0;
|
|
28885
|
+
}
|
|
28886
|
+
if (!status.available) {
|
|
28887
|
+
console.log(`Scalar lifecycle status is not available for run ${runId}.`);
|
|
28888
|
+
return 0;
|
|
28889
|
+
}
|
|
28890
|
+
const formatCount = (count) => count.value === null ? "unknown" : `${count.value}${count.confirmed ? "" : " (unconfirmed)"}`;
|
|
28891
|
+
console.log(`${status.lifecycle.status} \xB7 ${runId}`);
|
|
28892
|
+
console.log(
|
|
28893
|
+
`Map-step work (summed, not unique rows): completed ${formatCount(status.mapStepWork.completed)} / ${formatCount(status.mapStepWork.total)}, failed ${formatCount(status.mapStepWork.failed)}`
|
|
28894
|
+
);
|
|
28895
|
+
if (status.lifecycle.status === "waiting") {
|
|
28896
|
+
console.log(
|
|
28897
|
+
status.wait.confirmed && status.wait.kind ? `Waiting: ${status.wait.kind}` : "Waiting reason: unknown"
|
|
28898
|
+
);
|
|
28899
|
+
}
|
|
28900
|
+
return 0;
|
|
28901
|
+
}
|
|
28607
28902
|
async function handleRunsRerun(args) {
|
|
28608
28903
|
const usage = "Usage: deepline runs rerun <run-id> [--idempotency-key <key>] [--json]";
|
|
28609
28904
|
let runId;
|
|
@@ -29076,6 +29371,30 @@ async function handleRunStop(args) {
|
|
|
29076
29371
|
}
|
|
29077
29372
|
const client2 = new DeeplineClient();
|
|
29078
29373
|
const result = await client2.runs.stop(runId, { reason });
|
|
29374
|
+
if (result.cancelling === true) {
|
|
29375
|
+
printCommandEnvelope(
|
|
29376
|
+
{
|
|
29377
|
+
...result,
|
|
29378
|
+
render: {
|
|
29379
|
+
sections: [
|
|
29380
|
+
{
|
|
29381
|
+
title: "run stop",
|
|
29382
|
+
lines: [
|
|
29383
|
+
`Cancellation queued for ${result.runId || runId}; sandbox cleanup is pending`,
|
|
29384
|
+
...result.hitlCancelledCount > 0 ? [`cancelled HITL waits: ${result.hitlCancelledCount}`] : [],
|
|
29385
|
+
...result.hitlCancellationPending === true ? [
|
|
29386
|
+
"warning: HITL cancellation or same-card Slack refresh is still pending"
|
|
29387
|
+
] : [],
|
|
29388
|
+
`inspect: deepline runs get ${runId} --full --json`
|
|
29389
|
+
]
|
|
29390
|
+
}
|
|
29391
|
+
]
|
|
29392
|
+
}
|
|
29393
|
+
},
|
|
29394
|
+
{ json: argsWantJson(args) }
|
|
29395
|
+
);
|
|
29396
|
+
return 0;
|
|
29397
|
+
}
|
|
29079
29398
|
const stopNotConfirmed = result.stopped === false || result.staleSchedulerState === true;
|
|
29080
29399
|
if (stopNotConfirmed) {
|
|
29081
29400
|
const detail = typeof result.error === "string" && result.error.trim() ? result.error.trim() : result.staleSchedulerState === true ? "scheduler state for the run is stale" : "the server did not confirm the stop";
|
|
@@ -29190,6 +29509,7 @@ async function handleRunStopAll(args) {
|
|
|
29190
29509
|
const result = await client2.runs.stopAll({ reason });
|
|
29191
29510
|
const lines = [
|
|
29192
29511
|
`Stopped ${result.stopped} active run${result.stopped === 1 ? "" : "s"}`,
|
|
29512
|
+
...result.cancelling ? [`cancellation queued: ${result.cancelling}`] : [],
|
|
29193
29513
|
...result.partial ? ["partial: active runs may remain; rerun stop-all"] : [],
|
|
29194
29514
|
...result.failed > 0 ? [`failed stops: ${result.failed}`] : [],
|
|
29195
29515
|
...result.skipped > 0 ? [`skipped: ${result.skipped}`] : []
|
|
@@ -30979,6 +31299,12 @@ Examples:
|
|
|
30979
31299
|
deepline runs export play/my-play/run/20260501t000000-000 --out output.csv
|
|
30980
31300
|
`
|
|
30981
31301
|
);
|
|
31302
|
+
runs.command("status <runId>").description("Read bounded lifecycle and confirmed work counts for a run.").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (runId, options) => {
|
|
31303
|
+
process.exitCode = await handleRunLifecycleStatus([
|
|
31304
|
+
runId,
|
|
31305
|
+
...options.json ? ["--json"] : []
|
|
31306
|
+
]);
|
|
31307
|
+
});
|
|
30982
31308
|
runs.command("get <runId>").description(
|
|
30983
31309
|
"Get status, progress, result, errors, and recovery metadata for a play run."
|
|
30984
31310
|
).addHelpText(
|
|
@@ -36596,7 +36922,7 @@ function registerEnrichCommand(program) {
|
|
|
36596
36922
|
return exportResult;
|
|
36597
36923
|
}
|
|
36598
36924
|
const committedTempDir = inPlaceTempDir;
|
|
36599
|
-
await
|
|
36925
|
+
await rename2(inPlaceTempOutputPath, inPlaceCommitOutputPath);
|
|
36600
36926
|
inPlaceTempDir = null;
|
|
36601
36927
|
inPlaceTempOutputPath = null;
|
|
36602
36928
|
outputPath = inPlaceFinalOutputPath;
|