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.js
CHANGED
|
@@ -229,10 +229,10 @@ var import_node_path2 = require("path");
|
|
|
229
229
|
|
|
230
230
|
// src/release.ts
|
|
231
231
|
var SDK_RELEASE = {
|
|
232
|
-
version: "0.1.
|
|
232
|
+
version: "0.1.69",
|
|
233
233
|
apiContract: "2026-05-play-bootstrap-dataset-summary",
|
|
234
234
|
supportPolicy: {
|
|
235
|
-
latest: "0.1.
|
|
235
|
+
latest: "0.1.69",
|
|
236
236
|
minimumSupported: "0.1.53",
|
|
237
237
|
deprecatedBelow: "0.1.53"
|
|
238
238
|
}
|
|
@@ -739,7 +739,7 @@ var DeeplineClient = class {
|
|
|
739
739
|
list: (options2) => this.listRuns(options2),
|
|
740
740
|
tail: (runId, options2) => this.tailRun(runId, options2),
|
|
741
741
|
logs: (runId, options2) => this.getRunLogs(runId, options2),
|
|
742
|
-
exportDatasetRows: (
|
|
742
|
+
exportDatasetRows: (input2) => this.getPlaySheetRows(input2),
|
|
743
743
|
stop: (runId, options2) => this.stopRun(runId, options2)
|
|
744
744
|
};
|
|
745
745
|
}
|
|
@@ -826,6 +826,22 @@ var DeeplineClient = class {
|
|
|
826
826
|
};
|
|
827
827
|
}
|
|
828
828
|
// ——————————————————————————————————————————————————————————
|
|
829
|
+
// Secrets
|
|
830
|
+
// ——————————————————————————————————————————————————————————
|
|
831
|
+
async listSecrets() {
|
|
832
|
+
const response = await this.http.get(
|
|
833
|
+
"/api/v2/secrets"
|
|
834
|
+
);
|
|
835
|
+
return Array.isArray(response.secrets) ? response.secrets : [];
|
|
836
|
+
}
|
|
837
|
+
async checkSecret(name) {
|
|
838
|
+
const normalized = name.trim().toUpperCase();
|
|
839
|
+
const secrets = await this.listSecrets();
|
|
840
|
+
return secrets.find(
|
|
841
|
+
(secret) => secret.name === normalized && secret.status === "active" && secret.hasValue
|
|
842
|
+
) ?? null;
|
|
843
|
+
}
|
|
844
|
+
// ——————————————————————————————————————————————————————————
|
|
829
845
|
// Tools
|
|
830
846
|
// ——————————————————————————————————————————————————————————
|
|
831
847
|
/**
|
|
@@ -918,24 +934,24 @@ var DeeplineClient = class {
|
|
|
918
934
|
* Top-level fields such as `status`, `job_id`, and `billing` describe the
|
|
919
935
|
* Deepline execution envelope.
|
|
920
936
|
*/
|
|
921
|
-
async executeTool(toolId,
|
|
937
|
+
async executeTool(toolId, input2, options) {
|
|
922
938
|
const headers = {
|
|
923
939
|
[EXECUTE_RESPONSE_CONTRACT_HEADER]: V2_EXECUTE_RESPONSE_CONTRACT,
|
|
924
940
|
...options?.includeToolMetadata ? { [INCLUDE_TOOL_METADATA_HEADER]: "true" } : {}
|
|
925
941
|
};
|
|
926
942
|
return this.http.post(
|
|
927
943
|
`/api/v2/integrations/${encodeURIComponent(toolId)}/execute`,
|
|
928
|
-
{ payload:
|
|
944
|
+
{ payload: input2 },
|
|
929
945
|
headers
|
|
930
946
|
);
|
|
931
947
|
}
|
|
932
|
-
async executeToolRaw(toolId,
|
|
933
|
-
return this.executeTool(toolId,
|
|
948
|
+
async executeToolRaw(toolId, input2, options) {
|
|
949
|
+
return this.executeTool(toolId, input2, options);
|
|
934
950
|
}
|
|
935
|
-
async queryCustomerDb(
|
|
951
|
+
async queryCustomerDb(input2) {
|
|
936
952
|
return this.http.post("/api/v2/db/query", {
|
|
937
|
-
sql:
|
|
938
|
-
...
|
|
953
|
+
sql: input2.sql,
|
|
954
|
+
...input2.maxRows ? { max_rows: input2.maxRows } : {}
|
|
939
955
|
});
|
|
940
956
|
}
|
|
941
957
|
// ——————————————————————————————————————————————————————————
|
|
@@ -1042,15 +1058,15 @@ var DeeplineClient = class {
|
|
|
1042
1058
|
* Internal/advanced primitive used by packaging flows. Public callers should
|
|
1043
1059
|
* prefer the CLI, {@link submitPlay}, or {@link runPlay}.
|
|
1044
1060
|
*/
|
|
1045
|
-
async registerPlayArtifact(
|
|
1046
|
-
const compilerManifest =
|
|
1047
|
-
name:
|
|
1048
|
-
sourceCode:
|
|
1049
|
-
sourceFiles:
|
|
1050
|
-
artifact:
|
|
1061
|
+
async registerPlayArtifact(input2) {
|
|
1062
|
+
const compilerManifest = input2.compilerManifest ?? await this.compilePlayManifest({
|
|
1063
|
+
name: input2.name,
|
|
1064
|
+
sourceCode: input2.sourceCode,
|
|
1065
|
+
sourceFiles: input2.sourceFiles,
|
|
1066
|
+
artifact: input2.artifact
|
|
1051
1067
|
});
|
|
1052
1068
|
return this.http.post("/api/v2/plays/artifacts", {
|
|
1053
|
-
...
|
|
1069
|
+
...input2,
|
|
1054
1070
|
compilerManifest
|
|
1055
1071
|
});
|
|
1056
1072
|
}
|
|
@@ -1070,14 +1086,14 @@ var DeeplineClient = class {
|
|
|
1070
1086
|
artifacts: compiledArtifacts
|
|
1071
1087
|
});
|
|
1072
1088
|
}
|
|
1073
|
-
async compilePlayManifest(
|
|
1089
|
+
async compilePlayManifest(input2) {
|
|
1074
1090
|
const retryDelays = COMPILE_MANIFEST_RETRY_DELAYS_MS.slice(
|
|
1075
1091
|
0,
|
|
1076
1092
|
Math.max(0, this.config.maxRetries)
|
|
1077
1093
|
);
|
|
1078
1094
|
for (let attempt = 0; ; attempt += 1) {
|
|
1079
1095
|
try {
|
|
1080
|
-
const response = await this.http.post("/api/v2/plays/compile-manifest",
|
|
1096
|
+
const response = await this.http.post("/api/v2/plays/compile-manifest", input2);
|
|
1081
1097
|
return response.compilerManifest;
|
|
1082
1098
|
} catch (error) {
|
|
1083
1099
|
const delayMs = retryDelays[attempt];
|
|
@@ -1095,21 +1111,21 @@ var DeeplineClient = class {
|
|
|
1095
1111
|
* publish a revision, or start a run. It is the authoritative cloud validation
|
|
1096
1112
|
* path used by `deepline play check`.
|
|
1097
1113
|
*/
|
|
1098
|
-
async checkPlayArtifact(
|
|
1099
|
-
return this.http.post("/api/v2/plays/check",
|
|
1100
|
-
}
|
|
1101
|
-
async startPlayRunFromBundle(
|
|
1102
|
-
const compilerManifest =
|
|
1103
|
-
name:
|
|
1104
|
-
sourceCode:
|
|
1105
|
-
sourceFiles:
|
|
1106
|
-
artifact:
|
|
1114
|
+
async checkPlayArtifact(input2) {
|
|
1115
|
+
return this.http.post("/api/v2/plays/check", input2);
|
|
1116
|
+
}
|
|
1117
|
+
async startPlayRunFromBundle(input2) {
|
|
1118
|
+
const compilerManifest = input2.compilerManifest ?? await this.compilePlayManifest({
|
|
1119
|
+
name: input2.name,
|
|
1120
|
+
sourceCode: input2.sourceCode,
|
|
1121
|
+
sourceFiles: input2.sourceFiles,
|
|
1122
|
+
artifact: input2.artifact
|
|
1107
1123
|
});
|
|
1108
1124
|
const registeredArtifact = await this.registerPlayArtifact({
|
|
1109
|
-
name:
|
|
1110
|
-
sourceCode:
|
|
1111
|
-
sourceFiles:
|
|
1112
|
-
artifact:
|
|
1125
|
+
name: input2.name,
|
|
1126
|
+
sourceCode: input2.sourceCode,
|
|
1127
|
+
sourceFiles: input2.sourceFiles,
|
|
1128
|
+
artifact: input2.artifact,
|
|
1113
1129
|
compilerManifest,
|
|
1114
1130
|
publish: false
|
|
1115
1131
|
});
|
|
@@ -1119,13 +1135,13 @@ var DeeplineClient = class {
|
|
|
1119
1135
|
);
|
|
1120
1136
|
}
|
|
1121
1137
|
return this.startPlayRun({
|
|
1122
|
-
name:
|
|
1138
|
+
name: input2.name,
|
|
1123
1139
|
artifactStorageKey: registeredArtifact.artifactStorageKey,
|
|
1124
1140
|
compilerManifest,
|
|
1125
|
-
...
|
|
1126
|
-
...
|
|
1127
|
-
...
|
|
1128
|
-
...
|
|
1141
|
+
...input2.input ? { input: input2.input } : {},
|
|
1142
|
+
...input2.inputFile ? { inputFile: input2.inputFile } : {},
|
|
1143
|
+
...input2.packagedFiles?.length ? { packagedFiles: input2.packagedFiles } : {},
|
|
1144
|
+
...input2.force ? { force: true } : {}
|
|
1129
1145
|
});
|
|
1130
1146
|
}
|
|
1131
1147
|
/**
|
|
@@ -1470,17 +1486,17 @@ var DeeplineClient = class {
|
|
|
1470
1486
|
entries
|
|
1471
1487
|
};
|
|
1472
1488
|
}
|
|
1473
|
-
async getPlaySheetRows(
|
|
1489
|
+
async getPlaySheetRows(input2) {
|
|
1474
1490
|
const params = new URLSearchParams({
|
|
1475
|
-
tableNamespace:
|
|
1476
|
-
limit: String(
|
|
1477
|
-
offset: String(
|
|
1491
|
+
tableNamespace: input2.tableNamespace,
|
|
1492
|
+
limit: String(input2.limit ?? 5e3),
|
|
1493
|
+
offset: String(input2.offset ?? 0)
|
|
1478
1494
|
});
|
|
1479
|
-
if (
|
|
1480
|
-
params.set("runId",
|
|
1495
|
+
if (input2.runId?.trim()) {
|
|
1496
|
+
params.set("runId", input2.runId.trim());
|
|
1481
1497
|
}
|
|
1482
1498
|
return await this.http.get(
|
|
1483
|
-
`/api/v2/plays/${encodeURIComponent(
|
|
1499
|
+
`/api/v2/plays/${encodeURIComponent(input2.playName)}/sheet?${params.toString()}`
|
|
1484
1500
|
);
|
|
1485
1501
|
}
|
|
1486
1502
|
/**
|
|
@@ -1923,7 +1939,7 @@ function browserAppNameFromBundleId(bundleId) {
|
|
|
1923
1939
|
}
|
|
1924
1940
|
function readDefaultMacBrowserBundleId(runner = defaultBrowserCommandRunner) {
|
|
1925
1941
|
try {
|
|
1926
|
-
const
|
|
1942
|
+
const output2 = runner.execFileSync(
|
|
1927
1943
|
"/usr/bin/defaults",
|
|
1928
1944
|
[
|
|
1929
1945
|
"read",
|
|
@@ -1932,10 +1948,10 @@ function readDefaultMacBrowserBundleId(runner = defaultBrowserCommandRunner) {
|
|
|
1932
1948
|
],
|
|
1933
1949
|
{ encoding: "utf-8", stdio: ["ignore", "pipe", "ignore"] }
|
|
1934
1950
|
);
|
|
1935
|
-
const httpsMatch =
|
|
1951
|
+
const httpsMatch = output2.match(
|
|
1936
1952
|
/LSHandlerURLScheme\s*=\s*https;[\s\S]*?LSHandlerRole(?:All|Viewer|Editor)\s*=\s*"([^"]+)"/
|
|
1937
1953
|
);
|
|
1938
|
-
const httpMatch =
|
|
1954
|
+
const httpMatch = output2.match(
|
|
1939
1955
|
/LSHandlerURLScheme\s*=\s*http;[\s\S]*?LSHandlerRole(?:All|Viewer|Editor)\s*=\s*"([^"]+)"/
|
|
1940
1956
|
);
|
|
1941
1957
|
return (httpsMatch?.[1] ?? httpMatch?.[1] ?? "").trim();
|
|
@@ -3380,9 +3396,9 @@ function stripCsvProjectionColumns(columns, rows) {
|
|
|
3380
3396
|
(column) => column !== CSV_PROJECTED_FIELDS_KEY && !projectedFields.has(column)
|
|
3381
3397
|
);
|
|
3382
3398
|
}
|
|
3383
|
-
function sanitizeCsvProjectionInfo(
|
|
3384
|
-
const columns = stripCsvProjectionColumns(
|
|
3385
|
-
const rows =
|
|
3399
|
+
function sanitizeCsvProjectionInfo(input2) {
|
|
3400
|
+
const columns = stripCsvProjectionColumns(input2.columns, input2.rows);
|
|
3401
|
+
const rows = input2.rows.map(stripCsvProjectionFields);
|
|
3386
3402
|
return { rows, columns };
|
|
3387
3403
|
}
|
|
3388
3404
|
function isRecord2(value) {
|
|
@@ -3438,8 +3454,8 @@ function inferColumns(rows) {
|
|
|
3438
3454
|
}
|
|
3439
3455
|
return columns;
|
|
3440
3456
|
}
|
|
3441
|
-
function canonicalRowsInfoFromCandidate(
|
|
3442
|
-
const candidate =
|
|
3457
|
+
function canonicalRowsInfoFromCandidate(input2) {
|
|
3458
|
+
const candidate = input2;
|
|
3443
3459
|
if (isSerializedDataset(candidate.value)) {
|
|
3444
3460
|
const rawRows = rowArray(candidate.value.preview) ?? [];
|
|
3445
3461
|
const totalRows2 = readNumber(candidate.value.count) ?? rawRows.length;
|
|
@@ -3480,31 +3496,31 @@ function canonicalRowsInfoFromCandidate(input) {
|
|
|
3480
3496
|
source: candidate.source
|
|
3481
3497
|
};
|
|
3482
3498
|
}
|
|
3483
|
-
function collectDatasetCandidates(
|
|
3484
|
-
if (
|
|
3499
|
+
function collectDatasetCandidates(input2) {
|
|
3500
|
+
if (input2.depth && input2.depth > 16) {
|
|
3485
3501
|
return;
|
|
3486
3502
|
}
|
|
3487
|
-
if (isSerializedDataset(
|
|
3488
|
-
|
|
3489
|
-
source:
|
|
3490
|
-
value:
|
|
3491
|
-
total:
|
|
3503
|
+
if (isSerializedDataset(input2.value)) {
|
|
3504
|
+
input2.output.push({
|
|
3505
|
+
source: input2.path,
|
|
3506
|
+
value: input2.value,
|
|
3507
|
+
total: input2.total
|
|
3492
3508
|
});
|
|
3493
3509
|
return;
|
|
3494
3510
|
}
|
|
3495
|
-
if (!isRecord2(
|
|
3511
|
+
if (!isRecord2(input2.value)) {
|
|
3496
3512
|
return;
|
|
3497
3513
|
}
|
|
3498
|
-
for (const [key, child] of Object.entries(
|
|
3514
|
+
for (const [key, child] of Object.entries(input2.value)) {
|
|
3499
3515
|
if (key === "preview" || key === "access") {
|
|
3500
3516
|
continue;
|
|
3501
3517
|
}
|
|
3502
3518
|
collectDatasetCandidates({
|
|
3503
3519
|
value: child,
|
|
3504
|
-
path: `${
|
|
3505
|
-
total: totalRowsForDataset(
|
|
3506
|
-
output:
|
|
3507
|
-
depth: (
|
|
3520
|
+
path: `${input2.path}.${key}`,
|
|
3521
|
+
total: totalRowsForDataset(input2.value, `${input2.path}.${key}`),
|
|
3522
|
+
output: input2.output,
|
|
3523
|
+
depth: (input2.depth ?? 0) + 1
|
|
3508
3524
|
});
|
|
3509
3525
|
}
|
|
3510
3526
|
}
|
|
@@ -4022,26 +4038,26 @@ function writeCustomerDbCsv(result, outPath) {
|
|
|
4022
4038
|
);
|
|
4023
4039
|
return resolved;
|
|
4024
4040
|
}
|
|
4025
|
-
function dbQueryExportEnvelope(
|
|
4026
|
-
const destination =
|
|
4041
|
+
function dbQueryExportEnvelope(input2) {
|
|
4042
|
+
const destination = input2.outPath ?? "stdout";
|
|
4027
4043
|
return {
|
|
4028
|
-
command:
|
|
4029
|
-
format:
|
|
4030
|
-
row_count:
|
|
4031
|
-
row_count_returned:
|
|
4032
|
-
truncated:
|
|
4033
|
-
...
|
|
4034
|
-
next: { toolEquivalent:
|
|
4044
|
+
command: input2.result.command,
|
|
4045
|
+
format: input2.format,
|
|
4046
|
+
row_count: input2.result.row_count,
|
|
4047
|
+
row_count_returned: input2.result.row_count_returned,
|
|
4048
|
+
truncated: input2.result.truncated,
|
|
4049
|
+
...input2.outPath ? { file: input2.outPath, local: { file: input2.outPath } } : {},
|
|
4050
|
+
next: { toolEquivalent: input2.toolCommand },
|
|
4035
4051
|
render: {
|
|
4036
4052
|
sections: [
|
|
4037
4053
|
{
|
|
4038
4054
|
title: "customer db export",
|
|
4039
4055
|
lines: [
|
|
4040
|
-
`Rendered ${
|
|
4056
|
+
`Rendered ${input2.result.row_count_returned} row(s) as ${input2.format} to ${destination}`
|
|
4041
4057
|
]
|
|
4042
4058
|
}
|
|
4043
4059
|
],
|
|
4044
|
-
actions: [{ label: "Tool equivalent", command:
|
|
4060
|
+
actions: [{ label: "Tool equivalent", command: input2.toolCommand }]
|
|
4045
4061
|
}
|
|
4046
4062
|
};
|
|
4047
4063
|
}
|
|
@@ -4479,16 +4495,63 @@ var PLAY_RUNTIME_FEATURES = [
|
|
|
4479
4495
|
"durable_sleep",
|
|
4480
4496
|
"packaged_files"
|
|
4481
4497
|
];
|
|
4482
|
-
function buildPlayContractCompatibility(
|
|
4498
|
+
function buildPlayContractCompatibility(input2) {
|
|
4483
4499
|
return {
|
|
4484
4500
|
apiVersion: PLAY_PUBLIC_API_VERSION,
|
|
4485
4501
|
artifactVersion: PLAY_ARTIFACT_VERSION,
|
|
4486
4502
|
minRunnerVersion: PLAY_MIN_RUNNER_VERSION,
|
|
4487
4503
|
runtimeFeatures: [...PLAY_RUNTIME_FEATURES],
|
|
4488
|
-
runtimeBackend:
|
|
4504
|
+
runtimeBackend: input2?.runtimeBackend ?? null
|
|
4489
4505
|
};
|
|
4490
4506
|
}
|
|
4491
4507
|
|
|
4508
|
+
// ../shared_libs/plays/secret-guardrails.ts
|
|
4509
|
+
var SECRET_ENV_PATTERN = /\bprocess(?:\.env|\[['"]env['"]\])(?:\.|\[['"])([A-Z0-9_]*(?:API[_-]?KEY|TOKEN|SECRET|PASSWORD|PRIVATE[_-]?KEY|ACCESS[_-]?KEY)[A-Z0-9_]*)(?:['"]\])?/g;
|
|
4510
|
+
var PRIVATE_KEY_PATTERN = /-----BEGIN (?:RSA |EC |OPENSSH |PGP )?PRIVATE KEY-----/;
|
|
4511
|
+
var BEARER_LITERAL_PATTERN = /\bBearer\s+[A-Za-z0-9._~+/=-]{16,}/i;
|
|
4512
|
+
var ASSIGNMENT_SECRET_LITERAL_PATTERN = /\b(?:api[_-]?key|token|secret|password)\b\s*[:=]\s*['"][^'"]{12,}['"]/i;
|
|
4513
|
+
var HIGH_ENTROPY_LITERAL_PATTERN = /['"]([A-Za-z0-9+/=_-]{32,})['"]/g;
|
|
4514
|
+
function shannonEntropy(value) {
|
|
4515
|
+
const counts = /* @__PURE__ */ new Map();
|
|
4516
|
+
for (const char of value) counts.set(char, (counts.get(char) ?? 0) + 1);
|
|
4517
|
+
return [...counts.values()].reduce((entropy, count) => {
|
|
4518
|
+
const p = count / value.length;
|
|
4519
|
+
return entropy - p * Math.log2(p);
|
|
4520
|
+
}, 0);
|
|
4521
|
+
}
|
|
4522
|
+
function validatePlaySourceHasNoInlineSecrets(input2) {
|
|
4523
|
+
const findings = [];
|
|
4524
|
+
for (const match of input2.sourceCode.matchAll(SECRET_ENV_PATTERN)) {
|
|
4525
|
+
findings.push(`process.env.${match[1]}`);
|
|
4526
|
+
}
|
|
4527
|
+
if (PRIVATE_KEY_PATTERN.test(input2.sourceCode)) findings.push("private key block");
|
|
4528
|
+
if (BEARER_LITERAL_PATTERN.test(input2.sourceCode)) findings.push("bearer token literal");
|
|
4529
|
+
if (ASSIGNMENT_SECRET_LITERAL_PATTERN.test(input2.sourceCode)) {
|
|
4530
|
+
findings.push("secret-looking assignment literal");
|
|
4531
|
+
}
|
|
4532
|
+
for (const match of input2.sourceCode.matchAll(HIGH_ENTROPY_LITERAL_PATTERN)) {
|
|
4533
|
+
const literal = match[1] ?? "";
|
|
4534
|
+
if (literal.length >= 40 && shannonEntropy(literal) >= 4.2) {
|
|
4535
|
+
findings.push("high-entropy string literal");
|
|
4536
|
+
break;
|
|
4537
|
+
}
|
|
4538
|
+
}
|
|
4539
|
+
if (!findings.length) return;
|
|
4540
|
+
throw new Error(
|
|
4541
|
+
[
|
|
4542
|
+
`Play source ${input2.filePath} appears to contain inline secret material: ${[
|
|
4543
|
+
...new Set(findings)
|
|
4544
|
+
].join(", ")}.`,
|
|
4545
|
+
'Author secrets in the dashboard and use ctx.secrets.get("NAME") with an approved helper such as ctx.secrets.bearer(handle).'
|
|
4546
|
+
].join(" ")
|
|
4547
|
+
);
|
|
4548
|
+
}
|
|
4549
|
+
function validatePlaySourceFilesHaveNoInlineSecrets(sourceFiles) {
|
|
4550
|
+
for (const [filePath, sourceCode] of Object.entries(sourceFiles)) {
|
|
4551
|
+
validatePlaySourceHasNoInlineSecrets({ filePath, sourceCode });
|
|
4552
|
+
}
|
|
4553
|
+
}
|
|
4554
|
+
|
|
4492
4555
|
// ../shared_libs/plays/bundling/index.ts
|
|
4493
4556
|
var PLAY_BUNDLE_CACHE_VERSION = 24;
|
|
4494
4557
|
var MAX_PLAY_BUNDLE_BYTES = 30 * 1024 * 1024;
|
|
@@ -4550,12 +4613,12 @@ function createPlayWorkspace(entryFile) {
|
|
|
4550
4613
|
function isPathInsideDirectory(filePath, directory) {
|
|
4551
4614
|
return filePath === directory || filePath.startsWith(`${directory}/`);
|
|
4552
4615
|
}
|
|
4553
|
-
function assertWithinPlayWorkspace(
|
|
4554
|
-
if (isPathInsideDirectory(
|
|
4616
|
+
function assertWithinPlayWorkspace(input2) {
|
|
4617
|
+
if (isPathInsideDirectory(input2.resolvedPath, input2.workspace.rootDir)) {
|
|
4555
4618
|
return;
|
|
4556
4619
|
}
|
|
4557
4620
|
throw new Error(
|
|
4558
|
-
`${
|
|
4621
|
+
`${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.`
|
|
4559
4622
|
);
|
|
4560
4623
|
}
|
|
4561
4624
|
function getPackageName(specifier) {
|
|
@@ -5410,6 +5473,15 @@ entry-export:${exportName}`
|
|
|
5410
5473
|
workers-harness:${harnessFingerprint}`
|
|
5411
5474
|
);
|
|
5412
5475
|
}
|
|
5476
|
+
try {
|
|
5477
|
+
validatePlaySourceFilesHaveNoInlineSecrets(analysis.sourceFiles);
|
|
5478
|
+
} catch (error) {
|
|
5479
|
+
return {
|
|
5480
|
+
success: false,
|
|
5481
|
+
filePath: absolutePath,
|
|
5482
|
+
errors: [error instanceof Error ? error.message : String(error)]
|
|
5483
|
+
};
|
|
5484
|
+
}
|
|
5413
5485
|
const typecheckErrors = [
|
|
5414
5486
|
...await adapter.typecheckPlaySource?.({
|
|
5415
5487
|
sourceCode: analysis.sourceCode,
|
|
@@ -6012,11 +6084,13 @@ function createSdkPlayBundlingAdapter() {
|
|
|
6012
6084
|
};
|
|
6013
6085
|
}
|
|
6014
6086
|
async function bundlePlayFile2(filePath, options = {}) {
|
|
6015
|
-
|
|
6087
|
+
const result = await bundlePlayFile(filePath, {
|
|
6016
6088
|
target: options.target ?? defaultPlayBundleTarget(),
|
|
6017
6089
|
exportName: options.exportName,
|
|
6018
6090
|
adapter: createSdkPlayBundlingAdapter()
|
|
6019
6091
|
});
|
|
6092
|
+
if (result.success) validatePlaySourceFilesHaveNoInlineSecrets(result.sourceFiles);
|
|
6093
|
+
return result;
|
|
6020
6094
|
}
|
|
6021
6095
|
|
|
6022
6096
|
// src/cli/commands/plays/bootstrap.ts
|
|
@@ -6610,28 +6684,28 @@ function objectPropertySchema(schema, property) {
|
|
|
6610
6684
|
function finderResultTypeName(finder) {
|
|
6611
6685
|
return finder === "email_finder" ? "EmailFinderPlayResult" : "PhoneFinderPlayResult";
|
|
6612
6686
|
}
|
|
6613
|
-
function renderFinderPlayResultType(
|
|
6614
|
-
if (!
|
|
6615
|
-
const outputField = PLAY_BOOTSTRAP_OUTPUT_FIELD_BY_FINDER[
|
|
6687
|
+
function renderFinderPlayResultType(input2) {
|
|
6688
|
+
if (!input2.play) return null;
|
|
6689
|
+
const outputField = PLAY_BOOTSTRAP_OUTPUT_FIELD_BY_FINDER[input2.finder];
|
|
6616
6690
|
const fieldSchema = objectPropertySchema(
|
|
6617
|
-
|
|
6691
|
+
input2.play.outputSchema,
|
|
6618
6692
|
outputField
|
|
6619
6693
|
);
|
|
6620
6694
|
const fieldType = fieldSchema ? jsonSchemaTypeExpression(fieldSchema) : "string | null";
|
|
6621
|
-
return `type ${finderResultTypeName(
|
|
6695
|
+
return `type ${finderResultTypeName(input2.finder)} =
|
|
6622
6696
|
| string
|
|
6623
6697
|
| null
|
|
6624
6698
|
| {
|
|
6625
6699
|
${outputField}?: ${fieldType};
|
|
6626
6700
|
};`;
|
|
6627
6701
|
}
|
|
6628
|
-
function generatedFinderPlayResultTypes(
|
|
6702
|
+
function generatedFinderPlayResultTypes(input2) {
|
|
6629
6703
|
return ["email_finder", "phone_finder"].flatMap((finder) => {
|
|
6630
|
-
const stage = finderStage(
|
|
6704
|
+
const stage = finderStage(input2.options, finder);
|
|
6631
6705
|
if (stage?.kind !== "play") return [];
|
|
6632
6706
|
const typeDefinition = renderFinderPlayResultType({
|
|
6633
6707
|
finder,
|
|
6634
|
-
play:
|
|
6708
|
+
play: input2.finderPlays[finder]
|
|
6635
6709
|
});
|
|
6636
6710
|
return typeDefinition ? [typeDefinition] : [];
|
|
6637
6711
|
}).join("\n\n");
|
|
@@ -6689,8 +6763,8 @@ function generateCompanyInputObjectFromSchema(schema, indent, label, fallbackFie
|
|
|
6689
6763
|
${lines.join("\n")}
|
|
6690
6764
|
${indent.slice(2)}}`;
|
|
6691
6765
|
}
|
|
6692
|
-
function generateSourceProviderInputObject(
|
|
6693
|
-
const { tool, indent, label, entity } =
|
|
6766
|
+
function generateSourceProviderInputObject(input2) {
|
|
6767
|
+
const { tool, indent, label, entity } = input2;
|
|
6694
6768
|
const properties = inputPropertyNames(tool?.inputSchema);
|
|
6695
6769
|
const details = schemaFieldDetails(tool?.inputSchema);
|
|
6696
6770
|
const required = details.required;
|
|
@@ -6748,8 +6822,8 @@ function generateSourceProviderInputObject(input) {
|
|
|
6748
6822
|
${lines.join("\n")}
|
|
6749
6823
|
${indent.slice(2)}}`;
|
|
6750
6824
|
}
|
|
6751
|
-
function generatePlayInputObject(
|
|
6752
|
-
const { schema, indent, label, entity } =
|
|
6825
|
+
function generatePlayInputObject(input2) {
|
|
6826
|
+
const { schema, indent, label, entity } = input2;
|
|
6753
6827
|
const details = schemaFieldDetails(schema);
|
|
6754
6828
|
const fallback = entity === "company" ? ["domain", "company_name"] : ["first_name", "last_name", "domain"];
|
|
6755
6829
|
const required = details.required.length ? details.required : fallback;
|
|
@@ -6816,80 +6890,80 @@ function needsWhenImport(options) {
|
|
|
6816
6890
|
function sourceCollectionTypeName(entity) {
|
|
6817
6891
|
return entity === "company" ? "CompanySourceRow" : "ContactSourceRow";
|
|
6818
6892
|
}
|
|
6819
|
-
function renderPartialRowType(
|
|
6820
|
-
if (
|
|
6821
|
-
return `type ${
|
|
6893
|
+
function renderPartialRowType(input2) {
|
|
6894
|
+
if (input2.fields.length === 0) {
|
|
6895
|
+
return `type ${input2.typeName} = Record<string, unknown>;`;
|
|
6822
6896
|
}
|
|
6823
|
-
const properties =
|
|
6824
|
-
return `type ${
|
|
6825
|
-
// ${
|
|
6897
|
+
const properties = input2.fields.map((field) => ` ${jsString(field)}?: unknown;`).join("\n");
|
|
6898
|
+
return `type ${input2.typeName} = Record<string, unknown> & Partial<{
|
|
6899
|
+
// ${input2.comment}
|
|
6826
6900
|
${properties}
|
|
6827
6901
|
}>;`;
|
|
6828
6902
|
}
|
|
6829
|
-
function fieldsFromSchemaDetails(
|
|
6903
|
+
function fieldsFromSchemaDetails(input2) {
|
|
6830
6904
|
return [
|
|
6831
|
-
...
|
|
6832
|
-
...
|
|
6905
|
+
...input2.details.required.length ? input2.details.required : input2.fallbackFields,
|
|
6906
|
+
...input2.details.optional
|
|
6833
6907
|
];
|
|
6834
6908
|
}
|
|
6835
|
-
function schemaFieldsForStage(stage,
|
|
6909
|
+
function schemaFieldsForStage(stage, input2) {
|
|
6836
6910
|
switch (stage?.kind) {
|
|
6837
6911
|
case void 0:
|
|
6838
6912
|
return [];
|
|
6839
6913
|
case "play":
|
|
6840
6914
|
return fieldsFromSchemaDetails({
|
|
6841
|
-
details: schemaFieldDetails(
|
|
6842
|
-
fallbackFields:
|
|
6915
|
+
details: schemaFieldDetails(input2.play?.inputSchema),
|
|
6916
|
+
fallbackFields: input2.fallbackFields
|
|
6843
6917
|
});
|
|
6844
6918
|
case "providers":
|
|
6845
|
-
return
|
|
6919
|
+
return input2.tools.flatMap(
|
|
6846
6920
|
(tool) => fieldsFromSchemaDetails({
|
|
6847
6921
|
details: schemaFieldDetails(tool.inputSchema),
|
|
6848
|
-
fallbackFields:
|
|
6922
|
+
fallbackFields: input2.fallbackFields
|
|
6849
6923
|
})
|
|
6850
6924
|
);
|
|
6851
6925
|
}
|
|
6852
6926
|
}
|
|
6853
|
-
function sourceRowTypeDefinition(
|
|
6854
|
-
switch (
|
|
6927
|
+
function sourceRowTypeDefinition(input2) {
|
|
6928
|
+
switch (input2.options.from.kind) {
|
|
6855
6929
|
case "csv":
|
|
6856
|
-
return `type ${
|
|
6930
|
+
return `type ${input2.sourceTypeName} = SourceCsvRow;`;
|
|
6857
6931
|
case "providers":
|
|
6858
6932
|
return renderPartialRowType({
|
|
6859
|
-
typeName:
|
|
6933
|
+
typeName: input2.sourceTypeName,
|
|
6860
6934
|
fields: [
|
|
6861
|
-
...new Set(
|
|
6935
|
+
...new Set(input2.sourceTools.flatMap(listRowCandidateKeysFromTool))
|
|
6862
6936
|
].sort(),
|
|
6863
6937
|
comment: "Candidate source row keys from described list getters; confirm the actual provider keys with source_*.extractedLists.*.keys before mapping."
|
|
6864
6938
|
});
|
|
6865
6939
|
case "play": {
|
|
6866
|
-
const details = schemaFieldDetails(
|
|
6940
|
+
const details = schemaFieldDetails(input2.sourcePlay?.outputSchema);
|
|
6867
6941
|
return renderPartialRowType({
|
|
6868
|
-
typeName:
|
|
6942
|
+
typeName: input2.sourceTypeName,
|
|
6869
6943
|
fields: [...details.required, ...details.optional].sort(),
|
|
6870
6944
|
comment: "Candidate source play output fields; confirm the selected rows field before mapping."
|
|
6871
6945
|
});
|
|
6872
6946
|
}
|
|
6873
6947
|
}
|
|
6874
6948
|
}
|
|
6875
|
-
function contactBridgeRowTypeDefinition(
|
|
6876
|
-
const config = playBootstrapTemplateConfig(
|
|
6877
|
-
if (config.sourceEntity !== "company" || !
|
|
6878
|
-
const emailFields = schemaFieldsForStage(
|
|
6879
|
-
tools:
|
|
6880
|
-
play:
|
|
6949
|
+
function contactBridgeRowTypeDefinition(input2) {
|
|
6950
|
+
const config = playBootstrapTemplateConfig(input2.options.template);
|
|
6951
|
+
if (config.sourceEntity !== "company" || !input2.options.people) return null;
|
|
6952
|
+
const emailFields = schemaFieldsForStage(input2.options.email, {
|
|
6953
|
+
tools: input2.finderTools.email_finder ?? [],
|
|
6954
|
+
play: input2.finderPlays.email_finder,
|
|
6881
6955
|
fallbackFields: ["first_name", "last_name", "domain"]
|
|
6882
6956
|
});
|
|
6883
|
-
const phoneFields = schemaFieldsForStage(
|
|
6884
|
-
tools:
|
|
6885
|
-
play:
|
|
6957
|
+
const phoneFields = schemaFieldsForStage(input2.options.phone, {
|
|
6958
|
+
tools: input2.finderTools.phone_finder ?? [],
|
|
6959
|
+
play: input2.finderPlays.phone_finder,
|
|
6886
6960
|
fallbackFields: ["first_name", "last_name", "domain"]
|
|
6887
6961
|
});
|
|
6888
6962
|
return renderPartialRowType({
|
|
6889
6963
|
typeName: "ContactSourceRow",
|
|
6890
6964
|
fields: [
|
|
6891
6965
|
.../* @__PURE__ */ new Set([
|
|
6892
|
-
...inputPropertyNames(
|
|
6966
|
+
...inputPropertyNames(input2.peoplePlay?.outputSchema),
|
|
6893
6967
|
...emailFields,
|
|
6894
6968
|
...phoneFields
|
|
6895
6969
|
])
|
|
@@ -6897,27 +6971,27 @@ function contactBridgeRowTypeDefinition(input) {
|
|
|
6897
6971
|
comment: "Fields the people play or later finder stages may need; the generated code still requires explicit mapping."
|
|
6898
6972
|
});
|
|
6899
6973
|
}
|
|
6900
|
-
function generateRowTypeDefinitions(
|
|
6901
|
-
const config = playBootstrapTemplateConfig(
|
|
6974
|
+
function generateRowTypeDefinitions(input2) {
|
|
6975
|
+
const config = playBootstrapTemplateConfig(input2.options.template);
|
|
6902
6976
|
const sourceTypeName = sourceCollectionTypeName(config.sourceEntity);
|
|
6903
6977
|
const definitions = [
|
|
6904
6978
|
sourceRowTypeDefinition({
|
|
6905
|
-
options:
|
|
6979
|
+
options: input2.options,
|
|
6906
6980
|
sourceTypeName,
|
|
6907
|
-
sourceTools:
|
|
6908
|
-
sourcePlay:
|
|
6981
|
+
sourceTools: input2.sourceTools,
|
|
6982
|
+
sourcePlay: input2.sourcePlay
|
|
6909
6983
|
}),
|
|
6910
|
-
contactBridgeRowTypeDefinition(
|
|
6984
|
+
contactBridgeRowTypeDefinition(input2)
|
|
6911
6985
|
];
|
|
6912
6986
|
return definitions.filter(Boolean).join("\n\n");
|
|
6913
6987
|
}
|
|
6914
|
-
function validateBootstrapRoutes(
|
|
6915
|
-
const config = playBootstrapTemplateConfig(
|
|
6988
|
+
function validateBootstrapRoutes(input2) {
|
|
6989
|
+
const config = playBootstrapTemplateConfig(input2.options.template);
|
|
6916
6990
|
const sourceCategory = config.sourceEntity === "company" ? PLAY_BOOTSTRAP_COMPANY_PROVIDER_CATEGORY : PLAY_BOOTSTRAP_PEOPLE_PROVIDER_CATEGORY;
|
|
6917
|
-
for (const tool of
|
|
6991
|
+
for (const tool of input2.sourceTools) {
|
|
6918
6992
|
if (!tool.categories.includes(sourceCategory)) {
|
|
6919
6993
|
throw new PlayBootstrapValidationError(
|
|
6920
|
-
`Cannot use ${tool.toolId} as a ${config.sourceEntity} source for ${
|
|
6994
|
+
`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`
|
|
6921
6995
|
);
|
|
6922
6996
|
}
|
|
6923
6997
|
if (getterNamesFromTool(tool, "list").length === 0) {
|
|
@@ -6926,14 +7000,14 @@ function validateBootstrapRoutes(input) {
|
|
|
6926
7000
|
);
|
|
6927
7001
|
}
|
|
6928
7002
|
}
|
|
6929
|
-
if (
|
|
7003
|
+
if (input2.options.people?.kind === "providers") {
|
|
6930
7004
|
throw new PlayBootstrapValidationError(
|
|
6931
7005
|
"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."
|
|
6932
7006
|
);
|
|
6933
7007
|
}
|
|
6934
7008
|
for (const finder of ["email_finder", "phone_finder"]) {
|
|
6935
7009
|
const requiredCategory = PLAY_BOOTSTRAP_PROVIDER_CATEGORY_BY_FINDER[finder];
|
|
6936
|
-
for (const tool of
|
|
7010
|
+
for (const tool of input2.finderTools[finder] ?? []) {
|
|
6937
7011
|
if (!tool.categories.includes(requiredCategory)) {
|
|
6938
7012
|
throw new PlayBootstrapValidationError(
|
|
6939
7013
|
`Cannot use ${tool.toolId} for ${finder}: expected category ${requiredCategory}, got ${tool.categories.join(", ") || "none"}. Run: deepline tools grep ${requiredCategory} --categories ${requiredCategory} --json`
|
|
@@ -6955,118 +7029,118 @@ function sourceCollectionName(entity) {
|
|
|
6955
7029
|
return "contacts";
|
|
6956
7030
|
}
|
|
6957
7031
|
}
|
|
6958
|
-
function requiredGetterName(
|
|
6959
|
-
const getter = getterNamesFromTool(
|
|
7032
|
+
function requiredGetterName(input2) {
|
|
7033
|
+
const getter = getterNamesFromTool(input2.tool, input2.kind)[0];
|
|
6960
7034
|
if (!getter) {
|
|
6961
|
-
switch (
|
|
7035
|
+
switch (input2.kind) {
|
|
6962
7036
|
case "list":
|
|
6963
7037
|
throw new PlayBootstrapValidationError(
|
|
6964
|
-
`Cannot use ${
|
|
7038
|
+
`Cannot use ${input2.label} as a source: it exposes no extracted list getters.`
|
|
6965
7039
|
);
|
|
6966
7040
|
case "value":
|
|
6967
7041
|
throw new PlayBootstrapValidationError(
|
|
6968
|
-
`Cannot use ${
|
|
7042
|
+
`Cannot use ${input2.label} as a finder: it exposes no extracted value getters.`
|
|
6969
7043
|
);
|
|
6970
7044
|
}
|
|
6971
7045
|
}
|
|
6972
7046
|
return getter;
|
|
6973
7047
|
}
|
|
6974
|
-
function generateCsvSourceRowsBlock(
|
|
6975
|
-
return `const sourceDataset = await ctx.csv<SourceCsvRow>(${jsString(
|
|
6976
|
-
const ${
|
|
7048
|
+
function generateCsvSourceRowsBlock(input2) {
|
|
7049
|
+
return `const sourceDataset = await ctx.csv<SourceCsvRow>(${jsString(input2.packagedSourceCsvPath ?? input2.source.value)});
|
|
7050
|
+
const ${input2.collection}: ${input2.collectionType}[] = await sourceDataset.peek(limit);`;
|
|
6977
7051
|
}
|
|
6978
|
-
function generatePlaySourceRowsBlock(
|
|
7052
|
+
function generatePlaySourceRowsBlock(input2) {
|
|
6979
7053
|
const playInput = generatePlayInputObject({
|
|
6980
|
-
schema:
|
|
7054
|
+
schema: input2.sourcePlay?.inputSchema,
|
|
6981
7055
|
indent: " ",
|
|
6982
|
-
label:
|
|
6983
|
-
entity:
|
|
7056
|
+
label: input2.source.value,
|
|
7057
|
+
entity: input2.entity
|
|
6984
7058
|
});
|
|
6985
7059
|
return `const sourceInput = ${playInput};
|
|
6986
|
-
throw new Error(${jsString(`TODO: map sourceInput for ${
|
|
6987
|
-
const sourceResult = await ctx.runPlay('source_play', ${jsString(
|
|
6988
|
-
description: ${jsString(`Seed ${
|
|
7060
|
+
throw new Error(${jsString(`TODO: map sourceInput for ${input2.source.value}, choose the play output rows field, then delete this throw.`)});
|
|
7061
|
+
const sourceResult = await ctx.runPlay('source_play', ${jsString(input2.source.value)}, sourceInput, {
|
|
7062
|
+
description: ${jsString(`Seed ${input2.entity} rows from the selected play.`)},
|
|
6989
7063
|
});
|
|
6990
7064
|
// TODO: Replace sourceResult.rows with the selected play's actual row output field.
|
|
6991
|
-
const ${
|
|
7065
|
+
const ${input2.collection}: ${input2.collectionType}[] = (sourceResult.rows ?? []) as ${input2.collectionType}[];`;
|
|
6992
7066
|
}
|
|
6993
|
-
function generateProviderSourceBlock(
|
|
7067
|
+
function generateProviderSourceBlock(input2) {
|
|
6994
7068
|
const getter = requiredGetterName({
|
|
6995
|
-
tool:
|
|
7069
|
+
tool: input2.tool,
|
|
6996
7070
|
kind: "list",
|
|
6997
|
-
label:
|
|
7071
|
+
label: input2.provider
|
|
6998
7072
|
});
|
|
6999
|
-
const inputName = `${
|
|
7000
|
-
return `// ${
|
|
7073
|
+
const inputName = `${input2.entity}Input_${input2.index}`;
|
|
7074
|
+
return `// ${input2.entity === "company" ? "Company" : "People"} source provider: ${input2.provider}
|
|
7001
7075
|
const ${inputName}: Record<string, unknown> = ${generateSourceProviderInputObject(
|
|
7002
7076
|
{
|
|
7003
|
-
tool:
|
|
7077
|
+
tool: input2.tool,
|
|
7004
7078
|
indent: " ",
|
|
7005
|
-
label:
|
|
7006
|
-
entity:
|
|
7079
|
+
label: input2.provider,
|
|
7080
|
+
entity: input2.entity
|
|
7007
7081
|
}
|
|
7008
7082
|
)};
|
|
7009
|
-
throw new Error(${jsString(`TODO: fill ${inputName} for ${
|
|
7010
|
-
const source_${
|
|
7011
|
-
id: ${jsString(`${
|
|
7012
|
-
tool: ${jsString(
|
|
7083
|
+
throw new Error(${jsString(`TODO: fill ${inputName} for ${input2.provider}, then delete this throw.`)});
|
|
7084
|
+
const source_${input2.index} = await ctx.tools.execute({
|
|
7085
|
+
id: ${jsString(`${input2.entity}_source_${input2.index}`)},
|
|
7086
|
+
tool: ${jsString(input2.provider)},
|
|
7013
7087
|
input: ${inputName},
|
|
7014
|
-
description: ${jsString(`Seed ${
|
|
7088
|
+
description: ${jsString(`Seed ${input2.entity} rows from ${input2.provider}.`)},
|
|
7015
7089
|
});
|
|
7016
7090
|
// extractedLists.${getter}.get() returns provider-shaped rows. Do not assume canonical fields;
|
|
7017
|
-
// inspect source_${
|
|
7018
|
-
const sourceRows_${
|
|
7091
|
+
// inspect source_${input2.index}.extractedLists.${getter}.keys or the provider output schema, then map explicitly below.
|
|
7092
|
+
const sourceRows_${input2.index} = ${accessorExpression(`source_${input2.index}.extractedLists`, getter)}.get() as ${input2.collectionType}[];`;
|
|
7019
7093
|
}
|
|
7020
|
-
function generateProviderSourceRowsBlock(
|
|
7021
|
-
const blocks =
|
|
7094
|
+
function generateProviderSourceRowsBlock(input2) {
|
|
7095
|
+
const blocks = input2.source.values.map(
|
|
7022
7096
|
(provider, index) => generateProviderSourceBlock({
|
|
7023
7097
|
provider,
|
|
7024
7098
|
index,
|
|
7025
|
-
tool:
|
|
7026
|
-
entity:
|
|
7027
|
-
collectionType:
|
|
7099
|
+
tool: input2.sourceTools[index] ?? null,
|
|
7100
|
+
entity: input2.entity,
|
|
7101
|
+
collectionType: input2.collectionType
|
|
7028
7102
|
})
|
|
7029
7103
|
);
|
|
7030
7104
|
return `${blocks.join("\n\n ")}
|
|
7031
|
-
const ${
|
|
7105
|
+
const ${input2.collection}: ${input2.collectionType}[] = [${input2.source.values.map((_, index) => `...sourceRows_${index}`).join(", ")}];`;
|
|
7032
7106
|
}
|
|
7033
|
-
function generateSourceRowsBlock(
|
|
7034
|
-
const config = playBootstrapTemplateConfig(
|
|
7107
|
+
function generateSourceRowsBlock(input2) {
|
|
7108
|
+
const config = playBootstrapTemplateConfig(input2.options.template);
|
|
7035
7109
|
const entity = config.sourceEntity;
|
|
7036
7110
|
const collection = sourceCollectionName(entity);
|
|
7037
7111
|
const collectionType = sourceCollectionTypeName(entity);
|
|
7038
|
-
switch (
|
|
7112
|
+
switch (input2.options.from.kind) {
|
|
7039
7113
|
case "csv":
|
|
7040
7114
|
return generateCsvSourceRowsBlock({
|
|
7041
|
-
source:
|
|
7115
|
+
source: input2.options.from,
|
|
7042
7116
|
collection,
|
|
7043
7117
|
collectionType,
|
|
7044
|
-
packagedSourceCsvPath:
|
|
7118
|
+
packagedSourceCsvPath: input2.packagedSourceCsvPath
|
|
7045
7119
|
});
|
|
7046
7120
|
case "play":
|
|
7047
7121
|
return generatePlaySourceRowsBlock({
|
|
7048
|
-
source:
|
|
7049
|
-
sourcePlay:
|
|
7122
|
+
source: input2.options.from,
|
|
7123
|
+
sourcePlay: input2.sourcePlay,
|
|
7050
7124
|
entity,
|
|
7051
7125
|
collection,
|
|
7052
7126
|
collectionType
|
|
7053
7127
|
});
|
|
7054
7128
|
case "providers":
|
|
7055
7129
|
return generateProviderSourceRowsBlock({
|
|
7056
|
-
source:
|
|
7057
|
-
sourceTools:
|
|
7130
|
+
source: input2.options.from,
|
|
7131
|
+
sourceTools: input2.sourceTools,
|
|
7058
7132
|
entity,
|
|
7059
7133
|
collection,
|
|
7060
7134
|
collectionType
|
|
7061
7135
|
});
|
|
7062
7136
|
}
|
|
7063
7137
|
}
|
|
7064
|
-
function generateSourceSeedBlock(
|
|
7065
|
-
const sourceRows = generateSourceRowsBlock(
|
|
7066
|
-
const peoplePlayRef = stagePlayRef(
|
|
7138
|
+
function generateSourceSeedBlock(input2) {
|
|
7139
|
+
const sourceRows = generateSourceRowsBlock(input2);
|
|
7140
|
+
const peoplePlayRef = stagePlayRef(input2.options.people);
|
|
7067
7141
|
if (!peoplePlayRef) return sourceRows;
|
|
7068
7142
|
const peopleInput = generateCompanyInputObjectFromSchema(
|
|
7069
|
-
|
|
7143
|
+
input2.peoplePlay?.inputSchema,
|
|
7070
7144
|
" ",
|
|
7071
7145
|
peoplePlayRef,
|
|
7072
7146
|
["domain", "company_name"]
|
|
@@ -7088,15 +7162,15 @@ function generateSourceSeedBlock(input) {
|
|
|
7088
7162
|
contacts.push(...((peopleResult.rows ?? []) as ContactSourceRow[]));
|
|
7089
7163
|
}`;
|
|
7090
7164
|
}
|
|
7091
|
-
function finderProviderStepName(
|
|
7092
|
-
return `${
|
|
7165
|
+
function finderProviderStepName(input2) {
|
|
7166
|
+
return `${input2.aggregateStepName}${input2.index}_${safeIdentifier(input2.provider)}`;
|
|
7093
7167
|
}
|
|
7094
|
-
function finderValueGetter(
|
|
7095
|
-
const getters = getterNamesFromTool(
|
|
7096
|
-
const getter = getters.find((name) => name ===
|
|
7097
|
-
tool:
|
|
7168
|
+
function finderValueGetter(input2) {
|
|
7169
|
+
const getters = getterNamesFromTool(input2.tool, "value");
|
|
7170
|
+
const getter = getters.find((name) => name === input2.outputField) ?? requiredGetterName({
|
|
7171
|
+
tool: input2.tool,
|
|
7098
7172
|
kind: "value",
|
|
7099
|
-
label:
|
|
7173
|
+
label: input2.provider
|
|
7100
7174
|
});
|
|
7101
7175
|
return getter;
|
|
7102
7176
|
}
|
|
@@ -7104,157 +7178,157 @@ function optionalFinderValueExpression(candidateExpression, outputField) {
|
|
|
7104
7178
|
const valueExpression = /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(outputField) ? `${candidateExpression}?.${outputField}` : `${candidateExpression}?.[${jsString(outputField)}]`;
|
|
7105
7179
|
return `${valueExpression}?.trim()`;
|
|
7106
7180
|
}
|
|
7107
|
-
function generateFinderPlayStep(
|
|
7108
|
-
const outputField = PLAY_BOOTSTRAP_OUTPUT_FIELD_BY_FINDER[
|
|
7109
|
-
const resultTypeName = finderResultTypeName(
|
|
7181
|
+
function generateFinderPlayStep(input2) {
|
|
7182
|
+
const outputField = PLAY_BOOTSTRAP_OUTPUT_FIELD_BY_FINDER[input2.finder];
|
|
7183
|
+
const resultTypeName = finderResultTypeName(input2.finder);
|
|
7110
7184
|
const payload = generateContactInputObjectFromSchema(
|
|
7111
|
-
|
|
7185
|
+
input2.play?.inputSchema,
|
|
7112
7186
|
" ",
|
|
7113
|
-
|
|
7187
|
+
input2.stage.value
|
|
7114
7188
|
);
|
|
7115
7189
|
return `.step(${jsString(outputField)}, async (row, rowCtx) => {
|
|
7116
|
-
const ${
|
|
7117
|
-
throw new Error(${jsString(`TODO: map ${
|
|
7118
|
-
const ${
|
|
7119
|
-
${jsString(`${
|
|
7120
|
-
${jsString(
|
|
7121
|
-
${
|
|
7190
|
+
const ${input2.aggregateStepName}Input = ${payload};
|
|
7191
|
+
throw new Error(${jsString(`TODO: map ${input2.aggregateStepName}Input for ${input2.stage.value}, then delete this throw.`)});
|
|
7192
|
+
const ${input2.aggregateStepName}Result = await rowCtx.runPlay<${resultTypeName}>(
|
|
7193
|
+
${jsString(`${input2.aggregateStepName}Play`)},
|
|
7194
|
+
${jsString(input2.stage.value)},
|
|
7195
|
+
${input2.aggregateStepName}Input,
|
|
7122
7196
|
{
|
|
7123
|
-
description: ${jsString(`Run ${
|
|
7197
|
+
description: ${jsString(`Run ${input2.finder} play.`)},
|
|
7124
7198
|
},
|
|
7125
7199
|
);
|
|
7126
|
-
return typeof ${
|
|
7127
|
-
? ${
|
|
7128
|
-
: ${
|
|
7200
|
+
return typeof ${input2.aggregateStepName}Result === 'string'
|
|
7201
|
+
? ${input2.aggregateStepName}Result.trim() || null
|
|
7202
|
+
: ${input2.aggregateStepName}Result?.${outputField} ?? null;
|
|
7129
7203
|
})`;
|
|
7130
7204
|
}
|
|
7131
|
-
function generateFinderProviderResolver(
|
|
7205
|
+
function generateFinderProviderResolver(input2) {
|
|
7132
7206
|
const payload = generateContactInputObjectFromSchema(
|
|
7133
|
-
|
|
7207
|
+
input2.tool?.inputSchema,
|
|
7134
7208
|
" ",
|
|
7135
|
-
|
|
7209
|
+
input2.provider
|
|
7136
7210
|
);
|
|
7137
7211
|
const getter = finderValueGetter({
|
|
7138
|
-
tool:
|
|
7139
|
-
provider:
|
|
7140
|
-
outputField:
|
|
7212
|
+
tool: input2.tool,
|
|
7213
|
+
provider: input2.provider,
|
|
7214
|
+
outputField: input2.outputField
|
|
7141
7215
|
});
|
|
7142
7216
|
return `async (row, rowCtx) => {
|
|
7143
7217
|
const providerInput = ${payload};
|
|
7144
|
-
throw new Error(${jsString(`TODO: map providerInput for ${
|
|
7218
|
+
throw new Error(${jsString(`TODO: map providerInput for ${input2.provider}, then delete this throw.`)});
|
|
7145
7219
|
const result = await rowCtx.tools.execute({
|
|
7146
|
-
id: ${jsString(`${
|
|
7147
|
-
tool: ${jsString(
|
|
7220
|
+
id: ${jsString(`${input2.aggregateStepName}_${input2.providerIndex}`)},
|
|
7221
|
+
tool: ${jsString(input2.provider)},
|
|
7148
7222
|
input: providerInput,
|
|
7149
|
-
description: ${jsString(`Try ${
|
|
7223
|
+
description: ${jsString(`Try ${input2.provider} as a ${input2.finder}.`)},
|
|
7150
7224
|
});
|
|
7151
7225
|
return {
|
|
7152
|
-
${
|
|
7226
|
+
${input2.outputField}: (${accessorExpression("result.extractedValues", getter)}.get() as string | null) ?? null,
|
|
7153
7227
|
result,
|
|
7154
7228
|
};
|
|
7155
7229
|
}`;
|
|
7156
7230
|
}
|
|
7157
|
-
function generateFinderProviderStep(
|
|
7158
|
-
const stepName =
|
|
7159
|
-
switch (
|
|
7231
|
+
function generateFinderProviderStep(input2) {
|
|
7232
|
+
const stepName = input2.stepNames[input2.index];
|
|
7233
|
+
switch (input2.index) {
|
|
7160
7234
|
case 0:
|
|
7161
|
-
return `.step(${jsString(stepName)}, ${
|
|
7235
|
+
return `.step(${jsString(stepName)}, ${input2.resolver})`;
|
|
7162
7236
|
default: {
|
|
7163
|
-
const priorCandidates =
|
|
7237
|
+
const priorCandidates = input2.stepNames.slice(0, input2.index).map((name) => `row.${name}`).join(", ");
|
|
7164
7238
|
return `.step(
|
|
7165
7239
|
${jsString(stepName)},
|
|
7166
7240
|
when(
|
|
7167
|
-
(row) => ![${priorCandidates}].some((candidate) => ${optionalFinderValueExpression("candidate",
|
|
7168
|
-
${
|
|
7241
|
+
(row) => ![${priorCandidates}].some((candidate) => ${optionalFinderValueExpression("candidate", input2.outputField)}),
|
|
7242
|
+
${input2.resolver},
|
|
7169
7243
|
),
|
|
7170
7244
|
)`;
|
|
7171
7245
|
}
|
|
7172
7246
|
}
|
|
7173
7247
|
}
|
|
7174
|
-
function generateFinderProviderWaterfall(
|
|
7175
|
-
const legPrefix = finderProviderStepPrefix(
|
|
7176
|
-
const stepNames =
|
|
7248
|
+
function generateFinderProviderWaterfall(input2) {
|
|
7249
|
+
const legPrefix = finderProviderStepPrefix(input2.finder);
|
|
7250
|
+
const stepNames = input2.stage.values.map(
|
|
7177
7251
|
(provider, index) => finderProviderStepName({
|
|
7178
7252
|
aggregateStepName: legPrefix,
|
|
7179
7253
|
provider,
|
|
7180
7254
|
index
|
|
7181
7255
|
})
|
|
7182
7256
|
);
|
|
7183
|
-
const providerSteps =
|
|
7257
|
+
const providerSteps = input2.stage.values.map(
|
|
7184
7258
|
(provider, index) => generateFinderProviderStep({
|
|
7185
7259
|
index,
|
|
7186
7260
|
stepNames,
|
|
7187
|
-
outputField:
|
|
7261
|
+
outputField: input2.outputField,
|
|
7188
7262
|
resolver: generateFinderProviderResolver({
|
|
7189
|
-
finder:
|
|
7263
|
+
finder: input2.finder,
|
|
7190
7264
|
provider,
|
|
7191
7265
|
providerIndex: index,
|
|
7192
|
-
tool:
|
|
7193
|
-
aggregateStepName:
|
|
7194
|
-
outputField:
|
|
7266
|
+
tool: input2.tools[index] ?? null,
|
|
7267
|
+
aggregateStepName: input2.aggregateStepName,
|
|
7268
|
+
outputField: input2.outputField
|
|
7195
7269
|
})
|
|
7196
7270
|
})
|
|
7197
7271
|
);
|
|
7198
7272
|
const candidateNames = stepNames.map((name) => `row.${name}`).join(", ");
|
|
7199
|
-
return `// ${
|
|
7273
|
+
return `// ${input2.aggregateStepName} provider waterfall. Each provider leg is active once its TODO throw is removed;
|
|
7200
7274
|
// delete or comment out legs you do not want before running. Later legs are gated with when(...).
|
|
7201
7275
|
${providerSteps.join("\n ")}
|
|
7202
|
-
.step(${jsString(
|
|
7276
|
+
.step(${jsString(input2.aggregateStepName)}, (row) => {
|
|
7203
7277
|
const candidates = [${candidateNames}];
|
|
7204
|
-
const match = candidates.find((candidate) => ${optionalFinderValueExpression("candidate",
|
|
7205
|
-
return ${optionalFinderValueExpression("match",
|
|
7278
|
+
const match = candidates.find((candidate) => ${optionalFinderValueExpression("candidate", input2.outputField)});
|
|
7279
|
+
return ${optionalFinderValueExpression("match", input2.outputField)} ?? null;
|
|
7206
7280
|
})`;
|
|
7207
7281
|
}
|
|
7208
|
-
function generateFinderStageSteps(
|
|
7209
|
-
const outputField = PLAY_BOOTSTRAP_OUTPUT_FIELD_BY_FINDER[
|
|
7210
|
-
const aggregateStepName = stepFieldName(
|
|
7211
|
-
switch (
|
|
7282
|
+
function generateFinderStageSteps(input2) {
|
|
7283
|
+
const outputField = PLAY_BOOTSTRAP_OUTPUT_FIELD_BY_FINDER[input2.finder];
|
|
7284
|
+
const aggregateStepName = stepFieldName(input2.finder);
|
|
7285
|
+
switch (input2.stage.kind) {
|
|
7212
7286
|
case "play":
|
|
7213
7287
|
return generateFinderPlayStep({
|
|
7214
|
-
finder:
|
|
7215
|
-
stage:
|
|
7216
|
-
play:
|
|
7288
|
+
finder: input2.finder,
|
|
7289
|
+
stage: input2.stage,
|
|
7290
|
+
play: input2.finderPlays[input2.finder],
|
|
7217
7291
|
aggregateStepName
|
|
7218
7292
|
});
|
|
7219
7293
|
case "providers":
|
|
7220
7294
|
return generateFinderProviderWaterfall({
|
|
7221
|
-
finder:
|
|
7222
|
-
stage:
|
|
7223
|
-
tools:
|
|
7295
|
+
finder: input2.finder,
|
|
7296
|
+
stage: input2.stage,
|
|
7297
|
+
tools: input2.finderTools[input2.finder] ?? [],
|
|
7224
7298
|
aggregateStepName,
|
|
7225
7299
|
outputField
|
|
7226
7300
|
});
|
|
7227
7301
|
}
|
|
7228
7302
|
}
|
|
7229
|
-
function generateFinderSteps(
|
|
7303
|
+
function generateFinderSteps(input2) {
|
|
7230
7304
|
return ["email_finder", "phone_finder"].flatMap((finder) => {
|
|
7231
|
-
const stage = finderStage(
|
|
7305
|
+
const stage = finderStage(input2.options, finder);
|
|
7232
7306
|
return stage ? [
|
|
7233
7307
|
generateFinderStageSteps({
|
|
7234
|
-
...
|
|
7308
|
+
...input2,
|
|
7235
7309
|
finder,
|
|
7236
7310
|
stage
|
|
7237
7311
|
})
|
|
7238
7312
|
] : [];
|
|
7239
7313
|
}).join("\n ");
|
|
7240
7314
|
}
|
|
7241
|
-
function generateBootstrapPlaySource(
|
|
7242
|
-
const config = playBootstrapTemplateConfig(
|
|
7243
|
-
const sourceSeedBlock = generateSourceSeedBlock(
|
|
7244
|
-
const finderSteps = generateFinderSteps(
|
|
7245
|
-
const hasPeople = config.sourceEntity === "people" || Boolean(
|
|
7315
|
+
function generateBootstrapPlaySource(input2) {
|
|
7316
|
+
const config = playBootstrapTemplateConfig(input2.options.template);
|
|
7317
|
+
const sourceSeedBlock = generateSourceSeedBlock(input2);
|
|
7318
|
+
const finderSteps = generateFinderSteps(input2);
|
|
7319
|
+
const hasPeople = config.sourceEntity === "people" || Boolean(input2.options.people);
|
|
7246
7320
|
const sourceCollection = hasPeople ? "contacts" : "companies";
|
|
7247
7321
|
const mapSteps = finderSteps ? `
|
|
7248
7322
|
${finderSteps}` : "";
|
|
7249
|
-
const sourceCsvRowType =
|
|
7250
|
-
const rowTypeDefinitions = generateRowTypeDefinitions(
|
|
7251
|
-
const finderPlayResultTypes = generatedFinderPlayResultTypes(
|
|
7323
|
+
const sourceCsvRowType = input2.options.from.kind === "csv" ? renderSourceCsvRowType(input2.sourceCsvColumns) : "";
|
|
7324
|
+
const rowTypeDefinitions = generateRowTypeDefinitions(input2);
|
|
7325
|
+
const finderPlayResultTypes = generatedFinderPlayResultTypes(input2);
|
|
7252
7326
|
const typeDefinitions = [
|
|
7253
7327
|
sourceCsvRowType.trimEnd(),
|
|
7254
7328
|
rowTypeDefinitions,
|
|
7255
7329
|
finderPlayResultTypes
|
|
7256
7330
|
].filter((definition) => definition.trim().length > 0).join("\n\n");
|
|
7257
|
-
const importNames = needsWhenImport(
|
|
7331
|
+
const importNames = needsWhenImport(input2.options) ? "definePlay, when" : "definePlay";
|
|
7258
7332
|
return `import { ${importNames} } from 'deepline';
|
|
7259
7333
|
|
|
7260
7334
|
${typeDefinitions}
|
|
@@ -7263,8 +7337,8 @@ type Input = {
|
|
|
7263
7337
|
limit?: number;
|
|
7264
7338
|
};
|
|
7265
7339
|
|
|
7266
|
-
export default definePlay(${jsString(
|
|
7267
|
-
const limit = Math.max(1, Math.min(Number(input.limit ?? ${
|
|
7340
|
+
export default definePlay(${jsString(input2.options.name)}, async (ctx, input: Input = {}) => {
|
|
7341
|
+
const limit = Math.max(1, Math.min(Number(input.limit ?? ${input2.options.limit}), ${input2.options.limit}));
|
|
7268
7342
|
${sourceSeedBlock}
|
|
7269
7343
|
|
|
7270
7344
|
const rowsToProcess = ${sourceCollection}.slice(0, limit);
|
|
@@ -7276,7 +7350,7 @@ export default definePlay(${jsString(input.options.name)}, async (ctx, input: In
|
|
|
7276
7350
|
.map('bootstrap_rows', rowsToProcess)${mapSteps}
|
|
7277
7351
|
.run({
|
|
7278
7352
|
key: (_row, index) => index,
|
|
7279
|
-
description: ${jsString(`Bootstrap ${
|
|
7353
|
+
description: ${jsString(`Bootstrap ${input2.options.template}: seed source rows, run requested stages, then return the mapped rows.`)},
|
|
7280
7354
|
});
|
|
7281
7355
|
|
|
7282
7356
|
return {
|
|
@@ -7684,8 +7758,8 @@ var SHA256_ROUND_CONSTANTS = [
|
|
|
7684
7758
|
function rightRotate32(value, bits) {
|
|
7685
7759
|
return value >>> bits | value << 32 - bits;
|
|
7686
7760
|
}
|
|
7687
|
-
function sha256Hex(
|
|
7688
|
-
const bytes = Array.from(new TextEncoder().encode(
|
|
7761
|
+
function sha256Hex(input2) {
|
|
7762
|
+
const bytes = Array.from(new TextEncoder().encode(input2));
|
|
7689
7763
|
const bitLength = bytes.length * 8;
|
|
7690
7764
|
bytes.push(128);
|
|
7691
7765
|
while (bytes.length % 64 !== 56) {
|
|
@@ -7859,10 +7933,10 @@ function looksLikeInvalidExtractedGetter(error, sourceLine) {
|
|
|
7859
7933
|
if (!/Property '[^']+' does not exist on type/.test(error)) return false;
|
|
7860
7934
|
return /\bextracted(?:Values|Lists)\s*\./.test(sourceLine);
|
|
7861
7935
|
}
|
|
7862
|
-
function addPlayCheckRepairHints(
|
|
7936
|
+
function addPlayCheckRepairHints(input2) {
|
|
7863
7937
|
let addedHint = false;
|
|
7864
|
-
return
|
|
7865
|
-
const line = sourceLineForError(
|
|
7938
|
+
return input2.errors.map((error) => {
|
|
7939
|
+
const line = sourceLineForError(input2.sourceCode, error);
|
|
7866
7940
|
if (addedHint || !looksLikeInvalidExtractedGetter(error, line) || error.includes(EXTRACTED_GETTER_ERROR_HINT)) {
|
|
7867
7941
|
return error;
|
|
7868
7942
|
}
|
|
@@ -7924,9 +7998,9 @@ function parseReferencedPlayTarget2(target) {
|
|
|
7924
7998
|
function isPrebuiltReferenceTarget(target) {
|
|
7925
7999
|
return target.trim().toLowerCase().startsWith("prebuilt/");
|
|
7926
8000
|
}
|
|
7927
|
-
function buildBarePrebuiltReferenceError(
|
|
8001
|
+
function buildBarePrebuiltReferenceError(input2) {
|
|
7928
8002
|
return new Error(
|
|
7929
|
-
`Prebuilt play "${
|
|
8003
|
+
`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.`
|
|
7930
8004
|
);
|
|
7931
8005
|
}
|
|
7932
8006
|
async function assertCanonicalNamedPlayReference(client, target) {
|
|
@@ -7969,23 +8043,23 @@ function buildCloneEditStarter(play) {
|
|
|
7969
8043
|
checkCommand: `deepline plays check ${path}`
|
|
7970
8044
|
};
|
|
7971
8045
|
}
|
|
7972
|
-
function materializeRemotePlaySource(
|
|
7973
|
-
if (isFileTarget(
|
|
8046
|
+
function materializeRemotePlaySource(input2) {
|
|
8047
|
+
if (isFileTarget(input2.target)) {
|
|
7974
8048
|
return null;
|
|
7975
8049
|
}
|
|
7976
|
-
if (!
|
|
8050
|
+
if (!input2.sourceCode.trim()) {
|
|
7977
8051
|
return null;
|
|
7978
8052
|
}
|
|
7979
|
-
const outputPath =
|
|
8053
|
+
const outputPath = input2.outPath ?? defaultMaterializedPlayPath(input2.playName);
|
|
7980
8054
|
if ((0, import_node_fs10.existsSync)(outputPath)) {
|
|
7981
8055
|
const existingSource = (0, import_node_fs10.readFileSync)(outputPath, "utf-8");
|
|
7982
|
-
if (existingSource ===
|
|
8056
|
+
if (existingSource === input2.sourceCode) {
|
|
7983
8057
|
return { path: outputPath, status: "unchanged", created: false };
|
|
7984
8058
|
}
|
|
7985
|
-
(0, import_node_fs10.writeFileSync)(outputPath,
|
|
8059
|
+
(0, import_node_fs10.writeFileSync)(outputPath, input2.sourceCode, "utf-8");
|
|
7986
8060
|
return { path: outputPath, status: "updated", created: false };
|
|
7987
8061
|
}
|
|
7988
|
-
(0, import_node_fs10.writeFileSync)(outputPath,
|
|
8062
|
+
(0, import_node_fs10.writeFileSync)(outputPath, input2.sourceCode, "utf-8");
|
|
7989
8063
|
return { path: outputPath, status: "created", created: true };
|
|
7990
8064
|
}
|
|
7991
8065
|
function formatLoadedPlayMessage(materializedFile) {
|
|
@@ -8035,12 +8109,12 @@ function isFileTarget(target) {
|
|
|
8035
8109
|
function looksLikeRunId(target) {
|
|
8036
8110
|
return /^play\/[^/]+\/run\/[^/]+/.test(target.trim());
|
|
8037
8111
|
}
|
|
8038
|
-
function formatPlayCommandReceivedRunIdError(
|
|
8039
|
-
return `\`deepline plays ${
|
|
8112
|
+
function formatPlayCommandReceivedRunIdError(input2) {
|
|
8113
|
+
return `\`deepline plays ${input2.command} <run-id>\` expects a play name, but this looks like a run id.
|
|
8040
8114
|
Use:
|
|
8041
|
-
deepline runs get ${
|
|
8042
|
-
deepline runs logs ${
|
|
8043
|
-
deepline runs export ${
|
|
8115
|
+
deepline runs get ${input2.runId} --json
|
|
8116
|
+
deepline runs logs ${input2.runId} --json
|
|
8117
|
+
deepline runs export ${input2.runId} --out output.csv`;
|
|
8044
8118
|
}
|
|
8045
8119
|
function looksLikeFilePath(target) {
|
|
8046
8120
|
if (target.trim().toLowerCase().startsWith("prebuilt/")) {
|
|
@@ -8094,9 +8168,9 @@ function parseInputFlagValue(raw) {
|
|
|
8094
8168
|
}
|
|
8095
8169
|
return raw;
|
|
8096
8170
|
}
|
|
8097
|
-
function getDottedInputValue(
|
|
8171
|
+
function getDottedInputValue(input2, path) {
|
|
8098
8172
|
const parts = path.split(".").map((part) => part.trim()).filter(Boolean);
|
|
8099
|
-
let cursor =
|
|
8173
|
+
let cursor = input2;
|
|
8100
8174
|
for (const part of parts) {
|
|
8101
8175
|
if (!cursor || typeof cursor !== "object" || Array.isArray(cursor)) {
|
|
8102
8176
|
return void 0;
|
|
@@ -8105,12 +8179,12 @@ function getDottedInputValue(input, path) {
|
|
|
8105
8179
|
}
|
|
8106
8180
|
return cursor;
|
|
8107
8181
|
}
|
|
8108
|
-
function setDottedInputValue(
|
|
8182
|
+
function setDottedInputValue(input2, path, value) {
|
|
8109
8183
|
const parts = path.split(".").map((part) => part.trim()).filter(Boolean);
|
|
8110
8184
|
if (parts.length === 0) {
|
|
8111
8185
|
throw new Error(`Invalid play input flag path: ${path}`);
|
|
8112
8186
|
}
|
|
8113
|
-
let cursor =
|
|
8187
|
+
let cursor = input2;
|
|
8114
8188
|
for (const part of parts.slice(0, -1)) {
|
|
8115
8189
|
const existing = cursor[part];
|
|
8116
8190
|
if (existing !== void 0 && (!existing || typeof existing !== "object" || Array.isArray(existing))) {
|
|
@@ -8177,17 +8251,17 @@ function inputContainsLocalFilePath(value) {
|
|
|
8177
8251
|
}
|
|
8178
8252
|
return false;
|
|
8179
8253
|
}
|
|
8180
|
-
function namedRunNeedsPlayDefinition(
|
|
8181
|
-
return
|
|
8254
|
+
function namedRunNeedsPlayDefinition(input2) {
|
|
8255
|
+
return input2.revisionSelector === "latest" || inputContainsLocalFilePath(input2.runtimeInput);
|
|
8182
8256
|
}
|
|
8183
|
-
async function stageFileInputArgs(
|
|
8257
|
+
async function stageFileInputArgs(input2) {
|
|
8184
8258
|
const uniqueBindings = [
|
|
8185
8259
|
...new Map(
|
|
8186
|
-
|
|
8260
|
+
input2.bindings.map((binding) => [binding.inputPath, binding])
|
|
8187
8261
|
).values()
|
|
8188
8262
|
];
|
|
8189
8263
|
const localFiles = uniqueBindings.flatMap((binding) => {
|
|
8190
|
-
const value = getDottedInputValue(
|
|
8264
|
+
const value = getDottedInputValue(input2.runtimeInput, binding.inputPath);
|
|
8191
8265
|
if (!isLocalFilePathValue(value)) return [];
|
|
8192
8266
|
const absolutePath = (0, import_node_path12.resolve)(value);
|
|
8193
8267
|
return [{ binding, absolutePath, logicalPath: (0, import_node_path12.basename)(absolutePath) }];
|
|
@@ -8195,22 +8269,22 @@ async function stageFileInputArgs(input) {
|
|
|
8195
8269
|
if (localFiles.length === 0) {
|
|
8196
8270
|
return { inputFile: null, packagedFiles: [] };
|
|
8197
8271
|
}
|
|
8198
|
-
|
|
8272
|
+
input2.progress.phase(
|
|
8199
8273
|
localFiles.length === 1 ? "staging input file" : "staging input files"
|
|
8200
8274
|
);
|
|
8201
|
-
const staged = await
|
|
8275
|
+
const staged = await input2.client.stagePlayFiles(
|
|
8202
8276
|
localFiles.map((file) => stageFile(file.logicalPath, file.absolutePath))
|
|
8203
8277
|
);
|
|
8204
8278
|
for (const [index, file] of localFiles.entries()) {
|
|
8205
8279
|
setDottedInputValue(
|
|
8206
|
-
|
|
8280
|
+
input2.runtimeInput,
|
|
8207
8281
|
file.binding.inputPath,
|
|
8208
8282
|
file.logicalPath
|
|
8209
8283
|
);
|
|
8210
8284
|
const stagedFile = staged[index];
|
|
8211
8285
|
if (stagedFile && stagedFile.logicalPath !== file.logicalPath) {
|
|
8212
8286
|
setDottedInputValue(
|
|
8213
|
-
|
|
8287
|
+
input2.runtimeInput,
|
|
8214
8288
|
file.binding.inputPath,
|
|
8215
8289
|
stagedFile.logicalPath
|
|
8216
8290
|
);
|
|
@@ -8495,16 +8569,16 @@ function buildStepReceiptsDebugCommand(runId) {
|
|
|
8495
8569
|
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`;
|
|
8496
8570
|
return buildDebugDbQueryCommand(sql);
|
|
8497
8571
|
}
|
|
8498
|
-
function buildMapTableDebugCommand(
|
|
8572
|
+
function buildMapTableDebugCommand(input2) {
|
|
8499
8573
|
try {
|
|
8500
8574
|
const tableName = validatePlaySheetTableName(
|
|
8501
|
-
|
|
8502
|
-
|
|
8575
|
+
input2.playName,
|
|
8576
|
+
input2.tableNamespace
|
|
8503
8577
|
);
|
|
8504
8578
|
const table = `${quoteSqlIdentifier(
|
|
8505
8579
|
PLAY_CUSTOMER_STORAGE_SCHEMA_NAME
|
|
8506
8580
|
)}.${quoteSqlIdentifier(tableName)}`;
|
|
8507
|
-
const sql = `select * from ${table} where _run_id = ${quoteSqlLiteral(
|
|
8581
|
+
const sql = `select * from ${table} where _run_id = ${quoteSqlLiteral(input2.runId)} limit 20`;
|
|
8508
8582
|
return buildDebugDbQueryCommand(sql);
|
|
8509
8583
|
} catch {
|
|
8510
8584
|
return null;
|
|
@@ -8524,37 +8598,37 @@ function extractTableNamespaceFromLiveEvent(event) {
|
|
|
8524
8598
|
}
|
|
8525
8599
|
return null;
|
|
8526
8600
|
}
|
|
8527
|
-
function emitLiveDebugTableHints(
|
|
8528
|
-
if (
|
|
8601
|
+
function emitLiveDebugTableHints(input2) {
|
|
8602
|
+
if (input2.jsonOutput || !input2.runId || input2.runId === "pending") {
|
|
8529
8603
|
return;
|
|
8530
8604
|
}
|
|
8531
|
-
|
|
8532
|
-
const receiptsKey = `receipts:${
|
|
8533
|
-
if (!
|
|
8534
|
-
|
|
8535
|
-
|
|
8536
|
-
`Debug top-level outputs: ${buildStepReceiptsDebugCommand(
|
|
8605
|
+
input2.state.emittedDebugKeys ??= /* @__PURE__ */ new Set();
|
|
8606
|
+
const receiptsKey = `receipts:${input2.runId}`;
|
|
8607
|
+
if (!input2.state.emittedDebugKeys.has(receiptsKey)) {
|
|
8608
|
+
input2.state.emittedDebugKeys.add(receiptsKey);
|
|
8609
|
+
input2.progress.writeLine(
|
|
8610
|
+
`Debug top-level outputs: ${buildStepReceiptsDebugCommand(input2.runId)}`,
|
|
8537
8611
|
process.stdout
|
|
8538
8612
|
);
|
|
8539
8613
|
}
|
|
8540
|
-
const tableNamespace = extractTableNamespaceFromLiveEvent(
|
|
8614
|
+
const tableNamespace = extractTableNamespaceFromLiveEvent(input2.event);
|
|
8541
8615
|
if (!tableNamespace) {
|
|
8542
8616
|
return;
|
|
8543
8617
|
}
|
|
8544
|
-
const tableKey = `table:${
|
|
8545
|
-
if (
|
|
8618
|
+
const tableKey = `table:${input2.runId}:${tableNamespace}`;
|
|
8619
|
+
if (input2.state.emittedDebugKeys.has(tableKey)) {
|
|
8546
8620
|
return;
|
|
8547
8621
|
}
|
|
8548
8622
|
const command = buildMapTableDebugCommand({
|
|
8549
|
-
playName:
|
|
8550
|
-
runId:
|
|
8623
|
+
playName: input2.playName,
|
|
8624
|
+
runId: input2.runId,
|
|
8551
8625
|
tableNamespace
|
|
8552
8626
|
});
|
|
8553
8627
|
if (!command) {
|
|
8554
8628
|
return;
|
|
8555
8629
|
}
|
|
8556
|
-
|
|
8557
|
-
|
|
8630
|
+
input2.state.emittedDebugKeys.add(tableKey);
|
|
8631
|
+
input2.progress.writeLine(
|
|
8558
8632
|
`Debug rows for ${tableNamespace}: ${command}`,
|
|
8559
8633
|
process.stdout
|
|
8560
8634
|
);
|
|
@@ -8587,9 +8661,9 @@ function formatProgressLabel(raw) {
|
|
|
8587
8661
|
const value = typeof raw === "string" && raw.trim() ? raw.trim() : "step";
|
|
8588
8662
|
return value.replace(/^map:/, "").replace(/^tool:/, "");
|
|
8589
8663
|
}
|
|
8590
|
-
function formatProgressCounts(
|
|
8591
|
-
const completed = typeof
|
|
8592
|
-
const total = typeof
|
|
8664
|
+
function formatProgressCounts(input2) {
|
|
8665
|
+
const completed = typeof input2.completed === "number" && Number.isFinite(input2.completed) ? input2.completed : null;
|
|
8666
|
+
const total = typeof input2.total === "number" && Number.isFinite(input2.total) ? input2.total : null;
|
|
8593
8667
|
if (completed === null || total === null || total <= 0) {
|
|
8594
8668
|
return null;
|
|
8595
8669
|
}
|
|
@@ -8597,7 +8671,7 @@ function formatProgressCounts(input) {
|
|
|
8597
8671
|
0,
|
|
8598
8672
|
Math.min(100, Math.round(completed / total * 100))
|
|
8599
8673
|
);
|
|
8600
|
-
const failed = typeof
|
|
8674
|
+
const failed = typeof input2.failed === "number" && Number.isFinite(input2.failed) && input2.failed > 0 ? `, failed ${formatInteger(input2.failed)}` : "";
|
|
8601
8675
|
return `${formatInteger(completed)}/${formatInteger(total)} (${percent}%)${failed}`;
|
|
8602
8676
|
}
|
|
8603
8677
|
function getProgressLinesFromLiveEvent(event) {
|
|
@@ -8639,14 +8713,14 @@ function getProgressLinesFromLiveEvent(event) {
|
|
|
8639
8713
|
}
|
|
8640
8714
|
return lines;
|
|
8641
8715
|
}
|
|
8642
|
-
function printPlayProgressLines(
|
|
8643
|
-
for (const line of
|
|
8716
|
+
function printPlayProgressLines(input2) {
|
|
8717
|
+
for (const line of input2.lines) {
|
|
8644
8718
|
const signature = line.trim();
|
|
8645
|
-
if (!signature ||
|
|
8719
|
+
if (!signature || input2.state.lastProgressSignature === signature) {
|
|
8646
8720
|
continue;
|
|
8647
8721
|
}
|
|
8648
|
-
|
|
8649
|
-
|
|
8722
|
+
input2.state.lastProgressSignature = signature;
|
|
8723
|
+
input2.progress.writeLine(line);
|
|
8650
8724
|
}
|
|
8651
8725
|
}
|
|
8652
8726
|
function buildPlayDashboardUrl(baseUrl, playName) {
|
|
@@ -8654,102 +8728,102 @@ function buildPlayDashboardUrl(baseUrl, playName) {
|
|
|
8654
8728
|
const encodedPlayName = encodeURIComponent(playName);
|
|
8655
8729
|
return `${trimmedBase}/dashboard/plays/${encodedPlayName}`;
|
|
8656
8730
|
}
|
|
8657
|
-
function openPlayDashboard(
|
|
8658
|
-
if (
|
|
8731
|
+
function openPlayDashboard(input2) {
|
|
8732
|
+
if (input2.jsonOutput || input2.noOpen || !input2.dashboardUrl) {
|
|
8659
8733
|
return;
|
|
8660
8734
|
}
|
|
8661
|
-
openInBrowser(
|
|
8735
|
+
openInBrowser(input2.dashboardUrl);
|
|
8662
8736
|
}
|
|
8663
|
-
function printPlayLogLines(
|
|
8664
|
-
for (const line of
|
|
8665
|
-
if (
|
|
8737
|
+
function printPlayLogLines(input2) {
|
|
8738
|
+
for (const line of input2.lines) {
|
|
8739
|
+
if (input2.emitLogs) {
|
|
8666
8740
|
const formatted = formatPlayLogLine(
|
|
8667
8741
|
line,
|
|
8668
|
-
|
|
8669
|
-
|
|
8742
|
+
input2.status ?? void 0,
|
|
8743
|
+
input2.state
|
|
8670
8744
|
);
|
|
8671
8745
|
if (formatted) {
|
|
8672
|
-
|
|
8746
|
+
input2.progress.writeLogLine(formatted);
|
|
8673
8747
|
}
|
|
8674
8748
|
}
|
|
8675
|
-
|
|
8749
|
+
input2.state.lastLogIndex += 1;
|
|
8676
8750
|
}
|
|
8677
8751
|
}
|
|
8678
|
-
function assertPlayWaitNotTimedOut(
|
|
8679
|
-
if (
|
|
8680
|
-
const hasRealRunId =
|
|
8681
|
-
const phaseSuffix =
|
|
8682
|
-
const tailHint = hasRealRunId ? ` Run 'deepline runs tail ${
|
|
8752
|
+
function assertPlayWaitNotTimedOut(input2) {
|
|
8753
|
+
if (input2.waitTimeoutMs !== null && Date.now() - input2.startedAt >= input2.waitTimeoutMs) {
|
|
8754
|
+
const hasRealRunId = input2.workflowId.length > 0 && input2.workflowId !== "pending";
|
|
8755
|
+
const phaseSuffix = input2.lastPhase && input2.lastPhase.trim() ? ` (last observed phase: ${input2.lastPhase.trim()})` : "";
|
|
8756
|
+
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.`;
|
|
8683
8757
|
throw new DeeplineError(
|
|
8684
|
-
`Timed out waiting for play ${hasRealRunId ?
|
|
8758
|
+
`Timed out waiting for play ${hasRealRunId ? input2.workflowId : "<no run id>"} after ${Math.ceil(input2.waitTimeoutMs / 1e3)}s${phaseSuffix}.${tailHint}`,
|
|
8685
8759
|
void 0,
|
|
8686
8760
|
"PLAY_WAIT_TIMEOUT",
|
|
8687
8761
|
{
|
|
8688
|
-
...hasRealRunId ? { runId:
|
|
8689
|
-
...
|
|
8690
|
-
timeoutMs:
|
|
8762
|
+
...hasRealRunId ? { runId: input2.workflowId, workflowId: input2.workflowId } : {},
|
|
8763
|
+
...input2.lastPhase ? { phase: input2.lastPhase } : {},
|
|
8764
|
+
timeoutMs: input2.waitTimeoutMs
|
|
8691
8765
|
}
|
|
8692
8766
|
);
|
|
8693
8767
|
}
|
|
8694
8768
|
}
|
|
8695
|
-
async function waitForPlayCompletionByStream(
|
|
8769
|
+
async function waitForPlayCompletionByStream(input2) {
|
|
8696
8770
|
const controller = new AbortController();
|
|
8697
8771
|
let timedOut = false;
|
|
8698
8772
|
let lastPhase = null;
|
|
8699
|
-
const timeout =
|
|
8773
|
+
const timeout = input2.waitTimeoutMs === null ? null : setTimeout(
|
|
8700
8774
|
() => {
|
|
8701
8775
|
timedOut = true;
|
|
8702
8776
|
controller.abort();
|
|
8703
8777
|
},
|
|
8704
|
-
Math.max(1,
|
|
8778
|
+
Math.max(1, input2.waitTimeoutMs - (Date.now() - input2.startedAt))
|
|
8705
8779
|
);
|
|
8706
8780
|
try {
|
|
8707
|
-
for await (const event of
|
|
8708
|
-
|
|
8781
|
+
for await (const event of input2.client.streamPlayRunEvents(
|
|
8782
|
+
input2.workflowId,
|
|
8709
8783
|
{ signal: controller.signal }
|
|
8710
8784
|
)) {
|
|
8711
|
-
assertPlayWaitNotTimedOut({ ...
|
|
8785
|
+
assertPlayWaitNotTimedOut({ ...input2, lastPhase });
|
|
8712
8786
|
const phase = describeLiveEventPhase(event);
|
|
8713
8787
|
if (phase) {
|
|
8714
8788
|
lastPhase = phase;
|
|
8715
|
-
|
|
8789
|
+
input2.progress.phase(phase);
|
|
8716
8790
|
}
|
|
8717
8791
|
emitLiveDebugTableHints({
|
|
8718
8792
|
event,
|
|
8719
|
-
playName:
|
|
8720
|
-
runId:
|
|
8721
|
-
jsonOutput:
|
|
8722
|
-
state:
|
|
8723
|
-
progress:
|
|
8793
|
+
playName: input2.playName,
|
|
8794
|
+
runId: input2.workflowId,
|
|
8795
|
+
jsonOutput: input2.jsonOutput,
|
|
8796
|
+
state: input2.state,
|
|
8797
|
+
progress: input2.progress
|
|
8724
8798
|
});
|
|
8725
8799
|
printPlayLogLines({
|
|
8726
8800
|
lines: getLogLinesFromLiveEvent(event),
|
|
8727
8801
|
status: null,
|
|
8728
|
-
jsonOutput:
|
|
8729
|
-
emitLogs:
|
|
8730
|
-
state:
|
|
8731
|
-
progress:
|
|
8802
|
+
jsonOutput: input2.jsonOutput,
|
|
8803
|
+
emitLogs: input2.emitLogs,
|
|
8804
|
+
state: input2.state,
|
|
8805
|
+
progress: input2.progress
|
|
8732
8806
|
});
|
|
8733
|
-
if (!
|
|
8807
|
+
if (!input2.jsonOutput) {
|
|
8734
8808
|
printPlayProgressLines({
|
|
8735
8809
|
lines: getProgressLinesFromLiveEvent(event),
|
|
8736
|
-
state:
|
|
8737
|
-
progress:
|
|
8810
|
+
state: input2.state,
|
|
8811
|
+
progress: input2.progress
|
|
8738
8812
|
});
|
|
8739
8813
|
}
|
|
8740
8814
|
const status = getStatusFromLiveEvent(event);
|
|
8741
8815
|
if (status && TERMINAL_PLAY_STATUSES2.has(status)) {
|
|
8742
|
-
const finalStatus = await
|
|
8816
|
+
const finalStatus = await input2.client.getPlayStatus(input2.workflowId, {
|
|
8743
8817
|
billing: false
|
|
8744
8818
|
});
|
|
8745
8819
|
if (TERMINAL_PLAY_STATUSES2.has(finalStatus.status)) {
|
|
8746
|
-
return
|
|
8820
|
+
return input2.dashboardUrl ? { ...finalStatus, dashboardUrl: input2.dashboardUrl } : finalStatus;
|
|
8747
8821
|
}
|
|
8748
8822
|
}
|
|
8749
8823
|
}
|
|
8750
8824
|
} catch (error) {
|
|
8751
8825
|
if (timedOut) {
|
|
8752
|
-
assertPlayWaitNotTimedOut({ ...
|
|
8826
|
+
assertPlayWaitNotTimedOut({ ...input2, lastPhase });
|
|
8753
8827
|
}
|
|
8754
8828
|
throw error;
|
|
8755
8829
|
} finally {
|
|
@@ -8759,25 +8833,25 @@ async function waitForPlayCompletionByStream(input) {
|
|
|
8759
8833
|
}
|
|
8760
8834
|
const phaseSuffix = lastPhase && lastPhase.trim() ? ` (last observed phase: ${lastPhase.trim()})` : "";
|
|
8761
8835
|
throw new DeeplineError(
|
|
8762
|
-
`Play live stream ended before the run reached a terminal state runId=${
|
|
8836
|
+
`Play live stream ended before the run reached a terminal state runId=${input2.workflowId}${phaseSuffix}.`,
|
|
8763
8837
|
void 0,
|
|
8764
8838
|
"PLAY_LIVE_STREAM_ENDED",
|
|
8765
8839
|
{
|
|
8766
|
-
runId:
|
|
8767
|
-
workflowId:
|
|
8840
|
+
runId: input2.workflowId,
|
|
8841
|
+
workflowId: input2.workflowId,
|
|
8768
8842
|
...lastPhase ? { phase: lastPhase } : {}
|
|
8769
8843
|
}
|
|
8770
8844
|
);
|
|
8771
8845
|
}
|
|
8772
|
-
async function startAndWaitForPlayCompletionByStream(
|
|
8846
|
+
async function startAndWaitForPlayCompletionByStream(input2) {
|
|
8773
8847
|
for (let attempt = 0; attempt <= PLAY_START_TRANSIENT_RETRY_DELAYS_MS.length; attempt += 1) {
|
|
8774
|
-
const status = await startAndWaitForPlayCompletionByStreamOnce(
|
|
8848
|
+
const status = await startAndWaitForPlayCompletionByStreamOnce(input2);
|
|
8775
8849
|
const retryDelayMs = PLAY_START_TRANSIENT_RETRY_DELAYS_MS[attempt];
|
|
8776
8850
|
if (retryDelayMs === void 0 || !isRetryablePendingStartFailure(status)) {
|
|
8777
8851
|
return status;
|
|
8778
8852
|
}
|
|
8779
|
-
if (!
|
|
8780
|
-
|
|
8853
|
+
if (!input2.jsonOutput) {
|
|
8854
|
+
input2.progress.writeLine(
|
|
8781
8855
|
`[play watch] start failed before run id with a transient error; retrying (${playStatusErrorText(status)})`
|
|
8782
8856
|
);
|
|
8783
8857
|
}
|
|
@@ -8785,23 +8859,23 @@ async function startAndWaitForPlayCompletionByStream(input) {
|
|
|
8785
8859
|
phase: "cli.play_start_stream_retry",
|
|
8786
8860
|
ms: 0,
|
|
8787
8861
|
ok: true,
|
|
8788
|
-
playName:
|
|
8862
|
+
playName: input2.playName,
|
|
8789
8863
|
attempt: attempt + 1,
|
|
8790
8864
|
reason: playStatusErrorText(status)
|
|
8791
8865
|
});
|
|
8792
8866
|
await sleep4(retryDelayMs);
|
|
8793
8867
|
}
|
|
8794
8868
|
throw new DeeplineError(
|
|
8795
|
-
`Play ${
|
|
8869
|
+
`Play ${input2.playName} did not start after retrying transient start failures.`,
|
|
8796
8870
|
void 0,
|
|
8797
8871
|
"PLAY_START_RETRY_EXHAUSTED"
|
|
8798
8872
|
);
|
|
8799
8873
|
}
|
|
8800
|
-
async function startAndWaitForPlayCompletionByStreamOnce(
|
|
8874
|
+
async function startAndWaitForPlayCompletionByStreamOnce(input2) {
|
|
8801
8875
|
const startedAt = Date.now();
|
|
8802
8876
|
const dashboardUrl = buildPlayDashboardUrl(
|
|
8803
|
-
|
|
8804
|
-
|
|
8877
|
+
input2.client.baseUrl,
|
|
8878
|
+
input2.playName
|
|
8805
8879
|
);
|
|
8806
8880
|
const state = {
|
|
8807
8881
|
lastLogIndex: 0,
|
|
@@ -8815,15 +8889,15 @@ async function startAndWaitForPlayCompletionByStreamOnce(input) {
|
|
|
8815
8889
|
let eventCount = 0;
|
|
8816
8890
|
let firstRunIdMs = null;
|
|
8817
8891
|
let lastPhase = null;
|
|
8818
|
-
const timeout =
|
|
8892
|
+
const timeout = input2.waitTimeoutMs === null ? null : setTimeout(
|
|
8819
8893
|
() => {
|
|
8820
8894
|
timedOut = true;
|
|
8821
8895
|
controller.abort();
|
|
8822
8896
|
},
|
|
8823
|
-
Math.max(1,
|
|
8897
|
+
Math.max(1, input2.waitTimeoutMs)
|
|
8824
8898
|
);
|
|
8825
8899
|
try {
|
|
8826
|
-
for await (const event of
|
|
8900
|
+
for await (const event of input2.client.startPlayRunStream(input2.request, {
|
|
8827
8901
|
signal: controller.signal
|
|
8828
8902
|
})) {
|
|
8829
8903
|
eventCount += 1;
|
|
@@ -8834,55 +8908,55 @@ async function startAndWaitForPlayCompletionByStreamOnce(input) {
|
|
|
8834
8908
|
}
|
|
8835
8909
|
const workflowId = lastKnownWorkflowId || "pending";
|
|
8836
8910
|
if (workflowId !== "pending" && !emittedDashboardUrl) {
|
|
8837
|
-
if (!
|
|
8911
|
+
if (!input2.jsonOutput) {
|
|
8838
8912
|
writeStartedPlayRun({
|
|
8839
8913
|
runId: workflowId,
|
|
8840
|
-
playName:
|
|
8914
|
+
playName: input2.playName,
|
|
8841
8915
|
dashboardUrl,
|
|
8842
8916
|
jsonOutput: false,
|
|
8843
|
-
progress:
|
|
8917
|
+
progress: input2.progress
|
|
8844
8918
|
});
|
|
8845
8919
|
}
|
|
8846
8920
|
openPlayDashboard({
|
|
8847
8921
|
dashboardUrl,
|
|
8848
|
-
jsonOutput:
|
|
8849
|
-
noOpen:
|
|
8922
|
+
jsonOutput: input2.jsonOutput,
|
|
8923
|
+
noOpen: input2.noOpen
|
|
8850
8924
|
});
|
|
8851
|
-
|
|
8925
|
+
input2.progress.phase(`loading play on ${dashboardUrl}`);
|
|
8852
8926
|
emittedDashboardUrl = true;
|
|
8853
8927
|
}
|
|
8854
8928
|
assertPlayWaitNotTimedOut({
|
|
8855
8929
|
workflowId,
|
|
8856
8930
|
startedAt,
|
|
8857
|
-
waitTimeoutMs:
|
|
8931
|
+
waitTimeoutMs: input2.waitTimeoutMs,
|
|
8858
8932
|
lastPhase
|
|
8859
8933
|
});
|
|
8860
8934
|
const phase = describeLiveEventPhase(event);
|
|
8861
8935
|
if (phase) {
|
|
8862
8936
|
lastPhase = phase;
|
|
8863
|
-
|
|
8937
|
+
input2.progress.phase(phase);
|
|
8864
8938
|
}
|
|
8865
8939
|
printPlayLogLines({
|
|
8866
8940
|
lines: getLogLinesFromLiveEvent(event),
|
|
8867
8941
|
status: null,
|
|
8868
|
-
jsonOutput:
|
|
8869
|
-
emitLogs:
|
|
8942
|
+
jsonOutput: input2.jsonOutput,
|
|
8943
|
+
emitLogs: input2.emitLogs,
|
|
8870
8944
|
state,
|
|
8871
|
-
progress:
|
|
8945
|
+
progress: input2.progress
|
|
8872
8946
|
});
|
|
8873
8947
|
emitLiveDebugTableHints({
|
|
8874
8948
|
event,
|
|
8875
|
-
playName:
|
|
8949
|
+
playName: input2.playName,
|
|
8876
8950
|
runId: workflowId,
|
|
8877
|
-
jsonOutput:
|
|
8951
|
+
jsonOutput: input2.jsonOutput,
|
|
8878
8952
|
state,
|
|
8879
|
-
progress:
|
|
8953
|
+
progress: input2.progress
|
|
8880
8954
|
});
|
|
8881
|
-
if (!
|
|
8955
|
+
if (!input2.jsonOutput) {
|
|
8882
8956
|
printPlayProgressLines({
|
|
8883
8957
|
lines: getProgressLinesFromLiveEvent(event),
|
|
8884
8958
|
state,
|
|
8885
|
-
progress:
|
|
8959
|
+
progress: input2.progress
|
|
8886
8960
|
});
|
|
8887
8961
|
}
|
|
8888
8962
|
const finalStatus = getFinalStatusFromLiveEvent(event);
|
|
@@ -8891,7 +8965,7 @@ async function startAndWaitForPlayCompletionByStreamOnce(input) {
|
|
|
8891
8965
|
phase: "cli.play_start_stream_terminal",
|
|
8892
8966
|
ms: Date.now() - startedAt,
|
|
8893
8967
|
ok: true,
|
|
8894
|
-
playName:
|
|
8968
|
+
playName: input2.playName,
|
|
8895
8969
|
workflowId: finalStatus.runId || lastKnownWorkflowId || null,
|
|
8896
8970
|
eventCount,
|
|
8897
8971
|
firstRunIdMs,
|
|
@@ -8905,7 +8979,7 @@ async function startAndWaitForPlayCompletionByStreamOnce(input) {
|
|
|
8905
8979
|
assertPlayWaitNotTimedOut({
|
|
8906
8980
|
workflowId: lastKnownWorkflowId,
|
|
8907
8981
|
startedAt,
|
|
8908
|
-
waitTimeoutMs:
|
|
8982
|
+
waitTimeoutMs: input2.waitTimeoutMs,
|
|
8909
8983
|
lastPhase
|
|
8910
8984
|
});
|
|
8911
8985
|
}
|
|
@@ -8914,7 +8988,7 @@ async function startAndWaitForPlayCompletionByStreamOnce(input) {
|
|
|
8914
8988
|
clearTimeout(timeout);
|
|
8915
8989
|
}
|
|
8916
8990
|
const reason = error instanceof Error ? error.message : String(error);
|
|
8917
|
-
if (!
|
|
8991
|
+
if (!input2.jsonOutput) {
|
|
8918
8992
|
process.stderr.write(
|
|
8919
8993
|
`[play watch] start stream failed after run ${lastKnownWorkflowId}; reconnecting to run stream (${reason})
|
|
8920
8994
|
`
|
|
@@ -8924,7 +8998,7 @@ async function startAndWaitForPlayCompletionByStreamOnce(input) {
|
|
|
8924
8998
|
phase: "cli.play_start_stream_reconnect",
|
|
8925
8999
|
ms: Date.now() - startedAt,
|
|
8926
9000
|
ok: true,
|
|
8927
|
-
playName:
|
|
9001
|
+
playName: input2.playName,
|
|
8928
9002
|
workflowId: lastKnownWorkflowId,
|
|
8929
9003
|
eventCount,
|
|
8930
9004
|
firstRunIdMs,
|
|
@@ -8932,16 +9006,16 @@ async function startAndWaitForPlayCompletionByStreamOnce(input) {
|
|
|
8932
9006
|
reason
|
|
8933
9007
|
});
|
|
8934
9008
|
return waitForPlayCompletionByStream({
|
|
8935
|
-
client:
|
|
8936
|
-
playName:
|
|
9009
|
+
client: input2.client,
|
|
9010
|
+
playName: input2.playName,
|
|
8937
9011
|
workflowId: lastKnownWorkflowId,
|
|
8938
9012
|
dashboardUrl,
|
|
8939
|
-
jsonOutput:
|
|
8940
|
-
emitLogs:
|
|
8941
|
-
waitTimeoutMs:
|
|
9013
|
+
jsonOutput: input2.jsonOutput,
|
|
9014
|
+
emitLogs: input2.emitLogs,
|
|
9015
|
+
waitTimeoutMs: input2.waitTimeoutMs,
|
|
8942
9016
|
startedAt,
|
|
8943
9017
|
state,
|
|
8944
|
-
progress:
|
|
9018
|
+
progress: input2.progress
|
|
8945
9019
|
});
|
|
8946
9020
|
}
|
|
8947
9021
|
throw error;
|
|
@@ -8951,8 +9025,8 @@ async function startAndWaitForPlayCompletionByStreamOnce(input) {
|
|
|
8951
9025
|
}
|
|
8952
9026
|
}
|
|
8953
9027
|
if (lastKnownWorkflowId) {
|
|
8954
|
-
if (!
|
|
8955
|
-
|
|
9028
|
+
if (!input2.jsonOutput) {
|
|
9029
|
+
input2.progress.writeLine(
|
|
8956
9030
|
`[play watch] start stream ended after run ${lastKnownWorkflowId}; reconnecting to run stream`
|
|
8957
9031
|
);
|
|
8958
9032
|
}
|
|
@@ -8960,7 +9034,7 @@ async function startAndWaitForPlayCompletionByStreamOnce(input) {
|
|
|
8960
9034
|
phase: "cli.play_start_stream_reconnect",
|
|
8961
9035
|
ms: Date.now() - startedAt,
|
|
8962
9036
|
ok: true,
|
|
8963
|
-
playName:
|
|
9037
|
+
playName: input2.playName,
|
|
8964
9038
|
workflowId: lastKnownWorkflowId,
|
|
8965
9039
|
eventCount,
|
|
8966
9040
|
firstRunIdMs,
|
|
@@ -8968,16 +9042,16 @@ async function startAndWaitForPlayCompletionByStreamOnce(input) {
|
|
|
8968
9042
|
reason: "stream ended before terminal event"
|
|
8969
9043
|
});
|
|
8970
9044
|
return waitForPlayCompletionByStream({
|
|
8971
|
-
client:
|
|
8972
|
-
playName:
|
|
9045
|
+
client: input2.client,
|
|
9046
|
+
playName: input2.playName,
|
|
8973
9047
|
workflowId: lastKnownWorkflowId,
|
|
8974
9048
|
dashboardUrl,
|
|
8975
|
-
jsonOutput:
|
|
8976
|
-
emitLogs:
|
|
8977
|
-
waitTimeoutMs:
|
|
9049
|
+
jsonOutput: input2.jsonOutput,
|
|
9050
|
+
emitLogs: input2.emitLogs,
|
|
9051
|
+
waitTimeoutMs: input2.waitTimeoutMs,
|
|
8978
9052
|
startedAt,
|
|
8979
9053
|
state,
|
|
8980
|
-
progress:
|
|
9054
|
+
progress: input2.progress
|
|
8981
9055
|
});
|
|
8982
9056
|
}
|
|
8983
9057
|
const phaseSuffix = lastPhase && lastPhase.trim() ? ` (last observed phase: ${lastPhase.trim()})` : "";
|
|
@@ -9058,7 +9132,7 @@ function compactReturnValue(value, depth = 0) {
|
|
|
9058
9132
|
if (!value || typeof value !== "object") {
|
|
9059
9133
|
return value;
|
|
9060
9134
|
}
|
|
9061
|
-
const
|
|
9135
|
+
const output2 = {};
|
|
9062
9136
|
for (const [key, entry] of Object.entries(value)) {
|
|
9063
9137
|
if (depth === 0 && key === "_metadata") {
|
|
9064
9138
|
continue;
|
|
@@ -9069,9 +9143,9 @@ function compactReturnValue(value, depth = 0) {
|
|
|
9069
9143
|
if (key === "access") {
|
|
9070
9144
|
continue;
|
|
9071
9145
|
}
|
|
9072
|
-
|
|
9146
|
+
output2[key] = compactReturnValue(entry, depth + 1);
|
|
9073
9147
|
}
|
|
9074
|
-
return
|
|
9148
|
+
return output2;
|
|
9075
9149
|
}
|
|
9076
9150
|
function formatJsonPreview(value) {
|
|
9077
9151
|
const json = JSON.stringify(value, null, 2);
|
|
@@ -9280,22 +9354,22 @@ function extractBillingForStatus(status, error) {
|
|
|
9280
9354
|
const progressError = getStringField(status.progress, "error");
|
|
9281
9355
|
return extractBillingFromText(error) ?? extractBillingFromText(progressError) ?? getObjectField(status, "billing");
|
|
9282
9356
|
}
|
|
9283
|
-
function formatInsufficientCreditsMessage(
|
|
9284
|
-
const operation = getStringField(
|
|
9285
|
-
const balance = formatCreditAmount(
|
|
9286
|
-
const required = formatCreditAmount(
|
|
9357
|
+
function formatInsufficientCreditsMessage(input2) {
|
|
9358
|
+
const operation = getStringField(input2.billing, "operation_id") ?? getStringField(input2.billing, "operation") ?? extractToolIdFromErrorText(input2.error) ?? getStringField(input2.billing, "provider") ?? "tool call";
|
|
9359
|
+
const balance = formatCreditAmount(input2.billing.balance_credits);
|
|
9360
|
+
const required = formatCreditAmount(input2.billing.required_credits);
|
|
9287
9361
|
const recommended = formatCreditAmount(
|
|
9288
|
-
|
|
9362
|
+
input2.billing.recommended_add_credits ?? input2.billing.needed_credits
|
|
9289
9363
|
);
|
|
9290
|
-
const billingUrl = getStringField(
|
|
9291
|
-
const workspace = getStringField(
|
|
9364
|
+
const billingUrl = getStringField(input2.billing, "billing_url");
|
|
9365
|
+
const workspace = getStringField(input2.billing, "workspace_id") ?? getStringField(input2.billing, "workspaceId");
|
|
9292
9366
|
const workspaceSuffix = workspace ? ` (workspace=${workspace})` : "";
|
|
9293
9367
|
const addSuffix = billingUrl && recommended !== "-" ? ` Add >=${recommended} at ${billingUrl}.` : billingUrl ? ` Add credits at ${billingUrl}.` : "";
|
|
9294
9368
|
return `Workspace balance ${balance} < required ${required} for ${operation}${workspaceSuffix}.${addSuffix}`;
|
|
9295
9369
|
}
|
|
9296
|
-
function buildInsufficientCreditsSummaryLines(
|
|
9297
|
-
const progress =
|
|
9298
|
-
const rowsInfo = extractCanonicalRowsInfo(
|
|
9370
|
+
function buildInsufficientCreditsSummaryLines(input2) {
|
|
9371
|
+
const progress = input2.status.progress;
|
|
9372
|
+
const rowsInfo = extractCanonicalRowsInfo(input2.status);
|
|
9299
9373
|
const completed = getNumericField(progress, "completed") ?? getNumericField(progress, "completedRows") ?? rowsInfo?.rows.length ?? null;
|
|
9300
9374
|
const total = getNumericField(progress, "total") ?? getNumericField(progress, "totalRows") ?? rowsInfo?.totalRows ?? null;
|
|
9301
9375
|
const lines = [
|
|
@@ -9303,16 +9377,16 @@ function buildInsufficientCreditsSummaryLines(input) {
|
|
|
9303
9377
|
completed === null ? " completed rows: unknown" : ` completed rows: ${formatInteger(completed)}${total !== null ? ` of ${formatInteger(total)}` : ""}`,
|
|
9304
9378
|
" reusable receipts: yes; rerun after adding credits to continue from completed provider work"
|
|
9305
9379
|
];
|
|
9306
|
-
const billingUrl = getStringField(
|
|
9380
|
+
const billingUrl = getStringField(input2.billing, "billing_url");
|
|
9307
9381
|
const recommended = formatCreditAmount(
|
|
9308
|
-
|
|
9382
|
+
input2.billing.recommended_add_credits ?? input2.billing.needed_credits
|
|
9309
9383
|
);
|
|
9310
9384
|
if (billingUrl) {
|
|
9311
9385
|
lines.push(
|
|
9312
9386
|
recommended !== "-" ? ` add credits: add >=${recommended} at ${billingUrl}` : ` add credits: ${billingUrl}`
|
|
9313
9387
|
);
|
|
9314
9388
|
}
|
|
9315
|
-
const runId =
|
|
9389
|
+
const runId = input2.status.runId?.trim();
|
|
9316
9390
|
if (runId) {
|
|
9317
9391
|
lines.push(` inspect: deepline runs get ${runId} --json`);
|
|
9318
9392
|
lines.push(
|
|
@@ -9647,8 +9721,8 @@ function actionToCommand(action) {
|
|
|
9647
9721
|
}
|
|
9648
9722
|
function readFirstDatasetActions(packaged) {
|
|
9649
9723
|
for (const step of readRecordArray(packaged.steps)) {
|
|
9650
|
-
const
|
|
9651
|
-
const actions =
|
|
9724
|
+
const output2 = step.output && typeof step.output === "object" && !Array.isArray(step.output) ? step.output : null;
|
|
9725
|
+
const actions = output2?.actions && typeof output2.actions === "object" && !Array.isArray(output2.actions) ? output2.actions : null;
|
|
9652
9726
|
if (actions) {
|
|
9653
9727
|
return actions;
|
|
9654
9728
|
}
|
|
@@ -9670,12 +9744,12 @@ function buildRunPackageTextLines(packaged) {
|
|
|
9670
9744
|
const id = typeof step.id === "string" ? step.id : "step";
|
|
9671
9745
|
const kind = typeof step.kind === "string" ? step.kind : "step";
|
|
9672
9746
|
const stepStatus = typeof step.status === "string" ? step.status : status;
|
|
9673
|
-
const
|
|
9674
|
-
const rowCount =
|
|
9675
|
-
const preview =
|
|
9747
|
+
const output2 = step.output && typeof step.output === "object" && !Array.isArray(step.output) ? step.output : null;
|
|
9748
|
+
const rowCount = output2 && typeof output2.rowCount === "number" ? ` rows=${formatInteger(output2.rowCount)}` : "";
|
|
9749
|
+
const preview = output2?.preview && typeof output2.preview === "object" && !Array.isArray(output2.preview) ? output2.preview : null;
|
|
9676
9750
|
const previewRows = Array.isArray(preview?.rows) ? preview.rows.length : null;
|
|
9677
9751
|
lines.push(` ${kind} ${id}: ${stepStatus}${rowCount}`);
|
|
9678
|
-
lines.push(...formatPackageDatasetSummaryLines(
|
|
9752
|
+
lines.push(...formatPackageDatasetSummaryLines(output2?.summary));
|
|
9679
9753
|
if (previewRows !== null) {
|
|
9680
9754
|
lines.push(
|
|
9681
9755
|
` preview=${previewRows}${preview?.truncated ? " truncated" : ""}`
|
|
@@ -9758,19 +9832,19 @@ function writePlayResult(status, jsonOutput, options) {
|
|
|
9758
9832
|
` }
|
|
9759
9833
|
);
|
|
9760
9834
|
}
|
|
9761
|
-
async function resolvePlayRunOutputStatus(
|
|
9762
|
-
if (!getPlayRunPackage(
|
|
9763
|
-
return
|
|
9835
|
+
async function resolvePlayRunOutputStatus(input2) {
|
|
9836
|
+
if (!getPlayRunPackage(input2.status)) {
|
|
9837
|
+
return input2.status;
|
|
9764
9838
|
}
|
|
9765
|
-
const runId =
|
|
9839
|
+
const runId = input2.status.runId;
|
|
9766
9840
|
if (!runId) {
|
|
9767
|
-
return
|
|
9841
|
+
return input2.status;
|
|
9768
9842
|
}
|
|
9769
|
-
const refreshedStatus = await
|
|
9843
|
+
const refreshedStatus = await input2.client.getPlayStatus(runId, {
|
|
9770
9844
|
billing: false,
|
|
9771
|
-
full:
|
|
9845
|
+
full: input2.fullJson
|
|
9772
9846
|
});
|
|
9773
|
-
const dashboardUrl =
|
|
9847
|
+
const dashboardUrl = input2.status.dashboardUrl;
|
|
9774
9848
|
return typeof dashboardUrl === "string" ? { ...refreshedStatus, dashboardUrl } : refreshedStatus;
|
|
9775
9849
|
}
|
|
9776
9850
|
var RUN_EXPORT_PAGE_SIZE = 5e3;
|
|
@@ -9801,21 +9875,21 @@ function extractRunPlayName(status) {
|
|
|
9801
9875
|
function normalizeCustomerDbIdentifier(value) {
|
|
9802
9876
|
return value.split("/").pop().replace(/[^A-Za-z0-9]+/g, "_").replace(/^_+|_+$/g, "").toLowerCase();
|
|
9803
9877
|
}
|
|
9804
|
-
function buildCustomerDbQueryPlan(
|
|
9805
|
-
const playName = extractRunPlayName(
|
|
9806
|
-
const tableNamespace =
|
|
9807
|
-
if (!playName || !tableNamespace ||
|
|
9878
|
+
function buildCustomerDbQueryPlan(input2) {
|
|
9879
|
+
const playName = extractRunPlayName(input2.status);
|
|
9880
|
+
const tableNamespace = input2.rowsInfo.tableNamespace?.trim();
|
|
9881
|
+
if (!playName || !tableNamespace || input2.rowsInfo.totalRows <= 0) {
|
|
9808
9882
|
return null;
|
|
9809
9883
|
}
|
|
9810
9884
|
const tableName = `${normalizeCustomerDbIdentifier(playName)}_${normalizeCustomerDbIdentifier(
|
|
9811
9885
|
tableNamespace
|
|
9812
9886
|
)}`;
|
|
9813
|
-
const sql = `select * from "storage"."${tableName}" where _run_id = ${sqlStringLiteral(
|
|
9814
|
-
const base = `deepline customer-db query --sql ${shellSingleQuote(sql)} --max-rows ${
|
|
9887
|
+
const sql = `select * from "storage"."${tableName}" where _run_id = ${sqlStringLiteral(input2.status.runId)} limit ${input2.rowsInfo.totalRows}`;
|
|
9888
|
+
const base = `deepline customer-db query --sql ${shellSingleQuote(sql)} --max-rows ${input2.rowsInfo.totalRows}`;
|
|
9815
9889
|
return {
|
|
9816
9890
|
sql,
|
|
9817
9891
|
json: `${base} --json`,
|
|
9818
|
-
csv: `${base} --format csv --out ${shellSingleQuote((0, import_node_path12.resolve)(
|
|
9892
|
+
csv: `${base} --format csv --out ${shellSingleQuote((0, import_node_path12.resolve)(input2.outPath))}`
|
|
9819
9893
|
};
|
|
9820
9894
|
}
|
|
9821
9895
|
function exportableSheetRow(row) {
|
|
@@ -9866,20 +9940,20 @@ function mergeExportColumns(preferredColumns, rows) {
|
|
|
9866
9940
|
}
|
|
9867
9941
|
return columns;
|
|
9868
9942
|
}
|
|
9869
|
-
async function fetchBackingDatasetRows(
|
|
9870
|
-
const playName = extractRunPlayName(
|
|
9871
|
-
const tableNamespace =
|
|
9943
|
+
async function fetchBackingDatasetRows(input2) {
|
|
9944
|
+
const playName = extractRunPlayName(input2.status);
|
|
9945
|
+
const tableNamespace = input2.rowsInfo.tableNamespace?.trim();
|
|
9872
9946
|
if (!playName || !tableNamespace) {
|
|
9873
9947
|
return null;
|
|
9874
9948
|
}
|
|
9875
9949
|
const sheetRows = [];
|
|
9876
9950
|
let offset = 0;
|
|
9877
|
-
let expectedTotal =
|
|
9951
|
+
let expectedTotal = input2.rowsInfo.totalRows;
|
|
9878
9952
|
while (true) {
|
|
9879
|
-
const page = await
|
|
9953
|
+
const page = await input2.client.runs.exportDatasetRows({
|
|
9880
9954
|
playName,
|
|
9881
9955
|
tableNamespace,
|
|
9882
|
-
runId:
|
|
9956
|
+
runId: input2.status.runId,
|
|
9883
9957
|
limit: RUN_EXPORT_PAGE_SIZE,
|
|
9884
9958
|
offset
|
|
9885
9959
|
});
|
|
@@ -9894,20 +9968,20 @@ async function fetchBackingDatasetRows(input) {
|
|
|
9894
9968
|
offset += page.rows.length;
|
|
9895
9969
|
}
|
|
9896
9970
|
const rows = sheetRows.map(exportableSheetRow).filter((row) => Boolean(row));
|
|
9897
|
-
if (rows.length <
|
|
9971
|
+
if (rows.length < input2.rowsInfo.totalRows) {
|
|
9898
9972
|
return null;
|
|
9899
9973
|
}
|
|
9900
9974
|
const columns = mergeExportColumns(
|
|
9901
|
-
|
|
9975
|
+
input2.rowsInfo.columnsExplicit ? input2.rowsInfo.columns : [],
|
|
9902
9976
|
rows
|
|
9903
9977
|
);
|
|
9904
9978
|
return {
|
|
9905
|
-
...
|
|
9979
|
+
...input2.rowsInfo,
|
|
9906
9980
|
rows,
|
|
9907
9981
|
columns,
|
|
9908
9982
|
totalRows: rows.length,
|
|
9909
9983
|
complete: true,
|
|
9910
|
-
source: `${
|
|
9984
|
+
source: `${input2.rowsInfo.source ?? "result.rows"} -> /api/v2/plays/${playName}/sheet?tableNamespace=${tableNamespace}`
|
|
9911
9985
|
};
|
|
9912
9986
|
}
|
|
9913
9987
|
async function exportPlayStatusRows(client, status, outPath, options = {}) {
|
|
@@ -10009,11 +10083,11 @@ function extractActiveRunsFromError(error) {
|
|
|
10009
10083
|
function activeRunId(run) {
|
|
10010
10084
|
return getStringField(run, "workflowId") ?? getStringField(run, "runId");
|
|
10011
10085
|
}
|
|
10012
|
-
function formatActiveRunConflictError(
|
|
10086
|
+
function formatActiveRunConflictError(input2) {
|
|
10013
10087
|
const lines = [
|
|
10014
|
-
`Active run exists for ${
|
|
10088
|
+
`Active run exists for ${input2.playName}. Use --force to supersede, or inspect/stop the active run first.`
|
|
10015
10089
|
];
|
|
10016
|
-
for (const run of
|
|
10090
|
+
for (const run of input2.activeRuns.slice(0, 3)) {
|
|
10017
10091
|
const runId = activeRunId(run);
|
|
10018
10092
|
if (!runId) {
|
|
10019
10093
|
continue;
|
|
@@ -10127,49 +10201,49 @@ function renderServerResultView(value) {
|
|
|
10127
10201
|
}
|
|
10128
10202
|
return { lines: lines.length > 1 ? lines : [], actions: [] };
|
|
10129
10203
|
}
|
|
10130
|
-
function writeStartedPlayRun(
|
|
10131
|
-
if (
|
|
10132
|
-
if (
|
|
10133
|
-
printCommandEnvelope(
|
|
10204
|
+
function writeStartedPlayRun(input2) {
|
|
10205
|
+
if (input2.package && isPlayRunPackageValue(input2.package)) {
|
|
10206
|
+
if (input2.jsonOutput) {
|
|
10207
|
+
printCommandEnvelope(input2.package, { json: true });
|
|
10134
10208
|
return;
|
|
10135
10209
|
}
|
|
10136
|
-
const lines2 = buildRunPackageTextLines(
|
|
10137
|
-
const
|
|
10138
|
-
if (
|
|
10139
|
-
|
|
10210
|
+
const lines2 = buildRunPackageTextLines(input2.package);
|
|
10211
|
+
const output3 = lines2.join("\n");
|
|
10212
|
+
if (input2.progress) {
|
|
10213
|
+
input2.progress.writeLine(output3, process.stdout);
|
|
10140
10214
|
return;
|
|
10141
10215
|
}
|
|
10142
|
-
printCommandEnvelope(
|
|
10216
|
+
printCommandEnvelope(input2.package, {
|
|
10143
10217
|
json: false,
|
|
10144
|
-
text: `${
|
|
10218
|
+
text: `${output3}
|
|
10145
10219
|
`
|
|
10146
10220
|
});
|
|
10147
10221
|
return;
|
|
10148
10222
|
}
|
|
10149
10223
|
const payload = {
|
|
10150
|
-
runId:
|
|
10151
|
-
workflowId:
|
|
10152
|
-
name:
|
|
10153
|
-
status:
|
|
10154
|
-
dashboardUrl:
|
|
10224
|
+
runId: input2.runId,
|
|
10225
|
+
workflowId: input2.runId,
|
|
10226
|
+
name: input2.playName,
|
|
10227
|
+
status: input2.status ?? "started",
|
|
10228
|
+
dashboardUrl: input2.dashboardUrl,
|
|
10155
10229
|
next: {
|
|
10156
|
-
inspect: `deepline runs get ${
|
|
10157
|
-
full: `deepline runs get ${
|
|
10158
|
-
logs: `deepline runs logs ${
|
|
10159
|
-
export: `deepline runs export ${
|
|
10160
|
-
stop: `deepline runs stop ${
|
|
10230
|
+
inspect: `deepline runs get ${input2.runId} --json`,
|
|
10231
|
+
full: `deepline runs get ${input2.runId} --full --json`,
|
|
10232
|
+
logs: `deepline runs logs ${input2.runId} --json`,
|
|
10233
|
+
export: `deepline runs export ${input2.runId} --out output.csv`,
|
|
10234
|
+
stop: `deepline runs stop ${input2.runId} --reason "stale lock" --json`
|
|
10161
10235
|
}
|
|
10162
10236
|
};
|
|
10163
10237
|
const lines = [
|
|
10164
|
-
`Started ${
|
|
10165
|
-
` run id: ${
|
|
10166
|
-
` inspect: deepline runs get ${
|
|
10167
|
-
` full debug: deepline runs get ${
|
|
10168
|
-
` logs: deepline runs logs ${
|
|
10169
|
-
` export after completion: deepline runs export ${
|
|
10170
|
-
` stop run: deepline runs stop ${
|
|
10238
|
+
`Started ${input2.playName}`,
|
|
10239
|
+
` run id: ${input2.runId}`,
|
|
10240
|
+
` inspect: deepline runs get ${input2.runId} --json`,
|
|
10241
|
+
` full debug: deepline runs get ${input2.runId} --full --json`,
|
|
10242
|
+
` logs: deepline runs logs ${input2.runId} --json`,
|
|
10243
|
+
` export after completion: deepline runs export ${input2.runId} --out output.csv`,
|
|
10244
|
+
` stop run: deepline runs stop ${input2.runId} --reason "stale lock" --json`
|
|
10171
10245
|
];
|
|
10172
|
-
if (
|
|
10246
|
+
if (input2.jsonOutput) {
|
|
10173
10247
|
printCommandEnvelope(
|
|
10174
10248
|
{
|
|
10175
10249
|
...payload,
|
|
@@ -10179,12 +10253,12 @@ function writeStartedPlayRun(input) {
|
|
|
10179
10253
|
);
|
|
10180
10254
|
return;
|
|
10181
10255
|
}
|
|
10182
|
-
if (
|
|
10183
|
-
lines.push(` play page: ${
|
|
10256
|
+
if (input2.dashboardUrl) {
|
|
10257
|
+
lines.push(` play page: ${input2.dashboardUrl}`);
|
|
10184
10258
|
}
|
|
10185
|
-
const
|
|
10186
|
-
if (
|
|
10187
|
-
|
|
10259
|
+
const output2 = lines.join("\n");
|
|
10260
|
+
if (input2.progress) {
|
|
10261
|
+
input2.progress.writeLine(output2, process.stdout);
|
|
10188
10262
|
return;
|
|
10189
10263
|
}
|
|
10190
10264
|
printCommandEnvelope(
|
|
@@ -10192,7 +10266,7 @@ function writeStartedPlayRun(input) {
|
|
|
10192
10266
|
...payload,
|
|
10193
10267
|
render: { sections: [{ title: "play run", lines }] }
|
|
10194
10268
|
},
|
|
10195
|
-
{ json: false, text: `${
|
|
10269
|
+
{ json: false, text: `${output2}
|
|
10196
10270
|
` }
|
|
10197
10271
|
);
|
|
10198
10272
|
}
|
|
@@ -10200,7 +10274,7 @@ function parsePlayRunOptions(args) {
|
|
|
10200
10274
|
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.";
|
|
10201
10275
|
let filePath = null;
|
|
10202
10276
|
let playName = null;
|
|
10203
|
-
let
|
|
10277
|
+
let input2 = null;
|
|
10204
10278
|
let revisionId = null;
|
|
10205
10279
|
let revisionSelector = null;
|
|
10206
10280
|
const watch = !args.includes("--no-wait");
|
|
@@ -10221,7 +10295,7 @@ function parsePlayRunOptions(args) {
|
|
|
10221
10295
|
continue;
|
|
10222
10296
|
}
|
|
10223
10297
|
if ((arg === "--input" || arg === "-i") && args[index + 1]) {
|
|
10224
|
-
|
|
10298
|
+
input2 = parseJsonInput(args[++index]);
|
|
10225
10299
|
continue;
|
|
10226
10300
|
}
|
|
10227
10301
|
if (arg === "--revision-id" && args[index + 1]) {
|
|
@@ -10270,8 +10344,8 @@ function parsePlayRunOptions(args) {
|
|
|
10270
10344
|
}
|
|
10271
10345
|
if (arg.startsWith("--")) {
|
|
10272
10346
|
const { path, value } = parseInputFieldFlag(arg, args[index + 1]);
|
|
10273
|
-
|
|
10274
|
-
setDottedInputValue(
|
|
10347
|
+
input2 ??= {};
|
|
10348
|
+
setDottedInputValue(input2, path, parseInputFlagValue(value));
|
|
10275
10349
|
if (!arg.includes("=")) {
|
|
10276
10350
|
index += 1;
|
|
10277
10351
|
}
|
|
@@ -10306,7 +10380,7 @@ function parsePlayRunOptions(args) {
|
|
|
10306
10380
|
}
|
|
10307
10381
|
return {
|
|
10308
10382
|
target: filePath ? { kind: "file", path: filePath } : { kind: "name", name: playName },
|
|
10309
|
-
input,
|
|
10383
|
+
input: input2,
|
|
10310
10384
|
revisionId,
|
|
10311
10385
|
revisionSelector,
|
|
10312
10386
|
watch,
|
|
@@ -10673,15 +10747,15 @@ async function handleFileBackedRun(options) {
|
|
|
10673
10747
|
});
|
|
10674
10748
|
return 0;
|
|
10675
10749
|
}
|
|
10676
|
-
async function resolveNamedRunRevisionId(
|
|
10677
|
-
if (
|
|
10678
|
-
return
|
|
10750
|
+
async function resolveNamedRunRevisionId(input2) {
|
|
10751
|
+
if (input2.revisionId) {
|
|
10752
|
+
return input2.revisionId;
|
|
10679
10753
|
}
|
|
10680
|
-
if (
|
|
10681
|
-
const versions = await
|
|
10754
|
+
if (input2.selector === "latest") {
|
|
10755
|
+
const versions = await input2.client.listPlayVersions(input2.playName);
|
|
10682
10756
|
const latest = versions[0];
|
|
10683
10757
|
if (!latest?._id) {
|
|
10684
|
-
throw new Error(`No saved revisions found for ${
|
|
10758
|
+
throw new Error(`No saved revisions found for ${input2.playName}.`);
|
|
10685
10759
|
}
|
|
10686
10760
|
return latest._id;
|
|
10687
10761
|
}
|
|
@@ -12481,6 +12555,218 @@ async function handlePlayShareUnpublish(args) {
|
|
|
12481
12555
|
return 0;
|
|
12482
12556
|
}
|
|
12483
12557
|
|
|
12558
|
+
// src/cli/commands/secrets.ts
|
|
12559
|
+
var import_node_process = require("process");
|
|
12560
|
+
var hiddenInputBuffer = "";
|
|
12561
|
+
function normalizeSecretName(value) {
|
|
12562
|
+
const normalized = value.trim().toUpperCase();
|
|
12563
|
+
if (!/^[A-Z][A-Z0-9_]{1,63}$/.test(normalized)) {
|
|
12564
|
+
throw new Error(
|
|
12565
|
+
"Secret names must be 2-64 characters and use uppercase letters, numbers, and underscores."
|
|
12566
|
+
);
|
|
12567
|
+
}
|
|
12568
|
+
return normalized;
|
|
12569
|
+
}
|
|
12570
|
+
function renderSecret(secret) {
|
|
12571
|
+
const scope = secret.scope === "play" && secret.playName ? `play:${secret.playName}` : secret.scope;
|
|
12572
|
+
return `${secret.name} (${scope}) - ${secret.status}${secret.hasValue ? ", set" : ", empty"}`;
|
|
12573
|
+
}
|
|
12574
|
+
async function readHiddenLine(prompt) {
|
|
12575
|
+
if (!import_node_process.stdin.isTTY || !import_node_process.stdout.isTTY) {
|
|
12576
|
+
throw new Error(
|
|
12577
|
+
"Secret values must be entered from an interactive TTY. Do not pipe, pass, or script secret values."
|
|
12578
|
+
);
|
|
12579
|
+
}
|
|
12580
|
+
import_node_process.stdout.write(prompt);
|
|
12581
|
+
const previousRawMode = import_node_process.stdin.isRaw;
|
|
12582
|
+
if (typeof import_node_process.stdin.setRawMode === "function") import_node_process.stdin.setRawMode(true);
|
|
12583
|
+
let value = "";
|
|
12584
|
+
import_node_process.stdin.resume();
|
|
12585
|
+
return await new Promise((resolve12, reject) => {
|
|
12586
|
+
let settled = false;
|
|
12587
|
+
const cleanup = () => {
|
|
12588
|
+
import_node_process.stdin.off("data", onData);
|
|
12589
|
+
import_node_process.stdin.off("end", onEnd);
|
|
12590
|
+
import_node_process.stdin.off("error", onError);
|
|
12591
|
+
if (typeof import_node_process.stdin.setRawMode === "function") {
|
|
12592
|
+
import_node_process.stdin.setRawMode(previousRawMode);
|
|
12593
|
+
}
|
|
12594
|
+
};
|
|
12595
|
+
const finish = (line) => {
|
|
12596
|
+
if (settled) return;
|
|
12597
|
+
settled = true;
|
|
12598
|
+
import_node_process.stdout.write("\n");
|
|
12599
|
+
cleanup();
|
|
12600
|
+
resolve12(line);
|
|
12601
|
+
};
|
|
12602
|
+
const fail = (error) => {
|
|
12603
|
+
if (settled) return;
|
|
12604
|
+
settled = true;
|
|
12605
|
+
import_node_process.stdout.write("\n");
|
|
12606
|
+
cleanup();
|
|
12607
|
+
reject(error);
|
|
12608
|
+
};
|
|
12609
|
+
const processText = (text) => {
|
|
12610
|
+
for (let index = 0; index < text.length; index++) {
|
|
12611
|
+
const char = text[index];
|
|
12612
|
+
const code = char.charCodeAt(0);
|
|
12613
|
+
if (char === "\r" || char === "\n") {
|
|
12614
|
+
hiddenInputBuffer = text.slice(index + 1);
|
|
12615
|
+
finish(value);
|
|
12616
|
+
return;
|
|
12617
|
+
}
|
|
12618
|
+
if (code === 3) {
|
|
12619
|
+
fail(new Error("Secret input cancelled."));
|
|
12620
|
+
return;
|
|
12621
|
+
}
|
|
12622
|
+
if (code === 8 || code === 127) {
|
|
12623
|
+
value = value.slice(0, -1);
|
|
12624
|
+
continue;
|
|
12625
|
+
}
|
|
12626
|
+
if (code >= 32) {
|
|
12627
|
+
value += char;
|
|
12628
|
+
}
|
|
12629
|
+
}
|
|
12630
|
+
hiddenInputBuffer = "";
|
|
12631
|
+
};
|
|
12632
|
+
const onData = (chunk) => {
|
|
12633
|
+
processText(chunk.toString());
|
|
12634
|
+
};
|
|
12635
|
+
const onEnd = () => fail(new Error("Secret input ended before a value was entered."));
|
|
12636
|
+
const onError = (error) => fail(error);
|
|
12637
|
+
import_node_process.stdin.on("data", onData);
|
|
12638
|
+
import_node_process.stdin.once("end", onEnd);
|
|
12639
|
+
import_node_process.stdin.once("error", onError);
|
|
12640
|
+
if (hiddenInputBuffer) {
|
|
12641
|
+
const buffered = hiddenInputBuffer;
|
|
12642
|
+
hiddenInputBuffer = "";
|
|
12643
|
+
processText(buffered);
|
|
12644
|
+
}
|
|
12645
|
+
});
|
|
12646
|
+
}
|
|
12647
|
+
async function readSecretValue() {
|
|
12648
|
+
const first = await readHiddenLine("Secret value: ");
|
|
12649
|
+
if (!first) throw new Error("Secret value is required.");
|
|
12650
|
+
const second = await readHiddenLine("Confirm secret value: ");
|
|
12651
|
+
if (first !== second) {
|
|
12652
|
+
throw new Error("Secret values did not match.");
|
|
12653
|
+
}
|
|
12654
|
+
return first;
|
|
12655
|
+
}
|
|
12656
|
+
function preventShellHistoryLeak(forbidden) {
|
|
12657
|
+
if (forbidden.length > 0) {
|
|
12658
|
+
throw new Error(
|
|
12659
|
+
"Do not pass secret values as command arguments. Run `deepline secrets set NAME` and enter the value at the hidden prompt."
|
|
12660
|
+
);
|
|
12661
|
+
}
|
|
12662
|
+
}
|
|
12663
|
+
async function handleList(options) {
|
|
12664
|
+
const client = new DeeplineClient();
|
|
12665
|
+
const secrets = await client.listSecrets();
|
|
12666
|
+
printCommandEnvelope(
|
|
12667
|
+
{
|
|
12668
|
+
secrets,
|
|
12669
|
+
count: secrets.length,
|
|
12670
|
+
render: {
|
|
12671
|
+
sections: [
|
|
12672
|
+
{
|
|
12673
|
+
title: "secrets",
|
|
12674
|
+
lines: secrets.length ? secrets.map(renderSecret) : ["No play secrets are configured."]
|
|
12675
|
+
}
|
|
12676
|
+
]
|
|
12677
|
+
}
|
|
12678
|
+
},
|
|
12679
|
+
{ json: options.json }
|
|
12680
|
+
);
|
|
12681
|
+
}
|
|
12682
|
+
async function handleCheck(nameInput, options) {
|
|
12683
|
+
const name = normalizeSecretName(nameInput);
|
|
12684
|
+
const client = new DeeplineClient();
|
|
12685
|
+
const secret = await client.checkSecret(name);
|
|
12686
|
+
printCommandEnvelope(
|
|
12687
|
+
{
|
|
12688
|
+
ok: Boolean(secret),
|
|
12689
|
+
name,
|
|
12690
|
+
secret: secret ?? null,
|
|
12691
|
+
render: {
|
|
12692
|
+
sections: [
|
|
12693
|
+
{
|
|
12694
|
+
title: "secret check",
|
|
12695
|
+
lines: [
|
|
12696
|
+
secret ? `${name}: active` : `${name}: missing, disabled, or empty`
|
|
12697
|
+
]
|
|
12698
|
+
}
|
|
12699
|
+
]
|
|
12700
|
+
}
|
|
12701
|
+
},
|
|
12702
|
+
{ json: options.json }
|
|
12703
|
+
);
|
|
12704
|
+
if (!secret) process.exitCode = 4;
|
|
12705
|
+
}
|
|
12706
|
+
async function handleSet(nameInput, forbidden, options) {
|
|
12707
|
+
preventShellHistoryLeak(forbidden);
|
|
12708
|
+
const name = normalizeSecretName(nameInput);
|
|
12709
|
+
const scope = options.scope === "play" ? "play" : "org";
|
|
12710
|
+
const playName = options.play?.trim();
|
|
12711
|
+
if (scope === "play" && !playName) {
|
|
12712
|
+
throw new Error("--play <name> is required when --scope play is used.");
|
|
12713
|
+
}
|
|
12714
|
+
const value = await readSecretValue();
|
|
12715
|
+
const { http } = getAuthedHttpClient();
|
|
12716
|
+
const response = await http.post(
|
|
12717
|
+
"/api/v2/secrets",
|
|
12718
|
+
{
|
|
12719
|
+
name,
|
|
12720
|
+
value,
|
|
12721
|
+
scope,
|
|
12722
|
+
...playName ? { playName } : {}
|
|
12723
|
+
}
|
|
12724
|
+
);
|
|
12725
|
+
const secret = response.secret;
|
|
12726
|
+
printCommandEnvelope(
|
|
12727
|
+
{
|
|
12728
|
+
ok: true,
|
|
12729
|
+
secret,
|
|
12730
|
+
render: {
|
|
12731
|
+
sections: [
|
|
12732
|
+
{
|
|
12733
|
+
title: "secret saved",
|
|
12734
|
+
lines: [`${secret.name}: saved (${secret.scope})`]
|
|
12735
|
+
}
|
|
12736
|
+
]
|
|
12737
|
+
}
|
|
12738
|
+
},
|
|
12739
|
+
{ json: options.json }
|
|
12740
|
+
);
|
|
12741
|
+
}
|
|
12742
|
+
function registerSecretsCommands(program) {
|
|
12743
|
+
const secrets = program.command("secrets").description("Manage play secrets without revealing values.").addHelpText(
|
|
12744
|
+
"after",
|
|
12745
|
+
`
|
|
12746
|
+
Notes:
|
|
12747
|
+
Secret values are never accepted as command arguments, stdin pipes, env vars,
|
|
12748
|
+
or files. Use deepline secrets set NAME and type the value at the hidden TTY
|
|
12749
|
+
prompt. Agents can list/check metadata but should not enter secret values.
|
|
12750
|
+
|
|
12751
|
+
Examples:
|
|
12752
|
+
deepline secrets list
|
|
12753
|
+
deepline secrets check HUBSPOT_TOKEN
|
|
12754
|
+
deepline secrets set HUBSPOT_TOKEN
|
|
12755
|
+
`
|
|
12756
|
+
);
|
|
12757
|
+
secrets.command("list").description("List secret metadata only.").option("--json", "Emit JSON output").action(async (options) => {
|
|
12758
|
+
await handleList(options);
|
|
12759
|
+
});
|
|
12760
|
+
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) => {
|
|
12761
|
+
await handleCheck(name, options);
|
|
12762
|
+
});
|
|
12763
|
+
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(
|
|
12764
|
+
async (name, forbidden, options) => {
|
|
12765
|
+
await handleSet(name, forbidden ?? [], options);
|
|
12766
|
+
}
|
|
12767
|
+
);
|
|
12768
|
+
}
|
|
12769
|
+
|
|
12484
12770
|
// src/cli/commands/tools.ts
|
|
12485
12771
|
var import_commander2 = require("commander");
|
|
12486
12772
|
var import_node_fs12 = require("fs");
|
|
@@ -13686,25 +13972,25 @@ function shellQuote(value) {
|
|
|
13686
13972
|
function powerShellQuote(value) {
|
|
13687
13973
|
return `'${value.replace(/'/g, "''")}'`;
|
|
13688
13974
|
}
|
|
13689
|
-
function seedToolListScript(
|
|
13690
|
-
const stem = safeFileStem(
|
|
13975
|
+
function seedToolListScript(input2) {
|
|
13976
|
+
const stem = safeFileStem(input2.toolId);
|
|
13691
13977
|
const fileName = `${stem}-workflow-seed-${Date.now()}.play.ts`;
|
|
13692
13978
|
const scriptDir = (0, import_node_fs12.mkdtempSync)((0, import_node_path14.join)((0, import_node_os8.tmpdir)(), "deepline-workflow-seed-"));
|
|
13693
13979
|
(0, import_node_fs12.chmodSync)(scriptDir, 448);
|
|
13694
13980
|
const scriptPath = (0, import_node_path14.join)(scriptDir, fileName);
|
|
13695
13981
|
const projectDir = `deepline/projects/${stem}-workflow`;
|
|
13696
13982
|
const playName = `${stem}-workflow`;
|
|
13697
|
-
const sampleRows =
|
|
13698
|
-
const columns = Object.keys(
|
|
13699
|
-
const rowKey = Object.prototype.hasOwnProperty.call(
|
|
13983
|
+
const sampleRows = input2.rows.length > 0 ? `${JSON.stringify(input2.rows.slice(0, 2)).replace(/\]$/, "")}, ...]` : "[]";
|
|
13984
|
+
const columns = Object.keys(input2.rows[0] ?? {}).join(", ");
|
|
13985
|
+
const rowKey = Object.prototype.hasOwnProperty.call(input2.rows[0] ?? {}, "id") ? '"id"' : "(row) => JSON.stringify(row)";
|
|
13700
13986
|
const script = `import { definePlay } from 'deepline';
|
|
13701
13987
|
|
|
13702
13988
|
export default definePlay(${JSON.stringify(playName)}, async (ctx) => {
|
|
13703
13989
|
const result = await ctx.tools.execute({
|
|
13704
|
-
id: ${JSON.stringify(
|
|
13705
|
-
tool: ${JSON.stringify(
|
|
13706
|
-
input: ${JSON.stringify(
|
|
13707
|
-
description: ${JSON.stringify(`Seed ${
|
|
13990
|
+
id: ${JSON.stringify(input2.toolId)},
|
|
13991
|
+
tool: ${JSON.stringify(input2.toolId)},
|
|
13992
|
+
input: ${JSON.stringify(input2.payload)},
|
|
13993
|
+
description: ${JSON.stringify(`Seed ${input2.toolId} rows for workflow expansion.`)},
|
|
13708
13994
|
});
|
|
13709
13995
|
|
|
13710
13996
|
const list = Object.values(result.extractedLists)[0];
|
|
@@ -13736,23 +14022,23 @@ export default definePlay(${JSON.stringify(playName)}, async (ctx) => {
|
|
|
13736
14022
|
windowsCopyCommand: `New-Item -ItemType Directory -Force -Path ${powerShellQuote(projectDir.replace(/\//g, "\\"))} | Out-Null; Copy-Item -LiteralPath ${powerShellQuote(scriptPath)} -Destination ${powerShellQuote(`${projectDir.replace(/\//g, "\\")}\\${fileName}`)}`
|
|
13737
14023
|
};
|
|
13738
14024
|
}
|
|
13739
|
-
function buildToolExecuteBaseEnvelope(
|
|
13740
|
-
const envelope = commandEnvelopeFromRawResponse(
|
|
13741
|
-
const summaryEntries = Object.entries(
|
|
13742
|
-
const outputPreview =
|
|
14025
|
+
function buildToolExecuteBaseEnvelope(input2) {
|
|
14026
|
+
const envelope = commandEnvelopeFromRawResponse(input2.rawResponse);
|
|
14027
|
+
const summaryEntries = Object.entries(input2.summary);
|
|
14028
|
+
const outputPreview = input2.listConversion ? {
|
|
13743
14029
|
kind: "list",
|
|
13744
|
-
rowCount:
|
|
13745
|
-
columns: Object.keys(
|
|
13746
|
-
preview:
|
|
13747
|
-
listStrategy:
|
|
13748
|
-
listSourcePath:
|
|
14030
|
+
rowCount: input2.listConversion.rows.length,
|
|
14031
|
+
columns: Object.keys(input2.listConversion.rows[0] ?? {}),
|
|
14032
|
+
preview: input2.listConversion.rows.slice(0, 5),
|
|
14033
|
+
listStrategy: input2.listConversion.strategy,
|
|
14034
|
+
listSourcePath: input2.listConversion.sourcePath
|
|
13749
14035
|
} : {
|
|
13750
14036
|
kind: summaryEntries.length > 0 ? "object" : "raw",
|
|
13751
|
-
summary:
|
|
14037
|
+
summary: input2.summary
|
|
13752
14038
|
};
|
|
13753
14039
|
const envelopeHasCanonicalOutput = isRecord5(envelope.toolResponse) && Object.prototype.hasOwnProperty.call(envelope.toolResponse, "raw");
|
|
13754
|
-
const inspectCommand = `deepline tools execute ${
|
|
13755
|
-
const actions =
|
|
14040
|
+
const inspectCommand = `deepline tools execute ${input2.toolId} --input ${shellQuote(JSON.stringify(input2.params))} --json`;
|
|
14041
|
+
const actions = input2.listConversion ? [
|
|
13756
14042
|
{
|
|
13757
14043
|
label: "next",
|
|
13758
14044
|
command: "move starter script into a project folder and expand it into a Deepline play"
|
|
@@ -13761,24 +14047,24 @@ function buildToolExecuteBaseEnvelope(input) {
|
|
|
13761
14047
|
return {
|
|
13762
14048
|
...envelope,
|
|
13763
14049
|
...envelopeHasCanonicalOutput ? { output_preview: outputPreview } : { output: outputPreview },
|
|
13764
|
-
...summaryEntries.length > 0 ? { summary:
|
|
14050
|
+
...summaryEntries.length > 0 ? { summary: input2.summary } : {},
|
|
13765
14051
|
next: {
|
|
13766
14052
|
inspect: inspectCommand,
|
|
13767
14053
|
playDebugging: "When fixing a play getter, inspect the actual play run table with runs get / inspect rows; do not copy CLI preview paths blindly.",
|
|
13768
|
-
...
|
|
14054
|
+
...input2.listConversion ? {
|
|
13769
14055
|
expandToPlay: "Use stable map and step keys so reruns are idempotent: completed rows are reused, and only missing or stale work runs again.",
|
|
13770
|
-
listSourcePath:
|
|
14056
|
+
listSourcePath: input2.listConversion.sourcePath ?? "auto-detected list in the CLI response preview"
|
|
13771
14057
|
} : {}
|
|
13772
14058
|
},
|
|
13773
14059
|
render: {
|
|
13774
|
-
sections:
|
|
14060
|
+
sections: input2.listConversion ? [
|
|
13775
14061
|
{
|
|
13776
14062
|
title: "output",
|
|
13777
14063
|
lines: [
|
|
13778
|
-
`${
|
|
14064
|
+
`${input2.listConversion.rows.length} row(s) extracted from ${input2.listConversion.sourcePath ?? "auto-detected list"}`,
|
|
13779
14065
|
"paths above are observed from this execute response; use run table rows to debug play getters",
|
|
13780
|
-
`columns: ${JSON.stringify(Object.keys(
|
|
13781
|
-
`preview: ${JSON.stringify(
|
|
14066
|
+
`columns: ${JSON.stringify(Object.keys(input2.listConversion.rows[0] ?? {}))}`,
|
|
14067
|
+
`preview: ${JSON.stringify(input2.listConversion.rows.slice(0, 5))}`
|
|
13782
14068
|
]
|
|
13783
14069
|
}
|
|
13784
14070
|
] : [
|
|
@@ -13786,7 +14072,7 @@ function buildToolExecuteBaseEnvelope(input) {
|
|
|
13786
14072
|
title: "result",
|
|
13787
14073
|
lines: summaryEntries.length > 0 ? summaryEntries.map(
|
|
13788
14074
|
([key, value]) => `${key}=${String(value)}`
|
|
13789
|
-
) : [JSON.stringify(
|
|
14075
|
+
) : [JSON.stringify(input2.rawResponse, null, 2)]
|
|
13790
14076
|
}
|
|
13791
14077
|
],
|
|
13792
14078
|
actions
|
|
@@ -14107,6 +14393,174 @@ Examples:
|
|
|
14107
14393
|
});
|
|
14108
14394
|
}
|
|
14109
14395
|
|
|
14396
|
+
// ../shared_libs/cli/command-compatibility.json
|
|
14397
|
+
var command_compatibility_default = {
|
|
14398
|
+
enrich: {
|
|
14399
|
+
family: "python",
|
|
14400
|
+
label: "a legacy Python CLI enrichment command",
|
|
14401
|
+
sdk_alternative: "Use `deepline plays ...` for durable workflows or `deepline tools execute ...` for one tool call."
|
|
14402
|
+
},
|
|
14403
|
+
session: {
|
|
14404
|
+
family: "python",
|
|
14405
|
+
label: "a legacy Python CLI session/playground command",
|
|
14406
|
+
sdk_alternative: "Use SDK play run output and run commands such as `deepline plays run ...`."
|
|
14407
|
+
},
|
|
14408
|
+
workflows: {
|
|
14409
|
+
family: "python",
|
|
14410
|
+
label: "a legacy Python CLI workflow command",
|
|
14411
|
+
sdk_alternative: "Use `deepline plays ...` in the SDK CLI."
|
|
14412
|
+
},
|
|
14413
|
+
backend: {
|
|
14414
|
+
family: "python",
|
|
14415
|
+
label: "a legacy Python CLI playground backend command"
|
|
14416
|
+
},
|
|
14417
|
+
events: {
|
|
14418
|
+
family: "python",
|
|
14419
|
+
label: "a legacy Python CLI event command"
|
|
14420
|
+
},
|
|
14421
|
+
plays: {
|
|
14422
|
+
family: "sdk",
|
|
14423
|
+
label: "an SDK CLI play command",
|
|
14424
|
+
python_alternative: "Use `deepline workflows ...` only for legacy workflows."
|
|
14425
|
+
},
|
|
14426
|
+
play: {
|
|
14427
|
+
family: "sdk",
|
|
14428
|
+
label: "an SDK CLI play command",
|
|
14429
|
+
python_alternative: "Use `deepline workflows ...` only for legacy workflows."
|
|
14430
|
+
},
|
|
14431
|
+
runs: {
|
|
14432
|
+
family: "sdk",
|
|
14433
|
+
label: "an SDK CLI run inspection command"
|
|
14434
|
+
},
|
|
14435
|
+
health: {
|
|
14436
|
+
family: "sdk",
|
|
14437
|
+
label: "an SDK CLI health command"
|
|
14438
|
+
}
|
|
14439
|
+
};
|
|
14440
|
+
|
|
14441
|
+
// ../shared_libs/cli/install-commands.json
|
|
14442
|
+
var install_commands_default = {
|
|
14443
|
+
skills: {
|
|
14444
|
+
index_path: "/.well-known/skills/index.json",
|
|
14445
|
+
default_agents: ["codex", "claude-code", "cursor"],
|
|
14446
|
+
npx_binary: "npx",
|
|
14447
|
+
npx_add_args_template: [
|
|
14448
|
+
"--yes",
|
|
14449
|
+
"skills",
|
|
14450
|
+
"add",
|
|
14451
|
+
"{skills_index_url}",
|
|
14452
|
+
"--agent",
|
|
14453
|
+
"{agents}",
|
|
14454
|
+
"--global",
|
|
14455
|
+
"--yes",
|
|
14456
|
+
"--skill",
|
|
14457
|
+
"{skill_name}",
|
|
14458
|
+
"--full-depth"
|
|
14459
|
+
]
|
|
14460
|
+
},
|
|
14461
|
+
cli: {
|
|
14462
|
+
legacy_python_shell_template: "curl -s {base_url}/api/v2/cli/install | bash",
|
|
14463
|
+
sdk_npm_global: "npm install -g deepline@latest"
|
|
14464
|
+
}
|
|
14465
|
+
};
|
|
14466
|
+
|
|
14467
|
+
// src/cli/install-commands.ts
|
|
14468
|
+
var INSTALL_COMMANDS = install_commands_default;
|
|
14469
|
+
function normalizeBaseUrl2(baseUrl) {
|
|
14470
|
+
return baseUrl.replace(/\/$/, "");
|
|
14471
|
+
}
|
|
14472
|
+
function renderTemplate(template, values) {
|
|
14473
|
+
return template.replace(/\{([a-z_]+)\}/g, (match, key) => {
|
|
14474
|
+
return values[key] ?? match;
|
|
14475
|
+
});
|
|
14476
|
+
}
|
|
14477
|
+
function shellJoin(args) {
|
|
14478
|
+
return args.join(" ");
|
|
14479
|
+
}
|
|
14480
|
+
function skillsIndexUrl(baseUrl) {
|
|
14481
|
+
return `${normalizeBaseUrl2(baseUrl)}${INSTALL_COMMANDS.skills.index_path}`;
|
|
14482
|
+
}
|
|
14483
|
+
function buildSkillsAddArgs(baseUrl, skillName, options = {}) {
|
|
14484
|
+
const values = {
|
|
14485
|
+
skills_index_url: skillsIndexUrl(baseUrl),
|
|
14486
|
+
agents: INSTALL_COMMANDS.skills.default_agents.join(" "),
|
|
14487
|
+
skill_name: skillName
|
|
14488
|
+
};
|
|
14489
|
+
const rendered = INSTALL_COMMANDS.skills.npx_add_args_template.flatMap(
|
|
14490
|
+
(arg, index) => {
|
|
14491
|
+
const next = index === 0 && options.firstArg ? options.firstArg : arg;
|
|
14492
|
+
const value = renderTemplate(next, values);
|
|
14493
|
+
return arg === "{agents}" ? INSTALL_COMMANDS.skills.default_agents : value;
|
|
14494
|
+
}
|
|
14495
|
+
);
|
|
14496
|
+
return rendered;
|
|
14497
|
+
}
|
|
14498
|
+
function skillsInstallCommand(baseUrl, skillName) {
|
|
14499
|
+
return `${INSTALL_COMMANDS.skills.npx_binary} ${shellJoin(
|
|
14500
|
+
buildSkillsAddArgs(baseUrl, skillName)
|
|
14501
|
+
)}`;
|
|
14502
|
+
}
|
|
14503
|
+
function legacyPythonInstallCommand(baseUrl) {
|
|
14504
|
+
return renderTemplate(INSTALL_COMMANDS.cli.legacy_python_shell_template, {
|
|
14505
|
+
base_url: normalizeBaseUrl2(baseUrl)
|
|
14506
|
+
});
|
|
14507
|
+
}
|
|
14508
|
+
function sdkNpmGlobalInstallCommand() {
|
|
14509
|
+
return INSTALL_COMMANDS.cli.sdk_npm_global;
|
|
14510
|
+
}
|
|
14511
|
+
|
|
14512
|
+
// src/cli/command-compatibility.ts
|
|
14513
|
+
var COMMAND_COMPATIBILITY = command_compatibility_default;
|
|
14514
|
+
function cliFamilyLabel(family) {
|
|
14515
|
+
return family === "sdk" ? "SDK CLI" : "legacy Python CLI";
|
|
14516
|
+
}
|
|
14517
|
+
function commandCompatibilityHint(currentFamily, commandName, baseUrl) {
|
|
14518
|
+
const compatibility = COMMAND_COMPATIBILITY[commandName];
|
|
14519
|
+
if (!compatibility || compatibility.family === currentFamily) {
|
|
14520
|
+
return null;
|
|
14521
|
+
}
|
|
14522
|
+
const expectedFamily = compatibility.family;
|
|
14523
|
+
const currentLabel = cliFamilyLabel(currentFamily);
|
|
14524
|
+
const expectedLabel = cliFamilyLabel(expectedFamily);
|
|
14525
|
+
const lines = [
|
|
14526
|
+
"",
|
|
14527
|
+
"Command compatibility:",
|
|
14528
|
+
` \`deepline ${commandName}\` is ${compatibility.label}.`,
|
|
14529
|
+
` Current binary: ${currentLabel}. Required binary: ${expectedLabel}.`,
|
|
14530
|
+
" If this came from an agent skill, the installed skill likely targets the other Deepline CLI."
|
|
14531
|
+
];
|
|
14532
|
+
if (currentFamily === "sdk") {
|
|
14533
|
+
lines.push(
|
|
14534
|
+
"",
|
|
14535
|
+
" To stay on the SDK CLI, install the SDK agent skill:",
|
|
14536
|
+
` ${skillsInstallCommand(baseUrl, "deepline-sdk")}`,
|
|
14537
|
+
" To use the legacy Python CLI instead:",
|
|
14538
|
+
` ${legacyPythonInstallCommand(baseUrl)}`,
|
|
14539
|
+
" `deepline update` updates this SDK CLI, but it will not switch CLI families."
|
|
14540
|
+
);
|
|
14541
|
+
if (compatibility.sdk_alternative) {
|
|
14542
|
+
lines.push(` SDK alternative: ${compatibility.sdk_alternative}`);
|
|
14543
|
+
}
|
|
14544
|
+
} else {
|
|
14545
|
+
lines.push(
|
|
14546
|
+
"",
|
|
14547
|
+
" To use SDK commands, install the SDK CLI and SDK agent skill:",
|
|
14548
|
+
` ${sdkNpmGlobalInstallCommand()}`,
|
|
14549
|
+
` ${skillsInstallCommand(baseUrl, "deepline-sdk")}`,
|
|
14550
|
+
" `deepline update` updates this Python CLI and its skills, but it will not switch CLI families."
|
|
14551
|
+
);
|
|
14552
|
+
if (compatibility.python_alternative) {
|
|
14553
|
+
lines.push(` Python alternative: ${compatibility.python_alternative}`);
|
|
14554
|
+
}
|
|
14555
|
+
}
|
|
14556
|
+
return lines.join("\n");
|
|
14557
|
+
}
|
|
14558
|
+
function unknownCommandNameFromMessage(message) {
|
|
14559
|
+
const match = message.match(/unknown command ['"]([^'"]+)['"]/i);
|
|
14560
|
+
const command = match?.[1]?.trim();
|
|
14561
|
+
return command ? command : null;
|
|
14562
|
+
}
|
|
14563
|
+
|
|
14110
14564
|
// src/cli/skills-sync.ts
|
|
14111
14565
|
var import_node_child_process2 = require("child_process");
|
|
14112
14566
|
var import_node_fs14 = require("fs");
|
|
@@ -14114,7 +14568,6 @@ var import_node_os9 = require("os");
|
|
|
14114
14568
|
var import_node_path16 = require("path");
|
|
14115
14569
|
var CHECK_TIMEOUT_MS2 = 3e3;
|
|
14116
14570
|
var SDK_SKILL_NAME = "deepline-sdk";
|
|
14117
|
-
var SKILL_AGENTS = ["codex", "claude-code", "cursor"];
|
|
14118
14571
|
var attemptedSync = false;
|
|
14119
14572
|
function shouldSkipSkillsSync() {
|
|
14120
14573
|
const value = process.env.DEEPLINE_SKIP_SKILLS_SYNC?.trim().toLowerCase();
|
|
@@ -14211,42 +14664,10 @@ async function fetchSkillsUpdate(baseUrl, localVersion) {
|
|
|
14211
14664
|
}
|
|
14212
14665
|
}
|
|
14213
14666
|
function buildSkillsInstallArgs(baseUrl) {
|
|
14214
|
-
|
|
14215
|
-
"/.well-known/skills/index.json",
|
|
14216
|
-
baseUrl
|
|
14217
|
-
).toString();
|
|
14218
|
-
return [
|
|
14219
|
-
"--yes",
|
|
14220
|
-
"skills",
|
|
14221
|
-
"add",
|
|
14222
|
-
packageUrl,
|
|
14223
|
-
"--agent",
|
|
14224
|
-
...SKILL_AGENTS,
|
|
14225
|
-
"--global",
|
|
14226
|
-
"--yes",
|
|
14227
|
-
"--skill",
|
|
14228
|
-
SDK_SKILL_NAME,
|
|
14229
|
-
"--full-depth"
|
|
14230
|
-
];
|
|
14667
|
+
return buildSkillsAddArgs(baseUrl, SDK_SKILL_NAME);
|
|
14231
14668
|
}
|
|
14232
14669
|
function buildBunxSkillsInstallArgs(baseUrl) {
|
|
14233
|
-
|
|
14234
|
-
"/.well-known/skills/index.json",
|
|
14235
|
-
baseUrl
|
|
14236
|
-
).toString();
|
|
14237
|
-
return [
|
|
14238
|
-
"--bun",
|
|
14239
|
-
"skills",
|
|
14240
|
-
"add",
|
|
14241
|
-
packageUrl,
|
|
14242
|
-
"--agent",
|
|
14243
|
-
...SKILL_AGENTS,
|
|
14244
|
-
"--global",
|
|
14245
|
-
"--yes",
|
|
14246
|
-
"--skill",
|
|
14247
|
-
SDK_SKILL_NAME,
|
|
14248
|
-
"--full-depth"
|
|
14249
|
-
];
|
|
14670
|
+
return buildSkillsAddArgs(baseUrl, SDK_SKILL_NAME, { firstArg: "--bun" });
|
|
14250
14671
|
}
|
|
14251
14672
|
function hasCommand(command) {
|
|
14252
14673
|
const result = (0, import_node_child_process2.spawnSync)(command, ["--version"], {
|
|
@@ -14358,6 +14779,13 @@ async function syncSdkSkillsIfNeeded(baseUrl) {
|
|
|
14358
14779
|
}
|
|
14359
14780
|
|
|
14360
14781
|
// src/cli/index.ts
|
|
14782
|
+
function asCommanderError(error) {
|
|
14783
|
+
if (!(error instanceof Error) || !("code" in error)) {
|
|
14784
|
+
return null;
|
|
14785
|
+
}
|
|
14786
|
+
const code = error.code;
|
|
14787
|
+
return typeof code === "string" && code.startsWith("commander.") ? error : null;
|
|
14788
|
+
}
|
|
14361
14789
|
function shouldPrintStartupPhase() {
|
|
14362
14790
|
if (process.argv.includes("--json")) {
|
|
14363
14791
|
return false;
|
|
@@ -14443,7 +14871,7 @@ async function main() {
|
|
|
14443
14871
|
progress?.phase("loading deepline cli");
|
|
14444
14872
|
}
|
|
14445
14873
|
const program = new import_commander3.Command();
|
|
14446
|
-
program.name("deepline").description("Deepline CLI (TypeScript SDK)").version(SDK_VERSION, "-v, --version", "Show version").showHelpAfterError().showSuggestionAfterError(true).addHelpText(
|
|
14874
|
+
program.name("deepline").description("Deepline CLI (TypeScript SDK)").version(SDK_VERSION, "-v, --version", "Show version").exitOverride().showHelpAfterError().showSuggestionAfterError(true).addHelpText(
|
|
14447
14875
|
"after",
|
|
14448
14876
|
`
|
|
14449
14877
|
Common commands:
|
|
@@ -14452,6 +14880,7 @@ Common commands:
|
|
|
14452
14880
|
deepline plays search email --json
|
|
14453
14881
|
deepline plays describe person-linkedin-to-email --json
|
|
14454
14882
|
deepline plays run my.play.ts --input '{"domain":"stripe.com"}'
|
|
14883
|
+
deepline secrets check HUBSPOT_TOKEN
|
|
14455
14884
|
deepline tools execute hunter_email_verifier --input '{"email":"a@b.com"}'
|
|
14456
14885
|
deepline update
|
|
14457
14886
|
|
|
@@ -14501,6 +14930,7 @@ Exit codes:
|
|
|
14501
14930
|
registerAuthCommands(program);
|
|
14502
14931
|
registerToolsCommands(program);
|
|
14503
14932
|
registerPlayCommands(program);
|
|
14933
|
+
registerSecretsCommands(program);
|
|
14504
14934
|
registerBillingCommands(program);
|
|
14505
14935
|
registerOrgCommands(program);
|
|
14506
14936
|
registerCsvCommands(program);
|
|
@@ -14570,6 +15000,7 @@ Examples:
|
|
|
14570
15000
|
ok: true
|
|
14571
15001
|
});
|
|
14572
15002
|
} catch (error) {
|
|
15003
|
+
const commanderError = asCommanderError(error);
|
|
14573
15004
|
recordCliTrace({
|
|
14574
15005
|
phase: "cli.main_total",
|
|
14575
15006
|
ms: Date.now() - mainStartedAt,
|
|
@@ -14577,7 +15008,26 @@ Examples:
|
|
|
14577
15008
|
error: error instanceof Error ? error.message : String(error)
|
|
14578
15009
|
});
|
|
14579
15010
|
progress?.fail();
|
|
14580
|
-
|
|
15011
|
+
const wantsJson = process.argv.includes("--json");
|
|
15012
|
+
if (commanderError) {
|
|
15013
|
+
if (commanderError.code === "commander.unknownCommand") {
|
|
15014
|
+
const commandName = unknownCommandNameFromMessage(
|
|
15015
|
+
commanderError.message
|
|
15016
|
+
);
|
|
15017
|
+
if (commandName && !wantsJson) {
|
|
15018
|
+
const hint = commandCompatibilityHint(
|
|
15019
|
+
"sdk",
|
|
15020
|
+
commandName,
|
|
15021
|
+
autoDetectBaseUrl()
|
|
15022
|
+
);
|
|
15023
|
+
if (hint) {
|
|
15024
|
+
console.error(hint);
|
|
15025
|
+
}
|
|
15026
|
+
}
|
|
15027
|
+
}
|
|
15028
|
+
process.exitCode = commanderError.code === "commander.unknownCommand" && !wantsJson ? 2 : commanderError.exitCode ?? 1;
|
|
15029
|
+
return;
|
|
15030
|
+
} else if (wantsJson) {
|
|
14581
15031
|
printJsonError(error);
|
|
14582
15032
|
} else if (error instanceof Error) {
|
|
14583
15033
|
console.error(`Error: ${error.message}`);
|