deepline 0.1.67 → 0.1.70
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/cli/index.js +1033 -577
- package/dist/cli/index.mjs +1033 -577
- package/dist/index.d.mts +43 -1
- package/dist/index.d.ts +43 -1
- package/dist/index.js +19 -2
- package/dist/index.mjs +19 -2
- package/dist/repo/apps/play-runner-workers/src/entry.ts +122 -29
- package/dist/repo/sdk/src/client.ts +40 -0
- package/dist/repo/sdk/src/play.ts +33 -1
- package/dist/repo/sdk/src/plays/bundle-play-file.ts +4 -1
- package/dist/repo/sdk/src/release.ts +2 -2
- package/dist/repo/shared_libs/play-runtime/secret-capability.ts +103 -0
- package/dist/repo/shared_libs/play-runtime/secret-redaction.ts +90 -0
- package/dist/repo/shared_libs/plays/bundling/index.ts +10 -0
- package/dist/repo/shared_libs/plays/secret-guardrails.ts +57 -0
- package/package.json +1 -1
package/dist/cli/index.mjs
CHANGED
|
@@ -206,10 +206,10 @@ import { join as join2 } from "path";
|
|
|
206
206
|
|
|
207
207
|
// src/release.ts
|
|
208
208
|
var SDK_RELEASE = {
|
|
209
|
-
version: "0.1.
|
|
209
|
+
version: "0.1.70",
|
|
210
210
|
apiContract: "2026-05-play-bootstrap-dataset-summary",
|
|
211
211
|
supportPolicy: {
|
|
212
|
-
latest: "0.1.
|
|
212
|
+
latest: "0.1.70",
|
|
213
213
|
minimumSupported: "0.1.53",
|
|
214
214
|
deprecatedBelow: "0.1.53"
|
|
215
215
|
}
|
|
@@ -716,7 +716,7 @@ var DeeplineClient = class {
|
|
|
716
716
|
list: (options2) => this.listRuns(options2),
|
|
717
717
|
tail: (runId, options2) => this.tailRun(runId, options2),
|
|
718
718
|
logs: (runId, options2) => this.getRunLogs(runId, options2),
|
|
719
|
-
exportDatasetRows: (
|
|
719
|
+
exportDatasetRows: (input2) => this.getPlaySheetRows(input2),
|
|
720
720
|
stop: (runId, options2) => this.stopRun(runId, options2)
|
|
721
721
|
};
|
|
722
722
|
}
|
|
@@ -803,6 +803,22 @@ var DeeplineClient = class {
|
|
|
803
803
|
};
|
|
804
804
|
}
|
|
805
805
|
// ——————————————————————————————————————————————————————————
|
|
806
|
+
// Secrets
|
|
807
|
+
// ——————————————————————————————————————————————————————————
|
|
808
|
+
async listSecrets() {
|
|
809
|
+
const response = await this.http.get(
|
|
810
|
+
"/api/v2/secrets"
|
|
811
|
+
);
|
|
812
|
+
return Array.isArray(response.secrets) ? response.secrets : [];
|
|
813
|
+
}
|
|
814
|
+
async checkSecret(name) {
|
|
815
|
+
const normalized = name.trim().toUpperCase();
|
|
816
|
+
const secrets = await this.listSecrets();
|
|
817
|
+
return secrets.find(
|
|
818
|
+
(secret) => secret.name === normalized && secret.status === "active" && secret.hasValue
|
|
819
|
+
) ?? null;
|
|
820
|
+
}
|
|
821
|
+
// ——————————————————————————————————————————————————————————
|
|
806
822
|
// Tools
|
|
807
823
|
// ——————————————————————————————————————————————————————————
|
|
808
824
|
/**
|
|
@@ -895,24 +911,24 @@ var DeeplineClient = class {
|
|
|
895
911
|
* Top-level fields such as `status`, `job_id`, and `billing` describe the
|
|
896
912
|
* Deepline execution envelope.
|
|
897
913
|
*/
|
|
898
|
-
async executeTool(toolId,
|
|
914
|
+
async executeTool(toolId, input2, options) {
|
|
899
915
|
const headers = {
|
|
900
916
|
[EXECUTE_RESPONSE_CONTRACT_HEADER]: V2_EXECUTE_RESPONSE_CONTRACT,
|
|
901
917
|
...options?.includeToolMetadata ? { [INCLUDE_TOOL_METADATA_HEADER]: "true" } : {}
|
|
902
918
|
};
|
|
903
919
|
return this.http.post(
|
|
904
920
|
`/api/v2/integrations/${encodeURIComponent(toolId)}/execute`,
|
|
905
|
-
{ payload:
|
|
921
|
+
{ payload: input2 },
|
|
906
922
|
headers
|
|
907
923
|
);
|
|
908
924
|
}
|
|
909
|
-
async executeToolRaw(toolId,
|
|
910
|
-
return this.executeTool(toolId,
|
|
925
|
+
async executeToolRaw(toolId, input2, options) {
|
|
926
|
+
return this.executeTool(toolId, input2, options);
|
|
911
927
|
}
|
|
912
|
-
async queryCustomerDb(
|
|
928
|
+
async queryCustomerDb(input2) {
|
|
913
929
|
return this.http.post("/api/v2/db/query", {
|
|
914
|
-
sql:
|
|
915
|
-
...
|
|
930
|
+
sql: input2.sql,
|
|
931
|
+
...input2.maxRows ? { max_rows: input2.maxRows } : {}
|
|
916
932
|
});
|
|
917
933
|
}
|
|
918
934
|
// ——————————————————————————————————————————————————————————
|
|
@@ -998,6 +1014,7 @@ var DeeplineClient = class {
|
|
|
998
1014
|
...request.inputFile ? { inputFile: request.inputFile } : {},
|
|
999
1015
|
...request.packagedFiles?.length ? { packagedFiles: request.packagedFiles } : {},
|
|
1000
1016
|
...request.force ? { force: true } : {},
|
|
1017
|
+
...typeof request.waitForCompletionMs === "number" ? { waitForCompletionMs: request.waitForCompletionMs } : {},
|
|
1001
1018
|
...request.profile ? { profile: request.profile } : {}
|
|
1002
1019
|
};
|
|
1003
1020
|
for await (const event of this.http.streamSse(
|
|
@@ -1019,15 +1036,15 @@ var DeeplineClient = class {
|
|
|
1019
1036
|
* Internal/advanced primitive used by packaging flows. Public callers should
|
|
1020
1037
|
* prefer the CLI, {@link submitPlay}, or {@link runPlay}.
|
|
1021
1038
|
*/
|
|
1022
|
-
async registerPlayArtifact(
|
|
1023
|
-
const compilerManifest =
|
|
1024
|
-
name:
|
|
1025
|
-
sourceCode:
|
|
1026
|
-
sourceFiles:
|
|
1027
|
-
artifact:
|
|
1039
|
+
async registerPlayArtifact(input2) {
|
|
1040
|
+
const compilerManifest = input2.compilerManifest ?? await this.compilePlayManifest({
|
|
1041
|
+
name: input2.name,
|
|
1042
|
+
sourceCode: input2.sourceCode,
|
|
1043
|
+
sourceFiles: input2.sourceFiles,
|
|
1044
|
+
artifact: input2.artifact
|
|
1028
1045
|
});
|
|
1029
1046
|
return this.http.post("/api/v2/plays/artifacts", {
|
|
1030
|
-
...
|
|
1047
|
+
...input2,
|
|
1031
1048
|
compilerManifest
|
|
1032
1049
|
});
|
|
1033
1050
|
}
|
|
@@ -1047,14 +1064,14 @@ var DeeplineClient = class {
|
|
|
1047
1064
|
artifacts: compiledArtifacts
|
|
1048
1065
|
});
|
|
1049
1066
|
}
|
|
1050
|
-
async compilePlayManifest(
|
|
1067
|
+
async compilePlayManifest(input2) {
|
|
1051
1068
|
const retryDelays = COMPILE_MANIFEST_RETRY_DELAYS_MS.slice(
|
|
1052
1069
|
0,
|
|
1053
1070
|
Math.max(0, this.config.maxRetries)
|
|
1054
1071
|
);
|
|
1055
1072
|
for (let attempt = 0; ; attempt += 1) {
|
|
1056
1073
|
try {
|
|
1057
|
-
const response = await this.http.post("/api/v2/plays/compile-manifest",
|
|
1074
|
+
const response = await this.http.post("/api/v2/plays/compile-manifest", input2);
|
|
1058
1075
|
return response.compilerManifest;
|
|
1059
1076
|
} catch (error) {
|
|
1060
1077
|
const delayMs = retryDelays[attempt];
|
|
@@ -1072,21 +1089,21 @@ var DeeplineClient = class {
|
|
|
1072
1089
|
* publish a revision, or start a run. It is the authoritative cloud validation
|
|
1073
1090
|
* path used by `deepline play check`.
|
|
1074
1091
|
*/
|
|
1075
|
-
async checkPlayArtifact(
|
|
1076
|
-
return this.http.post("/api/v2/plays/check",
|
|
1077
|
-
}
|
|
1078
|
-
async startPlayRunFromBundle(
|
|
1079
|
-
const compilerManifest =
|
|
1080
|
-
name:
|
|
1081
|
-
sourceCode:
|
|
1082
|
-
sourceFiles:
|
|
1083
|
-
artifact:
|
|
1092
|
+
async checkPlayArtifact(input2) {
|
|
1093
|
+
return this.http.post("/api/v2/plays/check", input2);
|
|
1094
|
+
}
|
|
1095
|
+
async startPlayRunFromBundle(input2) {
|
|
1096
|
+
const compilerManifest = input2.compilerManifest ?? await this.compilePlayManifest({
|
|
1097
|
+
name: input2.name,
|
|
1098
|
+
sourceCode: input2.sourceCode,
|
|
1099
|
+
sourceFiles: input2.sourceFiles,
|
|
1100
|
+
artifact: input2.artifact
|
|
1084
1101
|
});
|
|
1085
1102
|
const registeredArtifact = await this.registerPlayArtifact({
|
|
1086
|
-
name:
|
|
1087
|
-
sourceCode:
|
|
1088
|
-
sourceFiles:
|
|
1089
|
-
artifact:
|
|
1103
|
+
name: input2.name,
|
|
1104
|
+
sourceCode: input2.sourceCode,
|
|
1105
|
+
sourceFiles: input2.sourceFiles,
|
|
1106
|
+
artifact: input2.artifact,
|
|
1090
1107
|
compilerManifest,
|
|
1091
1108
|
publish: false
|
|
1092
1109
|
});
|
|
@@ -1096,13 +1113,13 @@ var DeeplineClient = class {
|
|
|
1096
1113
|
);
|
|
1097
1114
|
}
|
|
1098
1115
|
return this.startPlayRun({
|
|
1099
|
-
name:
|
|
1116
|
+
name: input2.name,
|
|
1100
1117
|
artifactStorageKey: registeredArtifact.artifactStorageKey,
|
|
1101
1118
|
compilerManifest,
|
|
1102
|
-
...
|
|
1103
|
-
...
|
|
1104
|
-
...
|
|
1105
|
-
...
|
|
1119
|
+
...input2.input ? { input: input2.input } : {},
|
|
1120
|
+
...input2.inputFile ? { inputFile: input2.inputFile } : {},
|
|
1121
|
+
...input2.packagedFiles?.length ? { packagedFiles: input2.packagedFiles } : {},
|
|
1122
|
+
...input2.force ? { force: true } : {}
|
|
1106
1123
|
});
|
|
1107
1124
|
}
|
|
1108
1125
|
/**
|
|
@@ -1447,17 +1464,17 @@ var DeeplineClient = class {
|
|
|
1447
1464
|
entries
|
|
1448
1465
|
};
|
|
1449
1466
|
}
|
|
1450
|
-
async getPlaySheetRows(
|
|
1467
|
+
async getPlaySheetRows(input2) {
|
|
1451
1468
|
const params = new URLSearchParams({
|
|
1452
|
-
tableNamespace:
|
|
1453
|
-
limit: String(
|
|
1454
|
-
offset: String(
|
|
1469
|
+
tableNamespace: input2.tableNamespace,
|
|
1470
|
+
limit: String(input2.limit ?? 5e3),
|
|
1471
|
+
offset: String(input2.offset ?? 0)
|
|
1455
1472
|
});
|
|
1456
|
-
if (
|
|
1457
|
-
params.set("runId",
|
|
1473
|
+
if (input2.runId?.trim()) {
|
|
1474
|
+
params.set("runId", input2.runId.trim());
|
|
1458
1475
|
}
|
|
1459
1476
|
return await this.http.get(
|
|
1460
|
-
`/api/v2/plays/${encodeURIComponent(
|
|
1477
|
+
`/api/v2/plays/${encodeURIComponent(input2.playName)}/sheet?${params.toString()}`
|
|
1461
1478
|
);
|
|
1462
1479
|
}
|
|
1463
1480
|
/**
|
|
@@ -1906,7 +1923,7 @@ function browserAppNameFromBundleId(bundleId) {
|
|
|
1906
1923
|
}
|
|
1907
1924
|
function readDefaultMacBrowserBundleId(runner = defaultBrowserCommandRunner) {
|
|
1908
1925
|
try {
|
|
1909
|
-
const
|
|
1926
|
+
const output2 = runner.execFileSync(
|
|
1910
1927
|
"/usr/bin/defaults",
|
|
1911
1928
|
[
|
|
1912
1929
|
"read",
|
|
@@ -1915,10 +1932,10 @@ function readDefaultMacBrowserBundleId(runner = defaultBrowserCommandRunner) {
|
|
|
1915
1932
|
],
|
|
1916
1933
|
{ encoding: "utf-8", stdio: ["ignore", "pipe", "ignore"] }
|
|
1917
1934
|
);
|
|
1918
|
-
const httpsMatch =
|
|
1935
|
+
const httpsMatch = output2.match(
|
|
1919
1936
|
/LSHandlerURLScheme\s*=\s*https;[\s\S]*?LSHandlerRole(?:All|Viewer|Editor)\s*=\s*"([^"]+)"/
|
|
1920
1937
|
);
|
|
1921
|
-
const httpMatch =
|
|
1938
|
+
const httpMatch = output2.match(
|
|
1922
1939
|
/LSHandlerURLScheme\s*=\s*http;[\s\S]*?LSHandlerRole(?:All|Viewer|Editor)\s*=\s*"([^"]+)"/
|
|
1923
1940
|
);
|
|
1924
1941
|
return (httpsMatch?.[1] ?? httpMatch?.[1] ?? "").trim();
|
|
@@ -3363,9 +3380,9 @@ function stripCsvProjectionColumns(columns, rows) {
|
|
|
3363
3380
|
(column) => column !== CSV_PROJECTED_FIELDS_KEY && !projectedFields.has(column)
|
|
3364
3381
|
);
|
|
3365
3382
|
}
|
|
3366
|
-
function sanitizeCsvProjectionInfo(
|
|
3367
|
-
const columns = stripCsvProjectionColumns(
|
|
3368
|
-
const rows =
|
|
3383
|
+
function sanitizeCsvProjectionInfo(input2) {
|
|
3384
|
+
const columns = stripCsvProjectionColumns(input2.columns, input2.rows);
|
|
3385
|
+
const rows = input2.rows.map(stripCsvProjectionFields);
|
|
3369
3386
|
return { rows, columns };
|
|
3370
3387
|
}
|
|
3371
3388
|
function isRecord2(value) {
|
|
@@ -3421,8 +3438,8 @@ function inferColumns(rows) {
|
|
|
3421
3438
|
}
|
|
3422
3439
|
return columns;
|
|
3423
3440
|
}
|
|
3424
|
-
function canonicalRowsInfoFromCandidate(
|
|
3425
|
-
const candidate =
|
|
3441
|
+
function canonicalRowsInfoFromCandidate(input2) {
|
|
3442
|
+
const candidate = input2;
|
|
3426
3443
|
if (isSerializedDataset(candidate.value)) {
|
|
3427
3444
|
const rawRows = rowArray(candidate.value.preview) ?? [];
|
|
3428
3445
|
const totalRows2 = readNumber(candidate.value.count) ?? rawRows.length;
|
|
@@ -3463,31 +3480,31 @@ function canonicalRowsInfoFromCandidate(input) {
|
|
|
3463
3480
|
source: candidate.source
|
|
3464
3481
|
};
|
|
3465
3482
|
}
|
|
3466
|
-
function collectDatasetCandidates(
|
|
3467
|
-
if (
|
|
3483
|
+
function collectDatasetCandidates(input2) {
|
|
3484
|
+
if (input2.depth && input2.depth > 16) {
|
|
3468
3485
|
return;
|
|
3469
3486
|
}
|
|
3470
|
-
if (isSerializedDataset(
|
|
3471
|
-
|
|
3472
|
-
source:
|
|
3473
|
-
value:
|
|
3474
|
-
total:
|
|
3487
|
+
if (isSerializedDataset(input2.value)) {
|
|
3488
|
+
input2.output.push({
|
|
3489
|
+
source: input2.path,
|
|
3490
|
+
value: input2.value,
|
|
3491
|
+
total: input2.total
|
|
3475
3492
|
});
|
|
3476
3493
|
return;
|
|
3477
3494
|
}
|
|
3478
|
-
if (!isRecord2(
|
|
3495
|
+
if (!isRecord2(input2.value)) {
|
|
3479
3496
|
return;
|
|
3480
3497
|
}
|
|
3481
|
-
for (const [key, child] of Object.entries(
|
|
3498
|
+
for (const [key, child] of Object.entries(input2.value)) {
|
|
3482
3499
|
if (key === "preview" || key === "access") {
|
|
3483
3500
|
continue;
|
|
3484
3501
|
}
|
|
3485
3502
|
collectDatasetCandidates({
|
|
3486
3503
|
value: child,
|
|
3487
|
-
path: `${
|
|
3488
|
-
total: totalRowsForDataset(
|
|
3489
|
-
output:
|
|
3490
|
-
depth: (
|
|
3504
|
+
path: `${input2.path}.${key}`,
|
|
3505
|
+
total: totalRowsForDataset(input2.value, `${input2.path}.${key}`),
|
|
3506
|
+
output: input2.output,
|
|
3507
|
+
depth: (input2.depth ?? 0) + 1
|
|
3491
3508
|
});
|
|
3492
3509
|
}
|
|
3493
3510
|
}
|
|
@@ -4005,26 +4022,26 @@ function writeCustomerDbCsv(result, outPath) {
|
|
|
4005
4022
|
);
|
|
4006
4023
|
return resolved;
|
|
4007
4024
|
}
|
|
4008
|
-
function dbQueryExportEnvelope(
|
|
4009
|
-
const destination =
|
|
4025
|
+
function dbQueryExportEnvelope(input2) {
|
|
4026
|
+
const destination = input2.outPath ?? "stdout";
|
|
4010
4027
|
return {
|
|
4011
|
-
command:
|
|
4012
|
-
format:
|
|
4013
|
-
row_count:
|
|
4014
|
-
row_count_returned:
|
|
4015
|
-
truncated:
|
|
4016
|
-
...
|
|
4017
|
-
next: { toolEquivalent:
|
|
4028
|
+
command: input2.result.command,
|
|
4029
|
+
format: input2.format,
|
|
4030
|
+
row_count: input2.result.row_count,
|
|
4031
|
+
row_count_returned: input2.result.row_count_returned,
|
|
4032
|
+
truncated: input2.result.truncated,
|
|
4033
|
+
...input2.outPath ? { file: input2.outPath, local: { file: input2.outPath } } : {},
|
|
4034
|
+
next: { toolEquivalent: input2.toolCommand },
|
|
4018
4035
|
render: {
|
|
4019
4036
|
sections: [
|
|
4020
4037
|
{
|
|
4021
4038
|
title: "customer db export",
|
|
4022
4039
|
lines: [
|
|
4023
|
-
`Rendered ${
|
|
4040
|
+
`Rendered ${input2.result.row_count_returned} row(s) as ${input2.format} to ${destination}`
|
|
4024
4041
|
]
|
|
4025
4042
|
}
|
|
4026
4043
|
],
|
|
4027
|
-
actions: [{ label: "Tool equivalent", command:
|
|
4044
|
+
actions: [{ label: "Tool equivalent", command: input2.toolCommand }]
|
|
4028
4045
|
}
|
|
4029
4046
|
};
|
|
4030
4047
|
}
|
|
@@ -4475,16 +4492,63 @@ var PLAY_RUNTIME_FEATURES = [
|
|
|
4475
4492
|
"durable_sleep",
|
|
4476
4493
|
"packaged_files"
|
|
4477
4494
|
];
|
|
4478
|
-
function buildPlayContractCompatibility(
|
|
4495
|
+
function buildPlayContractCompatibility(input2) {
|
|
4479
4496
|
return {
|
|
4480
4497
|
apiVersion: PLAY_PUBLIC_API_VERSION,
|
|
4481
4498
|
artifactVersion: PLAY_ARTIFACT_VERSION,
|
|
4482
4499
|
minRunnerVersion: PLAY_MIN_RUNNER_VERSION,
|
|
4483
4500
|
runtimeFeatures: [...PLAY_RUNTIME_FEATURES],
|
|
4484
|
-
runtimeBackend:
|
|
4501
|
+
runtimeBackend: input2?.runtimeBackend ?? null
|
|
4485
4502
|
};
|
|
4486
4503
|
}
|
|
4487
4504
|
|
|
4505
|
+
// ../shared_libs/plays/secret-guardrails.ts
|
|
4506
|
+
var SECRET_ENV_PATTERN = /\bprocess(?:\.env|\[['"]env['"]\])(?:\.|\[['"])([A-Z0-9_]*(?:API[_-]?KEY|TOKEN|SECRET|PASSWORD|PRIVATE[_-]?KEY|ACCESS[_-]?KEY)[A-Z0-9_]*)(?:['"]\])?/g;
|
|
4507
|
+
var PRIVATE_KEY_PATTERN = /-----BEGIN (?:RSA |EC |OPENSSH |PGP )?PRIVATE KEY-----/;
|
|
4508
|
+
var BEARER_LITERAL_PATTERN = /\bBearer\s+[A-Za-z0-9._~+/=-]{16,}/i;
|
|
4509
|
+
var ASSIGNMENT_SECRET_LITERAL_PATTERN = /\b(?:api[_-]?key|token|secret|password)\b\s*[:=]\s*['"][^'"]{12,}['"]/i;
|
|
4510
|
+
var HIGH_ENTROPY_LITERAL_PATTERN = /['"]([A-Za-z0-9+/=_-]{32,})['"]/g;
|
|
4511
|
+
function shannonEntropy(value) {
|
|
4512
|
+
const counts = /* @__PURE__ */ new Map();
|
|
4513
|
+
for (const char of value) counts.set(char, (counts.get(char) ?? 0) + 1);
|
|
4514
|
+
return [...counts.values()].reduce((entropy, count) => {
|
|
4515
|
+
const p = count / value.length;
|
|
4516
|
+
return entropy - p * Math.log2(p);
|
|
4517
|
+
}, 0);
|
|
4518
|
+
}
|
|
4519
|
+
function validatePlaySourceHasNoInlineSecrets(input2) {
|
|
4520
|
+
const findings = [];
|
|
4521
|
+
for (const match of input2.sourceCode.matchAll(SECRET_ENV_PATTERN)) {
|
|
4522
|
+
findings.push(`process.env.${match[1]}`);
|
|
4523
|
+
}
|
|
4524
|
+
if (PRIVATE_KEY_PATTERN.test(input2.sourceCode)) findings.push("private key block");
|
|
4525
|
+
if (BEARER_LITERAL_PATTERN.test(input2.sourceCode)) findings.push("bearer token literal");
|
|
4526
|
+
if (ASSIGNMENT_SECRET_LITERAL_PATTERN.test(input2.sourceCode)) {
|
|
4527
|
+
findings.push("secret-looking assignment literal");
|
|
4528
|
+
}
|
|
4529
|
+
for (const match of input2.sourceCode.matchAll(HIGH_ENTROPY_LITERAL_PATTERN)) {
|
|
4530
|
+
const literal = match[1] ?? "";
|
|
4531
|
+
if (literal.length >= 40 && shannonEntropy(literal) >= 4.2) {
|
|
4532
|
+
findings.push("high-entropy string literal");
|
|
4533
|
+
break;
|
|
4534
|
+
}
|
|
4535
|
+
}
|
|
4536
|
+
if (!findings.length) return;
|
|
4537
|
+
throw new Error(
|
|
4538
|
+
[
|
|
4539
|
+
`Play source ${input2.filePath} appears to contain inline secret material: ${[
|
|
4540
|
+
...new Set(findings)
|
|
4541
|
+
].join(", ")}.`,
|
|
4542
|
+
'Author secrets in the dashboard and use ctx.secrets.get("NAME") with an approved helper such as ctx.secrets.bearer(handle).'
|
|
4543
|
+
].join(" ")
|
|
4544
|
+
);
|
|
4545
|
+
}
|
|
4546
|
+
function validatePlaySourceFilesHaveNoInlineSecrets(sourceFiles) {
|
|
4547
|
+
for (const [filePath, sourceCode] of Object.entries(sourceFiles)) {
|
|
4548
|
+
validatePlaySourceHasNoInlineSecrets({ filePath, sourceCode });
|
|
4549
|
+
}
|
|
4550
|
+
}
|
|
4551
|
+
|
|
4488
4552
|
// ../shared_libs/plays/bundling/index.ts
|
|
4489
4553
|
var PLAY_BUNDLE_CACHE_VERSION = 24;
|
|
4490
4554
|
var MAX_PLAY_BUNDLE_BYTES = 30 * 1024 * 1024;
|
|
@@ -4546,12 +4610,12 @@ function createPlayWorkspace(entryFile) {
|
|
|
4546
4610
|
function isPathInsideDirectory(filePath, directory) {
|
|
4547
4611
|
return filePath === directory || filePath.startsWith(`${directory}/`);
|
|
4548
4612
|
}
|
|
4549
|
-
function assertWithinPlayWorkspace(
|
|
4550
|
-
if (isPathInsideDirectory(
|
|
4613
|
+
function assertWithinPlayWorkspace(input2) {
|
|
4614
|
+
if (isPathInsideDirectory(input2.resolvedPath, input2.workspace.rootDir)) {
|
|
4551
4615
|
return;
|
|
4552
4616
|
}
|
|
4553
4617
|
throw new Error(
|
|
4554
|
-
`${
|
|
4618
|
+
`${input2.importer}:${input2.line}:${input2.column} Local play imports must stay inside the play workspace (${input2.workspace.rootDir}). Import "${input2.specifier}" resolved to ${input2.resolvedPath}, which crosses into app/backend code. Use the public SDK/API surface or move shared helpers into the play workspace.`
|
|
4555
4619
|
);
|
|
4556
4620
|
}
|
|
4557
4621
|
function getPackageName(specifier) {
|
|
@@ -5406,6 +5470,15 @@ entry-export:${exportName}`
|
|
|
5406
5470
|
workers-harness:${harnessFingerprint}`
|
|
5407
5471
|
);
|
|
5408
5472
|
}
|
|
5473
|
+
try {
|
|
5474
|
+
validatePlaySourceFilesHaveNoInlineSecrets(analysis.sourceFiles);
|
|
5475
|
+
} catch (error) {
|
|
5476
|
+
return {
|
|
5477
|
+
success: false,
|
|
5478
|
+
filePath: absolutePath,
|
|
5479
|
+
errors: [error instanceof Error ? error.message : String(error)]
|
|
5480
|
+
};
|
|
5481
|
+
}
|
|
5409
5482
|
const typecheckErrors = [
|
|
5410
5483
|
...await adapter.typecheckPlaySource?.({
|
|
5411
5484
|
sourceCode: analysis.sourceCode,
|
|
@@ -6015,11 +6088,13 @@ function createSdkPlayBundlingAdapter() {
|
|
|
6015
6088
|
};
|
|
6016
6089
|
}
|
|
6017
6090
|
async function bundlePlayFile2(filePath, options = {}) {
|
|
6018
|
-
|
|
6091
|
+
const result = await bundlePlayFile(filePath, {
|
|
6019
6092
|
target: options.target ?? defaultPlayBundleTarget(),
|
|
6020
6093
|
exportName: options.exportName,
|
|
6021
6094
|
adapter: createSdkPlayBundlingAdapter()
|
|
6022
6095
|
});
|
|
6096
|
+
if (result.success) validatePlaySourceFilesHaveNoInlineSecrets(result.sourceFiles);
|
|
6097
|
+
return result;
|
|
6023
6098
|
}
|
|
6024
6099
|
|
|
6025
6100
|
// src/cli/commands/plays/bootstrap.ts
|
|
@@ -6613,28 +6688,28 @@ function objectPropertySchema(schema, property) {
|
|
|
6613
6688
|
function finderResultTypeName(finder) {
|
|
6614
6689
|
return finder === "email_finder" ? "EmailFinderPlayResult" : "PhoneFinderPlayResult";
|
|
6615
6690
|
}
|
|
6616
|
-
function renderFinderPlayResultType(
|
|
6617
|
-
if (!
|
|
6618
|
-
const outputField = PLAY_BOOTSTRAP_OUTPUT_FIELD_BY_FINDER[
|
|
6691
|
+
function renderFinderPlayResultType(input2) {
|
|
6692
|
+
if (!input2.play) return null;
|
|
6693
|
+
const outputField = PLAY_BOOTSTRAP_OUTPUT_FIELD_BY_FINDER[input2.finder];
|
|
6619
6694
|
const fieldSchema = objectPropertySchema(
|
|
6620
|
-
|
|
6695
|
+
input2.play.outputSchema,
|
|
6621
6696
|
outputField
|
|
6622
6697
|
);
|
|
6623
6698
|
const fieldType = fieldSchema ? jsonSchemaTypeExpression(fieldSchema) : "string | null";
|
|
6624
|
-
return `type ${finderResultTypeName(
|
|
6699
|
+
return `type ${finderResultTypeName(input2.finder)} =
|
|
6625
6700
|
| string
|
|
6626
6701
|
| null
|
|
6627
6702
|
| {
|
|
6628
6703
|
${outputField}?: ${fieldType};
|
|
6629
6704
|
};`;
|
|
6630
6705
|
}
|
|
6631
|
-
function generatedFinderPlayResultTypes(
|
|
6706
|
+
function generatedFinderPlayResultTypes(input2) {
|
|
6632
6707
|
return ["email_finder", "phone_finder"].flatMap((finder) => {
|
|
6633
|
-
const stage = finderStage(
|
|
6708
|
+
const stage = finderStage(input2.options, finder);
|
|
6634
6709
|
if (stage?.kind !== "play") return [];
|
|
6635
6710
|
const typeDefinition = renderFinderPlayResultType({
|
|
6636
6711
|
finder,
|
|
6637
|
-
play:
|
|
6712
|
+
play: input2.finderPlays[finder]
|
|
6638
6713
|
});
|
|
6639
6714
|
return typeDefinition ? [typeDefinition] : [];
|
|
6640
6715
|
}).join("\n\n");
|
|
@@ -6692,8 +6767,8 @@ function generateCompanyInputObjectFromSchema(schema, indent, label, fallbackFie
|
|
|
6692
6767
|
${lines.join("\n")}
|
|
6693
6768
|
${indent.slice(2)}}`;
|
|
6694
6769
|
}
|
|
6695
|
-
function generateSourceProviderInputObject(
|
|
6696
|
-
const { tool, indent, label, entity } =
|
|
6770
|
+
function generateSourceProviderInputObject(input2) {
|
|
6771
|
+
const { tool, indent, label, entity } = input2;
|
|
6697
6772
|
const properties = inputPropertyNames(tool?.inputSchema);
|
|
6698
6773
|
const details = schemaFieldDetails(tool?.inputSchema);
|
|
6699
6774
|
const required = details.required;
|
|
@@ -6751,8 +6826,8 @@ function generateSourceProviderInputObject(input) {
|
|
|
6751
6826
|
${lines.join("\n")}
|
|
6752
6827
|
${indent.slice(2)}}`;
|
|
6753
6828
|
}
|
|
6754
|
-
function generatePlayInputObject(
|
|
6755
|
-
const { schema, indent, label, entity } =
|
|
6829
|
+
function generatePlayInputObject(input2) {
|
|
6830
|
+
const { schema, indent, label, entity } = input2;
|
|
6756
6831
|
const details = schemaFieldDetails(schema);
|
|
6757
6832
|
const fallback = entity === "company" ? ["domain", "company_name"] : ["first_name", "last_name", "domain"];
|
|
6758
6833
|
const required = details.required.length ? details.required : fallback;
|
|
@@ -6819,80 +6894,80 @@ function needsWhenImport(options) {
|
|
|
6819
6894
|
function sourceCollectionTypeName(entity) {
|
|
6820
6895
|
return entity === "company" ? "CompanySourceRow" : "ContactSourceRow";
|
|
6821
6896
|
}
|
|
6822
|
-
function renderPartialRowType(
|
|
6823
|
-
if (
|
|
6824
|
-
return `type ${
|
|
6897
|
+
function renderPartialRowType(input2) {
|
|
6898
|
+
if (input2.fields.length === 0) {
|
|
6899
|
+
return `type ${input2.typeName} = Record<string, unknown>;`;
|
|
6825
6900
|
}
|
|
6826
|
-
const properties =
|
|
6827
|
-
return `type ${
|
|
6828
|
-
// ${
|
|
6901
|
+
const properties = input2.fields.map((field) => ` ${jsString(field)}?: unknown;`).join("\n");
|
|
6902
|
+
return `type ${input2.typeName} = Record<string, unknown> & Partial<{
|
|
6903
|
+
// ${input2.comment}
|
|
6829
6904
|
${properties}
|
|
6830
6905
|
}>;`;
|
|
6831
6906
|
}
|
|
6832
|
-
function fieldsFromSchemaDetails(
|
|
6907
|
+
function fieldsFromSchemaDetails(input2) {
|
|
6833
6908
|
return [
|
|
6834
|
-
...
|
|
6835
|
-
...
|
|
6909
|
+
...input2.details.required.length ? input2.details.required : input2.fallbackFields,
|
|
6910
|
+
...input2.details.optional
|
|
6836
6911
|
];
|
|
6837
6912
|
}
|
|
6838
|
-
function schemaFieldsForStage(stage,
|
|
6913
|
+
function schemaFieldsForStage(stage, input2) {
|
|
6839
6914
|
switch (stage?.kind) {
|
|
6840
6915
|
case void 0:
|
|
6841
6916
|
return [];
|
|
6842
6917
|
case "play":
|
|
6843
6918
|
return fieldsFromSchemaDetails({
|
|
6844
|
-
details: schemaFieldDetails(
|
|
6845
|
-
fallbackFields:
|
|
6919
|
+
details: schemaFieldDetails(input2.play?.inputSchema),
|
|
6920
|
+
fallbackFields: input2.fallbackFields
|
|
6846
6921
|
});
|
|
6847
6922
|
case "providers":
|
|
6848
|
-
return
|
|
6923
|
+
return input2.tools.flatMap(
|
|
6849
6924
|
(tool) => fieldsFromSchemaDetails({
|
|
6850
6925
|
details: schemaFieldDetails(tool.inputSchema),
|
|
6851
|
-
fallbackFields:
|
|
6926
|
+
fallbackFields: input2.fallbackFields
|
|
6852
6927
|
})
|
|
6853
6928
|
);
|
|
6854
6929
|
}
|
|
6855
6930
|
}
|
|
6856
|
-
function sourceRowTypeDefinition(
|
|
6857
|
-
switch (
|
|
6931
|
+
function sourceRowTypeDefinition(input2) {
|
|
6932
|
+
switch (input2.options.from.kind) {
|
|
6858
6933
|
case "csv":
|
|
6859
|
-
return `type ${
|
|
6934
|
+
return `type ${input2.sourceTypeName} = SourceCsvRow;`;
|
|
6860
6935
|
case "providers":
|
|
6861
6936
|
return renderPartialRowType({
|
|
6862
|
-
typeName:
|
|
6937
|
+
typeName: input2.sourceTypeName,
|
|
6863
6938
|
fields: [
|
|
6864
|
-
...new Set(
|
|
6939
|
+
...new Set(input2.sourceTools.flatMap(listRowCandidateKeysFromTool))
|
|
6865
6940
|
].sort(),
|
|
6866
6941
|
comment: "Candidate source row keys from described list getters; confirm the actual provider keys with source_*.extractedLists.*.keys before mapping."
|
|
6867
6942
|
});
|
|
6868
6943
|
case "play": {
|
|
6869
|
-
const details = schemaFieldDetails(
|
|
6944
|
+
const details = schemaFieldDetails(input2.sourcePlay?.outputSchema);
|
|
6870
6945
|
return renderPartialRowType({
|
|
6871
|
-
typeName:
|
|
6946
|
+
typeName: input2.sourceTypeName,
|
|
6872
6947
|
fields: [...details.required, ...details.optional].sort(),
|
|
6873
6948
|
comment: "Candidate source play output fields; confirm the selected rows field before mapping."
|
|
6874
6949
|
});
|
|
6875
6950
|
}
|
|
6876
6951
|
}
|
|
6877
6952
|
}
|
|
6878
|
-
function contactBridgeRowTypeDefinition(
|
|
6879
|
-
const config = playBootstrapTemplateConfig(
|
|
6880
|
-
if (config.sourceEntity !== "company" || !
|
|
6881
|
-
const emailFields = schemaFieldsForStage(
|
|
6882
|
-
tools:
|
|
6883
|
-
play:
|
|
6953
|
+
function contactBridgeRowTypeDefinition(input2) {
|
|
6954
|
+
const config = playBootstrapTemplateConfig(input2.options.template);
|
|
6955
|
+
if (config.sourceEntity !== "company" || !input2.options.people) return null;
|
|
6956
|
+
const emailFields = schemaFieldsForStage(input2.options.email, {
|
|
6957
|
+
tools: input2.finderTools.email_finder ?? [],
|
|
6958
|
+
play: input2.finderPlays.email_finder,
|
|
6884
6959
|
fallbackFields: ["first_name", "last_name", "domain"]
|
|
6885
6960
|
});
|
|
6886
|
-
const phoneFields = schemaFieldsForStage(
|
|
6887
|
-
tools:
|
|
6888
|
-
play:
|
|
6961
|
+
const phoneFields = schemaFieldsForStage(input2.options.phone, {
|
|
6962
|
+
tools: input2.finderTools.phone_finder ?? [],
|
|
6963
|
+
play: input2.finderPlays.phone_finder,
|
|
6889
6964
|
fallbackFields: ["first_name", "last_name", "domain"]
|
|
6890
6965
|
});
|
|
6891
6966
|
return renderPartialRowType({
|
|
6892
6967
|
typeName: "ContactSourceRow",
|
|
6893
6968
|
fields: [
|
|
6894
6969
|
.../* @__PURE__ */ new Set([
|
|
6895
|
-
...inputPropertyNames(
|
|
6970
|
+
...inputPropertyNames(input2.peoplePlay?.outputSchema),
|
|
6896
6971
|
...emailFields,
|
|
6897
6972
|
...phoneFields
|
|
6898
6973
|
])
|
|
@@ -6900,27 +6975,27 @@ function contactBridgeRowTypeDefinition(input) {
|
|
|
6900
6975
|
comment: "Fields the people play or later finder stages may need; the generated code still requires explicit mapping."
|
|
6901
6976
|
});
|
|
6902
6977
|
}
|
|
6903
|
-
function generateRowTypeDefinitions(
|
|
6904
|
-
const config = playBootstrapTemplateConfig(
|
|
6978
|
+
function generateRowTypeDefinitions(input2) {
|
|
6979
|
+
const config = playBootstrapTemplateConfig(input2.options.template);
|
|
6905
6980
|
const sourceTypeName = sourceCollectionTypeName(config.sourceEntity);
|
|
6906
6981
|
const definitions = [
|
|
6907
6982
|
sourceRowTypeDefinition({
|
|
6908
|
-
options:
|
|
6983
|
+
options: input2.options,
|
|
6909
6984
|
sourceTypeName,
|
|
6910
|
-
sourceTools:
|
|
6911
|
-
sourcePlay:
|
|
6985
|
+
sourceTools: input2.sourceTools,
|
|
6986
|
+
sourcePlay: input2.sourcePlay
|
|
6912
6987
|
}),
|
|
6913
|
-
contactBridgeRowTypeDefinition(
|
|
6988
|
+
contactBridgeRowTypeDefinition(input2)
|
|
6914
6989
|
];
|
|
6915
6990
|
return definitions.filter(Boolean).join("\n\n");
|
|
6916
6991
|
}
|
|
6917
|
-
function validateBootstrapRoutes(
|
|
6918
|
-
const config = playBootstrapTemplateConfig(
|
|
6992
|
+
function validateBootstrapRoutes(input2) {
|
|
6993
|
+
const config = playBootstrapTemplateConfig(input2.options.template);
|
|
6919
6994
|
const sourceCategory = config.sourceEntity === "company" ? PLAY_BOOTSTRAP_COMPANY_PROVIDER_CATEGORY : PLAY_BOOTSTRAP_PEOPLE_PROVIDER_CATEGORY;
|
|
6920
|
-
for (const tool of
|
|
6995
|
+
for (const tool of input2.sourceTools) {
|
|
6921
6996
|
if (!tool.categories.includes(sourceCategory)) {
|
|
6922
6997
|
throw new PlayBootstrapValidationError(
|
|
6923
|
-
`Cannot use ${tool.toolId} as a ${config.sourceEntity} source for ${
|
|
6998
|
+
`Cannot use ${tool.toolId} as a ${config.sourceEntity} source for ${input2.options.template}: expected category ${sourceCategory}, got ${tool.categories.join(", ") || "none"}. Run: deepline tools grep ${sourceCategory} --categories ${sourceCategory} --json`
|
|
6924
6999
|
);
|
|
6925
7000
|
}
|
|
6926
7001
|
if (getterNamesFromTool(tool, "list").length === 0) {
|
|
@@ -6929,14 +7004,14 @@ function validateBootstrapRoutes(input) {
|
|
|
6929
7004
|
);
|
|
6930
7005
|
}
|
|
6931
7006
|
}
|
|
6932
|
-
if (
|
|
7007
|
+
if (input2.options.people?.kind === "providers") {
|
|
6933
7008
|
throw new PlayBootstrapValidationError(
|
|
6934
7009
|
"Company-to-people bootstrap only accepts --people play:<play-ref> for now. Providers are too task-specific; choose or create a people play so the generated file can show the mapping contract."
|
|
6935
7010
|
);
|
|
6936
7011
|
}
|
|
6937
7012
|
for (const finder of ["email_finder", "phone_finder"]) {
|
|
6938
7013
|
const requiredCategory = PLAY_BOOTSTRAP_PROVIDER_CATEGORY_BY_FINDER[finder];
|
|
6939
|
-
for (const tool of
|
|
7014
|
+
for (const tool of input2.finderTools[finder] ?? []) {
|
|
6940
7015
|
if (!tool.categories.includes(requiredCategory)) {
|
|
6941
7016
|
throw new PlayBootstrapValidationError(
|
|
6942
7017
|
`Cannot use ${tool.toolId} for ${finder}: expected category ${requiredCategory}, got ${tool.categories.join(", ") || "none"}. Run: deepline tools grep ${requiredCategory} --categories ${requiredCategory} --json`
|
|
@@ -6958,118 +7033,118 @@ function sourceCollectionName(entity) {
|
|
|
6958
7033
|
return "contacts";
|
|
6959
7034
|
}
|
|
6960
7035
|
}
|
|
6961
|
-
function requiredGetterName(
|
|
6962
|
-
const getter = getterNamesFromTool(
|
|
7036
|
+
function requiredGetterName(input2) {
|
|
7037
|
+
const getter = getterNamesFromTool(input2.tool, input2.kind)[0];
|
|
6963
7038
|
if (!getter) {
|
|
6964
|
-
switch (
|
|
7039
|
+
switch (input2.kind) {
|
|
6965
7040
|
case "list":
|
|
6966
7041
|
throw new PlayBootstrapValidationError(
|
|
6967
|
-
`Cannot use ${
|
|
7042
|
+
`Cannot use ${input2.label} as a source: it exposes no extracted list getters.`
|
|
6968
7043
|
);
|
|
6969
7044
|
case "value":
|
|
6970
7045
|
throw new PlayBootstrapValidationError(
|
|
6971
|
-
`Cannot use ${
|
|
7046
|
+
`Cannot use ${input2.label} as a finder: it exposes no extracted value getters.`
|
|
6972
7047
|
);
|
|
6973
7048
|
}
|
|
6974
7049
|
}
|
|
6975
7050
|
return getter;
|
|
6976
7051
|
}
|
|
6977
|
-
function generateCsvSourceRowsBlock(
|
|
6978
|
-
return `const sourceDataset = await ctx.csv<SourceCsvRow>(${jsString(
|
|
6979
|
-
const ${
|
|
7052
|
+
function generateCsvSourceRowsBlock(input2) {
|
|
7053
|
+
return `const sourceDataset = await ctx.csv<SourceCsvRow>(${jsString(input2.packagedSourceCsvPath ?? input2.source.value)});
|
|
7054
|
+
const ${input2.collection}: ${input2.collectionType}[] = await sourceDataset.peek(limit);`;
|
|
6980
7055
|
}
|
|
6981
|
-
function generatePlaySourceRowsBlock(
|
|
7056
|
+
function generatePlaySourceRowsBlock(input2) {
|
|
6982
7057
|
const playInput = generatePlayInputObject({
|
|
6983
|
-
schema:
|
|
7058
|
+
schema: input2.sourcePlay?.inputSchema,
|
|
6984
7059
|
indent: " ",
|
|
6985
|
-
label:
|
|
6986
|
-
entity:
|
|
7060
|
+
label: input2.source.value,
|
|
7061
|
+
entity: input2.entity
|
|
6987
7062
|
});
|
|
6988
7063
|
return `const sourceInput = ${playInput};
|
|
6989
|
-
throw new Error(${jsString(`TODO: map sourceInput for ${
|
|
6990
|
-
const sourceResult = await ctx.runPlay('source_play', ${jsString(
|
|
6991
|
-
description: ${jsString(`Seed ${
|
|
7064
|
+
throw new Error(${jsString(`TODO: map sourceInput for ${input2.source.value}, choose the play output rows field, then delete this throw.`)});
|
|
7065
|
+
const sourceResult = await ctx.runPlay('source_play', ${jsString(input2.source.value)}, sourceInput, {
|
|
7066
|
+
description: ${jsString(`Seed ${input2.entity} rows from the selected play.`)},
|
|
6992
7067
|
});
|
|
6993
7068
|
// TODO: Replace sourceResult.rows with the selected play's actual row output field.
|
|
6994
|
-
const ${
|
|
7069
|
+
const ${input2.collection}: ${input2.collectionType}[] = (sourceResult.rows ?? []) as ${input2.collectionType}[];`;
|
|
6995
7070
|
}
|
|
6996
|
-
function generateProviderSourceBlock(
|
|
7071
|
+
function generateProviderSourceBlock(input2) {
|
|
6997
7072
|
const getter = requiredGetterName({
|
|
6998
|
-
tool:
|
|
7073
|
+
tool: input2.tool,
|
|
6999
7074
|
kind: "list",
|
|
7000
|
-
label:
|
|
7075
|
+
label: input2.provider
|
|
7001
7076
|
});
|
|
7002
|
-
const inputName = `${
|
|
7003
|
-
return `// ${
|
|
7077
|
+
const inputName = `${input2.entity}Input_${input2.index}`;
|
|
7078
|
+
return `// ${input2.entity === "company" ? "Company" : "People"} source provider: ${input2.provider}
|
|
7004
7079
|
const ${inputName}: Record<string, unknown> = ${generateSourceProviderInputObject(
|
|
7005
7080
|
{
|
|
7006
|
-
tool:
|
|
7081
|
+
tool: input2.tool,
|
|
7007
7082
|
indent: " ",
|
|
7008
|
-
label:
|
|
7009
|
-
entity:
|
|
7083
|
+
label: input2.provider,
|
|
7084
|
+
entity: input2.entity
|
|
7010
7085
|
}
|
|
7011
7086
|
)};
|
|
7012
|
-
throw new Error(${jsString(`TODO: fill ${inputName} for ${
|
|
7013
|
-
const source_${
|
|
7014
|
-
id: ${jsString(`${
|
|
7015
|
-
tool: ${jsString(
|
|
7087
|
+
throw new Error(${jsString(`TODO: fill ${inputName} for ${input2.provider}, then delete this throw.`)});
|
|
7088
|
+
const source_${input2.index} = await ctx.tools.execute({
|
|
7089
|
+
id: ${jsString(`${input2.entity}_source_${input2.index}`)},
|
|
7090
|
+
tool: ${jsString(input2.provider)},
|
|
7016
7091
|
input: ${inputName},
|
|
7017
|
-
description: ${jsString(`Seed ${
|
|
7092
|
+
description: ${jsString(`Seed ${input2.entity} rows from ${input2.provider}.`)},
|
|
7018
7093
|
});
|
|
7019
7094
|
// extractedLists.${getter}.get() returns provider-shaped rows. Do not assume canonical fields;
|
|
7020
|
-
// inspect source_${
|
|
7021
|
-
const sourceRows_${
|
|
7095
|
+
// inspect source_${input2.index}.extractedLists.${getter}.keys or the provider output schema, then map explicitly below.
|
|
7096
|
+
const sourceRows_${input2.index} = ${accessorExpression(`source_${input2.index}.extractedLists`, getter)}.get() as ${input2.collectionType}[];`;
|
|
7022
7097
|
}
|
|
7023
|
-
function generateProviderSourceRowsBlock(
|
|
7024
|
-
const blocks =
|
|
7098
|
+
function generateProviderSourceRowsBlock(input2) {
|
|
7099
|
+
const blocks = input2.source.values.map(
|
|
7025
7100
|
(provider, index) => generateProviderSourceBlock({
|
|
7026
7101
|
provider,
|
|
7027
7102
|
index,
|
|
7028
|
-
tool:
|
|
7029
|
-
entity:
|
|
7030
|
-
collectionType:
|
|
7103
|
+
tool: input2.sourceTools[index] ?? null,
|
|
7104
|
+
entity: input2.entity,
|
|
7105
|
+
collectionType: input2.collectionType
|
|
7031
7106
|
})
|
|
7032
7107
|
);
|
|
7033
7108
|
return `${blocks.join("\n\n ")}
|
|
7034
|
-
const ${
|
|
7109
|
+
const ${input2.collection}: ${input2.collectionType}[] = [${input2.source.values.map((_, index) => `...sourceRows_${index}`).join(", ")}];`;
|
|
7035
7110
|
}
|
|
7036
|
-
function generateSourceRowsBlock(
|
|
7037
|
-
const config = playBootstrapTemplateConfig(
|
|
7111
|
+
function generateSourceRowsBlock(input2) {
|
|
7112
|
+
const config = playBootstrapTemplateConfig(input2.options.template);
|
|
7038
7113
|
const entity = config.sourceEntity;
|
|
7039
7114
|
const collection = sourceCollectionName(entity);
|
|
7040
7115
|
const collectionType = sourceCollectionTypeName(entity);
|
|
7041
|
-
switch (
|
|
7116
|
+
switch (input2.options.from.kind) {
|
|
7042
7117
|
case "csv":
|
|
7043
7118
|
return generateCsvSourceRowsBlock({
|
|
7044
|
-
source:
|
|
7119
|
+
source: input2.options.from,
|
|
7045
7120
|
collection,
|
|
7046
7121
|
collectionType,
|
|
7047
|
-
packagedSourceCsvPath:
|
|
7122
|
+
packagedSourceCsvPath: input2.packagedSourceCsvPath
|
|
7048
7123
|
});
|
|
7049
7124
|
case "play":
|
|
7050
7125
|
return generatePlaySourceRowsBlock({
|
|
7051
|
-
source:
|
|
7052
|
-
sourcePlay:
|
|
7126
|
+
source: input2.options.from,
|
|
7127
|
+
sourcePlay: input2.sourcePlay,
|
|
7053
7128
|
entity,
|
|
7054
7129
|
collection,
|
|
7055
7130
|
collectionType
|
|
7056
7131
|
});
|
|
7057
7132
|
case "providers":
|
|
7058
7133
|
return generateProviderSourceRowsBlock({
|
|
7059
|
-
source:
|
|
7060
|
-
sourceTools:
|
|
7134
|
+
source: input2.options.from,
|
|
7135
|
+
sourceTools: input2.sourceTools,
|
|
7061
7136
|
entity,
|
|
7062
7137
|
collection,
|
|
7063
7138
|
collectionType
|
|
7064
7139
|
});
|
|
7065
7140
|
}
|
|
7066
7141
|
}
|
|
7067
|
-
function generateSourceSeedBlock(
|
|
7068
|
-
const sourceRows = generateSourceRowsBlock(
|
|
7069
|
-
const peoplePlayRef = stagePlayRef(
|
|
7142
|
+
function generateSourceSeedBlock(input2) {
|
|
7143
|
+
const sourceRows = generateSourceRowsBlock(input2);
|
|
7144
|
+
const peoplePlayRef = stagePlayRef(input2.options.people);
|
|
7070
7145
|
if (!peoplePlayRef) return sourceRows;
|
|
7071
7146
|
const peopleInput = generateCompanyInputObjectFromSchema(
|
|
7072
|
-
|
|
7147
|
+
input2.peoplePlay?.inputSchema,
|
|
7073
7148
|
" ",
|
|
7074
7149
|
peoplePlayRef,
|
|
7075
7150
|
["domain", "company_name"]
|
|
@@ -7091,15 +7166,15 @@ function generateSourceSeedBlock(input) {
|
|
|
7091
7166
|
contacts.push(...((peopleResult.rows ?? []) as ContactSourceRow[]));
|
|
7092
7167
|
}`;
|
|
7093
7168
|
}
|
|
7094
|
-
function finderProviderStepName(
|
|
7095
|
-
return `${
|
|
7169
|
+
function finderProviderStepName(input2) {
|
|
7170
|
+
return `${input2.aggregateStepName}${input2.index}_${safeIdentifier(input2.provider)}`;
|
|
7096
7171
|
}
|
|
7097
|
-
function finderValueGetter(
|
|
7098
|
-
const getters = getterNamesFromTool(
|
|
7099
|
-
const getter = getters.find((name) => name ===
|
|
7100
|
-
tool:
|
|
7172
|
+
function finderValueGetter(input2) {
|
|
7173
|
+
const getters = getterNamesFromTool(input2.tool, "value");
|
|
7174
|
+
const getter = getters.find((name) => name === input2.outputField) ?? requiredGetterName({
|
|
7175
|
+
tool: input2.tool,
|
|
7101
7176
|
kind: "value",
|
|
7102
|
-
label:
|
|
7177
|
+
label: input2.provider
|
|
7103
7178
|
});
|
|
7104
7179
|
return getter;
|
|
7105
7180
|
}
|
|
@@ -7107,157 +7182,157 @@ function optionalFinderValueExpression(candidateExpression, outputField) {
|
|
|
7107
7182
|
const valueExpression = /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(outputField) ? `${candidateExpression}?.${outputField}` : `${candidateExpression}?.[${jsString(outputField)}]`;
|
|
7108
7183
|
return `${valueExpression}?.trim()`;
|
|
7109
7184
|
}
|
|
7110
|
-
function generateFinderPlayStep(
|
|
7111
|
-
const outputField = PLAY_BOOTSTRAP_OUTPUT_FIELD_BY_FINDER[
|
|
7112
|
-
const resultTypeName = finderResultTypeName(
|
|
7185
|
+
function generateFinderPlayStep(input2) {
|
|
7186
|
+
const outputField = PLAY_BOOTSTRAP_OUTPUT_FIELD_BY_FINDER[input2.finder];
|
|
7187
|
+
const resultTypeName = finderResultTypeName(input2.finder);
|
|
7113
7188
|
const payload = generateContactInputObjectFromSchema(
|
|
7114
|
-
|
|
7189
|
+
input2.play?.inputSchema,
|
|
7115
7190
|
" ",
|
|
7116
|
-
|
|
7191
|
+
input2.stage.value
|
|
7117
7192
|
);
|
|
7118
7193
|
return `.step(${jsString(outputField)}, async (row, rowCtx) => {
|
|
7119
|
-
const ${
|
|
7120
|
-
throw new Error(${jsString(`TODO: map ${
|
|
7121
|
-
const ${
|
|
7122
|
-
${jsString(`${
|
|
7123
|
-
${jsString(
|
|
7124
|
-
${
|
|
7194
|
+
const ${input2.aggregateStepName}Input = ${payload};
|
|
7195
|
+
throw new Error(${jsString(`TODO: map ${input2.aggregateStepName}Input for ${input2.stage.value}, then delete this throw.`)});
|
|
7196
|
+
const ${input2.aggregateStepName}Result = await rowCtx.runPlay<${resultTypeName}>(
|
|
7197
|
+
${jsString(`${input2.aggregateStepName}Play`)},
|
|
7198
|
+
${jsString(input2.stage.value)},
|
|
7199
|
+
${input2.aggregateStepName}Input,
|
|
7125
7200
|
{
|
|
7126
|
-
description: ${jsString(`Run ${
|
|
7201
|
+
description: ${jsString(`Run ${input2.finder} play.`)},
|
|
7127
7202
|
},
|
|
7128
7203
|
);
|
|
7129
|
-
return typeof ${
|
|
7130
|
-
? ${
|
|
7131
|
-
: ${
|
|
7204
|
+
return typeof ${input2.aggregateStepName}Result === 'string'
|
|
7205
|
+
? ${input2.aggregateStepName}Result.trim() || null
|
|
7206
|
+
: ${input2.aggregateStepName}Result?.${outputField} ?? null;
|
|
7132
7207
|
})`;
|
|
7133
7208
|
}
|
|
7134
|
-
function generateFinderProviderResolver(
|
|
7209
|
+
function generateFinderProviderResolver(input2) {
|
|
7135
7210
|
const payload = generateContactInputObjectFromSchema(
|
|
7136
|
-
|
|
7211
|
+
input2.tool?.inputSchema,
|
|
7137
7212
|
" ",
|
|
7138
|
-
|
|
7213
|
+
input2.provider
|
|
7139
7214
|
);
|
|
7140
7215
|
const getter = finderValueGetter({
|
|
7141
|
-
tool:
|
|
7142
|
-
provider:
|
|
7143
|
-
outputField:
|
|
7216
|
+
tool: input2.tool,
|
|
7217
|
+
provider: input2.provider,
|
|
7218
|
+
outputField: input2.outputField
|
|
7144
7219
|
});
|
|
7145
7220
|
return `async (row, rowCtx) => {
|
|
7146
7221
|
const providerInput = ${payload};
|
|
7147
|
-
throw new Error(${jsString(`TODO: map providerInput for ${
|
|
7222
|
+
throw new Error(${jsString(`TODO: map providerInput for ${input2.provider}, then delete this throw.`)});
|
|
7148
7223
|
const result = await rowCtx.tools.execute({
|
|
7149
|
-
id: ${jsString(`${
|
|
7150
|
-
tool: ${jsString(
|
|
7224
|
+
id: ${jsString(`${input2.aggregateStepName}_${input2.providerIndex}`)},
|
|
7225
|
+
tool: ${jsString(input2.provider)},
|
|
7151
7226
|
input: providerInput,
|
|
7152
|
-
description: ${jsString(`Try ${
|
|
7227
|
+
description: ${jsString(`Try ${input2.provider} as a ${input2.finder}.`)},
|
|
7153
7228
|
});
|
|
7154
7229
|
return {
|
|
7155
|
-
${
|
|
7230
|
+
${input2.outputField}: (${accessorExpression("result.extractedValues", getter)}.get() as string | null) ?? null,
|
|
7156
7231
|
result,
|
|
7157
7232
|
};
|
|
7158
7233
|
}`;
|
|
7159
7234
|
}
|
|
7160
|
-
function generateFinderProviderStep(
|
|
7161
|
-
const stepName =
|
|
7162
|
-
switch (
|
|
7235
|
+
function generateFinderProviderStep(input2) {
|
|
7236
|
+
const stepName = input2.stepNames[input2.index];
|
|
7237
|
+
switch (input2.index) {
|
|
7163
7238
|
case 0:
|
|
7164
|
-
return `.step(${jsString(stepName)}, ${
|
|
7239
|
+
return `.step(${jsString(stepName)}, ${input2.resolver})`;
|
|
7165
7240
|
default: {
|
|
7166
|
-
const priorCandidates =
|
|
7241
|
+
const priorCandidates = input2.stepNames.slice(0, input2.index).map((name) => `row.${name}`).join(", ");
|
|
7167
7242
|
return `.step(
|
|
7168
7243
|
${jsString(stepName)},
|
|
7169
7244
|
when(
|
|
7170
|
-
(row) => ![${priorCandidates}].some((candidate) => ${optionalFinderValueExpression("candidate",
|
|
7171
|
-
${
|
|
7245
|
+
(row) => ![${priorCandidates}].some((candidate) => ${optionalFinderValueExpression("candidate", input2.outputField)}),
|
|
7246
|
+
${input2.resolver},
|
|
7172
7247
|
),
|
|
7173
7248
|
)`;
|
|
7174
7249
|
}
|
|
7175
7250
|
}
|
|
7176
7251
|
}
|
|
7177
|
-
function generateFinderProviderWaterfall(
|
|
7178
|
-
const legPrefix = finderProviderStepPrefix(
|
|
7179
|
-
const stepNames =
|
|
7252
|
+
function generateFinderProviderWaterfall(input2) {
|
|
7253
|
+
const legPrefix = finderProviderStepPrefix(input2.finder);
|
|
7254
|
+
const stepNames = input2.stage.values.map(
|
|
7180
7255
|
(provider, index) => finderProviderStepName({
|
|
7181
7256
|
aggregateStepName: legPrefix,
|
|
7182
7257
|
provider,
|
|
7183
7258
|
index
|
|
7184
7259
|
})
|
|
7185
7260
|
);
|
|
7186
|
-
const providerSteps =
|
|
7261
|
+
const providerSteps = input2.stage.values.map(
|
|
7187
7262
|
(provider, index) => generateFinderProviderStep({
|
|
7188
7263
|
index,
|
|
7189
7264
|
stepNames,
|
|
7190
|
-
outputField:
|
|
7265
|
+
outputField: input2.outputField,
|
|
7191
7266
|
resolver: generateFinderProviderResolver({
|
|
7192
|
-
finder:
|
|
7267
|
+
finder: input2.finder,
|
|
7193
7268
|
provider,
|
|
7194
7269
|
providerIndex: index,
|
|
7195
|
-
tool:
|
|
7196
|
-
aggregateStepName:
|
|
7197
|
-
outputField:
|
|
7270
|
+
tool: input2.tools[index] ?? null,
|
|
7271
|
+
aggregateStepName: input2.aggregateStepName,
|
|
7272
|
+
outputField: input2.outputField
|
|
7198
7273
|
})
|
|
7199
7274
|
})
|
|
7200
7275
|
);
|
|
7201
7276
|
const candidateNames = stepNames.map((name) => `row.${name}`).join(", ");
|
|
7202
|
-
return `// ${
|
|
7277
|
+
return `// ${input2.aggregateStepName} provider waterfall. Each provider leg is active once its TODO throw is removed;
|
|
7203
7278
|
// delete or comment out legs you do not want before running. Later legs are gated with when(...).
|
|
7204
7279
|
${providerSteps.join("\n ")}
|
|
7205
|
-
.step(${jsString(
|
|
7280
|
+
.step(${jsString(input2.aggregateStepName)}, (row) => {
|
|
7206
7281
|
const candidates = [${candidateNames}];
|
|
7207
|
-
const match = candidates.find((candidate) => ${optionalFinderValueExpression("candidate",
|
|
7208
|
-
return ${optionalFinderValueExpression("match",
|
|
7282
|
+
const match = candidates.find((candidate) => ${optionalFinderValueExpression("candidate", input2.outputField)});
|
|
7283
|
+
return ${optionalFinderValueExpression("match", input2.outputField)} ?? null;
|
|
7209
7284
|
})`;
|
|
7210
7285
|
}
|
|
7211
|
-
function generateFinderStageSteps(
|
|
7212
|
-
const outputField = PLAY_BOOTSTRAP_OUTPUT_FIELD_BY_FINDER[
|
|
7213
|
-
const aggregateStepName = stepFieldName(
|
|
7214
|
-
switch (
|
|
7286
|
+
function generateFinderStageSteps(input2) {
|
|
7287
|
+
const outputField = PLAY_BOOTSTRAP_OUTPUT_FIELD_BY_FINDER[input2.finder];
|
|
7288
|
+
const aggregateStepName = stepFieldName(input2.finder);
|
|
7289
|
+
switch (input2.stage.kind) {
|
|
7215
7290
|
case "play":
|
|
7216
7291
|
return generateFinderPlayStep({
|
|
7217
|
-
finder:
|
|
7218
|
-
stage:
|
|
7219
|
-
play:
|
|
7292
|
+
finder: input2.finder,
|
|
7293
|
+
stage: input2.stage,
|
|
7294
|
+
play: input2.finderPlays[input2.finder],
|
|
7220
7295
|
aggregateStepName
|
|
7221
7296
|
});
|
|
7222
7297
|
case "providers":
|
|
7223
7298
|
return generateFinderProviderWaterfall({
|
|
7224
|
-
finder:
|
|
7225
|
-
stage:
|
|
7226
|
-
tools:
|
|
7299
|
+
finder: input2.finder,
|
|
7300
|
+
stage: input2.stage,
|
|
7301
|
+
tools: input2.finderTools[input2.finder] ?? [],
|
|
7227
7302
|
aggregateStepName,
|
|
7228
7303
|
outputField
|
|
7229
7304
|
});
|
|
7230
7305
|
}
|
|
7231
7306
|
}
|
|
7232
|
-
function generateFinderSteps(
|
|
7307
|
+
function generateFinderSteps(input2) {
|
|
7233
7308
|
return ["email_finder", "phone_finder"].flatMap((finder) => {
|
|
7234
|
-
const stage = finderStage(
|
|
7309
|
+
const stage = finderStage(input2.options, finder);
|
|
7235
7310
|
return stage ? [
|
|
7236
7311
|
generateFinderStageSteps({
|
|
7237
|
-
...
|
|
7312
|
+
...input2,
|
|
7238
7313
|
finder,
|
|
7239
7314
|
stage
|
|
7240
7315
|
})
|
|
7241
7316
|
] : [];
|
|
7242
7317
|
}).join("\n ");
|
|
7243
7318
|
}
|
|
7244
|
-
function generateBootstrapPlaySource(
|
|
7245
|
-
const config = playBootstrapTemplateConfig(
|
|
7246
|
-
const sourceSeedBlock = generateSourceSeedBlock(
|
|
7247
|
-
const finderSteps = generateFinderSteps(
|
|
7248
|
-
const hasPeople = config.sourceEntity === "people" || Boolean(
|
|
7319
|
+
function generateBootstrapPlaySource(input2) {
|
|
7320
|
+
const config = playBootstrapTemplateConfig(input2.options.template);
|
|
7321
|
+
const sourceSeedBlock = generateSourceSeedBlock(input2);
|
|
7322
|
+
const finderSteps = generateFinderSteps(input2);
|
|
7323
|
+
const hasPeople = config.sourceEntity === "people" || Boolean(input2.options.people);
|
|
7249
7324
|
const sourceCollection = hasPeople ? "contacts" : "companies";
|
|
7250
7325
|
const mapSteps = finderSteps ? `
|
|
7251
7326
|
${finderSteps}` : "";
|
|
7252
|
-
const sourceCsvRowType =
|
|
7253
|
-
const rowTypeDefinitions = generateRowTypeDefinitions(
|
|
7254
|
-
const finderPlayResultTypes = generatedFinderPlayResultTypes(
|
|
7327
|
+
const sourceCsvRowType = input2.options.from.kind === "csv" ? renderSourceCsvRowType(input2.sourceCsvColumns) : "";
|
|
7328
|
+
const rowTypeDefinitions = generateRowTypeDefinitions(input2);
|
|
7329
|
+
const finderPlayResultTypes = generatedFinderPlayResultTypes(input2);
|
|
7255
7330
|
const typeDefinitions = [
|
|
7256
7331
|
sourceCsvRowType.trimEnd(),
|
|
7257
7332
|
rowTypeDefinitions,
|
|
7258
7333
|
finderPlayResultTypes
|
|
7259
7334
|
].filter((definition) => definition.trim().length > 0).join("\n\n");
|
|
7260
|
-
const importNames = needsWhenImport(
|
|
7335
|
+
const importNames = needsWhenImport(input2.options) ? "definePlay, when" : "definePlay";
|
|
7261
7336
|
return `import { ${importNames} } from 'deepline';
|
|
7262
7337
|
|
|
7263
7338
|
${typeDefinitions}
|
|
@@ -7266,8 +7341,8 @@ type Input = {
|
|
|
7266
7341
|
limit?: number;
|
|
7267
7342
|
};
|
|
7268
7343
|
|
|
7269
|
-
export default definePlay(${jsString(
|
|
7270
|
-
const limit = Math.max(1, Math.min(Number(input.limit ?? ${
|
|
7344
|
+
export default definePlay(${jsString(input2.options.name)}, async (ctx, input: Input = {}) => {
|
|
7345
|
+
const limit = Math.max(1, Math.min(Number(input.limit ?? ${input2.options.limit}), ${input2.options.limit}));
|
|
7271
7346
|
${sourceSeedBlock}
|
|
7272
7347
|
|
|
7273
7348
|
const rowsToProcess = ${sourceCollection}.slice(0, limit);
|
|
@@ -7279,7 +7354,7 @@ export default definePlay(${jsString(input.options.name)}, async (ctx, input: In
|
|
|
7279
7354
|
.map('bootstrap_rows', rowsToProcess)${mapSteps}
|
|
7280
7355
|
.run({
|
|
7281
7356
|
key: (_row, index) => index,
|
|
7282
|
-
description: ${jsString(`Bootstrap ${
|
|
7357
|
+
description: ${jsString(`Bootstrap ${input2.options.template}: seed source rows, run requested stages, then return the mapped rows.`)},
|
|
7283
7358
|
});
|
|
7284
7359
|
|
|
7285
7360
|
return {
|
|
@@ -7687,8 +7762,8 @@ var SHA256_ROUND_CONSTANTS = [
|
|
|
7687
7762
|
function rightRotate32(value, bits) {
|
|
7688
7763
|
return value >>> bits | value << 32 - bits;
|
|
7689
7764
|
}
|
|
7690
|
-
function sha256Hex(
|
|
7691
|
-
const bytes = Array.from(new TextEncoder().encode(
|
|
7765
|
+
function sha256Hex(input2) {
|
|
7766
|
+
const bytes = Array.from(new TextEncoder().encode(input2));
|
|
7692
7767
|
const bitLength = bytes.length * 8;
|
|
7693
7768
|
bytes.push(128);
|
|
7694
7769
|
while (bytes.length % 64 !== 56) {
|
|
@@ -7862,10 +7937,10 @@ function looksLikeInvalidExtractedGetter(error, sourceLine) {
|
|
|
7862
7937
|
if (!/Property '[^']+' does not exist on type/.test(error)) return false;
|
|
7863
7938
|
return /\bextracted(?:Values|Lists)\s*\./.test(sourceLine);
|
|
7864
7939
|
}
|
|
7865
|
-
function addPlayCheckRepairHints(
|
|
7940
|
+
function addPlayCheckRepairHints(input2) {
|
|
7866
7941
|
let addedHint = false;
|
|
7867
|
-
return
|
|
7868
|
-
const line = sourceLineForError(
|
|
7942
|
+
return input2.errors.map((error) => {
|
|
7943
|
+
const line = sourceLineForError(input2.sourceCode, error);
|
|
7869
7944
|
if (addedHint || !looksLikeInvalidExtractedGetter(error, line) || error.includes(EXTRACTED_GETTER_ERROR_HINT)) {
|
|
7870
7945
|
return error;
|
|
7871
7946
|
}
|
|
@@ -7876,6 +7951,7 @@ ${EXTRACTED_GETTER_ERROR_HINT}`;
|
|
|
7876
7951
|
}
|
|
7877
7952
|
|
|
7878
7953
|
// src/cli/commands/play.ts
|
|
7954
|
+
var PLAY_START_STREAM_FAST_COMPLETION_WAIT_MS = 2500;
|
|
7879
7955
|
var PLAY_RUN_RESERVED_BOOLEAN_FLAGS = /* @__PURE__ */ new Set([
|
|
7880
7956
|
"--json",
|
|
7881
7957
|
"--wait",
|
|
@@ -7927,9 +8003,9 @@ function parseReferencedPlayTarget2(target) {
|
|
|
7927
8003
|
function isPrebuiltReferenceTarget(target) {
|
|
7928
8004
|
return target.trim().toLowerCase().startsWith("prebuilt/");
|
|
7929
8005
|
}
|
|
7930
|
-
function buildBarePrebuiltReferenceError(
|
|
8006
|
+
function buildBarePrebuiltReferenceError(input2) {
|
|
7931
8007
|
return new Error(
|
|
7932
|
-
`Prebuilt play "${
|
|
8008
|
+
`Prebuilt play "${input2.requested}" must be referenced as "${input2.reference}". Use the prebuilt/ namespace anywhere you run, describe, get, or link to Deepline-managed plays.`
|
|
7933
8009
|
);
|
|
7934
8010
|
}
|
|
7935
8011
|
async function assertCanonicalNamedPlayReference(client, target) {
|
|
@@ -7972,23 +8048,23 @@ function buildCloneEditStarter(play) {
|
|
|
7972
8048
|
checkCommand: `deepline plays check ${path}`
|
|
7973
8049
|
};
|
|
7974
8050
|
}
|
|
7975
|
-
function materializeRemotePlaySource(
|
|
7976
|
-
if (isFileTarget(
|
|
8051
|
+
function materializeRemotePlaySource(input2) {
|
|
8052
|
+
if (isFileTarget(input2.target)) {
|
|
7977
8053
|
return null;
|
|
7978
8054
|
}
|
|
7979
|
-
if (!
|
|
8055
|
+
if (!input2.sourceCode.trim()) {
|
|
7980
8056
|
return null;
|
|
7981
8057
|
}
|
|
7982
|
-
const outputPath =
|
|
8058
|
+
const outputPath = input2.outPath ?? defaultMaterializedPlayPath(input2.playName);
|
|
7983
8059
|
if (existsSync7(outputPath)) {
|
|
7984
8060
|
const existingSource = readFileSync6(outputPath, "utf-8");
|
|
7985
|
-
if (existingSource ===
|
|
8061
|
+
if (existingSource === input2.sourceCode) {
|
|
7986
8062
|
return { path: outputPath, status: "unchanged", created: false };
|
|
7987
8063
|
}
|
|
7988
|
-
writeFileSync6(outputPath,
|
|
8064
|
+
writeFileSync6(outputPath, input2.sourceCode, "utf-8");
|
|
7989
8065
|
return { path: outputPath, status: "updated", created: false };
|
|
7990
8066
|
}
|
|
7991
|
-
writeFileSync6(outputPath,
|
|
8067
|
+
writeFileSync6(outputPath, input2.sourceCode, "utf-8");
|
|
7992
8068
|
return { path: outputPath, status: "created", created: true };
|
|
7993
8069
|
}
|
|
7994
8070
|
function formatLoadedPlayMessage(materializedFile) {
|
|
@@ -8038,12 +8114,12 @@ function isFileTarget(target) {
|
|
|
8038
8114
|
function looksLikeRunId(target) {
|
|
8039
8115
|
return /^play\/[^/]+\/run\/[^/]+/.test(target.trim());
|
|
8040
8116
|
}
|
|
8041
|
-
function formatPlayCommandReceivedRunIdError(
|
|
8042
|
-
return `\`deepline plays ${
|
|
8117
|
+
function formatPlayCommandReceivedRunIdError(input2) {
|
|
8118
|
+
return `\`deepline plays ${input2.command} <run-id>\` expects a play name, but this looks like a run id.
|
|
8043
8119
|
Use:
|
|
8044
|
-
deepline runs get ${
|
|
8045
|
-
deepline runs logs ${
|
|
8046
|
-
deepline runs export ${
|
|
8120
|
+
deepline runs get ${input2.runId} --json
|
|
8121
|
+
deepline runs logs ${input2.runId} --json
|
|
8122
|
+
deepline runs export ${input2.runId} --out output.csv`;
|
|
8047
8123
|
}
|
|
8048
8124
|
function looksLikeFilePath(target) {
|
|
8049
8125
|
if (target.trim().toLowerCase().startsWith("prebuilt/")) {
|
|
@@ -8097,9 +8173,9 @@ function parseInputFlagValue(raw) {
|
|
|
8097
8173
|
}
|
|
8098
8174
|
return raw;
|
|
8099
8175
|
}
|
|
8100
|
-
function getDottedInputValue(
|
|
8176
|
+
function getDottedInputValue(input2, path) {
|
|
8101
8177
|
const parts = path.split(".").map((part) => part.trim()).filter(Boolean);
|
|
8102
|
-
let cursor =
|
|
8178
|
+
let cursor = input2;
|
|
8103
8179
|
for (const part of parts) {
|
|
8104
8180
|
if (!cursor || typeof cursor !== "object" || Array.isArray(cursor)) {
|
|
8105
8181
|
return void 0;
|
|
@@ -8108,12 +8184,12 @@ function getDottedInputValue(input, path) {
|
|
|
8108
8184
|
}
|
|
8109
8185
|
return cursor;
|
|
8110
8186
|
}
|
|
8111
|
-
function setDottedInputValue(
|
|
8187
|
+
function setDottedInputValue(input2, path, value) {
|
|
8112
8188
|
const parts = path.split(".").map((part) => part.trim()).filter(Boolean);
|
|
8113
8189
|
if (parts.length === 0) {
|
|
8114
8190
|
throw new Error(`Invalid play input flag path: ${path}`);
|
|
8115
8191
|
}
|
|
8116
|
-
let cursor =
|
|
8192
|
+
let cursor = input2;
|
|
8117
8193
|
for (const part of parts.slice(0, -1)) {
|
|
8118
8194
|
const existing = cursor[part];
|
|
8119
8195
|
if (existing !== void 0 && (!existing || typeof existing !== "object" || Array.isArray(existing))) {
|
|
@@ -8180,17 +8256,17 @@ function inputContainsLocalFilePath(value) {
|
|
|
8180
8256
|
}
|
|
8181
8257
|
return false;
|
|
8182
8258
|
}
|
|
8183
|
-
function namedRunNeedsPlayDefinition(
|
|
8184
|
-
return
|
|
8259
|
+
function namedRunNeedsPlayDefinition(input2) {
|
|
8260
|
+
return input2.revisionSelector === "latest" || inputContainsLocalFilePath(input2.runtimeInput);
|
|
8185
8261
|
}
|
|
8186
|
-
async function stageFileInputArgs(
|
|
8262
|
+
async function stageFileInputArgs(input2) {
|
|
8187
8263
|
const uniqueBindings = [
|
|
8188
8264
|
...new Map(
|
|
8189
|
-
|
|
8265
|
+
input2.bindings.map((binding) => [binding.inputPath, binding])
|
|
8190
8266
|
).values()
|
|
8191
8267
|
];
|
|
8192
8268
|
const localFiles = uniqueBindings.flatMap((binding) => {
|
|
8193
|
-
const value = getDottedInputValue(
|
|
8269
|
+
const value = getDottedInputValue(input2.runtimeInput, binding.inputPath);
|
|
8194
8270
|
if (!isLocalFilePathValue(value)) return [];
|
|
8195
8271
|
const absolutePath = resolve10(value);
|
|
8196
8272
|
return [{ binding, absolutePath, logicalPath: basename3(absolutePath) }];
|
|
@@ -8198,22 +8274,22 @@ async function stageFileInputArgs(input) {
|
|
|
8198
8274
|
if (localFiles.length === 0) {
|
|
8199
8275
|
return { inputFile: null, packagedFiles: [] };
|
|
8200
8276
|
}
|
|
8201
|
-
|
|
8277
|
+
input2.progress.phase(
|
|
8202
8278
|
localFiles.length === 1 ? "staging input file" : "staging input files"
|
|
8203
8279
|
);
|
|
8204
|
-
const staged = await
|
|
8280
|
+
const staged = await input2.client.stagePlayFiles(
|
|
8205
8281
|
localFiles.map((file) => stageFile(file.logicalPath, file.absolutePath))
|
|
8206
8282
|
);
|
|
8207
8283
|
for (const [index, file] of localFiles.entries()) {
|
|
8208
8284
|
setDottedInputValue(
|
|
8209
|
-
|
|
8285
|
+
input2.runtimeInput,
|
|
8210
8286
|
file.binding.inputPath,
|
|
8211
8287
|
file.logicalPath
|
|
8212
8288
|
);
|
|
8213
8289
|
const stagedFile = staged[index];
|
|
8214
8290
|
if (stagedFile && stagedFile.logicalPath !== file.logicalPath) {
|
|
8215
8291
|
setDottedInputValue(
|
|
8216
|
-
|
|
8292
|
+
input2.runtimeInput,
|
|
8217
8293
|
file.binding.inputPath,
|
|
8218
8294
|
stagedFile.logicalPath
|
|
8219
8295
|
);
|
|
@@ -8498,16 +8574,16 @@ function buildStepReceiptsDebugCommand(runId) {
|
|
|
8498
8574
|
const sql = `select convert_from(k, 'UTF8') as receipt_key, case status when 0 then 'pending' when 1 then 'running' when 2 then 'completed' when 3 then 'failed' when 4 then 'skipped' else status::text end as status, output, error, updated_at from ${table} where run_id = ${quoteSqlLiteral(runId)} order by updated_at asc, receipt_key asc limit 20`;
|
|
8499
8575
|
return buildDebugDbQueryCommand(sql);
|
|
8500
8576
|
}
|
|
8501
|
-
function buildMapTableDebugCommand(
|
|
8577
|
+
function buildMapTableDebugCommand(input2) {
|
|
8502
8578
|
try {
|
|
8503
8579
|
const tableName = validatePlaySheetTableName(
|
|
8504
|
-
|
|
8505
|
-
|
|
8580
|
+
input2.playName,
|
|
8581
|
+
input2.tableNamespace
|
|
8506
8582
|
);
|
|
8507
8583
|
const table = `${quoteSqlIdentifier(
|
|
8508
8584
|
PLAY_CUSTOMER_STORAGE_SCHEMA_NAME
|
|
8509
8585
|
)}.${quoteSqlIdentifier(tableName)}`;
|
|
8510
|
-
const sql = `select * from ${table} where _run_id = ${quoteSqlLiteral(
|
|
8586
|
+
const sql = `select * from ${table} where _run_id = ${quoteSqlLiteral(input2.runId)} limit 20`;
|
|
8511
8587
|
return buildDebugDbQueryCommand(sql);
|
|
8512
8588
|
} catch {
|
|
8513
8589
|
return null;
|
|
@@ -8527,37 +8603,37 @@ function extractTableNamespaceFromLiveEvent(event) {
|
|
|
8527
8603
|
}
|
|
8528
8604
|
return null;
|
|
8529
8605
|
}
|
|
8530
|
-
function emitLiveDebugTableHints(
|
|
8531
|
-
if (
|
|
8606
|
+
function emitLiveDebugTableHints(input2) {
|
|
8607
|
+
if (input2.jsonOutput || !input2.runId || input2.runId === "pending") {
|
|
8532
8608
|
return;
|
|
8533
8609
|
}
|
|
8534
|
-
|
|
8535
|
-
const receiptsKey = `receipts:${
|
|
8536
|
-
if (!
|
|
8537
|
-
|
|
8538
|
-
|
|
8539
|
-
`Debug top-level outputs: ${buildStepReceiptsDebugCommand(
|
|
8610
|
+
input2.state.emittedDebugKeys ??= /* @__PURE__ */ new Set();
|
|
8611
|
+
const receiptsKey = `receipts:${input2.runId}`;
|
|
8612
|
+
if (!input2.state.emittedDebugKeys.has(receiptsKey)) {
|
|
8613
|
+
input2.state.emittedDebugKeys.add(receiptsKey);
|
|
8614
|
+
input2.progress.writeLine(
|
|
8615
|
+
`Debug top-level outputs: ${buildStepReceiptsDebugCommand(input2.runId)}`,
|
|
8540
8616
|
process.stdout
|
|
8541
8617
|
);
|
|
8542
8618
|
}
|
|
8543
|
-
const tableNamespace = extractTableNamespaceFromLiveEvent(
|
|
8619
|
+
const tableNamespace = extractTableNamespaceFromLiveEvent(input2.event);
|
|
8544
8620
|
if (!tableNamespace) {
|
|
8545
8621
|
return;
|
|
8546
8622
|
}
|
|
8547
|
-
const tableKey = `table:${
|
|
8548
|
-
if (
|
|
8623
|
+
const tableKey = `table:${input2.runId}:${tableNamespace}`;
|
|
8624
|
+
if (input2.state.emittedDebugKeys.has(tableKey)) {
|
|
8549
8625
|
return;
|
|
8550
8626
|
}
|
|
8551
8627
|
const command = buildMapTableDebugCommand({
|
|
8552
|
-
playName:
|
|
8553
|
-
runId:
|
|
8628
|
+
playName: input2.playName,
|
|
8629
|
+
runId: input2.runId,
|
|
8554
8630
|
tableNamespace
|
|
8555
8631
|
});
|
|
8556
8632
|
if (!command) {
|
|
8557
8633
|
return;
|
|
8558
8634
|
}
|
|
8559
|
-
|
|
8560
|
-
|
|
8635
|
+
input2.state.emittedDebugKeys.add(tableKey);
|
|
8636
|
+
input2.progress.writeLine(
|
|
8561
8637
|
`Debug rows for ${tableNamespace}: ${command}`,
|
|
8562
8638
|
process.stdout
|
|
8563
8639
|
);
|
|
@@ -8590,9 +8666,9 @@ function formatProgressLabel(raw) {
|
|
|
8590
8666
|
const value = typeof raw === "string" && raw.trim() ? raw.trim() : "step";
|
|
8591
8667
|
return value.replace(/^map:/, "").replace(/^tool:/, "");
|
|
8592
8668
|
}
|
|
8593
|
-
function formatProgressCounts(
|
|
8594
|
-
const completed = typeof
|
|
8595
|
-
const total = typeof
|
|
8669
|
+
function formatProgressCounts(input2) {
|
|
8670
|
+
const completed = typeof input2.completed === "number" && Number.isFinite(input2.completed) ? input2.completed : null;
|
|
8671
|
+
const total = typeof input2.total === "number" && Number.isFinite(input2.total) ? input2.total : null;
|
|
8596
8672
|
if (completed === null || total === null || total <= 0) {
|
|
8597
8673
|
return null;
|
|
8598
8674
|
}
|
|
@@ -8600,7 +8676,7 @@ function formatProgressCounts(input) {
|
|
|
8600
8676
|
0,
|
|
8601
8677
|
Math.min(100, Math.round(completed / total * 100))
|
|
8602
8678
|
);
|
|
8603
|
-
const failed = typeof
|
|
8679
|
+
const failed = typeof input2.failed === "number" && Number.isFinite(input2.failed) && input2.failed > 0 ? `, failed ${formatInteger(input2.failed)}` : "";
|
|
8604
8680
|
return `${formatInteger(completed)}/${formatInteger(total)} (${percent}%)${failed}`;
|
|
8605
8681
|
}
|
|
8606
8682
|
function getProgressLinesFromLiveEvent(event) {
|
|
@@ -8642,14 +8718,14 @@ function getProgressLinesFromLiveEvent(event) {
|
|
|
8642
8718
|
}
|
|
8643
8719
|
return lines;
|
|
8644
8720
|
}
|
|
8645
|
-
function printPlayProgressLines(
|
|
8646
|
-
for (const line of
|
|
8721
|
+
function printPlayProgressLines(input2) {
|
|
8722
|
+
for (const line of input2.lines) {
|
|
8647
8723
|
const signature = line.trim();
|
|
8648
|
-
if (!signature ||
|
|
8724
|
+
if (!signature || input2.state.lastProgressSignature === signature) {
|
|
8649
8725
|
continue;
|
|
8650
8726
|
}
|
|
8651
|
-
|
|
8652
|
-
|
|
8727
|
+
input2.state.lastProgressSignature = signature;
|
|
8728
|
+
input2.progress.writeLine(line);
|
|
8653
8729
|
}
|
|
8654
8730
|
}
|
|
8655
8731
|
function buildPlayDashboardUrl(baseUrl, playName) {
|
|
@@ -8657,102 +8733,102 @@ function buildPlayDashboardUrl(baseUrl, playName) {
|
|
|
8657
8733
|
const encodedPlayName = encodeURIComponent(playName);
|
|
8658
8734
|
return `${trimmedBase}/dashboard/plays/${encodedPlayName}`;
|
|
8659
8735
|
}
|
|
8660
|
-
function openPlayDashboard(
|
|
8661
|
-
if (
|
|
8736
|
+
function openPlayDashboard(input2) {
|
|
8737
|
+
if (input2.jsonOutput || input2.noOpen || !input2.dashboardUrl) {
|
|
8662
8738
|
return;
|
|
8663
8739
|
}
|
|
8664
|
-
openInBrowser(
|
|
8740
|
+
openInBrowser(input2.dashboardUrl);
|
|
8665
8741
|
}
|
|
8666
|
-
function printPlayLogLines(
|
|
8667
|
-
for (const line of
|
|
8668
|
-
if (
|
|
8742
|
+
function printPlayLogLines(input2) {
|
|
8743
|
+
for (const line of input2.lines) {
|
|
8744
|
+
if (input2.emitLogs) {
|
|
8669
8745
|
const formatted = formatPlayLogLine(
|
|
8670
8746
|
line,
|
|
8671
|
-
|
|
8672
|
-
|
|
8747
|
+
input2.status ?? void 0,
|
|
8748
|
+
input2.state
|
|
8673
8749
|
);
|
|
8674
8750
|
if (formatted) {
|
|
8675
|
-
|
|
8751
|
+
input2.progress.writeLogLine(formatted);
|
|
8676
8752
|
}
|
|
8677
8753
|
}
|
|
8678
|
-
|
|
8754
|
+
input2.state.lastLogIndex += 1;
|
|
8679
8755
|
}
|
|
8680
8756
|
}
|
|
8681
|
-
function assertPlayWaitNotTimedOut(
|
|
8682
|
-
if (
|
|
8683
|
-
const hasRealRunId =
|
|
8684
|
-
const phaseSuffix =
|
|
8685
|
-
const tailHint = hasRealRunId ? ` Run 'deepline runs tail ${
|
|
8757
|
+
function assertPlayWaitNotTimedOut(input2) {
|
|
8758
|
+
if (input2.waitTimeoutMs !== null && Date.now() - input2.startedAt >= input2.waitTimeoutMs) {
|
|
8759
|
+
const hasRealRunId = input2.workflowId.length > 0 && input2.workflowId !== "pending";
|
|
8760
|
+
const phaseSuffix = input2.lastPhase && input2.lastPhase.trim() ? ` (last observed phase: ${input2.lastPhase.trim()})` : "";
|
|
8761
|
+
const tailHint = hasRealRunId ? ` Run 'deepline runs tail ${input2.workflowId} --json' to inspect it, or rerun with a larger --tail-timeout-ms.` : ` The run never reported a workflow id \u2014 the start request likely failed before reaching the scheduler. Check server logs and rerun with a larger --tail-timeout-ms.`;
|
|
8686
8762
|
throw new DeeplineError(
|
|
8687
|
-
`Timed out waiting for play ${hasRealRunId ?
|
|
8763
|
+
`Timed out waiting for play ${hasRealRunId ? input2.workflowId : "<no run id>"} after ${Math.ceil(input2.waitTimeoutMs / 1e3)}s${phaseSuffix}.${tailHint}`,
|
|
8688
8764
|
void 0,
|
|
8689
8765
|
"PLAY_WAIT_TIMEOUT",
|
|
8690
8766
|
{
|
|
8691
|
-
...hasRealRunId ? { runId:
|
|
8692
|
-
...
|
|
8693
|
-
timeoutMs:
|
|
8767
|
+
...hasRealRunId ? { runId: input2.workflowId, workflowId: input2.workflowId } : {},
|
|
8768
|
+
...input2.lastPhase ? { phase: input2.lastPhase } : {},
|
|
8769
|
+
timeoutMs: input2.waitTimeoutMs
|
|
8694
8770
|
}
|
|
8695
8771
|
);
|
|
8696
8772
|
}
|
|
8697
8773
|
}
|
|
8698
|
-
async function waitForPlayCompletionByStream(
|
|
8774
|
+
async function waitForPlayCompletionByStream(input2) {
|
|
8699
8775
|
const controller = new AbortController();
|
|
8700
8776
|
let timedOut = false;
|
|
8701
8777
|
let lastPhase = null;
|
|
8702
|
-
const timeout =
|
|
8778
|
+
const timeout = input2.waitTimeoutMs === null ? null : setTimeout(
|
|
8703
8779
|
() => {
|
|
8704
8780
|
timedOut = true;
|
|
8705
8781
|
controller.abort();
|
|
8706
8782
|
},
|
|
8707
|
-
Math.max(1,
|
|
8783
|
+
Math.max(1, input2.waitTimeoutMs - (Date.now() - input2.startedAt))
|
|
8708
8784
|
);
|
|
8709
8785
|
try {
|
|
8710
|
-
for await (const event of
|
|
8711
|
-
|
|
8786
|
+
for await (const event of input2.client.streamPlayRunEvents(
|
|
8787
|
+
input2.workflowId,
|
|
8712
8788
|
{ signal: controller.signal }
|
|
8713
8789
|
)) {
|
|
8714
|
-
assertPlayWaitNotTimedOut({ ...
|
|
8790
|
+
assertPlayWaitNotTimedOut({ ...input2, lastPhase });
|
|
8715
8791
|
const phase = describeLiveEventPhase(event);
|
|
8716
8792
|
if (phase) {
|
|
8717
8793
|
lastPhase = phase;
|
|
8718
|
-
|
|
8794
|
+
input2.progress.phase(phase);
|
|
8719
8795
|
}
|
|
8720
8796
|
emitLiveDebugTableHints({
|
|
8721
8797
|
event,
|
|
8722
|
-
playName:
|
|
8723
|
-
runId:
|
|
8724
|
-
jsonOutput:
|
|
8725
|
-
state:
|
|
8726
|
-
progress:
|
|
8798
|
+
playName: input2.playName,
|
|
8799
|
+
runId: input2.workflowId,
|
|
8800
|
+
jsonOutput: input2.jsonOutput,
|
|
8801
|
+
state: input2.state,
|
|
8802
|
+
progress: input2.progress
|
|
8727
8803
|
});
|
|
8728
8804
|
printPlayLogLines({
|
|
8729
8805
|
lines: getLogLinesFromLiveEvent(event),
|
|
8730
8806
|
status: null,
|
|
8731
|
-
jsonOutput:
|
|
8732
|
-
emitLogs:
|
|
8733
|
-
state:
|
|
8734
|
-
progress:
|
|
8807
|
+
jsonOutput: input2.jsonOutput,
|
|
8808
|
+
emitLogs: input2.emitLogs,
|
|
8809
|
+
state: input2.state,
|
|
8810
|
+
progress: input2.progress
|
|
8735
8811
|
});
|
|
8736
|
-
if (!
|
|
8812
|
+
if (!input2.jsonOutput) {
|
|
8737
8813
|
printPlayProgressLines({
|
|
8738
8814
|
lines: getProgressLinesFromLiveEvent(event),
|
|
8739
|
-
state:
|
|
8740
|
-
progress:
|
|
8815
|
+
state: input2.state,
|
|
8816
|
+
progress: input2.progress
|
|
8741
8817
|
});
|
|
8742
8818
|
}
|
|
8743
8819
|
const status = getStatusFromLiveEvent(event);
|
|
8744
8820
|
if (status && TERMINAL_PLAY_STATUSES2.has(status)) {
|
|
8745
|
-
const finalStatus = await
|
|
8821
|
+
const finalStatus = await input2.client.getPlayStatus(input2.workflowId, {
|
|
8746
8822
|
billing: false
|
|
8747
8823
|
});
|
|
8748
8824
|
if (TERMINAL_PLAY_STATUSES2.has(finalStatus.status)) {
|
|
8749
|
-
return
|
|
8825
|
+
return input2.dashboardUrl ? { ...finalStatus, dashboardUrl: input2.dashboardUrl } : finalStatus;
|
|
8750
8826
|
}
|
|
8751
8827
|
}
|
|
8752
8828
|
}
|
|
8753
8829
|
} catch (error) {
|
|
8754
8830
|
if (timedOut) {
|
|
8755
|
-
assertPlayWaitNotTimedOut({ ...
|
|
8831
|
+
assertPlayWaitNotTimedOut({ ...input2, lastPhase });
|
|
8756
8832
|
}
|
|
8757
8833
|
throw error;
|
|
8758
8834
|
} finally {
|
|
@@ -8762,25 +8838,25 @@ async function waitForPlayCompletionByStream(input) {
|
|
|
8762
8838
|
}
|
|
8763
8839
|
const phaseSuffix = lastPhase && lastPhase.trim() ? ` (last observed phase: ${lastPhase.trim()})` : "";
|
|
8764
8840
|
throw new DeeplineError(
|
|
8765
|
-
`Play live stream ended before the run reached a terminal state runId=${
|
|
8841
|
+
`Play live stream ended before the run reached a terminal state runId=${input2.workflowId}${phaseSuffix}.`,
|
|
8766
8842
|
void 0,
|
|
8767
8843
|
"PLAY_LIVE_STREAM_ENDED",
|
|
8768
8844
|
{
|
|
8769
|
-
runId:
|
|
8770
|
-
workflowId:
|
|
8845
|
+
runId: input2.workflowId,
|
|
8846
|
+
workflowId: input2.workflowId,
|
|
8771
8847
|
...lastPhase ? { phase: lastPhase } : {}
|
|
8772
8848
|
}
|
|
8773
8849
|
);
|
|
8774
8850
|
}
|
|
8775
|
-
async function startAndWaitForPlayCompletionByStream(
|
|
8851
|
+
async function startAndWaitForPlayCompletionByStream(input2) {
|
|
8776
8852
|
for (let attempt = 0; attempt <= PLAY_START_TRANSIENT_RETRY_DELAYS_MS.length; attempt += 1) {
|
|
8777
|
-
const status = await startAndWaitForPlayCompletionByStreamOnce(
|
|
8853
|
+
const status = await startAndWaitForPlayCompletionByStreamOnce(input2);
|
|
8778
8854
|
const retryDelayMs = PLAY_START_TRANSIENT_RETRY_DELAYS_MS[attempt];
|
|
8779
8855
|
if (retryDelayMs === void 0 || !isRetryablePendingStartFailure(status)) {
|
|
8780
8856
|
return status;
|
|
8781
8857
|
}
|
|
8782
|
-
if (!
|
|
8783
|
-
|
|
8858
|
+
if (!input2.jsonOutput) {
|
|
8859
|
+
input2.progress.writeLine(
|
|
8784
8860
|
`[play watch] start failed before run id with a transient error; retrying (${playStatusErrorText(status)})`
|
|
8785
8861
|
);
|
|
8786
8862
|
}
|
|
@@ -8788,23 +8864,23 @@ async function startAndWaitForPlayCompletionByStream(input) {
|
|
|
8788
8864
|
phase: "cli.play_start_stream_retry",
|
|
8789
8865
|
ms: 0,
|
|
8790
8866
|
ok: true,
|
|
8791
|
-
playName:
|
|
8867
|
+
playName: input2.playName,
|
|
8792
8868
|
attempt: attempt + 1,
|
|
8793
8869
|
reason: playStatusErrorText(status)
|
|
8794
8870
|
});
|
|
8795
8871
|
await sleep4(retryDelayMs);
|
|
8796
8872
|
}
|
|
8797
8873
|
throw new DeeplineError(
|
|
8798
|
-
`Play ${
|
|
8874
|
+
`Play ${input2.playName} did not start after retrying transient start failures.`,
|
|
8799
8875
|
void 0,
|
|
8800
8876
|
"PLAY_START_RETRY_EXHAUSTED"
|
|
8801
8877
|
);
|
|
8802
8878
|
}
|
|
8803
|
-
async function startAndWaitForPlayCompletionByStreamOnce(
|
|
8879
|
+
async function startAndWaitForPlayCompletionByStreamOnce(input2) {
|
|
8804
8880
|
const startedAt = Date.now();
|
|
8805
8881
|
const dashboardUrl = buildPlayDashboardUrl(
|
|
8806
|
-
|
|
8807
|
-
|
|
8882
|
+
input2.client.baseUrl,
|
|
8883
|
+
input2.playName
|
|
8808
8884
|
);
|
|
8809
8885
|
const state = {
|
|
8810
8886
|
lastLogIndex: 0,
|
|
@@ -8818,15 +8894,19 @@ async function startAndWaitForPlayCompletionByStreamOnce(input) {
|
|
|
8818
8894
|
let eventCount = 0;
|
|
8819
8895
|
let firstRunIdMs = null;
|
|
8820
8896
|
let lastPhase = null;
|
|
8821
|
-
const
|
|
8897
|
+
const startRequest = {
|
|
8898
|
+
...input2.request,
|
|
8899
|
+
waitForCompletionMs: typeof input2.request.waitForCompletionMs === "number" ? input2.request.waitForCompletionMs : PLAY_START_STREAM_FAST_COMPLETION_WAIT_MS
|
|
8900
|
+
};
|
|
8901
|
+
const timeout = input2.waitTimeoutMs === null ? null : setTimeout(
|
|
8822
8902
|
() => {
|
|
8823
8903
|
timedOut = true;
|
|
8824
8904
|
controller.abort();
|
|
8825
8905
|
},
|
|
8826
|
-
Math.max(1,
|
|
8906
|
+
Math.max(1, input2.waitTimeoutMs)
|
|
8827
8907
|
);
|
|
8828
8908
|
try {
|
|
8829
|
-
for await (const event of
|
|
8909
|
+
for await (const event of input2.client.startPlayRunStream(startRequest, {
|
|
8830
8910
|
signal: controller.signal
|
|
8831
8911
|
})) {
|
|
8832
8912
|
eventCount += 1;
|
|
@@ -8837,55 +8917,55 @@ async function startAndWaitForPlayCompletionByStreamOnce(input) {
|
|
|
8837
8917
|
}
|
|
8838
8918
|
const workflowId = lastKnownWorkflowId || "pending";
|
|
8839
8919
|
if (workflowId !== "pending" && !emittedDashboardUrl) {
|
|
8840
|
-
if (!
|
|
8920
|
+
if (!input2.jsonOutput) {
|
|
8841
8921
|
writeStartedPlayRun({
|
|
8842
8922
|
runId: workflowId,
|
|
8843
|
-
playName:
|
|
8923
|
+
playName: input2.playName,
|
|
8844
8924
|
dashboardUrl,
|
|
8845
8925
|
jsonOutput: false,
|
|
8846
|
-
progress:
|
|
8926
|
+
progress: input2.progress
|
|
8847
8927
|
});
|
|
8848
8928
|
}
|
|
8849
8929
|
openPlayDashboard({
|
|
8850
8930
|
dashboardUrl,
|
|
8851
|
-
jsonOutput:
|
|
8852
|
-
noOpen:
|
|
8931
|
+
jsonOutput: input2.jsonOutput,
|
|
8932
|
+
noOpen: input2.noOpen
|
|
8853
8933
|
});
|
|
8854
|
-
|
|
8934
|
+
input2.progress.phase(`loading play on ${dashboardUrl}`);
|
|
8855
8935
|
emittedDashboardUrl = true;
|
|
8856
8936
|
}
|
|
8857
8937
|
assertPlayWaitNotTimedOut({
|
|
8858
8938
|
workflowId,
|
|
8859
8939
|
startedAt,
|
|
8860
|
-
waitTimeoutMs:
|
|
8940
|
+
waitTimeoutMs: input2.waitTimeoutMs,
|
|
8861
8941
|
lastPhase
|
|
8862
8942
|
});
|
|
8863
8943
|
const phase = describeLiveEventPhase(event);
|
|
8864
8944
|
if (phase) {
|
|
8865
8945
|
lastPhase = phase;
|
|
8866
|
-
|
|
8946
|
+
input2.progress.phase(phase);
|
|
8867
8947
|
}
|
|
8868
8948
|
printPlayLogLines({
|
|
8869
8949
|
lines: getLogLinesFromLiveEvent(event),
|
|
8870
8950
|
status: null,
|
|
8871
|
-
jsonOutput:
|
|
8872
|
-
emitLogs:
|
|
8951
|
+
jsonOutput: input2.jsonOutput,
|
|
8952
|
+
emitLogs: input2.emitLogs,
|
|
8873
8953
|
state,
|
|
8874
|
-
progress:
|
|
8954
|
+
progress: input2.progress
|
|
8875
8955
|
});
|
|
8876
8956
|
emitLiveDebugTableHints({
|
|
8877
8957
|
event,
|
|
8878
|
-
playName:
|
|
8958
|
+
playName: input2.playName,
|
|
8879
8959
|
runId: workflowId,
|
|
8880
|
-
jsonOutput:
|
|
8960
|
+
jsonOutput: input2.jsonOutput,
|
|
8881
8961
|
state,
|
|
8882
|
-
progress:
|
|
8962
|
+
progress: input2.progress
|
|
8883
8963
|
});
|
|
8884
|
-
if (!
|
|
8964
|
+
if (!input2.jsonOutput) {
|
|
8885
8965
|
printPlayProgressLines({
|
|
8886
8966
|
lines: getProgressLinesFromLiveEvent(event),
|
|
8887
8967
|
state,
|
|
8888
|
-
progress:
|
|
8968
|
+
progress: input2.progress
|
|
8889
8969
|
});
|
|
8890
8970
|
}
|
|
8891
8971
|
const finalStatus = getFinalStatusFromLiveEvent(event);
|
|
@@ -8894,7 +8974,7 @@ async function startAndWaitForPlayCompletionByStreamOnce(input) {
|
|
|
8894
8974
|
phase: "cli.play_start_stream_terminal",
|
|
8895
8975
|
ms: Date.now() - startedAt,
|
|
8896
8976
|
ok: true,
|
|
8897
|
-
playName:
|
|
8977
|
+
playName: input2.playName,
|
|
8898
8978
|
workflowId: finalStatus.runId || lastKnownWorkflowId || null,
|
|
8899
8979
|
eventCount,
|
|
8900
8980
|
firstRunIdMs,
|
|
@@ -8908,7 +8988,7 @@ async function startAndWaitForPlayCompletionByStreamOnce(input) {
|
|
|
8908
8988
|
assertPlayWaitNotTimedOut({
|
|
8909
8989
|
workflowId: lastKnownWorkflowId,
|
|
8910
8990
|
startedAt,
|
|
8911
|
-
waitTimeoutMs:
|
|
8991
|
+
waitTimeoutMs: input2.waitTimeoutMs,
|
|
8912
8992
|
lastPhase
|
|
8913
8993
|
});
|
|
8914
8994
|
}
|
|
@@ -8917,7 +8997,7 @@ async function startAndWaitForPlayCompletionByStreamOnce(input) {
|
|
|
8917
8997
|
clearTimeout(timeout);
|
|
8918
8998
|
}
|
|
8919
8999
|
const reason = error instanceof Error ? error.message : String(error);
|
|
8920
|
-
if (!
|
|
9000
|
+
if (!input2.jsonOutput) {
|
|
8921
9001
|
process.stderr.write(
|
|
8922
9002
|
`[play watch] start stream failed after run ${lastKnownWorkflowId}; reconnecting to run stream (${reason})
|
|
8923
9003
|
`
|
|
@@ -8927,7 +9007,7 @@ async function startAndWaitForPlayCompletionByStreamOnce(input) {
|
|
|
8927
9007
|
phase: "cli.play_start_stream_reconnect",
|
|
8928
9008
|
ms: Date.now() - startedAt,
|
|
8929
9009
|
ok: true,
|
|
8930
|
-
playName:
|
|
9010
|
+
playName: input2.playName,
|
|
8931
9011
|
workflowId: lastKnownWorkflowId,
|
|
8932
9012
|
eventCount,
|
|
8933
9013
|
firstRunIdMs,
|
|
@@ -8935,16 +9015,16 @@ async function startAndWaitForPlayCompletionByStreamOnce(input) {
|
|
|
8935
9015
|
reason
|
|
8936
9016
|
});
|
|
8937
9017
|
return waitForPlayCompletionByStream({
|
|
8938
|
-
client:
|
|
8939
|
-
playName:
|
|
9018
|
+
client: input2.client,
|
|
9019
|
+
playName: input2.playName,
|
|
8940
9020
|
workflowId: lastKnownWorkflowId,
|
|
8941
9021
|
dashboardUrl,
|
|
8942
|
-
jsonOutput:
|
|
8943
|
-
emitLogs:
|
|
8944
|
-
waitTimeoutMs:
|
|
9022
|
+
jsonOutput: input2.jsonOutput,
|
|
9023
|
+
emitLogs: input2.emitLogs,
|
|
9024
|
+
waitTimeoutMs: input2.waitTimeoutMs,
|
|
8945
9025
|
startedAt,
|
|
8946
9026
|
state,
|
|
8947
|
-
progress:
|
|
9027
|
+
progress: input2.progress
|
|
8948
9028
|
});
|
|
8949
9029
|
}
|
|
8950
9030
|
throw error;
|
|
@@ -8954,8 +9034,8 @@ async function startAndWaitForPlayCompletionByStreamOnce(input) {
|
|
|
8954
9034
|
}
|
|
8955
9035
|
}
|
|
8956
9036
|
if (lastKnownWorkflowId) {
|
|
8957
|
-
if (!
|
|
8958
|
-
|
|
9037
|
+
if (!input2.jsonOutput) {
|
|
9038
|
+
input2.progress.writeLine(
|
|
8959
9039
|
`[play watch] start stream ended after run ${lastKnownWorkflowId}; reconnecting to run stream`
|
|
8960
9040
|
);
|
|
8961
9041
|
}
|
|
@@ -8963,7 +9043,7 @@ async function startAndWaitForPlayCompletionByStreamOnce(input) {
|
|
|
8963
9043
|
phase: "cli.play_start_stream_reconnect",
|
|
8964
9044
|
ms: Date.now() - startedAt,
|
|
8965
9045
|
ok: true,
|
|
8966
|
-
playName:
|
|
9046
|
+
playName: input2.playName,
|
|
8967
9047
|
workflowId: lastKnownWorkflowId,
|
|
8968
9048
|
eventCount,
|
|
8969
9049
|
firstRunIdMs,
|
|
@@ -8971,16 +9051,16 @@ async function startAndWaitForPlayCompletionByStreamOnce(input) {
|
|
|
8971
9051
|
reason: "stream ended before terminal event"
|
|
8972
9052
|
});
|
|
8973
9053
|
return waitForPlayCompletionByStream({
|
|
8974
|
-
client:
|
|
8975
|
-
playName:
|
|
9054
|
+
client: input2.client,
|
|
9055
|
+
playName: input2.playName,
|
|
8976
9056
|
workflowId: lastKnownWorkflowId,
|
|
8977
9057
|
dashboardUrl,
|
|
8978
|
-
jsonOutput:
|
|
8979
|
-
emitLogs:
|
|
8980
|
-
waitTimeoutMs:
|
|
9058
|
+
jsonOutput: input2.jsonOutput,
|
|
9059
|
+
emitLogs: input2.emitLogs,
|
|
9060
|
+
waitTimeoutMs: input2.waitTimeoutMs,
|
|
8981
9061
|
startedAt,
|
|
8982
9062
|
state,
|
|
8983
|
-
progress:
|
|
9063
|
+
progress: input2.progress
|
|
8984
9064
|
});
|
|
8985
9065
|
}
|
|
8986
9066
|
const phaseSuffix = lastPhase && lastPhase.trim() ? ` (last observed phase: ${lastPhase.trim()})` : "";
|
|
@@ -9061,7 +9141,7 @@ function compactReturnValue(value, depth = 0) {
|
|
|
9061
9141
|
if (!value || typeof value !== "object") {
|
|
9062
9142
|
return value;
|
|
9063
9143
|
}
|
|
9064
|
-
const
|
|
9144
|
+
const output2 = {};
|
|
9065
9145
|
for (const [key, entry] of Object.entries(value)) {
|
|
9066
9146
|
if (depth === 0 && key === "_metadata") {
|
|
9067
9147
|
continue;
|
|
@@ -9072,9 +9152,9 @@ function compactReturnValue(value, depth = 0) {
|
|
|
9072
9152
|
if (key === "access") {
|
|
9073
9153
|
continue;
|
|
9074
9154
|
}
|
|
9075
|
-
|
|
9155
|
+
output2[key] = compactReturnValue(entry, depth + 1);
|
|
9076
9156
|
}
|
|
9077
|
-
return
|
|
9157
|
+
return output2;
|
|
9078
9158
|
}
|
|
9079
9159
|
function formatJsonPreview(value) {
|
|
9080
9160
|
const json = JSON.stringify(value, null, 2);
|
|
@@ -9283,22 +9363,22 @@ function extractBillingForStatus(status, error) {
|
|
|
9283
9363
|
const progressError = getStringField(status.progress, "error");
|
|
9284
9364
|
return extractBillingFromText(error) ?? extractBillingFromText(progressError) ?? getObjectField(status, "billing");
|
|
9285
9365
|
}
|
|
9286
|
-
function formatInsufficientCreditsMessage(
|
|
9287
|
-
const operation = getStringField(
|
|
9288
|
-
const balance = formatCreditAmount(
|
|
9289
|
-
const required = formatCreditAmount(
|
|
9366
|
+
function formatInsufficientCreditsMessage(input2) {
|
|
9367
|
+
const operation = getStringField(input2.billing, "operation_id") ?? getStringField(input2.billing, "operation") ?? extractToolIdFromErrorText(input2.error) ?? getStringField(input2.billing, "provider") ?? "tool call";
|
|
9368
|
+
const balance = formatCreditAmount(input2.billing.balance_credits);
|
|
9369
|
+
const required = formatCreditAmount(input2.billing.required_credits);
|
|
9290
9370
|
const recommended = formatCreditAmount(
|
|
9291
|
-
|
|
9371
|
+
input2.billing.recommended_add_credits ?? input2.billing.needed_credits
|
|
9292
9372
|
);
|
|
9293
|
-
const billingUrl = getStringField(
|
|
9294
|
-
const workspace = getStringField(
|
|
9373
|
+
const billingUrl = getStringField(input2.billing, "billing_url");
|
|
9374
|
+
const workspace = getStringField(input2.billing, "workspace_id") ?? getStringField(input2.billing, "workspaceId");
|
|
9295
9375
|
const workspaceSuffix = workspace ? ` (workspace=${workspace})` : "";
|
|
9296
9376
|
const addSuffix = billingUrl && recommended !== "-" ? ` Add >=${recommended} at ${billingUrl}.` : billingUrl ? ` Add credits at ${billingUrl}.` : "";
|
|
9297
9377
|
return `Workspace balance ${balance} < required ${required} for ${operation}${workspaceSuffix}.${addSuffix}`;
|
|
9298
9378
|
}
|
|
9299
|
-
function buildInsufficientCreditsSummaryLines(
|
|
9300
|
-
const progress =
|
|
9301
|
-
const rowsInfo = extractCanonicalRowsInfo(
|
|
9379
|
+
function buildInsufficientCreditsSummaryLines(input2) {
|
|
9380
|
+
const progress = input2.status.progress;
|
|
9381
|
+
const rowsInfo = extractCanonicalRowsInfo(input2.status);
|
|
9302
9382
|
const completed = getNumericField(progress, "completed") ?? getNumericField(progress, "completedRows") ?? rowsInfo?.rows.length ?? null;
|
|
9303
9383
|
const total = getNumericField(progress, "total") ?? getNumericField(progress, "totalRows") ?? rowsInfo?.totalRows ?? null;
|
|
9304
9384
|
const lines = [
|
|
@@ -9306,16 +9386,16 @@ function buildInsufficientCreditsSummaryLines(input) {
|
|
|
9306
9386
|
completed === null ? " completed rows: unknown" : ` completed rows: ${formatInteger(completed)}${total !== null ? ` of ${formatInteger(total)}` : ""}`,
|
|
9307
9387
|
" reusable receipts: yes; rerun after adding credits to continue from completed provider work"
|
|
9308
9388
|
];
|
|
9309
|
-
const billingUrl = getStringField(
|
|
9389
|
+
const billingUrl = getStringField(input2.billing, "billing_url");
|
|
9310
9390
|
const recommended = formatCreditAmount(
|
|
9311
|
-
|
|
9391
|
+
input2.billing.recommended_add_credits ?? input2.billing.needed_credits
|
|
9312
9392
|
);
|
|
9313
9393
|
if (billingUrl) {
|
|
9314
9394
|
lines.push(
|
|
9315
9395
|
recommended !== "-" ? ` add credits: add >=${recommended} at ${billingUrl}` : ` add credits: ${billingUrl}`
|
|
9316
9396
|
);
|
|
9317
9397
|
}
|
|
9318
|
-
const runId =
|
|
9398
|
+
const runId = input2.status.runId?.trim();
|
|
9319
9399
|
if (runId) {
|
|
9320
9400
|
lines.push(` inspect: deepline runs get ${runId} --json`);
|
|
9321
9401
|
lines.push(
|
|
@@ -9650,8 +9730,8 @@ function actionToCommand(action) {
|
|
|
9650
9730
|
}
|
|
9651
9731
|
function readFirstDatasetActions(packaged) {
|
|
9652
9732
|
for (const step of readRecordArray(packaged.steps)) {
|
|
9653
|
-
const
|
|
9654
|
-
const actions =
|
|
9733
|
+
const output2 = step.output && typeof step.output === "object" && !Array.isArray(step.output) ? step.output : null;
|
|
9734
|
+
const actions = output2?.actions && typeof output2.actions === "object" && !Array.isArray(output2.actions) ? output2.actions : null;
|
|
9655
9735
|
if (actions) {
|
|
9656
9736
|
return actions;
|
|
9657
9737
|
}
|
|
@@ -9673,12 +9753,12 @@ function buildRunPackageTextLines(packaged) {
|
|
|
9673
9753
|
const id = typeof step.id === "string" ? step.id : "step";
|
|
9674
9754
|
const kind = typeof step.kind === "string" ? step.kind : "step";
|
|
9675
9755
|
const stepStatus = typeof step.status === "string" ? step.status : status;
|
|
9676
|
-
const
|
|
9677
|
-
const rowCount =
|
|
9678
|
-
const preview =
|
|
9756
|
+
const output2 = step.output && typeof step.output === "object" && !Array.isArray(step.output) ? step.output : null;
|
|
9757
|
+
const rowCount = output2 && typeof output2.rowCount === "number" ? ` rows=${formatInteger(output2.rowCount)}` : "";
|
|
9758
|
+
const preview = output2?.preview && typeof output2.preview === "object" && !Array.isArray(output2.preview) ? output2.preview : null;
|
|
9679
9759
|
const previewRows = Array.isArray(preview?.rows) ? preview.rows.length : null;
|
|
9680
9760
|
lines.push(` ${kind} ${id}: ${stepStatus}${rowCount}`);
|
|
9681
|
-
lines.push(...formatPackageDatasetSummaryLines(
|
|
9761
|
+
lines.push(...formatPackageDatasetSummaryLines(output2?.summary));
|
|
9682
9762
|
if (previewRows !== null) {
|
|
9683
9763
|
lines.push(
|
|
9684
9764
|
` preview=${previewRows}${preview?.truncated ? " truncated" : ""}`
|
|
@@ -9761,19 +9841,19 @@ function writePlayResult(status, jsonOutput, options) {
|
|
|
9761
9841
|
` }
|
|
9762
9842
|
);
|
|
9763
9843
|
}
|
|
9764
|
-
async function resolvePlayRunOutputStatus(
|
|
9765
|
-
if (!getPlayRunPackage(
|
|
9766
|
-
return
|
|
9844
|
+
async function resolvePlayRunOutputStatus(input2) {
|
|
9845
|
+
if (!getPlayRunPackage(input2.status)) {
|
|
9846
|
+
return input2.status;
|
|
9767
9847
|
}
|
|
9768
|
-
const runId =
|
|
9848
|
+
const runId = input2.status.runId;
|
|
9769
9849
|
if (!runId) {
|
|
9770
|
-
return
|
|
9850
|
+
return input2.status;
|
|
9771
9851
|
}
|
|
9772
|
-
const refreshedStatus = await
|
|
9852
|
+
const refreshedStatus = await input2.client.getPlayStatus(runId, {
|
|
9773
9853
|
billing: false,
|
|
9774
|
-
full:
|
|
9854
|
+
full: input2.fullJson
|
|
9775
9855
|
});
|
|
9776
|
-
const dashboardUrl =
|
|
9856
|
+
const dashboardUrl = input2.status.dashboardUrl;
|
|
9777
9857
|
return typeof dashboardUrl === "string" ? { ...refreshedStatus, dashboardUrl } : refreshedStatus;
|
|
9778
9858
|
}
|
|
9779
9859
|
var RUN_EXPORT_PAGE_SIZE = 5e3;
|
|
@@ -9804,21 +9884,21 @@ function extractRunPlayName(status) {
|
|
|
9804
9884
|
function normalizeCustomerDbIdentifier(value) {
|
|
9805
9885
|
return value.split("/").pop().replace(/[^A-Za-z0-9]+/g, "_").replace(/^_+|_+$/g, "").toLowerCase();
|
|
9806
9886
|
}
|
|
9807
|
-
function buildCustomerDbQueryPlan(
|
|
9808
|
-
const playName = extractRunPlayName(
|
|
9809
|
-
const tableNamespace =
|
|
9810
|
-
if (!playName || !tableNamespace ||
|
|
9887
|
+
function buildCustomerDbQueryPlan(input2) {
|
|
9888
|
+
const playName = extractRunPlayName(input2.status);
|
|
9889
|
+
const tableNamespace = input2.rowsInfo.tableNamespace?.trim();
|
|
9890
|
+
if (!playName || !tableNamespace || input2.rowsInfo.totalRows <= 0) {
|
|
9811
9891
|
return null;
|
|
9812
9892
|
}
|
|
9813
9893
|
const tableName = `${normalizeCustomerDbIdentifier(playName)}_${normalizeCustomerDbIdentifier(
|
|
9814
9894
|
tableNamespace
|
|
9815
9895
|
)}`;
|
|
9816
|
-
const sql = `select * from "storage"."${tableName}" where _run_id = ${sqlStringLiteral(
|
|
9817
|
-
const base = `deepline customer-db query --sql ${shellSingleQuote(sql)} --max-rows ${
|
|
9896
|
+
const sql = `select * from "storage"."${tableName}" where _run_id = ${sqlStringLiteral(input2.status.runId)} limit ${input2.rowsInfo.totalRows}`;
|
|
9897
|
+
const base = `deepline customer-db query --sql ${shellSingleQuote(sql)} --max-rows ${input2.rowsInfo.totalRows}`;
|
|
9818
9898
|
return {
|
|
9819
9899
|
sql,
|
|
9820
9900
|
json: `${base} --json`,
|
|
9821
|
-
csv: `${base} --format csv --out ${shellSingleQuote(resolve10(
|
|
9901
|
+
csv: `${base} --format csv --out ${shellSingleQuote(resolve10(input2.outPath))}`
|
|
9822
9902
|
};
|
|
9823
9903
|
}
|
|
9824
9904
|
function exportableSheetRow(row) {
|
|
@@ -9869,20 +9949,20 @@ function mergeExportColumns(preferredColumns, rows) {
|
|
|
9869
9949
|
}
|
|
9870
9950
|
return columns;
|
|
9871
9951
|
}
|
|
9872
|
-
async function fetchBackingDatasetRows(
|
|
9873
|
-
const playName = extractRunPlayName(
|
|
9874
|
-
const tableNamespace =
|
|
9952
|
+
async function fetchBackingDatasetRows(input2) {
|
|
9953
|
+
const playName = extractRunPlayName(input2.status);
|
|
9954
|
+
const tableNamespace = input2.rowsInfo.tableNamespace?.trim();
|
|
9875
9955
|
if (!playName || !tableNamespace) {
|
|
9876
9956
|
return null;
|
|
9877
9957
|
}
|
|
9878
9958
|
const sheetRows = [];
|
|
9879
9959
|
let offset = 0;
|
|
9880
|
-
let expectedTotal =
|
|
9960
|
+
let expectedTotal = input2.rowsInfo.totalRows;
|
|
9881
9961
|
while (true) {
|
|
9882
|
-
const page = await
|
|
9962
|
+
const page = await input2.client.runs.exportDatasetRows({
|
|
9883
9963
|
playName,
|
|
9884
9964
|
tableNamespace,
|
|
9885
|
-
runId:
|
|
9965
|
+
runId: input2.status.runId,
|
|
9886
9966
|
limit: RUN_EXPORT_PAGE_SIZE,
|
|
9887
9967
|
offset
|
|
9888
9968
|
});
|
|
@@ -9897,20 +9977,20 @@ async function fetchBackingDatasetRows(input) {
|
|
|
9897
9977
|
offset += page.rows.length;
|
|
9898
9978
|
}
|
|
9899
9979
|
const rows = sheetRows.map(exportableSheetRow).filter((row) => Boolean(row));
|
|
9900
|
-
if (rows.length <
|
|
9980
|
+
if (rows.length < input2.rowsInfo.totalRows) {
|
|
9901
9981
|
return null;
|
|
9902
9982
|
}
|
|
9903
9983
|
const columns = mergeExportColumns(
|
|
9904
|
-
|
|
9984
|
+
input2.rowsInfo.columnsExplicit ? input2.rowsInfo.columns : [],
|
|
9905
9985
|
rows
|
|
9906
9986
|
);
|
|
9907
9987
|
return {
|
|
9908
|
-
...
|
|
9988
|
+
...input2.rowsInfo,
|
|
9909
9989
|
rows,
|
|
9910
9990
|
columns,
|
|
9911
9991
|
totalRows: rows.length,
|
|
9912
9992
|
complete: true,
|
|
9913
|
-
source: `${
|
|
9993
|
+
source: `${input2.rowsInfo.source ?? "result.rows"} -> /api/v2/plays/${playName}/sheet?tableNamespace=${tableNamespace}`
|
|
9914
9994
|
};
|
|
9915
9995
|
}
|
|
9916
9996
|
async function exportPlayStatusRows(client, status, outPath, options = {}) {
|
|
@@ -10012,11 +10092,11 @@ function extractActiveRunsFromError(error) {
|
|
|
10012
10092
|
function activeRunId(run) {
|
|
10013
10093
|
return getStringField(run, "workflowId") ?? getStringField(run, "runId");
|
|
10014
10094
|
}
|
|
10015
|
-
function formatActiveRunConflictError(
|
|
10095
|
+
function formatActiveRunConflictError(input2) {
|
|
10016
10096
|
const lines = [
|
|
10017
|
-
`Active run exists for ${
|
|
10097
|
+
`Active run exists for ${input2.playName}. Use --force to supersede, or inspect/stop the active run first.`
|
|
10018
10098
|
];
|
|
10019
|
-
for (const run of
|
|
10099
|
+
for (const run of input2.activeRuns.slice(0, 3)) {
|
|
10020
10100
|
const runId = activeRunId(run);
|
|
10021
10101
|
if (!runId) {
|
|
10022
10102
|
continue;
|
|
@@ -10130,49 +10210,49 @@ function renderServerResultView(value) {
|
|
|
10130
10210
|
}
|
|
10131
10211
|
return { lines: lines.length > 1 ? lines : [], actions: [] };
|
|
10132
10212
|
}
|
|
10133
|
-
function writeStartedPlayRun(
|
|
10134
|
-
if (
|
|
10135
|
-
if (
|
|
10136
|
-
printCommandEnvelope(
|
|
10213
|
+
function writeStartedPlayRun(input2) {
|
|
10214
|
+
if (input2.package && isPlayRunPackageValue(input2.package)) {
|
|
10215
|
+
if (input2.jsonOutput) {
|
|
10216
|
+
printCommandEnvelope(input2.package, { json: true });
|
|
10137
10217
|
return;
|
|
10138
10218
|
}
|
|
10139
|
-
const lines2 = buildRunPackageTextLines(
|
|
10140
|
-
const
|
|
10141
|
-
if (
|
|
10142
|
-
|
|
10219
|
+
const lines2 = buildRunPackageTextLines(input2.package);
|
|
10220
|
+
const output3 = lines2.join("\n");
|
|
10221
|
+
if (input2.progress) {
|
|
10222
|
+
input2.progress.writeLine(output3, process.stdout);
|
|
10143
10223
|
return;
|
|
10144
10224
|
}
|
|
10145
|
-
printCommandEnvelope(
|
|
10225
|
+
printCommandEnvelope(input2.package, {
|
|
10146
10226
|
json: false,
|
|
10147
|
-
text: `${
|
|
10227
|
+
text: `${output3}
|
|
10148
10228
|
`
|
|
10149
10229
|
});
|
|
10150
10230
|
return;
|
|
10151
10231
|
}
|
|
10152
10232
|
const payload = {
|
|
10153
|
-
runId:
|
|
10154
|
-
workflowId:
|
|
10155
|
-
name:
|
|
10156
|
-
status:
|
|
10157
|
-
dashboardUrl:
|
|
10233
|
+
runId: input2.runId,
|
|
10234
|
+
workflowId: input2.runId,
|
|
10235
|
+
name: input2.playName,
|
|
10236
|
+
status: input2.status ?? "started",
|
|
10237
|
+
dashboardUrl: input2.dashboardUrl,
|
|
10158
10238
|
next: {
|
|
10159
|
-
inspect: `deepline runs get ${
|
|
10160
|
-
full: `deepline runs get ${
|
|
10161
|
-
logs: `deepline runs logs ${
|
|
10162
|
-
export: `deepline runs export ${
|
|
10163
|
-
stop: `deepline runs stop ${
|
|
10239
|
+
inspect: `deepline runs get ${input2.runId} --json`,
|
|
10240
|
+
full: `deepline runs get ${input2.runId} --full --json`,
|
|
10241
|
+
logs: `deepline runs logs ${input2.runId} --json`,
|
|
10242
|
+
export: `deepline runs export ${input2.runId} --out output.csv`,
|
|
10243
|
+
stop: `deepline runs stop ${input2.runId} --reason "stale lock" --json`
|
|
10164
10244
|
}
|
|
10165
10245
|
};
|
|
10166
10246
|
const lines = [
|
|
10167
|
-
`Started ${
|
|
10168
|
-
` run id: ${
|
|
10169
|
-
` inspect: deepline runs get ${
|
|
10170
|
-
` full debug: deepline runs get ${
|
|
10171
|
-
` logs: deepline runs logs ${
|
|
10172
|
-
` export after completion: deepline runs export ${
|
|
10173
|
-
` stop run: deepline runs stop ${
|
|
10247
|
+
`Started ${input2.playName}`,
|
|
10248
|
+
` run id: ${input2.runId}`,
|
|
10249
|
+
` inspect: deepline runs get ${input2.runId} --json`,
|
|
10250
|
+
` full debug: deepline runs get ${input2.runId} --full --json`,
|
|
10251
|
+
` logs: deepline runs logs ${input2.runId} --json`,
|
|
10252
|
+
` export after completion: deepline runs export ${input2.runId} --out output.csv`,
|
|
10253
|
+
` stop run: deepline runs stop ${input2.runId} --reason "stale lock" --json`
|
|
10174
10254
|
];
|
|
10175
|
-
if (
|
|
10255
|
+
if (input2.jsonOutput) {
|
|
10176
10256
|
printCommandEnvelope(
|
|
10177
10257
|
{
|
|
10178
10258
|
...payload,
|
|
@@ -10182,12 +10262,12 @@ function writeStartedPlayRun(input) {
|
|
|
10182
10262
|
);
|
|
10183
10263
|
return;
|
|
10184
10264
|
}
|
|
10185
|
-
if (
|
|
10186
|
-
lines.push(` play page: ${
|
|
10265
|
+
if (input2.dashboardUrl) {
|
|
10266
|
+
lines.push(` play page: ${input2.dashboardUrl}`);
|
|
10187
10267
|
}
|
|
10188
|
-
const
|
|
10189
|
-
if (
|
|
10190
|
-
|
|
10268
|
+
const output2 = lines.join("\n");
|
|
10269
|
+
if (input2.progress) {
|
|
10270
|
+
input2.progress.writeLine(output2, process.stdout);
|
|
10191
10271
|
return;
|
|
10192
10272
|
}
|
|
10193
10273
|
printCommandEnvelope(
|
|
@@ -10195,7 +10275,7 @@ function writeStartedPlayRun(input) {
|
|
|
10195
10275
|
...payload,
|
|
10196
10276
|
render: { sections: [{ title: "play run", lines }] }
|
|
10197
10277
|
},
|
|
10198
|
-
{ json: false, text: `${
|
|
10278
|
+
{ json: false, text: `${output2}
|
|
10199
10279
|
` }
|
|
10200
10280
|
);
|
|
10201
10281
|
}
|
|
@@ -10203,7 +10283,7 @@ function parsePlayRunOptions(args) {
|
|
|
10203
10283
|
const usage = "Usage: deepline plays run <play-name> [--input '{...}'] [--no-wait] [--tail-timeout-ms 30000] [--force] [--full] [--<input> value]\n deepline plays run <play-file.ts> [--input '{...}'] [--no-wait] [--tail-timeout-ms 30000] [--force] [--full] [--<input> value]\n deepline plays run --file <play-file.ts> [--input '{...}'] [--no-wait] [--tail-timeout-ms 30000] [--force] [--full] [--<input> value]\n deepline plays run --name <name> [--input '{...}'] [--live|--latest|--revision-id <id>] [--no-wait] [--tail-timeout-ms 30000] [--force] [--no-open] [--json] [--full] [--<input> value]\n Unknown --<input> value flags, such as --limit 5, are passed into play input.\nRun `deepline plays run --help` for idempotency, tool call id, and ctx.map guidance.";
|
|
10204
10284
|
let filePath = null;
|
|
10205
10285
|
let playName = null;
|
|
10206
|
-
let
|
|
10286
|
+
let input2 = null;
|
|
10207
10287
|
let revisionId = null;
|
|
10208
10288
|
let revisionSelector = null;
|
|
10209
10289
|
const watch = !args.includes("--no-wait");
|
|
@@ -10224,7 +10304,7 @@ function parsePlayRunOptions(args) {
|
|
|
10224
10304
|
continue;
|
|
10225
10305
|
}
|
|
10226
10306
|
if ((arg === "--input" || arg === "-i") && args[index + 1]) {
|
|
10227
|
-
|
|
10307
|
+
input2 = parseJsonInput(args[++index]);
|
|
10228
10308
|
continue;
|
|
10229
10309
|
}
|
|
10230
10310
|
if (arg === "--revision-id" && args[index + 1]) {
|
|
@@ -10273,8 +10353,8 @@ function parsePlayRunOptions(args) {
|
|
|
10273
10353
|
}
|
|
10274
10354
|
if (arg.startsWith("--")) {
|
|
10275
10355
|
const { path, value } = parseInputFieldFlag(arg, args[index + 1]);
|
|
10276
|
-
|
|
10277
|
-
setDottedInputValue(
|
|
10356
|
+
input2 ??= {};
|
|
10357
|
+
setDottedInputValue(input2, path, parseInputFlagValue(value));
|
|
10278
10358
|
if (!arg.includes("=")) {
|
|
10279
10359
|
index += 1;
|
|
10280
10360
|
}
|
|
@@ -10309,7 +10389,7 @@ function parsePlayRunOptions(args) {
|
|
|
10309
10389
|
}
|
|
10310
10390
|
return {
|
|
10311
10391
|
target: filePath ? { kind: "file", path: filePath } : { kind: "name", name: playName },
|
|
10312
|
-
input,
|
|
10392
|
+
input: input2,
|
|
10313
10393
|
revisionId,
|
|
10314
10394
|
revisionSelector,
|
|
10315
10395
|
watch,
|
|
@@ -10676,15 +10756,15 @@ async function handleFileBackedRun(options) {
|
|
|
10676
10756
|
});
|
|
10677
10757
|
return 0;
|
|
10678
10758
|
}
|
|
10679
|
-
async function resolveNamedRunRevisionId(
|
|
10680
|
-
if (
|
|
10681
|
-
return
|
|
10759
|
+
async function resolveNamedRunRevisionId(input2) {
|
|
10760
|
+
if (input2.revisionId) {
|
|
10761
|
+
return input2.revisionId;
|
|
10682
10762
|
}
|
|
10683
|
-
if (
|
|
10684
|
-
const versions = await
|
|
10763
|
+
if (input2.selector === "latest") {
|
|
10764
|
+
const versions = await input2.client.listPlayVersions(input2.playName);
|
|
10685
10765
|
const latest = versions[0];
|
|
10686
10766
|
if (!latest?._id) {
|
|
10687
|
-
throw new Error(`No saved revisions found for ${
|
|
10767
|
+
throw new Error(`No saved revisions found for ${input2.playName}.`);
|
|
10688
10768
|
}
|
|
10689
10769
|
return latest._id;
|
|
10690
10770
|
}
|
|
@@ -12484,6 +12564,218 @@ async function handlePlayShareUnpublish(args) {
|
|
|
12484
12564
|
return 0;
|
|
12485
12565
|
}
|
|
12486
12566
|
|
|
12567
|
+
// src/cli/commands/secrets.ts
|
|
12568
|
+
import { stdin as input, stdout as output } from "process";
|
|
12569
|
+
var hiddenInputBuffer = "";
|
|
12570
|
+
function normalizeSecretName(value) {
|
|
12571
|
+
const normalized = value.trim().toUpperCase();
|
|
12572
|
+
if (!/^[A-Z][A-Z0-9_]{1,63}$/.test(normalized)) {
|
|
12573
|
+
throw new Error(
|
|
12574
|
+
"Secret names must be 2-64 characters and use uppercase letters, numbers, and underscores."
|
|
12575
|
+
);
|
|
12576
|
+
}
|
|
12577
|
+
return normalized;
|
|
12578
|
+
}
|
|
12579
|
+
function renderSecret(secret) {
|
|
12580
|
+
const scope = secret.scope === "play" && secret.playName ? `play:${secret.playName}` : secret.scope;
|
|
12581
|
+
return `${secret.name} (${scope}) - ${secret.status}${secret.hasValue ? ", set" : ", empty"}`;
|
|
12582
|
+
}
|
|
12583
|
+
async function readHiddenLine(prompt) {
|
|
12584
|
+
if (!input.isTTY || !output.isTTY) {
|
|
12585
|
+
throw new Error(
|
|
12586
|
+
"Secret values must be entered from an interactive TTY. Do not pipe, pass, or script secret values."
|
|
12587
|
+
);
|
|
12588
|
+
}
|
|
12589
|
+
output.write(prompt);
|
|
12590
|
+
const previousRawMode = input.isRaw;
|
|
12591
|
+
if (typeof input.setRawMode === "function") input.setRawMode(true);
|
|
12592
|
+
let value = "";
|
|
12593
|
+
input.resume();
|
|
12594
|
+
return await new Promise((resolve12, reject) => {
|
|
12595
|
+
let settled = false;
|
|
12596
|
+
const cleanup = () => {
|
|
12597
|
+
input.off("data", onData);
|
|
12598
|
+
input.off("end", onEnd);
|
|
12599
|
+
input.off("error", onError);
|
|
12600
|
+
if (typeof input.setRawMode === "function") {
|
|
12601
|
+
input.setRawMode(previousRawMode);
|
|
12602
|
+
}
|
|
12603
|
+
};
|
|
12604
|
+
const finish = (line) => {
|
|
12605
|
+
if (settled) return;
|
|
12606
|
+
settled = true;
|
|
12607
|
+
output.write("\n");
|
|
12608
|
+
cleanup();
|
|
12609
|
+
resolve12(line);
|
|
12610
|
+
};
|
|
12611
|
+
const fail = (error) => {
|
|
12612
|
+
if (settled) return;
|
|
12613
|
+
settled = true;
|
|
12614
|
+
output.write("\n");
|
|
12615
|
+
cleanup();
|
|
12616
|
+
reject(error);
|
|
12617
|
+
};
|
|
12618
|
+
const processText = (text) => {
|
|
12619
|
+
for (let index = 0; index < text.length; index++) {
|
|
12620
|
+
const char = text[index];
|
|
12621
|
+
const code = char.charCodeAt(0);
|
|
12622
|
+
if (char === "\r" || char === "\n") {
|
|
12623
|
+
hiddenInputBuffer = text.slice(index + 1);
|
|
12624
|
+
finish(value);
|
|
12625
|
+
return;
|
|
12626
|
+
}
|
|
12627
|
+
if (code === 3) {
|
|
12628
|
+
fail(new Error("Secret input cancelled."));
|
|
12629
|
+
return;
|
|
12630
|
+
}
|
|
12631
|
+
if (code === 8 || code === 127) {
|
|
12632
|
+
value = value.slice(0, -1);
|
|
12633
|
+
continue;
|
|
12634
|
+
}
|
|
12635
|
+
if (code >= 32) {
|
|
12636
|
+
value += char;
|
|
12637
|
+
}
|
|
12638
|
+
}
|
|
12639
|
+
hiddenInputBuffer = "";
|
|
12640
|
+
};
|
|
12641
|
+
const onData = (chunk) => {
|
|
12642
|
+
processText(chunk.toString());
|
|
12643
|
+
};
|
|
12644
|
+
const onEnd = () => fail(new Error("Secret input ended before a value was entered."));
|
|
12645
|
+
const onError = (error) => fail(error);
|
|
12646
|
+
input.on("data", onData);
|
|
12647
|
+
input.once("end", onEnd);
|
|
12648
|
+
input.once("error", onError);
|
|
12649
|
+
if (hiddenInputBuffer) {
|
|
12650
|
+
const buffered = hiddenInputBuffer;
|
|
12651
|
+
hiddenInputBuffer = "";
|
|
12652
|
+
processText(buffered);
|
|
12653
|
+
}
|
|
12654
|
+
});
|
|
12655
|
+
}
|
|
12656
|
+
async function readSecretValue() {
|
|
12657
|
+
const first = await readHiddenLine("Secret value: ");
|
|
12658
|
+
if (!first) throw new Error("Secret value is required.");
|
|
12659
|
+
const second = await readHiddenLine("Confirm secret value: ");
|
|
12660
|
+
if (first !== second) {
|
|
12661
|
+
throw new Error("Secret values did not match.");
|
|
12662
|
+
}
|
|
12663
|
+
return first;
|
|
12664
|
+
}
|
|
12665
|
+
function preventShellHistoryLeak(forbidden) {
|
|
12666
|
+
if (forbidden.length > 0) {
|
|
12667
|
+
throw new Error(
|
|
12668
|
+
"Do not pass secret values as command arguments. Run `deepline secrets set NAME` and enter the value at the hidden prompt."
|
|
12669
|
+
);
|
|
12670
|
+
}
|
|
12671
|
+
}
|
|
12672
|
+
async function handleList(options) {
|
|
12673
|
+
const client = new DeeplineClient();
|
|
12674
|
+
const secrets = await client.listSecrets();
|
|
12675
|
+
printCommandEnvelope(
|
|
12676
|
+
{
|
|
12677
|
+
secrets,
|
|
12678
|
+
count: secrets.length,
|
|
12679
|
+
render: {
|
|
12680
|
+
sections: [
|
|
12681
|
+
{
|
|
12682
|
+
title: "secrets",
|
|
12683
|
+
lines: secrets.length ? secrets.map(renderSecret) : ["No play secrets are configured."]
|
|
12684
|
+
}
|
|
12685
|
+
]
|
|
12686
|
+
}
|
|
12687
|
+
},
|
|
12688
|
+
{ json: options.json }
|
|
12689
|
+
);
|
|
12690
|
+
}
|
|
12691
|
+
async function handleCheck(nameInput, options) {
|
|
12692
|
+
const name = normalizeSecretName(nameInput);
|
|
12693
|
+
const client = new DeeplineClient();
|
|
12694
|
+
const secret = await client.checkSecret(name);
|
|
12695
|
+
printCommandEnvelope(
|
|
12696
|
+
{
|
|
12697
|
+
ok: Boolean(secret),
|
|
12698
|
+
name,
|
|
12699
|
+
secret: secret ?? null,
|
|
12700
|
+
render: {
|
|
12701
|
+
sections: [
|
|
12702
|
+
{
|
|
12703
|
+
title: "secret check",
|
|
12704
|
+
lines: [
|
|
12705
|
+
secret ? `${name}: active` : `${name}: missing, disabled, or empty`
|
|
12706
|
+
]
|
|
12707
|
+
}
|
|
12708
|
+
]
|
|
12709
|
+
}
|
|
12710
|
+
},
|
|
12711
|
+
{ json: options.json }
|
|
12712
|
+
);
|
|
12713
|
+
if (!secret) process.exitCode = 4;
|
|
12714
|
+
}
|
|
12715
|
+
async function handleSet(nameInput, forbidden, options) {
|
|
12716
|
+
preventShellHistoryLeak(forbidden);
|
|
12717
|
+
const name = normalizeSecretName(nameInput);
|
|
12718
|
+
const scope = options.scope === "play" ? "play" : "org";
|
|
12719
|
+
const playName = options.play?.trim();
|
|
12720
|
+
if (scope === "play" && !playName) {
|
|
12721
|
+
throw new Error("--play <name> is required when --scope play is used.");
|
|
12722
|
+
}
|
|
12723
|
+
const value = await readSecretValue();
|
|
12724
|
+
const { http } = getAuthedHttpClient();
|
|
12725
|
+
const response = await http.post(
|
|
12726
|
+
"/api/v2/secrets",
|
|
12727
|
+
{
|
|
12728
|
+
name,
|
|
12729
|
+
value,
|
|
12730
|
+
scope,
|
|
12731
|
+
...playName ? { playName } : {}
|
|
12732
|
+
}
|
|
12733
|
+
);
|
|
12734
|
+
const secret = response.secret;
|
|
12735
|
+
printCommandEnvelope(
|
|
12736
|
+
{
|
|
12737
|
+
ok: true,
|
|
12738
|
+
secret,
|
|
12739
|
+
render: {
|
|
12740
|
+
sections: [
|
|
12741
|
+
{
|
|
12742
|
+
title: "secret saved",
|
|
12743
|
+
lines: [`${secret.name}: saved (${secret.scope})`]
|
|
12744
|
+
}
|
|
12745
|
+
]
|
|
12746
|
+
}
|
|
12747
|
+
},
|
|
12748
|
+
{ json: options.json }
|
|
12749
|
+
);
|
|
12750
|
+
}
|
|
12751
|
+
function registerSecretsCommands(program) {
|
|
12752
|
+
const secrets = program.command("secrets").description("Manage play secrets without revealing values.").addHelpText(
|
|
12753
|
+
"after",
|
|
12754
|
+
`
|
|
12755
|
+
Notes:
|
|
12756
|
+
Secret values are never accepted as command arguments, stdin pipes, env vars,
|
|
12757
|
+
or files. Use deepline secrets set NAME and type the value at the hidden TTY
|
|
12758
|
+
prompt. Agents can list/check metadata but should not enter secret values.
|
|
12759
|
+
|
|
12760
|
+
Examples:
|
|
12761
|
+
deepline secrets list
|
|
12762
|
+
deepline secrets check HUBSPOT_TOKEN
|
|
12763
|
+
deepline secrets set HUBSPOT_TOKEN
|
|
12764
|
+
`
|
|
12765
|
+
);
|
|
12766
|
+
secrets.command("list").description("List secret metadata only.").option("--json", "Emit JSON output").action(async (options) => {
|
|
12767
|
+
await handleList(options);
|
|
12768
|
+
});
|
|
12769
|
+
secrets.command("check").description("Check whether a secret exists and is active.").argument("<name>", "Secret name").option("--json", "Emit JSON output").action(async (name, options) => {
|
|
12770
|
+
await handleCheck(name, options);
|
|
12771
|
+
});
|
|
12772
|
+
secrets.command("set").description("Set or rotate a secret through a hidden interactive prompt.").argument("<name>", "Secret name").argument("[forbidden...]", "Do not pass secret values here").option("--json", "Emit JSON output").option("--scope <scope>", "Secret scope: org or play", "org").option("--play <name>", "Play name for play-scoped secrets").action(
|
|
12773
|
+
async (name, forbidden, options) => {
|
|
12774
|
+
await handleSet(name, forbidden ?? [], options);
|
|
12775
|
+
}
|
|
12776
|
+
);
|
|
12777
|
+
}
|
|
12778
|
+
|
|
12487
12779
|
// src/cli/commands/tools.ts
|
|
12488
12780
|
import { Option } from "commander";
|
|
12489
12781
|
import { chmodSync, mkdtempSync, writeFileSync as writeFileSync8 } from "fs";
|
|
@@ -13689,25 +13981,25 @@ function shellQuote(value) {
|
|
|
13689
13981
|
function powerShellQuote(value) {
|
|
13690
13982
|
return `'${value.replace(/'/g, "''")}'`;
|
|
13691
13983
|
}
|
|
13692
|
-
function seedToolListScript(
|
|
13693
|
-
const stem = safeFileStem(
|
|
13984
|
+
function seedToolListScript(input2) {
|
|
13985
|
+
const stem = safeFileStem(input2.toolId);
|
|
13694
13986
|
const fileName = `${stem}-workflow-seed-${Date.now()}.play.ts`;
|
|
13695
13987
|
const scriptDir = mkdtempSync(join9(tmpdir3(), "deepline-workflow-seed-"));
|
|
13696
13988
|
chmodSync(scriptDir, 448);
|
|
13697
13989
|
const scriptPath = join9(scriptDir, fileName);
|
|
13698
13990
|
const projectDir = `deepline/projects/${stem}-workflow`;
|
|
13699
13991
|
const playName = `${stem}-workflow`;
|
|
13700
|
-
const sampleRows =
|
|
13701
|
-
const columns = Object.keys(
|
|
13702
|
-
const rowKey = Object.prototype.hasOwnProperty.call(
|
|
13992
|
+
const sampleRows = input2.rows.length > 0 ? `${JSON.stringify(input2.rows.slice(0, 2)).replace(/\]$/, "")}, ...]` : "[]";
|
|
13993
|
+
const columns = Object.keys(input2.rows[0] ?? {}).join(", ");
|
|
13994
|
+
const rowKey = Object.prototype.hasOwnProperty.call(input2.rows[0] ?? {}, "id") ? '"id"' : "(row) => JSON.stringify(row)";
|
|
13703
13995
|
const script = `import { definePlay } from 'deepline';
|
|
13704
13996
|
|
|
13705
13997
|
export default definePlay(${JSON.stringify(playName)}, async (ctx) => {
|
|
13706
13998
|
const result = await ctx.tools.execute({
|
|
13707
|
-
id: ${JSON.stringify(
|
|
13708
|
-
tool: ${JSON.stringify(
|
|
13709
|
-
input: ${JSON.stringify(
|
|
13710
|
-
description: ${JSON.stringify(`Seed ${
|
|
13999
|
+
id: ${JSON.stringify(input2.toolId)},
|
|
14000
|
+
tool: ${JSON.stringify(input2.toolId)},
|
|
14001
|
+
input: ${JSON.stringify(input2.payload)},
|
|
14002
|
+
description: ${JSON.stringify(`Seed ${input2.toolId} rows for workflow expansion.`)},
|
|
13711
14003
|
});
|
|
13712
14004
|
|
|
13713
14005
|
const list = Object.values(result.extractedLists)[0];
|
|
@@ -13739,23 +14031,23 @@ export default definePlay(${JSON.stringify(playName)}, async (ctx) => {
|
|
|
13739
14031
|
windowsCopyCommand: `New-Item -ItemType Directory -Force -Path ${powerShellQuote(projectDir.replace(/\//g, "\\"))} | Out-Null; Copy-Item -LiteralPath ${powerShellQuote(scriptPath)} -Destination ${powerShellQuote(`${projectDir.replace(/\//g, "\\")}\\${fileName}`)}`
|
|
13740
14032
|
};
|
|
13741
14033
|
}
|
|
13742
|
-
function buildToolExecuteBaseEnvelope(
|
|
13743
|
-
const envelope = commandEnvelopeFromRawResponse(
|
|
13744
|
-
const summaryEntries = Object.entries(
|
|
13745
|
-
const outputPreview =
|
|
14034
|
+
function buildToolExecuteBaseEnvelope(input2) {
|
|
14035
|
+
const envelope = commandEnvelopeFromRawResponse(input2.rawResponse);
|
|
14036
|
+
const summaryEntries = Object.entries(input2.summary);
|
|
14037
|
+
const outputPreview = input2.listConversion ? {
|
|
13746
14038
|
kind: "list",
|
|
13747
|
-
rowCount:
|
|
13748
|
-
columns: Object.keys(
|
|
13749
|
-
preview:
|
|
13750
|
-
listStrategy:
|
|
13751
|
-
listSourcePath:
|
|
14039
|
+
rowCount: input2.listConversion.rows.length,
|
|
14040
|
+
columns: Object.keys(input2.listConversion.rows[0] ?? {}),
|
|
14041
|
+
preview: input2.listConversion.rows.slice(0, 5),
|
|
14042
|
+
listStrategy: input2.listConversion.strategy,
|
|
14043
|
+
listSourcePath: input2.listConversion.sourcePath
|
|
13752
14044
|
} : {
|
|
13753
14045
|
kind: summaryEntries.length > 0 ? "object" : "raw",
|
|
13754
|
-
summary:
|
|
14046
|
+
summary: input2.summary
|
|
13755
14047
|
};
|
|
13756
14048
|
const envelopeHasCanonicalOutput = isRecord5(envelope.toolResponse) && Object.prototype.hasOwnProperty.call(envelope.toolResponse, "raw");
|
|
13757
|
-
const inspectCommand = `deepline tools execute ${
|
|
13758
|
-
const actions =
|
|
14049
|
+
const inspectCommand = `deepline tools execute ${input2.toolId} --input ${shellQuote(JSON.stringify(input2.params))} --json`;
|
|
14050
|
+
const actions = input2.listConversion ? [
|
|
13759
14051
|
{
|
|
13760
14052
|
label: "next",
|
|
13761
14053
|
command: "move starter script into a project folder and expand it into a Deepline play"
|
|
@@ -13764,24 +14056,24 @@ function buildToolExecuteBaseEnvelope(input) {
|
|
|
13764
14056
|
return {
|
|
13765
14057
|
...envelope,
|
|
13766
14058
|
...envelopeHasCanonicalOutput ? { output_preview: outputPreview } : { output: outputPreview },
|
|
13767
|
-
...summaryEntries.length > 0 ? { summary:
|
|
14059
|
+
...summaryEntries.length > 0 ? { summary: input2.summary } : {},
|
|
13768
14060
|
next: {
|
|
13769
14061
|
inspect: inspectCommand,
|
|
13770
14062
|
playDebugging: "When fixing a play getter, inspect the actual play run table with runs get / inspect rows; do not copy CLI preview paths blindly.",
|
|
13771
|
-
...
|
|
14063
|
+
...input2.listConversion ? {
|
|
13772
14064
|
expandToPlay: "Use stable map and step keys so reruns are idempotent: completed rows are reused, and only missing or stale work runs again.",
|
|
13773
|
-
listSourcePath:
|
|
14065
|
+
listSourcePath: input2.listConversion.sourcePath ?? "auto-detected list in the CLI response preview"
|
|
13774
14066
|
} : {}
|
|
13775
14067
|
},
|
|
13776
14068
|
render: {
|
|
13777
|
-
sections:
|
|
14069
|
+
sections: input2.listConversion ? [
|
|
13778
14070
|
{
|
|
13779
14071
|
title: "output",
|
|
13780
14072
|
lines: [
|
|
13781
|
-
`${
|
|
14073
|
+
`${input2.listConversion.rows.length} row(s) extracted from ${input2.listConversion.sourcePath ?? "auto-detected list"}`,
|
|
13782
14074
|
"paths above are observed from this execute response; use run table rows to debug play getters",
|
|
13783
|
-
`columns: ${JSON.stringify(Object.keys(
|
|
13784
|
-
`preview: ${JSON.stringify(
|
|
14075
|
+
`columns: ${JSON.stringify(Object.keys(input2.listConversion.rows[0] ?? {}))}`,
|
|
14076
|
+
`preview: ${JSON.stringify(input2.listConversion.rows.slice(0, 5))}`
|
|
13785
14077
|
]
|
|
13786
14078
|
}
|
|
13787
14079
|
] : [
|
|
@@ -13789,7 +14081,7 @@ function buildToolExecuteBaseEnvelope(input) {
|
|
|
13789
14081
|
title: "result",
|
|
13790
14082
|
lines: summaryEntries.length > 0 ? summaryEntries.map(
|
|
13791
14083
|
([key, value]) => `${key}=${String(value)}`
|
|
13792
|
-
) : [JSON.stringify(
|
|
14084
|
+
) : [JSON.stringify(input2.rawResponse, null, 2)]
|
|
13793
14085
|
}
|
|
13794
14086
|
],
|
|
13795
14087
|
actions
|
|
@@ -14110,6 +14402,174 @@ Examples:
|
|
|
14110
14402
|
});
|
|
14111
14403
|
}
|
|
14112
14404
|
|
|
14405
|
+
// ../shared_libs/cli/command-compatibility.json
|
|
14406
|
+
var command_compatibility_default = {
|
|
14407
|
+
enrich: {
|
|
14408
|
+
family: "python",
|
|
14409
|
+
label: "a legacy Python CLI enrichment command",
|
|
14410
|
+
sdk_alternative: "Use `deepline plays ...` for durable workflows or `deepline tools execute ...` for one tool call."
|
|
14411
|
+
},
|
|
14412
|
+
session: {
|
|
14413
|
+
family: "python",
|
|
14414
|
+
label: "a legacy Python CLI session/playground command",
|
|
14415
|
+
sdk_alternative: "Use SDK play run output and run commands such as `deepline plays run ...`."
|
|
14416
|
+
},
|
|
14417
|
+
workflows: {
|
|
14418
|
+
family: "python",
|
|
14419
|
+
label: "a legacy Python CLI workflow command",
|
|
14420
|
+
sdk_alternative: "Use `deepline plays ...` in the SDK CLI."
|
|
14421
|
+
},
|
|
14422
|
+
backend: {
|
|
14423
|
+
family: "python",
|
|
14424
|
+
label: "a legacy Python CLI playground backend command"
|
|
14425
|
+
},
|
|
14426
|
+
events: {
|
|
14427
|
+
family: "python",
|
|
14428
|
+
label: "a legacy Python CLI event command"
|
|
14429
|
+
},
|
|
14430
|
+
plays: {
|
|
14431
|
+
family: "sdk",
|
|
14432
|
+
label: "an SDK CLI play command",
|
|
14433
|
+
python_alternative: "Use `deepline workflows ...` only for legacy workflows."
|
|
14434
|
+
},
|
|
14435
|
+
play: {
|
|
14436
|
+
family: "sdk",
|
|
14437
|
+
label: "an SDK CLI play command",
|
|
14438
|
+
python_alternative: "Use `deepline workflows ...` only for legacy workflows."
|
|
14439
|
+
},
|
|
14440
|
+
runs: {
|
|
14441
|
+
family: "sdk",
|
|
14442
|
+
label: "an SDK CLI run inspection command"
|
|
14443
|
+
},
|
|
14444
|
+
health: {
|
|
14445
|
+
family: "sdk",
|
|
14446
|
+
label: "an SDK CLI health command"
|
|
14447
|
+
}
|
|
14448
|
+
};
|
|
14449
|
+
|
|
14450
|
+
// ../shared_libs/cli/install-commands.json
|
|
14451
|
+
var install_commands_default = {
|
|
14452
|
+
skills: {
|
|
14453
|
+
index_path: "/.well-known/skills/index.json",
|
|
14454
|
+
default_agents: ["codex", "claude-code", "cursor"],
|
|
14455
|
+
npx_binary: "npx",
|
|
14456
|
+
npx_add_args_template: [
|
|
14457
|
+
"--yes",
|
|
14458
|
+
"skills",
|
|
14459
|
+
"add",
|
|
14460
|
+
"{skills_index_url}",
|
|
14461
|
+
"--agent",
|
|
14462
|
+
"{agents}",
|
|
14463
|
+
"--global",
|
|
14464
|
+
"--yes",
|
|
14465
|
+
"--skill",
|
|
14466
|
+
"{skill_name}",
|
|
14467
|
+
"--full-depth"
|
|
14468
|
+
]
|
|
14469
|
+
},
|
|
14470
|
+
cli: {
|
|
14471
|
+
legacy_python_shell_template: "curl -s {base_url}/api/v2/cli/install | bash",
|
|
14472
|
+
sdk_npm_global: "npm install -g deepline@latest"
|
|
14473
|
+
}
|
|
14474
|
+
};
|
|
14475
|
+
|
|
14476
|
+
// src/cli/install-commands.ts
|
|
14477
|
+
var INSTALL_COMMANDS = install_commands_default;
|
|
14478
|
+
function normalizeBaseUrl2(baseUrl) {
|
|
14479
|
+
return baseUrl.replace(/\/$/, "");
|
|
14480
|
+
}
|
|
14481
|
+
function renderTemplate(template, values) {
|
|
14482
|
+
return template.replace(/\{([a-z_]+)\}/g, (match, key) => {
|
|
14483
|
+
return values[key] ?? match;
|
|
14484
|
+
});
|
|
14485
|
+
}
|
|
14486
|
+
function shellJoin(args) {
|
|
14487
|
+
return args.join(" ");
|
|
14488
|
+
}
|
|
14489
|
+
function skillsIndexUrl(baseUrl) {
|
|
14490
|
+
return `${normalizeBaseUrl2(baseUrl)}${INSTALL_COMMANDS.skills.index_path}`;
|
|
14491
|
+
}
|
|
14492
|
+
function buildSkillsAddArgs(baseUrl, skillName, options = {}) {
|
|
14493
|
+
const values = {
|
|
14494
|
+
skills_index_url: skillsIndexUrl(baseUrl),
|
|
14495
|
+
agents: INSTALL_COMMANDS.skills.default_agents.join(" "),
|
|
14496
|
+
skill_name: skillName
|
|
14497
|
+
};
|
|
14498
|
+
const rendered = INSTALL_COMMANDS.skills.npx_add_args_template.flatMap(
|
|
14499
|
+
(arg, index) => {
|
|
14500
|
+
const next = index === 0 && options.firstArg ? options.firstArg : arg;
|
|
14501
|
+
const value = renderTemplate(next, values);
|
|
14502
|
+
return arg === "{agents}" ? INSTALL_COMMANDS.skills.default_agents : value;
|
|
14503
|
+
}
|
|
14504
|
+
);
|
|
14505
|
+
return rendered;
|
|
14506
|
+
}
|
|
14507
|
+
function skillsInstallCommand(baseUrl, skillName) {
|
|
14508
|
+
return `${INSTALL_COMMANDS.skills.npx_binary} ${shellJoin(
|
|
14509
|
+
buildSkillsAddArgs(baseUrl, skillName)
|
|
14510
|
+
)}`;
|
|
14511
|
+
}
|
|
14512
|
+
function legacyPythonInstallCommand(baseUrl) {
|
|
14513
|
+
return renderTemplate(INSTALL_COMMANDS.cli.legacy_python_shell_template, {
|
|
14514
|
+
base_url: normalizeBaseUrl2(baseUrl)
|
|
14515
|
+
});
|
|
14516
|
+
}
|
|
14517
|
+
function sdkNpmGlobalInstallCommand() {
|
|
14518
|
+
return INSTALL_COMMANDS.cli.sdk_npm_global;
|
|
14519
|
+
}
|
|
14520
|
+
|
|
14521
|
+
// src/cli/command-compatibility.ts
|
|
14522
|
+
var COMMAND_COMPATIBILITY = command_compatibility_default;
|
|
14523
|
+
function cliFamilyLabel(family) {
|
|
14524
|
+
return family === "sdk" ? "SDK CLI" : "legacy Python CLI";
|
|
14525
|
+
}
|
|
14526
|
+
function commandCompatibilityHint(currentFamily, commandName, baseUrl) {
|
|
14527
|
+
const compatibility = COMMAND_COMPATIBILITY[commandName];
|
|
14528
|
+
if (!compatibility || compatibility.family === currentFamily) {
|
|
14529
|
+
return null;
|
|
14530
|
+
}
|
|
14531
|
+
const expectedFamily = compatibility.family;
|
|
14532
|
+
const currentLabel = cliFamilyLabel(currentFamily);
|
|
14533
|
+
const expectedLabel = cliFamilyLabel(expectedFamily);
|
|
14534
|
+
const lines = [
|
|
14535
|
+
"",
|
|
14536
|
+
"Command compatibility:",
|
|
14537
|
+
` \`deepline ${commandName}\` is ${compatibility.label}.`,
|
|
14538
|
+
` Current binary: ${currentLabel}. Required binary: ${expectedLabel}.`,
|
|
14539
|
+
" If this came from an agent skill, the installed skill likely targets the other Deepline CLI."
|
|
14540
|
+
];
|
|
14541
|
+
if (currentFamily === "sdk") {
|
|
14542
|
+
lines.push(
|
|
14543
|
+
"",
|
|
14544
|
+
" To stay on the SDK CLI, install the SDK agent skill:",
|
|
14545
|
+
` ${skillsInstallCommand(baseUrl, "deepline-sdk")}`,
|
|
14546
|
+
" To use the legacy Python CLI instead:",
|
|
14547
|
+
` ${legacyPythonInstallCommand(baseUrl)}`,
|
|
14548
|
+
" `deepline update` updates this SDK CLI, but it will not switch CLI families."
|
|
14549
|
+
);
|
|
14550
|
+
if (compatibility.sdk_alternative) {
|
|
14551
|
+
lines.push(` SDK alternative: ${compatibility.sdk_alternative}`);
|
|
14552
|
+
}
|
|
14553
|
+
} else {
|
|
14554
|
+
lines.push(
|
|
14555
|
+
"",
|
|
14556
|
+
" To use SDK commands, install the SDK CLI and SDK agent skill:",
|
|
14557
|
+
` ${sdkNpmGlobalInstallCommand()}`,
|
|
14558
|
+
` ${skillsInstallCommand(baseUrl, "deepline-sdk")}`,
|
|
14559
|
+
" `deepline update` updates this Python CLI and its skills, but it will not switch CLI families."
|
|
14560
|
+
);
|
|
14561
|
+
if (compatibility.python_alternative) {
|
|
14562
|
+
lines.push(` Python alternative: ${compatibility.python_alternative}`);
|
|
14563
|
+
}
|
|
14564
|
+
}
|
|
14565
|
+
return lines.join("\n");
|
|
14566
|
+
}
|
|
14567
|
+
function unknownCommandNameFromMessage(message) {
|
|
14568
|
+
const match = message.match(/unknown command ['"]([^'"]+)['"]/i);
|
|
14569
|
+
const command = match?.[1]?.trim();
|
|
14570
|
+
return command ? command : null;
|
|
14571
|
+
}
|
|
14572
|
+
|
|
14113
14573
|
// src/cli/skills-sync.ts
|
|
14114
14574
|
import { spawn as spawn2, spawnSync } from "child_process";
|
|
14115
14575
|
import {
|
|
@@ -14124,7 +14584,6 @@ import { homedir as homedir5 } from "os";
|
|
|
14124
14584
|
import { dirname as dirname10, join as join11 } from "path";
|
|
14125
14585
|
var CHECK_TIMEOUT_MS2 = 3e3;
|
|
14126
14586
|
var SDK_SKILL_NAME = "deepline-sdk";
|
|
14127
|
-
var SKILL_AGENTS = ["codex", "claude-code", "cursor"];
|
|
14128
14587
|
var attemptedSync = false;
|
|
14129
14588
|
function shouldSkipSkillsSync() {
|
|
14130
14589
|
const value = process.env.DEEPLINE_SKIP_SKILLS_SYNC?.trim().toLowerCase();
|
|
@@ -14221,42 +14680,10 @@ async function fetchSkillsUpdate(baseUrl, localVersion) {
|
|
|
14221
14680
|
}
|
|
14222
14681
|
}
|
|
14223
14682
|
function buildSkillsInstallArgs(baseUrl) {
|
|
14224
|
-
|
|
14225
|
-
"/.well-known/skills/index.json",
|
|
14226
|
-
baseUrl
|
|
14227
|
-
).toString();
|
|
14228
|
-
return [
|
|
14229
|
-
"--yes",
|
|
14230
|
-
"skills",
|
|
14231
|
-
"add",
|
|
14232
|
-
packageUrl,
|
|
14233
|
-
"--agent",
|
|
14234
|
-
...SKILL_AGENTS,
|
|
14235
|
-
"--global",
|
|
14236
|
-
"--yes",
|
|
14237
|
-
"--skill",
|
|
14238
|
-
SDK_SKILL_NAME,
|
|
14239
|
-
"--full-depth"
|
|
14240
|
-
];
|
|
14683
|
+
return buildSkillsAddArgs(baseUrl, SDK_SKILL_NAME);
|
|
14241
14684
|
}
|
|
14242
14685
|
function buildBunxSkillsInstallArgs(baseUrl) {
|
|
14243
|
-
|
|
14244
|
-
"/.well-known/skills/index.json",
|
|
14245
|
-
baseUrl
|
|
14246
|
-
).toString();
|
|
14247
|
-
return [
|
|
14248
|
-
"--bun",
|
|
14249
|
-
"skills",
|
|
14250
|
-
"add",
|
|
14251
|
-
packageUrl,
|
|
14252
|
-
"--agent",
|
|
14253
|
-
...SKILL_AGENTS,
|
|
14254
|
-
"--global",
|
|
14255
|
-
"--yes",
|
|
14256
|
-
"--skill",
|
|
14257
|
-
SDK_SKILL_NAME,
|
|
14258
|
-
"--full-depth"
|
|
14259
|
-
];
|
|
14686
|
+
return buildSkillsAddArgs(baseUrl, SDK_SKILL_NAME, { firstArg: "--bun" });
|
|
14260
14687
|
}
|
|
14261
14688
|
function hasCommand(command) {
|
|
14262
14689
|
const result = spawnSync(command, ["--version"], {
|
|
@@ -14368,6 +14795,13 @@ async function syncSdkSkillsIfNeeded(baseUrl) {
|
|
|
14368
14795
|
}
|
|
14369
14796
|
|
|
14370
14797
|
// src/cli/index.ts
|
|
14798
|
+
function asCommanderError(error) {
|
|
14799
|
+
if (!(error instanceof Error) || !("code" in error)) {
|
|
14800
|
+
return null;
|
|
14801
|
+
}
|
|
14802
|
+
const code = error.code;
|
|
14803
|
+
return typeof code === "string" && code.startsWith("commander.") ? error : null;
|
|
14804
|
+
}
|
|
14371
14805
|
function shouldPrintStartupPhase() {
|
|
14372
14806
|
if (process.argv.includes("--json")) {
|
|
14373
14807
|
return false;
|
|
@@ -14453,7 +14887,7 @@ async function main() {
|
|
|
14453
14887
|
progress?.phase("loading deepline cli");
|
|
14454
14888
|
}
|
|
14455
14889
|
const program = new Command3();
|
|
14456
|
-
program.name("deepline").description("Deepline CLI (TypeScript SDK)").version(SDK_VERSION, "-v, --version", "Show version").showHelpAfterError().showSuggestionAfterError(true).addHelpText(
|
|
14890
|
+
program.name("deepline").description("Deepline CLI (TypeScript SDK)").version(SDK_VERSION, "-v, --version", "Show version").exitOverride().showHelpAfterError().showSuggestionAfterError(true).addHelpText(
|
|
14457
14891
|
"after",
|
|
14458
14892
|
`
|
|
14459
14893
|
Common commands:
|
|
@@ -14462,6 +14896,7 @@ Common commands:
|
|
|
14462
14896
|
deepline plays search email --json
|
|
14463
14897
|
deepline plays describe person-linkedin-to-email --json
|
|
14464
14898
|
deepline plays run my.play.ts --input '{"domain":"stripe.com"}'
|
|
14899
|
+
deepline secrets check HUBSPOT_TOKEN
|
|
14465
14900
|
deepline tools execute hunter_email_verifier --input '{"email":"a@b.com"}'
|
|
14466
14901
|
deepline update
|
|
14467
14902
|
|
|
@@ -14511,6 +14946,7 @@ Exit codes:
|
|
|
14511
14946
|
registerAuthCommands(program);
|
|
14512
14947
|
registerToolsCommands(program);
|
|
14513
14948
|
registerPlayCommands(program);
|
|
14949
|
+
registerSecretsCommands(program);
|
|
14514
14950
|
registerBillingCommands(program);
|
|
14515
14951
|
registerOrgCommands(program);
|
|
14516
14952
|
registerCsvCommands(program);
|
|
@@ -14580,6 +15016,7 @@ Examples:
|
|
|
14580
15016
|
ok: true
|
|
14581
15017
|
});
|
|
14582
15018
|
} catch (error) {
|
|
15019
|
+
const commanderError = asCommanderError(error);
|
|
14583
15020
|
recordCliTrace({
|
|
14584
15021
|
phase: "cli.main_total",
|
|
14585
15022
|
ms: Date.now() - mainStartedAt,
|
|
@@ -14587,7 +15024,26 @@ Examples:
|
|
|
14587
15024
|
error: error instanceof Error ? error.message : String(error)
|
|
14588
15025
|
});
|
|
14589
15026
|
progress?.fail();
|
|
14590
|
-
|
|
15027
|
+
const wantsJson = process.argv.includes("--json");
|
|
15028
|
+
if (commanderError) {
|
|
15029
|
+
if (commanderError.code === "commander.unknownCommand") {
|
|
15030
|
+
const commandName = unknownCommandNameFromMessage(
|
|
15031
|
+
commanderError.message
|
|
15032
|
+
);
|
|
15033
|
+
if (commandName && !wantsJson) {
|
|
15034
|
+
const hint = commandCompatibilityHint(
|
|
15035
|
+
"sdk",
|
|
15036
|
+
commandName,
|
|
15037
|
+
autoDetectBaseUrl()
|
|
15038
|
+
);
|
|
15039
|
+
if (hint) {
|
|
15040
|
+
console.error(hint);
|
|
15041
|
+
}
|
|
15042
|
+
}
|
|
15043
|
+
}
|
|
15044
|
+
process.exitCode = commanderError.code === "commander.unknownCommand" && !wantsJson ? 2 : commanderError.exitCode ?? 1;
|
|
15045
|
+
return;
|
|
15046
|
+
} else if (wantsJson) {
|
|
14591
15047
|
printJsonError(error);
|
|
14592
15048
|
} else if (error instanceof Error) {
|
|
14593
15049
|
console.error(`Error: ${error.message}`);
|