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