deepline 0.1.66 → 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 +1410 -577
- package/dist/cli/index.mjs +1410 -577
- package/dist/index.d.mts +121 -1
- package/dist/index.d.ts +121 -1
- package/dist/index.js +76 -2
- package/dist/index.mjs +76 -2
- package/dist/repo/apps/play-runner-workers/src/entry.ts +122 -29
- package/dist/repo/sdk/src/client.ts +110 -0
- package/dist/repo/sdk/src/http.ts +9 -1
- 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/sdk/src/types.ts +59 -0
- 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
|
}
|
|
@@ -483,6 +483,9 @@ var HttpClient = class {
|
|
|
483
483
|
headers
|
|
484
484
|
});
|
|
485
485
|
}
|
|
486
|
+
async patch(path, body, headers) {
|
|
487
|
+
return this.request(path, { method: "PATCH", body, headers });
|
|
488
|
+
}
|
|
486
489
|
/**
|
|
487
490
|
* Send a DELETE request.
|
|
488
491
|
*
|
|
@@ -736,7 +739,7 @@ var DeeplineClient = class {
|
|
|
736
739
|
list: (options2) => this.listRuns(options2),
|
|
737
740
|
tail: (runId, options2) => this.tailRun(runId, options2),
|
|
738
741
|
logs: (runId, options2) => this.getRunLogs(runId, options2),
|
|
739
|
-
exportDatasetRows: (
|
|
742
|
+
exportDatasetRows: (input2) => this.getPlaySheetRows(input2),
|
|
740
743
|
stop: (runId, options2) => this.stopRun(runId, options2)
|
|
741
744
|
};
|
|
742
745
|
}
|
|
@@ -823,6 +826,22 @@ var DeeplineClient = class {
|
|
|
823
826
|
};
|
|
824
827
|
}
|
|
825
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
|
+
// ——————————————————————————————————————————————————————————
|
|
826
845
|
// Tools
|
|
827
846
|
// ——————————————————————————————————————————————————————————
|
|
828
847
|
/**
|
|
@@ -915,24 +934,24 @@ var DeeplineClient = class {
|
|
|
915
934
|
* Top-level fields such as `status`, `job_id`, and `billing` describe the
|
|
916
935
|
* Deepline execution envelope.
|
|
917
936
|
*/
|
|
918
|
-
async executeTool(toolId,
|
|
937
|
+
async executeTool(toolId, input2, options) {
|
|
919
938
|
const headers = {
|
|
920
939
|
[EXECUTE_RESPONSE_CONTRACT_HEADER]: V2_EXECUTE_RESPONSE_CONTRACT,
|
|
921
940
|
...options?.includeToolMetadata ? { [INCLUDE_TOOL_METADATA_HEADER]: "true" } : {}
|
|
922
941
|
};
|
|
923
942
|
return this.http.post(
|
|
924
943
|
`/api/v2/integrations/${encodeURIComponent(toolId)}/execute`,
|
|
925
|
-
{ payload:
|
|
944
|
+
{ payload: input2 },
|
|
926
945
|
headers
|
|
927
946
|
);
|
|
928
947
|
}
|
|
929
|
-
async executeToolRaw(toolId,
|
|
930
|
-
return this.executeTool(toolId,
|
|
948
|
+
async executeToolRaw(toolId, input2, options) {
|
|
949
|
+
return this.executeTool(toolId, input2, options);
|
|
931
950
|
}
|
|
932
|
-
async queryCustomerDb(
|
|
951
|
+
async queryCustomerDb(input2) {
|
|
933
952
|
return this.http.post("/api/v2/db/query", {
|
|
934
|
-
sql:
|
|
935
|
-
...
|
|
953
|
+
sql: input2.sql,
|
|
954
|
+
...input2.maxRows ? { max_rows: input2.maxRows } : {}
|
|
936
955
|
});
|
|
937
956
|
}
|
|
938
957
|
// ——————————————————————————————————————————————————————————
|
|
@@ -1039,15 +1058,15 @@ var DeeplineClient = class {
|
|
|
1039
1058
|
* Internal/advanced primitive used by packaging flows. Public callers should
|
|
1040
1059
|
* prefer the CLI, {@link submitPlay}, or {@link runPlay}.
|
|
1041
1060
|
*/
|
|
1042
|
-
async registerPlayArtifact(
|
|
1043
|
-
const compilerManifest =
|
|
1044
|
-
name:
|
|
1045
|
-
sourceCode:
|
|
1046
|
-
sourceFiles:
|
|
1047
|
-
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
|
|
1048
1067
|
});
|
|
1049
1068
|
return this.http.post("/api/v2/plays/artifacts", {
|
|
1050
|
-
...
|
|
1069
|
+
...input2,
|
|
1051
1070
|
compilerManifest
|
|
1052
1071
|
});
|
|
1053
1072
|
}
|
|
@@ -1067,14 +1086,14 @@ var DeeplineClient = class {
|
|
|
1067
1086
|
artifacts: compiledArtifacts
|
|
1068
1087
|
});
|
|
1069
1088
|
}
|
|
1070
|
-
async compilePlayManifest(
|
|
1089
|
+
async compilePlayManifest(input2) {
|
|
1071
1090
|
const retryDelays = COMPILE_MANIFEST_RETRY_DELAYS_MS.slice(
|
|
1072
1091
|
0,
|
|
1073
1092
|
Math.max(0, this.config.maxRetries)
|
|
1074
1093
|
);
|
|
1075
1094
|
for (let attempt = 0; ; attempt += 1) {
|
|
1076
1095
|
try {
|
|
1077
|
-
const response = await this.http.post("/api/v2/plays/compile-manifest",
|
|
1096
|
+
const response = await this.http.post("/api/v2/plays/compile-manifest", input2);
|
|
1078
1097
|
return response.compilerManifest;
|
|
1079
1098
|
} catch (error) {
|
|
1080
1099
|
const delayMs = retryDelays[attempt];
|
|
@@ -1092,21 +1111,21 @@ var DeeplineClient = class {
|
|
|
1092
1111
|
* publish a revision, or start a run. It is the authoritative cloud validation
|
|
1093
1112
|
* path used by `deepline play check`.
|
|
1094
1113
|
*/
|
|
1095
|
-
async checkPlayArtifact(
|
|
1096
|
-
return this.http.post("/api/v2/plays/check",
|
|
1097
|
-
}
|
|
1098
|
-
async startPlayRunFromBundle(
|
|
1099
|
-
const compilerManifest =
|
|
1100
|
-
name:
|
|
1101
|
-
sourceCode:
|
|
1102
|
-
sourceFiles:
|
|
1103
|
-
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
|
|
1104
1123
|
});
|
|
1105
1124
|
const registeredArtifact = await this.registerPlayArtifact({
|
|
1106
|
-
name:
|
|
1107
|
-
sourceCode:
|
|
1108
|
-
sourceFiles:
|
|
1109
|
-
artifact:
|
|
1125
|
+
name: input2.name,
|
|
1126
|
+
sourceCode: input2.sourceCode,
|
|
1127
|
+
sourceFiles: input2.sourceFiles,
|
|
1128
|
+
artifact: input2.artifact,
|
|
1110
1129
|
compilerManifest,
|
|
1111
1130
|
publish: false
|
|
1112
1131
|
});
|
|
@@ -1116,13 +1135,13 @@ var DeeplineClient = class {
|
|
|
1116
1135
|
);
|
|
1117
1136
|
}
|
|
1118
1137
|
return this.startPlayRun({
|
|
1119
|
-
name:
|
|
1138
|
+
name: input2.name,
|
|
1120
1139
|
artifactStorageKey: registeredArtifact.artifactStorageKey,
|
|
1121
1140
|
compilerManifest,
|
|
1122
|
-
...
|
|
1123
|
-
...
|
|
1124
|
-
...
|
|
1125
|
-
...
|
|
1141
|
+
...input2.input ? { input: input2.input } : {},
|
|
1142
|
+
...input2.inputFile ? { inputFile: input2.inputFile } : {},
|
|
1143
|
+
...input2.packagedFiles?.length ? { packagedFiles: input2.packagedFiles } : {},
|
|
1144
|
+
...input2.force ? { force: true } : {}
|
|
1126
1145
|
});
|
|
1127
1146
|
}
|
|
1128
1147
|
/**
|
|
@@ -1467,17 +1486,17 @@ var DeeplineClient = class {
|
|
|
1467
1486
|
entries
|
|
1468
1487
|
};
|
|
1469
1488
|
}
|
|
1470
|
-
async getPlaySheetRows(
|
|
1489
|
+
async getPlaySheetRows(input2) {
|
|
1471
1490
|
const params = new URLSearchParams({
|
|
1472
|
-
tableNamespace:
|
|
1473
|
-
limit: String(
|
|
1474
|
-
offset: String(
|
|
1491
|
+
tableNamespace: input2.tableNamespace,
|
|
1492
|
+
limit: String(input2.limit ?? 5e3),
|
|
1493
|
+
offset: String(input2.offset ?? 0)
|
|
1475
1494
|
});
|
|
1476
|
-
if (
|
|
1477
|
-
params.set("runId",
|
|
1495
|
+
if (input2.runId?.trim()) {
|
|
1496
|
+
params.set("runId", input2.runId.trim());
|
|
1478
1497
|
}
|
|
1479
1498
|
return await this.http.get(
|
|
1480
|
-
`/api/v2/plays/${encodeURIComponent(
|
|
1499
|
+
`/api/v2/plays/${encodeURIComponent(input2.playName)}/sheet?${params.toString()}`
|
|
1481
1500
|
);
|
|
1482
1501
|
}
|
|
1483
1502
|
/**
|
|
@@ -1606,6 +1625,61 @@ var DeeplineClient = class {
|
|
|
1606
1625
|
return this.http.delete(`/api/v2/plays/${encodedName}`);
|
|
1607
1626
|
}
|
|
1608
1627
|
// ——————————————————————————————————————————————————————————
|
|
1628
|
+
// Plays — public share pages
|
|
1629
|
+
// ——————————————————————————————————————————————————————————
|
|
1630
|
+
/**
|
|
1631
|
+
* Current share status for a play: the public page (if any), the published
|
|
1632
|
+
* copy, and the revision picker. Read-only.
|
|
1633
|
+
*/
|
|
1634
|
+
async getSharePage(name) {
|
|
1635
|
+
const encodedName = encodeURIComponent(name);
|
|
1636
|
+
return this.http.get(`/api/v2/plays/${encodedName}/share`);
|
|
1637
|
+
}
|
|
1638
|
+
/**
|
|
1639
|
+
* Publish (or repoint) the play's public share page to a revision. Requires
|
|
1640
|
+
* `acknowledgedUnlisted: true` — the page is publicly viewable. Org-admin only.
|
|
1641
|
+
*/
|
|
1642
|
+
async publishSharePage(name, request) {
|
|
1643
|
+
const encodedName = encodeURIComponent(name);
|
|
1644
|
+
return this.http.post(
|
|
1645
|
+
`/api/v2/plays/${encodedName}/share`,
|
|
1646
|
+
request
|
|
1647
|
+
);
|
|
1648
|
+
}
|
|
1649
|
+
/**
|
|
1650
|
+
* Update share-page settings (SEO indexing, credit-cost / latency display)
|
|
1651
|
+
* without moving the published pointer. Org-admin only.
|
|
1652
|
+
*/
|
|
1653
|
+
async updateSharePage(name, request) {
|
|
1654
|
+
const encodedName = encodeURIComponent(name);
|
|
1655
|
+
return this.http.patch(
|
|
1656
|
+
`/api/v2/plays/${encodedName}/share`,
|
|
1657
|
+
request
|
|
1658
|
+
);
|
|
1659
|
+
}
|
|
1660
|
+
/**
|
|
1661
|
+
* Unshare: hard-delete the play's public page and its cards. Returns the
|
|
1662
|
+
* fresh status (now `share: null`). Org-admin only. Idempotent — a no-op when
|
|
1663
|
+
* the play was never published.
|
|
1664
|
+
*/
|
|
1665
|
+
async unpublishSharePage(name) {
|
|
1666
|
+
const encodedName = encodeURIComponent(name);
|
|
1667
|
+
return this.http.delete(
|
|
1668
|
+
`/api/v2/plays/${encodedName}/share`
|
|
1669
|
+
);
|
|
1670
|
+
}
|
|
1671
|
+
/**
|
|
1672
|
+
* Regenerate the LLM landing-page copy for a revision (defaults to the
|
|
1673
|
+
* published one). Org-admin only.
|
|
1674
|
+
*/
|
|
1675
|
+
async regenerateSharePage(name, request = {}) {
|
|
1676
|
+
const encodedName = encodeURIComponent(name);
|
|
1677
|
+
return this.http.post(
|
|
1678
|
+
`/api/v2/plays/${encodedName}/share/regenerate`,
|
|
1679
|
+
request
|
|
1680
|
+
);
|
|
1681
|
+
}
|
|
1682
|
+
// ——————————————————————————————————————————————————————————
|
|
1609
1683
|
// Plays — high-level orchestration
|
|
1610
1684
|
// ——————————————————————————————————————————————————————————
|
|
1611
1685
|
/**
|
|
@@ -1865,7 +1939,7 @@ function browserAppNameFromBundleId(bundleId) {
|
|
|
1865
1939
|
}
|
|
1866
1940
|
function readDefaultMacBrowserBundleId(runner = defaultBrowserCommandRunner) {
|
|
1867
1941
|
try {
|
|
1868
|
-
const
|
|
1942
|
+
const output2 = runner.execFileSync(
|
|
1869
1943
|
"/usr/bin/defaults",
|
|
1870
1944
|
[
|
|
1871
1945
|
"read",
|
|
@@ -1874,10 +1948,10 @@ function readDefaultMacBrowserBundleId(runner = defaultBrowserCommandRunner) {
|
|
|
1874
1948
|
],
|
|
1875
1949
|
{ encoding: "utf-8", stdio: ["ignore", "pipe", "ignore"] }
|
|
1876
1950
|
);
|
|
1877
|
-
const httpsMatch =
|
|
1951
|
+
const httpsMatch = output2.match(
|
|
1878
1952
|
/LSHandlerURLScheme\s*=\s*https;[\s\S]*?LSHandlerRole(?:All|Viewer|Editor)\s*=\s*"([^"]+)"/
|
|
1879
1953
|
);
|
|
1880
|
-
const httpMatch =
|
|
1954
|
+
const httpMatch = output2.match(
|
|
1881
1955
|
/LSHandlerURLScheme\s*=\s*http;[\s\S]*?LSHandlerRole(?:All|Viewer|Editor)\s*=\s*"([^"]+)"/
|
|
1882
1956
|
);
|
|
1883
1957
|
return (httpsMatch?.[1] ?? httpMatch?.[1] ?? "").trim();
|
|
@@ -3322,9 +3396,9 @@ function stripCsvProjectionColumns(columns, rows) {
|
|
|
3322
3396
|
(column) => column !== CSV_PROJECTED_FIELDS_KEY && !projectedFields.has(column)
|
|
3323
3397
|
);
|
|
3324
3398
|
}
|
|
3325
|
-
function sanitizeCsvProjectionInfo(
|
|
3326
|
-
const columns = stripCsvProjectionColumns(
|
|
3327
|
-
const rows =
|
|
3399
|
+
function sanitizeCsvProjectionInfo(input2) {
|
|
3400
|
+
const columns = stripCsvProjectionColumns(input2.columns, input2.rows);
|
|
3401
|
+
const rows = input2.rows.map(stripCsvProjectionFields);
|
|
3328
3402
|
return { rows, columns };
|
|
3329
3403
|
}
|
|
3330
3404
|
function isRecord2(value) {
|
|
@@ -3380,8 +3454,8 @@ function inferColumns(rows) {
|
|
|
3380
3454
|
}
|
|
3381
3455
|
return columns;
|
|
3382
3456
|
}
|
|
3383
|
-
function canonicalRowsInfoFromCandidate(
|
|
3384
|
-
const candidate =
|
|
3457
|
+
function canonicalRowsInfoFromCandidate(input2) {
|
|
3458
|
+
const candidate = input2;
|
|
3385
3459
|
if (isSerializedDataset(candidate.value)) {
|
|
3386
3460
|
const rawRows = rowArray(candidate.value.preview) ?? [];
|
|
3387
3461
|
const totalRows2 = readNumber(candidate.value.count) ?? rawRows.length;
|
|
@@ -3422,31 +3496,31 @@ function canonicalRowsInfoFromCandidate(input) {
|
|
|
3422
3496
|
source: candidate.source
|
|
3423
3497
|
};
|
|
3424
3498
|
}
|
|
3425
|
-
function collectDatasetCandidates(
|
|
3426
|
-
if (
|
|
3499
|
+
function collectDatasetCandidates(input2) {
|
|
3500
|
+
if (input2.depth && input2.depth > 16) {
|
|
3427
3501
|
return;
|
|
3428
3502
|
}
|
|
3429
|
-
if (isSerializedDataset(
|
|
3430
|
-
|
|
3431
|
-
source:
|
|
3432
|
-
value:
|
|
3433
|
-
total:
|
|
3503
|
+
if (isSerializedDataset(input2.value)) {
|
|
3504
|
+
input2.output.push({
|
|
3505
|
+
source: input2.path,
|
|
3506
|
+
value: input2.value,
|
|
3507
|
+
total: input2.total
|
|
3434
3508
|
});
|
|
3435
3509
|
return;
|
|
3436
3510
|
}
|
|
3437
|
-
if (!isRecord2(
|
|
3511
|
+
if (!isRecord2(input2.value)) {
|
|
3438
3512
|
return;
|
|
3439
3513
|
}
|
|
3440
|
-
for (const [key, child] of Object.entries(
|
|
3514
|
+
for (const [key, child] of Object.entries(input2.value)) {
|
|
3441
3515
|
if (key === "preview" || key === "access") {
|
|
3442
3516
|
continue;
|
|
3443
3517
|
}
|
|
3444
3518
|
collectDatasetCandidates({
|
|
3445
3519
|
value: child,
|
|
3446
|
-
path: `${
|
|
3447
|
-
total: totalRowsForDataset(
|
|
3448
|
-
output:
|
|
3449
|
-
depth: (
|
|
3520
|
+
path: `${input2.path}.${key}`,
|
|
3521
|
+
total: totalRowsForDataset(input2.value, `${input2.path}.${key}`),
|
|
3522
|
+
output: input2.output,
|
|
3523
|
+
depth: (input2.depth ?? 0) + 1
|
|
3450
3524
|
});
|
|
3451
3525
|
}
|
|
3452
3526
|
}
|
|
@@ -3964,26 +4038,26 @@ function writeCustomerDbCsv(result, outPath) {
|
|
|
3964
4038
|
);
|
|
3965
4039
|
return resolved;
|
|
3966
4040
|
}
|
|
3967
|
-
function dbQueryExportEnvelope(
|
|
3968
|
-
const destination =
|
|
4041
|
+
function dbQueryExportEnvelope(input2) {
|
|
4042
|
+
const destination = input2.outPath ?? "stdout";
|
|
3969
4043
|
return {
|
|
3970
|
-
command:
|
|
3971
|
-
format:
|
|
3972
|
-
row_count:
|
|
3973
|
-
row_count_returned:
|
|
3974
|
-
truncated:
|
|
3975
|
-
...
|
|
3976
|
-
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 },
|
|
3977
4051
|
render: {
|
|
3978
4052
|
sections: [
|
|
3979
4053
|
{
|
|
3980
4054
|
title: "customer db export",
|
|
3981
4055
|
lines: [
|
|
3982
|
-
`Rendered ${
|
|
4056
|
+
`Rendered ${input2.result.row_count_returned} row(s) as ${input2.format} to ${destination}`
|
|
3983
4057
|
]
|
|
3984
4058
|
}
|
|
3985
4059
|
],
|
|
3986
|
-
actions: [{ label: "Tool equivalent", command:
|
|
4060
|
+
actions: [{ label: "Tool equivalent", command: input2.toolCommand }]
|
|
3987
4061
|
}
|
|
3988
4062
|
};
|
|
3989
4063
|
}
|
|
@@ -4421,16 +4495,63 @@ var PLAY_RUNTIME_FEATURES = [
|
|
|
4421
4495
|
"durable_sleep",
|
|
4422
4496
|
"packaged_files"
|
|
4423
4497
|
];
|
|
4424
|
-
function buildPlayContractCompatibility(
|
|
4498
|
+
function buildPlayContractCompatibility(input2) {
|
|
4425
4499
|
return {
|
|
4426
4500
|
apiVersion: PLAY_PUBLIC_API_VERSION,
|
|
4427
4501
|
artifactVersion: PLAY_ARTIFACT_VERSION,
|
|
4428
4502
|
minRunnerVersion: PLAY_MIN_RUNNER_VERSION,
|
|
4429
4503
|
runtimeFeatures: [...PLAY_RUNTIME_FEATURES],
|
|
4430
|
-
runtimeBackend:
|
|
4504
|
+
runtimeBackend: input2?.runtimeBackend ?? null
|
|
4431
4505
|
};
|
|
4432
4506
|
}
|
|
4433
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
|
+
|
|
4434
4555
|
// ../shared_libs/plays/bundling/index.ts
|
|
4435
4556
|
var PLAY_BUNDLE_CACHE_VERSION = 24;
|
|
4436
4557
|
var MAX_PLAY_BUNDLE_BYTES = 30 * 1024 * 1024;
|
|
@@ -4492,12 +4613,12 @@ function createPlayWorkspace(entryFile) {
|
|
|
4492
4613
|
function isPathInsideDirectory(filePath, directory) {
|
|
4493
4614
|
return filePath === directory || filePath.startsWith(`${directory}/`);
|
|
4494
4615
|
}
|
|
4495
|
-
function assertWithinPlayWorkspace(
|
|
4496
|
-
if (isPathInsideDirectory(
|
|
4616
|
+
function assertWithinPlayWorkspace(input2) {
|
|
4617
|
+
if (isPathInsideDirectory(input2.resolvedPath, input2.workspace.rootDir)) {
|
|
4497
4618
|
return;
|
|
4498
4619
|
}
|
|
4499
4620
|
throw new Error(
|
|
4500
|
-
`${
|
|
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.`
|
|
4501
4622
|
);
|
|
4502
4623
|
}
|
|
4503
4624
|
function getPackageName(specifier) {
|
|
@@ -5352,6 +5473,15 @@ entry-export:${exportName}`
|
|
|
5352
5473
|
workers-harness:${harnessFingerprint}`
|
|
5353
5474
|
);
|
|
5354
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
|
+
}
|
|
5355
5485
|
const typecheckErrors = [
|
|
5356
5486
|
...await adapter.typecheckPlaySource?.({
|
|
5357
5487
|
sourceCode: analysis.sourceCode,
|
|
@@ -5954,11 +6084,13 @@ function createSdkPlayBundlingAdapter() {
|
|
|
5954
6084
|
};
|
|
5955
6085
|
}
|
|
5956
6086
|
async function bundlePlayFile2(filePath, options = {}) {
|
|
5957
|
-
|
|
6087
|
+
const result = await bundlePlayFile(filePath, {
|
|
5958
6088
|
target: options.target ?? defaultPlayBundleTarget(),
|
|
5959
6089
|
exportName: options.exportName,
|
|
5960
6090
|
adapter: createSdkPlayBundlingAdapter()
|
|
5961
6091
|
});
|
|
6092
|
+
if (result.success) validatePlaySourceFilesHaveNoInlineSecrets(result.sourceFiles);
|
|
6093
|
+
return result;
|
|
5962
6094
|
}
|
|
5963
6095
|
|
|
5964
6096
|
// src/cli/commands/plays/bootstrap.ts
|
|
@@ -6552,28 +6684,28 @@ function objectPropertySchema(schema, property) {
|
|
|
6552
6684
|
function finderResultTypeName(finder) {
|
|
6553
6685
|
return finder === "email_finder" ? "EmailFinderPlayResult" : "PhoneFinderPlayResult";
|
|
6554
6686
|
}
|
|
6555
|
-
function renderFinderPlayResultType(
|
|
6556
|
-
if (!
|
|
6557
|
-
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];
|
|
6558
6690
|
const fieldSchema = objectPropertySchema(
|
|
6559
|
-
|
|
6691
|
+
input2.play.outputSchema,
|
|
6560
6692
|
outputField
|
|
6561
6693
|
);
|
|
6562
6694
|
const fieldType = fieldSchema ? jsonSchemaTypeExpression(fieldSchema) : "string | null";
|
|
6563
|
-
return `type ${finderResultTypeName(
|
|
6695
|
+
return `type ${finderResultTypeName(input2.finder)} =
|
|
6564
6696
|
| string
|
|
6565
6697
|
| null
|
|
6566
6698
|
| {
|
|
6567
6699
|
${outputField}?: ${fieldType};
|
|
6568
6700
|
};`;
|
|
6569
6701
|
}
|
|
6570
|
-
function generatedFinderPlayResultTypes(
|
|
6702
|
+
function generatedFinderPlayResultTypes(input2) {
|
|
6571
6703
|
return ["email_finder", "phone_finder"].flatMap((finder) => {
|
|
6572
|
-
const stage = finderStage(
|
|
6704
|
+
const stage = finderStage(input2.options, finder);
|
|
6573
6705
|
if (stage?.kind !== "play") return [];
|
|
6574
6706
|
const typeDefinition = renderFinderPlayResultType({
|
|
6575
6707
|
finder,
|
|
6576
|
-
play:
|
|
6708
|
+
play: input2.finderPlays[finder]
|
|
6577
6709
|
});
|
|
6578
6710
|
return typeDefinition ? [typeDefinition] : [];
|
|
6579
6711
|
}).join("\n\n");
|
|
@@ -6631,8 +6763,8 @@ function generateCompanyInputObjectFromSchema(schema, indent, label, fallbackFie
|
|
|
6631
6763
|
${lines.join("\n")}
|
|
6632
6764
|
${indent.slice(2)}}`;
|
|
6633
6765
|
}
|
|
6634
|
-
function generateSourceProviderInputObject(
|
|
6635
|
-
const { tool, indent, label, entity } =
|
|
6766
|
+
function generateSourceProviderInputObject(input2) {
|
|
6767
|
+
const { tool, indent, label, entity } = input2;
|
|
6636
6768
|
const properties = inputPropertyNames(tool?.inputSchema);
|
|
6637
6769
|
const details = schemaFieldDetails(tool?.inputSchema);
|
|
6638
6770
|
const required = details.required;
|
|
@@ -6690,8 +6822,8 @@ function generateSourceProviderInputObject(input) {
|
|
|
6690
6822
|
${lines.join("\n")}
|
|
6691
6823
|
${indent.slice(2)}}`;
|
|
6692
6824
|
}
|
|
6693
|
-
function generatePlayInputObject(
|
|
6694
|
-
const { schema, indent, label, entity } =
|
|
6825
|
+
function generatePlayInputObject(input2) {
|
|
6826
|
+
const { schema, indent, label, entity } = input2;
|
|
6695
6827
|
const details = schemaFieldDetails(schema);
|
|
6696
6828
|
const fallback = entity === "company" ? ["domain", "company_name"] : ["first_name", "last_name", "domain"];
|
|
6697
6829
|
const required = details.required.length ? details.required : fallback;
|
|
@@ -6758,80 +6890,80 @@ function needsWhenImport(options) {
|
|
|
6758
6890
|
function sourceCollectionTypeName(entity) {
|
|
6759
6891
|
return entity === "company" ? "CompanySourceRow" : "ContactSourceRow";
|
|
6760
6892
|
}
|
|
6761
|
-
function renderPartialRowType(
|
|
6762
|
-
if (
|
|
6763
|
-
return `type ${
|
|
6893
|
+
function renderPartialRowType(input2) {
|
|
6894
|
+
if (input2.fields.length === 0) {
|
|
6895
|
+
return `type ${input2.typeName} = Record<string, unknown>;`;
|
|
6764
6896
|
}
|
|
6765
|
-
const properties =
|
|
6766
|
-
return `type ${
|
|
6767
|
-
// ${
|
|
6897
|
+
const properties = input2.fields.map((field) => ` ${jsString(field)}?: unknown;`).join("\n");
|
|
6898
|
+
return `type ${input2.typeName} = Record<string, unknown> & Partial<{
|
|
6899
|
+
// ${input2.comment}
|
|
6768
6900
|
${properties}
|
|
6769
6901
|
}>;`;
|
|
6770
6902
|
}
|
|
6771
|
-
function fieldsFromSchemaDetails(
|
|
6903
|
+
function fieldsFromSchemaDetails(input2) {
|
|
6772
6904
|
return [
|
|
6773
|
-
...
|
|
6774
|
-
...
|
|
6905
|
+
...input2.details.required.length ? input2.details.required : input2.fallbackFields,
|
|
6906
|
+
...input2.details.optional
|
|
6775
6907
|
];
|
|
6776
6908
|
}
|
|
6777
|
-
function schemaFieldsForStage(stage,
|
|
6909
|
+
function schemaFieldsForStage(stage, input2) {
|
|
6778
6910
|
switch (stage?.kind) {
|
|
6779
6911
|
case void 0:
|
|
6780
6912
|
return [];
|
|
6781
6913
|
case "play":
|
|
6782
6914
|
return fieldsFromSchemaDetails({
|
|
6783
|
-
details: schemaFieldDetails(
|
|
6784
|
-
fallbackFields:
|
|
6915
|
+
details: schemaFieldDetails(input2.play?.inputSchema),
|
|
6916
|
+
fallbackFields: input2.fallbackFields
|
|
6785
6917
|
});
|
|
6786
6918
|
case "providers":
|
|
6787
|
-
return
|
|
6919
|
+
return input2.tools.flatMap(
|
|
6788
6920
|
(tool) => fieldsFromSchemaDetails({
|
|
6789
6921
|
details: schemaFieldDetails(tool.inputSchema),
|
|
6790
|
-
fallbackFields:
|
|
6922
|
+
fallbackFields: input2.fallbackFields
|
|
6791
6923
|
})
|
|
6792
6924
|
);
|
|
6793
6925
|
}
|
|
6794
6926
|
}
|
|
6795
|
-
function sourceRowTypeDefinition(
|
|
6796
|
-
switch (
|
|
6927
|
+
function sourceRowTypeDefinition(input2) {
|
|
6928
|
+
switch (input2.options.from.kind) {
|
|
6797
6929
|
case "csv":
|
|
6798
|
-
return `type ${
|
|
6930
|
+
return `type ${input2.sourceTypeName} = SourceCsvRow;`;
|
|
6799
6931
|
case "providers":
|
|
6800
6932
|
return renderPartialRowType({
|
|
6801
|
-
typeName:
|
|
6933
|
+
typeName: input2.sourceTypeName,
|
|
6802
6934
|
fields: [
|
|
6803
|
-
...new Set(
|
|
6935
|
+
...new Set(input2.sourceTools.flatMap(listRowCandidateKeysFromTool))
|
|
6804
6936
|
].sort(),
|
|
6805
6937
|
comment: "Candidate source row keys from described list getters; confirm the actual provider keys with source_*.extractedLists.*.keys before mapping."
|
|
6806
6938
|
});
|
|
6807
6939
|
case "play": {
|
|
6808
|
-
const details = schemaFieldDetails(
|
|
6940
|
+
const details = schemaFieldDetails(input2.sourcePlay?.outputSchema);
|
|
6809
6941
|
return renderPartialRowType({
|
|
6810
|
-
typeName:
|
|
6942
|
+
typeName: input2.sourceTypeName,
|
|
6811
6943
|
fields: [...details.required, ...details.optional].sort(),
|
|
6812
6944
|
comment: "Candidate source play output fields; confirm the selected rows field before mapping."
|
|
6813
6945
|
});
|
|
6814
6946
|
}
|
|
6815
6947
|
}
|
|
6816
6948
|
}
|
|
6817
|
-
function contactBridgeRowTypeDefinition(
|
|
6818
|
-
const config = playBootstrapTemplateConfig(
|
|
6819
|
-
if (config.sourceEntity !== "company" || !
|
|
6820
|
-
const emailFields = schemaFieldsForStage(
|
|
6821
|
-
tools:
|
|
6822
|
-
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,
|
|
6823
6955
|
fallbackFields: ["first_name", "last_name", "domain"]
|
|
6824
6956
|
});
|
|
6825
|
-
const phoneFields = schemaFieldsForStage(
|
|
6826
|
-
tools:
|
|
6827
|
-
play:
|
|
6957
|
+
const phoneFields = schemaFieldsForStage(input2.options.phone, {
|
|
6958
|
+
tools: input2.finderTools.phone_finder ?? [],
|
|
6959
|
+
play: input2.finderPlays.phone_finder,
|
|
6828
6960
|
fallbackFields: ["first_name", "last_name", "domain"]
|
|
6829
6961
|
});
|
|
6830
6962
|
return renderPartialRowType({
|
|
6831
6963
|
typeName: "ContactSourceRow",
|
|
6832
6964
|
fields: [
|
|
6833
6965
|
.../* @__PURE__ */ new Set([
|
|
6834
|
-
...inputPropertyNames(
|
|
6966
|
+
...inputPropertyNames(input2.peoplePlay?.outputSchema),
|
|
6835
6967
|
...emailFields,
|
|
6836
6968
|
...phoneFields
|
|
6837
6969
|
])
|
|
@@ -6839,27 +6971,27 @@ function contactBridgeRowTypeDefinition(input) {
|
|
|
6839
6971
|
comment: "Fields the people play or later finder stages may need; the generated code still requires explicit mapping."
|
|
6840
6972
|
});
|
|
6841
6973
|
}
|
|
6842
|
-
function generateRowTypeDefinitions(
|
|
6843
|
-
const config = playBootstrapTemplateConfig(
|
|
6974
|
+
function generateRowTypeDefinitions(input2) {
|
|
6975
|
+
const config = playBootstrapTemplateConfig(input2.options.template);
|
|
6844
6976
|
const sourceTypeName = sourceCollectionTypeName(config.sourceEntity);
|
|
6845
6977
|
const definitions = [
|
|
6846
6978
|
sourceRowTypeDefinition({
|
|
6847
|
-
options:
|
|
6979
|
+
options: input2.options,
|
|
6848
6980
|
sourceTypeName,
|
|
6849
|
-
sourceTools:
|
|
6850
|
-
sourcePlay:
|
|
6981
|
+
sourceTools: input2.sourceTools,
|
|
6982
|
+
sourcePlay: input2.sourcePlay
|
|
6851
6983
|
}),
|
|
6852
|
-
contactBridgeRowTypeDefinition(
|
|
6984
|
+
contactBridgeRowTypeDefinition(input2)
|
|
6853
6985
|
];
|
|
6854
6986
|
return definitions.filter(Boolean).join("\n\n");
|
|
6855
6987
|
}
|
|
6856
|
-
function validateBootstrapRoutes(
|
|
6857
|
-
const config = playBootstrapTemplateConfig(
|
|
6988
|
+
function validateBootstrapRoutes(input2) {
|
|
6989
|
+
const config = playBootstrapTemplateConfig(input2.options.template);
|
|
6858
6990
|
const sourceCategory = config.sourceEntity === "company" ? PLAY_BOOTSTRAP_COMPANY_PROVIDER_CATEGORY : PLAY_BOOTSTRAP_PEOPLE_PROVIDER_CATEGORY;
|
|
6859
|
-
for (const tool of
|
|
6991
|
+
for (const tool of input2.sourceTools) {
|
|
6860
6992
|
if (!tool.categories.includes(sourceCategory)) {
|
|
6861
6993
|
throw new PlayBootstrapValidationError(
|
|
6862
|
-
`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`
|
|
6863
6995
|
);
|
|
6864
6996
|
}
|
|
6865
6997
|
if (getterNamesFromTool(tool, "list").length === 0) {
|
|
@@ -6868,14 +7000,14 @@ function validateBootstrapRoutes(input) {
|
|
|
6868
7000
|
);
|
|
6869
7001
|
}
|
|
6870
7002
|
}
|
|
6871
|
-
if (
|
|
7003
|
+
if (input2.options.people?.kind === "providers") {
|
|
6872
7004
|
throw new PlayBootstrapValidationError(
|
|
6873
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."
|
|
6874
7006
|
);
|
|
6875
7007
|
}
|
|
6876
7008
|
for (const finder of ["email_finder", "phone_finder"]) {
|
|
6877
7009
|
const requiredCategory = PLAY_BOOTSTRAP_PROVIDER_CATEGORY_BY_FINDER[finder];
|
|
6878
|
-
for (const tool of
|
|
7010
|
+
for (const tool of input2.finderTools[finder] ?? []) {
|
|
6879
7011
|
if (!tool.categories.includes(requiredCategory)) {
|
|
6880
7012
|
throw new PlayBootstrapValidationError(
|
|
6881
7013
|
`Cannot use ${tool.toolId} for ${finder}: expected category ${requiredCategory}, got ${tool.categories.join(", ") || "none"}. Run: deepline tools grep ${requiredCategory} --categories ${requiredCategory} --json`
|
|
@@ -6897,118 +7029,118 @@ function sourceCollectionName(entity) {
|
|
|
6897
7029
|
return "contacts";
|
|
6898
7030
|
}
|
|
6899
7031
|
}
|
|
6900
|
-
function requiredGetterName(
|
|
6901
|
-
const getter = getterNamesFromTool(
|
|
7032
|
+
function requiredGetterName(input2) {
|
|
7033
|
+
const getter = getterNamesFromTool(input2.tool, input2.kind)[0];
|
|
6902
7034
|
if (!getter) {
|
|
6903
|
-
switch (
|
|
7035
|
+
switch (input2.kind) {
|
|
6904
7036
|
case "list":
|
|
6905
7037
|
throw new PlayBootstrapValidationError(
|
|
6906
|
-
`Cannot use ${
|
|
7038
|
+
`Cannot use ${input2.label} as a source: it exposes no extracted list getters.`
|
|
6907
7039
|
);
|
|
6908
7040
|
case "value":
|
|
6909
7041
|
throw new PlayBootstrapValidationError(
|
|
6910
|
-
`Cannot use ${
|
|
7042
|
+
`Cannot use ${input2.label} as a finder: it exposes no extracted value getters.`
|
|
6911
7043
|
);
|
|
6912
7044
|
}
|
|
6913
7045
|
}
|
|
6914
7046
|
return getter;
|
|
6915
7047
|
}
|
|
6916
|
-
function generateCsvSourceRowsBlock(
|
|
6917
|
-
return `const sourceDataset = await ctx.csv<SourceCsvRow>(${jsString(
|
|
6918
|
-
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);`;
|
|
6919
7051
|
}
|
|
6920
|
-
function generatePlaySourceRowsBlock(
|
|
7052
|
+
function generatePlaySourceRowsBlock(input2) {
|
|
6921
7053
|
const playInput = generatePlayInputObject({
|
|
6922
|
-
schema:
|
|
7054
|
+
schema: input2.sourcePlay?.inputSchema,
|
|
6923
7055
|
indent: " ",
|
|
6924
|
-
label:
|
|
6925
|
-
entity:
|
|
7056
|
+
label: input2.source.value,
|
|
7057
|
+
entity: input2.entity
|
|
6926
7058
|
});
|
|
6927
7059
|
return `const sourceInput = ${playInput};
|
|
6928
|
-
throw new Error(${jsString(`TODO: map sourceInput for ${
|
|
6929
|
-
const sourceResult = await ctx.runPlay('source_play', ${jsString(
|
|
6930
|
-
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.`)},
|
|
6931
7063
|
});
|
|
6932
7064
|
// TODO: Replace sourceResult.rows with the selected play's actual row output field.
|
|
6933
|
-
const ${
|
|
7065
|
+
const ${input2.collection}: ${input2.collectionType}[] = (sourceResult.rows ?? []) as ${input2.collectionType}[];`;
|
|
6934
7066
|
}
|
|
6935
|
-
function generateProviderSourceBlock(
|
|
7067
|
+
function generateProviderSourceBlock(input2) {
|
|
6936
7068
|
const getter = requiredGetterName({
|
|
6937
|
-
tool:
|
|
7069
|
+
tool: input2.tool,
|
|
6938
7070
|
kind: "list",
|
|
6939
|
-
label:
|
|
7071
|
+
label: input2.provider
|
|
6940
7072
|
});
|
|
6941
|
-
const inputName = `${
|
|
6942
|
-
return `// ${
|
|
7073
|
+
const inputName = `${input2.entity}Input_${input2.index}`;
|
|
7074
|
+
return `// ${input2.entity === "company" ? "Company" : "People"} source provider: ${input2.provider}
|
|
6943
7075
|
const ${inputName}: Record<string, unknown> = ${generateSourceProviderInputObject(
|
|
6944
7076
|
{
|
|
6945
|
-
tool:
|
|
7077
|
+
tool: input2.tool,
|
|
6946
7078
|
indent: " ",
|
|
6947
|
-
label:
|
|
6948
|
-
entity:
|
|
7079
|
+
label: input2.provider,
|
|
7080
|
+
entity: input2.entity
|
|
6949
7081
|
}
|
|
6950
7082
|
)};
|
|
6951
|
-
throw new Error(${jsString(`TODO: fill ${inputName} for ${
|
|
6952
|
-
const source_${
|
|
6953
|
-
id: ${jsString(`${
|
|
6954
|
-
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)},
|
|
6955
7087
|
input: ${inputName},
|
|
6956
|
-
description: ${jsString(`Seed ${
|
|
7088
|
+
description: ${jsString(`Seed ${input2.entity} rows from ${input2.provider}.`)},
|
|
6957
7089
|
});
|
|
6958
7090
|
// extractedLists.${getter}.get() returns provider-shaped rows. Do not assume canonical fields;
|
|
6959
|
-
// inspect source_${
|
|
6960
|
-
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}[];`;
|
|
6961
7093
|
}
|
|
6962
|
-
function generateProviderSourceRowsBlock(
|
|
6963
|
-
const blocks =
|
|
7094
|
+
function generateProviderSourceRowsBlock(input2) {
|
|
7095
|
+
const blocks = input2.source.values.map(
|
|
6964
7096
|
(provider, index) => generateProviderSourceBlock({
|
|
6965
7097
|
provider,
|
|
6966
7098
|
index,
|
|
6967
|
-
tool:
|
|
6968
|
-
entity:
|
|
6969
|
-
collectionType:
|
|
7099
|
+
tool: input2.sourceTools[index] ?? null,
|
|
7100
|
+
entity: input2.entity,
|
|
7101
|
+
collectionType: input2.collectionType
|
|
6970
7102
|
})
|
|
6971
7103
|
);
|
|
6972
7104
|
return `${blocks.join("\n\n ")}
|
|
6973
|
-
const ${
|
|
7105
|
+
const ${input2.collection}: ${input2.collectionType}[] = [${input2.source.values.map((_, index) => `...sourceRows_${index}`).join(", ")}];`;
|
|
6974
7106
|
}
|
|
6975
|
-
function generateSourceRowsBlock(
|
|
6976
|
-
const config = playBootstrapTemplateConfig(
|
|
7107
|
+
function generateSourceRowsBlock(input2) {
|
|
7108
|
+
const config = playBootstrapTemplateConfig(input2.options.template);
|
|
6977
7109
|
const entity = config.sourceEntity;
|
|
6978
7110
|
const collection = sourceCollectionName(entity);
|
|
6979
7111
|
const collectionType = sourceCollectionTypeName(entity);
|
|
6980
|
-
switch (
|
|
7112
|
+
switch (input2.options.from.kind) {
|
|
6981
7113
|
case "csv":
|
|
6982
7114
|
return generateCsvSourceRowsBlock({
|
|
6983
|
-
source:
|
|
7115
|
+
source: input2.options.from,
|
|
6984
7116
|
collection,
|
|
6985
7117
|
collectionType,
|
|
6986
|
-
packagedSourceCsvPath:
|
|
7118
|
+
packagedSourceCsvPath: input2.packagedSourceCsvPath
|
|
6987
7119
|
});
|
|
6988
7120
|
case "play":
|
|
6989
7121
|
return generatePlaySourceRowsBlock({
|
|
6990
|
-
source:
|
|
6991
|
-
sourcePlay:
|
|
7122
|
+
source: input2.options.from,
|
|
7123
|
+
sourcePlay: input2.sourcePlay,
|
|
6992
7124
|
entity,
|
|
6993
7125
|
collection,
|
|
6994
7126
|
collectionType
|
|
6995
7127
|
});
|
|
6996
7128
|
case "providers":
|
|
6997
7129
|
return generateProviderSourceRowsBlock({
|
|
6998
|
-
source:
|
|
6999
|
-
sourceTools:
|
|
7130
|
+
source: input2.options.from,
|
|
7131
|
+
sourceTools: input2.sourceTools,
|
|
7000
7132
|
entity,
|
|
7001
7133
|
collection,
|
|
7002
7134
|
collectionType
|
|
7003
7135
|
});
|
|
7004
7136
|
}
|
|
7005
7137
|
}
|
|
7006
|
-
function generateSourceSeedBlock(
|
|
7007
|
-
const sourceRows = generateSourceRowsBlock(
|
|
7008
|
-
const peoplePlayRef = stagePlayRef(
|
|
7138
|
+
function generateSourceSeedBlock(input2) {
|
|
7139
|
+
const sourceRows = generateSourceRowsBlock(input2);
|
|
7140
|
+
const peoplePlayRef = stagePlayRef(input2.options.people);
|
|
7009
7141
|
if (!peoplePlayRef) return sourceRows;
|
|
7010
7142
|
const peopleInput = generateCompanyInputObjectFromSchema(
|
|
7011
|
-
|
|
7143
|
+
input2.peoplePlay?.inputSchema,
|
|
7012
7144
|
" ",
|
|
7013
7145
|
peoplePlayRef,
|
|
7014
7146
|
["domain", "company_name"]
|
|
@@ -7030,15 +7162,15 @@ function generateSourceSeedBlock(input) {
|
|
|
7030
7162
|
contacts.push(...((peopleResult.rows ?? []) as ContactSourceRow[]));
|
|
7031
7163
|
}`;
|
|
7032
7164
|
}
|
|
7033
|
-
function finderProviderStepName(
|
|
7034
|
-
return `${
|
|
7165
|
+
function finderProviderStepName(input2) {
|
|
7166
|
+
return `${input2.aggregateStepName}${input2.index}_${safeIdentifier(input2.provider)}`;
|
|
7035
7167
|
}
|
|
7036
|
-
function finderValueGetter(
|
|
7037
|
-
const getters = getterNamesFromTool(
|
|
7038
|
-
const getter = getters.find((name) => name ===
|
|
7039
|
-
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,
|
|
7040
7172
|
kind: "value",
|
|
7041
|
-
label:
|
|
7173
|
+
label: input2.provider
|
|
7042
7174
|
});
|
|
7043
7175
|
return getter;
|
|
7044
7176
|
}
|
|
@@ -7046,157 +7178,157 @@ function optionalFinderValueExpression(candidateExpression, outputField) {
|
|
|
7046
7178
|
const valueExpression = /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(outputField) ? `${candidateExpression}?.${outputField}` : `${candidateExpression}?.[${jsString(outputField)}]`;
|
|
7047
7179
|
return `${valueExpression}?.trim()`;
|
|
7048
7180
|
}
|
|
7049
|
-
function generateFinderPlayStep(
|
|
7050
|
-
const outputField = PLAY_BOOTSTRAP_OUTPUT_FIELD_BY_FINDER[
|
|
7051
|
-
const resultTypeName = finderResultTypeName(
|
|
7181
|
+
function generateFinderPlayStep(input2) {
|
|
7182
|
+
const outputField = PLAY_BOOTSTRAP_OUTPUT_FIELD_BY_FINDER[input2.finder];
|
|
7183
|
+
const resultTypeName = finderResultTypeName(input2.finder);
|
|
7052
7184
|
const payload = generateContactInputObjectFromSchema(
|
|
7053
|
-
|
|
7185
|
+
input2.play?.inputSchema,
|
|
7054
7186
|
" ",
|
|
7055
|
-
|
|
7187
|
+
input2.stage.value
|
|
7056
7188
|
);
|
|
7057
7189
|
return `.step(${jsString(outputField)}, async (row, rowCtx) => {
|
|
7058
|
-
const ${
|
|
7059
|
-
throw new Error(${jsString(`TODO: map ${
|
|
7060
|
-
const ${
|
|
7061
|
-
${jsString(`${
|
|
7062
|
-
${jsString(
|
|
7063
|
-
${
|
|
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,
|
|
7064
7196
|
{
|
|
7065
|
-
description: ${jsString(`Run ${
|
|
7197
|
+
description: ${jsString(`Run ${input2.finder} play.`)},
|
|
7066
7198
|
},
|
|
7067
7199
|
);
|
|
7068
|
-
return typeof ${
|
|
7069
|
-
? ${
|
|
7070
|
-
: ${
|
|
7200
|
+
return typeof ${input2.aggregateStepName}Result === 'string'
|
|
7201
|
+
? ${input2.aggregateStepName}Result.trim() || null
|
|
7202
|
+
: ${input2.aggregateStepName}Result?.${outputField} ?? null;
|
|
7071
7203
|
})`;
|
|
7072
7204
|
}
|
|
7073
|
-
function generateFinderProviderResolver(
|
|
7205
|
+
function generateFinderProviderResolver(input2) {
|
|
7074
7206
|
const payload = generateContactInputObjectFromSchema(
|
|
7075
|
-
|
|
7207
|
+
input2.tool?.inputSchema,
|
|
7076
7208
|
" ",
|
|
7077
|
-
|
|
7209
|
+
input2.provider
|
|
7078
7210
|
);
|
|
7079
7211
|
const getter = finderValueGetter({
|
|
7080
|
-
tool:
|
|
7081
|
-
provider:
|
|
7082
|
-
outputField:
|
|
7212
|
+
tool: input2.tool,
|
|
7213
|
+
provider: input2.provider,
|
|
7214
|
+
outputField: input2.outputField
|
|
7083
7215
|
});
|
|
7084
7216
|
return `async (row, rowCtx) => {
|
|
7085
7217
|
const providerInput = ${payload};
|
|
7086
|
-
throw new Error(${jsString(`TODO: map providerInput for ${
|
|
7218
|
+
throw new Error(${jsString(`TODO: map providerInput for ${input2.provider}, then delete this throw.`)});
|
|
7087
7219
|
const result = await rowCtx.tools.execute({
|
|
7088
|
-
id: ${jsString(`${
|
|
7089
|
-
tool: ${jsString(
|
|
7220
|
+
id: ${jsString(`${input2.aggregateStepName}_${input2.providerIndex}`)},
|
|
7221
|
+
tool: ${jsString(input2.provider)},
|
|
7090
7222
|
input: providerInput,
|
|
7091
|
-
description: ${jsString(`Try ${
|
|
7223
|
+
description: ${jsString(`Try ${input2.provider} as a ${input2.finder}.`)},
|
|
7092
7224
|
});
|
|
7093
7225
|
return {
|
|
7094
|
-
${
|
|
7226
|
+
${input2.outputField}: (${accessorExpression("result.extractedValues", getter)}.get() as string | null) ?? null,
|
|
7095
7227
|
result,
|
|
7096
7228
|
};
|
|
7097
7229
|
}`;
|
|
7098
7230
|
}
|
|
7099
|
-
function generateFinderProviderStep(
|
|
7100
|
-
const stepName =
|
|
7101
|
-
switch (
|
|
7231
|
+
function generateFinderProviderStep(input2) {
|
|
7232
|
+
const stepName = input2.stepNames[input2.index];
|
|
7233
|
+
switch (input2.index) {
|
|
7102
7234
|
case 0:
|
|
7103
|
-
return `.step(${jsString(stepName)}, ${
|
|
7235
|
+
return `.step(${jsString(stepName)}, ${input2.resolver})`;
|
|
7104
7236
|
default: {
|
|
7105
|
-
const priorCandidates =
|
|
7237
|
+
const priorCandidates = input2.stepNames.slice(0, input2.index).map((name) => `row.${name}`).join(", ");
|
|
7106
7238
|
return `.step(
|
|
7107
7239
|
${jsString(stepName)},
|
|
7108
7240
|
when(
|
|
7109
|
-
(row) => ![${priorCandidates}].some((candidate) => ${optionalFinderValueExpression("candidate",
|
|
7110
|
-
${
|
|
7241
|
+
(row) => ![${priorCandidates}].some((candidate) => ${optionalFinderValueExpression("candidate", input2.outputField)}),
|
|
7242
|
+
${input2.resolver},
|
|
7111
7243
|
),
|
|
7112
7244
|
)`;
|
|
7113
7245
|
}
|
|
7114
7246
|
}
|
|
7115
7247
|
}
|
|
7116
|
-
function generateFinderProviderWaterfall(
|
|
7117
|
-
const legPrefix = finderProviderStepPrefix(
|
|
7118
|
-
const stepNames =
|
|
7248
|
+
function generateFinderProviderWaterfall(input2) {
|
|
7249
|
+
const legPrefix = finderProviderStepPrefix(input2.finder);
|
|
7250
|
+
const stepNames = input2.stage.values.map(
|
|
7119
7251
|
(provider, index) => finderProviderStepName({
|
|
7120
7252
|
aggregateStepName: legPrefix,
|
|
7121
7253
|
provider,
|
|
7122
7254
|
index
|
|
7123
7255
|
})
|
|
7124
7256
|
);
|
|
7125
|
-
const providerSteps =
|
|
7257
|
+
const providerSteps = input2.stage.values.map(
|
|
7126
7258
|
(provider, index) => generateFinderProviderStep({
|
|
7127
7259
|
index,
|
|
7128
7260
|
stepNames,
|
|
7129
|
-
outputField:
|
|
7261
|
+
outputField: input2.outputField,
|
|
7130
7262
|
resolver: generateFinderProviderResolver({
|
|
7131
|
-
finder:
|
|
7263
|
+
finder: input2.finder,
|
|
7132
7264
|
provider,
|
|
7133
7265
|
providerIndex: index,
|
|
7134
|
-
tool:
|
|
7135
|
-
aggregateStepName:
|
|
7136
|
-
outputField:
|
|
7266
|
+
tool: input2.tools[index] ?? null,
|
|
7267
|
+
aggregateStepName: input2.aggregateStepName,
|
|
7268
|
+
outputField: input2.outputField
|
|
7137
7269
|
})
|
|
7138
7270
|
})
|
|
7139
7271
|
);
|
|
7140
7272
|
const candidateNames = stepNames.map((name) => `row.${name}`).join(", ");
|
|
7141
|
-
return `// ${
|
|
7273
|
+
return `// ${input2.aggregateStepName} provider waterfall. Each provider leg is active once its TODO throw is removed;
|
|
7142
7274
|
// delete or comment out legs you do not want before running. Later legs are gated with when(...).
|
|
7143
7275
|
${providerSteps.join("\n ")}
|
|
7144
|
-
.step(${jsString(
|
|
7276
|
+
.step(${jsString(input2.aggregateStepName)}, (row) => {
|
|
7145
7277
|
const candidates = [${candidateNames}];
|
|
7146
|
-
const match = candidates.find((candidate) => ${optionalFinderValueExpression("candidate",
|
|
7147
|
-
return ${optionalFinderValueExpression("match",
|
|
7278
|
+
const match = candidates.find((candidate) => ${optionalFinderValueExpression("candidate", input2.outputField)});
|
|
7279
|
+
return ${optionalFinderValueExpression("match", input2.outputField)} ?? null;
|
|
7148
7280
|
})`;
|
|
7149
7281
|
}
|
|
7150
|
-
function generateFinderStageSteps(
|
|
7151
|
-
const outputField = PLAY_BOOTSTRAP_OUTPUT_FIELD_BY_FINDER[
|
|
7152
|
-
const aggregateStepName = stepFieldName(
|
|
7153
|
-
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) {
|
|
7154
7286
|
case "play":
|
|
7155
7287
|
return generateFinderPlayStep({
|
|
7156
|
-
finder:
|
|
7157
|
-
stage:
|
|
7158
|
-
play:
|
|
7288
|
+
finder: input2.finder,
|
|
7289
|
+
stage: input2.stage,
|
|
7290
|
+
play: input2.finderPlays[input2.finder],
|
|
7159
7291
|
aggregateStepName
|
|
7160
7292
|
});
|
|
7161
7293
|
case "providers":
|
|
7162
7294
|
return generateFinderProviderWaterfall({
|
|
7163
|
-
finder:
|
|
7164
|
-
stage:
|
|
7165
|
-
tools:
|
|
7295
|
+
finder: input2.finder,
|
|
7296
|
+
stage: input2.stage,
|
|
7297
|
+
tools: input2.finderTools[input2.finder] ?? [],
|
|
7166
7298
|
aggregateStepName,
|
|
7167
7299
|
outputField
|
|
7168
7300
|
});
|
|
7169
7301
|
}
|
|
7170
7302
|
}
|
|
7171
|
-
function generateFinderSteps(
|
|
7303
|
+
function generateFinderSteps(input2) {
|
|
7172
7304
|
return ["email_finder", "phone_finder"].flatMap((finder) => {
|
|
7173
|
-
const stage = finderStage(
|
|
7305
|
+
const stage = finderStage(input2.options, finder);
|
|
7174
7306
|
return stage ? [
|
|
7175
7307
|
generateFinderStageSteps({
|
|
7176
|
-
...
|
|
7308
|
+
...input2,
|
|
7177
7309
|
finder,
|
|
7178
7310
|
stage
|
|
7179
7311
|
})
|
|
7180
7312
|
] : [];
|
|
7181
7313
|
}).join("\n ");
|
|
7182
7314
|
}
|
|
7183
|
-
function generateBootstrapPlaySource(
|
|
7184
|
-
const config = playBootstrapTemplateConfig(
|
|
7185
|
-
const sourceSeedBlock = generateSourceSeedBlock(
|
|
7186
|
-
const finderSteps = generateFinderSteps(
|
|
7187
|
-
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);
|
|
7188
7320
|
const sourceCollection = hasPeople ? "contacts" : "companies";
|
|
7189
7321
|
const mapSteps = finderSteps ? `
|
|
7190
7322
|
${finderSteps}` : "";
|
|
7191
|
-
const sourceCsvRowType =
|
|
7192
|
-
const rowTypeDefinitions = generateRowTypeDefinitions(
|
|
7193
|
-
const finderPlayResultTypes = generatedFinderPlayResultTypes(
|
|
7323
|
+
const sourceCsvRowType = input2.options.from.kind === "csv" ? renderSourceCsvRowType(input2.sourceCsvColumns) : "";
|
|
7324
|
+
const rowTypeDefinitions = generateRowTypeDefinitions(input2);
|
|
7325
|
+
const finderPlayResultTypes = generatedFinderPlayResultTypes(input2);
|
|
7194
7326
|
const typeDefinitions = [
|
|
7195
7327
|
sourceCsvRowType.trimEnd(),
|
|
7196
7328
|
rowTypeDefinitions,
|
|
7197
7329
|
finderPlayResultTypes
|
|
7198
7330
|
].filter((definition) => definition.trim().length > 0).join("\n\n");
|
|
7199
|
-
const importNames = needsWhenImport(
|
|
7331
|
+
const importNames = needsWhenImport(input2.options) ? "definePlay, when" : "definePlay";
|
|
7200
7332
|
return `import { ${importNames} } from 'deepline';
|
|
7201
7333
|
|
|
7202
7334
|
${typeDefinitions}
|
|
@@ -7205,8 +7337,8 @@ type Input = {
|
|
|
7205
7337
|
limit?: number;
|
|
7206
7338
|
};
|
|
7207
7339
|
|
|
7208
|
-
export default definePlay(${jsString(
|
|
7209
|
-
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}));
|
|
7210
7342
|
${sourceSeedBlock}
|
|
7211
7343
|
|
|
7212
7344
|
const rowsToProcess = ${sourceCollection}.slice(0, limit);
|
|
@@ -7218,7 +7350,7 @@ export default definePlay(${jsString(input.options.name)}, async (ctx, input: In
|
|
|
7218
7350
|
.map('bootstrap_rows', rowsToProcess)${mapSteps}
|
|
7219
7351
|
.run({
|
|
7220
7352
|
key: (_row, index) => index,
|
|
7221
|
-
description: ${jsString(`Bootstrap ${
|
|
7353
|
+
description: ${jsString(`Bootstrap ${input2.options.template}: seed source rows, run requested stages, then return the mapped rows.`)},
|
|
7222
7354
|
});
|
|
7223
7355
|
|
|
7224
7356
|
return {
|
|
@@ -7626,8 +7758,8 @@ var SHA256_ROUND_CONSTANTS = [
|
|
|
7626
7758
|
function rightRotate32(value, bits) {
|
|
7627
7759
|
return value >>> bits | value << 32 - bits;
|
|
7628
7760
|
}
|
|
7629
|
-
function sha256Hex(
|
|
7630
|
-
const bytes = Array.from(new TextEncoder().encode(
|
|
7761
|
+
function sha256Hex(input2) {
|
|
7762
|
+
const bytes = Array.from(new TextEncoder().encode(input2));
|
|
7631
7763
|
const bitLength = bytes.length * 8;
|
|
7632
7764
|
bytes.push(128);
|
|
7633
7765
|
while (bytes.length % 64 !== 56) {
|
|
@@ -7801,10 +7933,10 @@ function looksLikeInvalidExtractedGetter(error, sourceLine) {
|
|
|
7801
7933
|
if (!/Property '[^']+' does not exist on type/.test(error)) return false;
|
|
7802
7934
|
return /\bextracted(?:Values|Lists)\s*\./.test(sourceLine);
|
|
7803
7935
|
}
|
|
7804
|
-
function addPlayCheckRepairHints(
|
|
7936
|
+
function addPlayCheckRepairHints(input2) {
|
|
7805
7937
|
let addedHint = false;
|
|
7806
|
-
return
|
|
7807
|
-
const line = sourceLineForError(
|
|
7938
|
+
return input2.errors.map((error) => {
|
|
7939
|
+
const line = sourceLineForError(input2.sourceCode, error);
|
|
7808
7940
|
if (addedHint || !looksLikeInvalidExtractedGetter(error, line) || error.includes(EXTRACTED_GETTER_ERROR_HINT)) {
|
|
7809
7941
|
return error;
|
|
7810
7942
|
}
|
|
@@ -7866,9 +7998,9 @@ function parseReferencedPlayTarget2(target) {
|
|
|
7866
7998
|
function isPrebuiltReferenceTarget(target) {
|
|
7867
7999
|
return target.trim().toLowerCase().startsWith("prebuilt/");
|
|
7868
8000
|
}
|
|
7869
|
-
function buildBarePrebuiltReferenceError(
|
|
8001
|
+
function buildBarePrebuiltReferenceError(input2) {
|
|
7870
8002
|
return new Error(
|
|
7871
|
-
`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.`
|
|
7872
8004
|
);
|
|
7873
8005
|
}
|
|
7874
8006
|
async function assertCanonicalNamedPlayReference(client, target) {
|
|
@@ -7911,23 +8043,23 @@ function buildCloneEditStarter(play) {
|
|
|
7911
8043
|
checkCommand: `deepline plays check ${path}`
|
|
7912
8044
|
};
|
|
7913
8045
|
}
|
|
7914
|
-
function materializeRemotePlaySource(
|
|
7915
|
-
if (isFileTarget(
|
|
8046
|
+
function materializeRemotePlaySource(input2) {
|
|
8047
|
+
if (isFileTarget(input2.target)) {
|
|
7916
8048
|
return null;
|
|
7917
8049
|
}
|
|
7918
|
-
if (!
|
|
8050
|
+
if (!input2.sourceCode.trim()) {
|
|
7919
8051
|
return null;
|
|
7920
8052
|
}
|
|
7921
|
-
const outputPath =
|
|
8053
|
+
const outputPath = input2.outPath ?? defaultMaterializedPlayPath(input2.playName);
|
|
7922
8054
|
if ((0, import_node_fs10.existsSync)(outputPath)) {
|
|
7923
8055
|
const existingSource = (0, import_node_fs10.readFileSync)(outputPath, "utf-8");
|
|
7924
|
-
if (existingSource ===
|
|
8056
|
+
if (existingSource === input2.sourceCode) {
|
|
7925
8057
|
return { path: outputPath, status: "unchanged", created: false };
|
|
7926
8058
|
}
|
|
7927
|
-
(0, import_node_fs10.writeFileSync)(outputPath,
|
|
8059
|
+
(0, import_node_fs10.writeFileSync)(outputPath, input2.sourceCode, "utf-8");
|
|
7928
8060
|
return { path: outputPath, status: "updated", created: false };
|
|
7929
8061
|
}
|
|
7930
|
-
(0, import_node_fs10.writeFileSync)(outputPath,
|
|
8062
|
+
(0, import_node_fs10.writeFileSync)(outputPath, input2.sourceCode, "utf-8");
|
|
7931
8063
|
return { path: outputPath, status: "created", created: true };
|
|
7932
8064
|
}
|
|
7933
8065
|
function formatLoadedPlayMessage(materializedFile) {
|
|
@@ -7977,12 +8109,12 @@ function isFileTarget(target) {
|
|
|
7977
8109
|
function looksLikeRunId(target) {
|
|
7978
8110
|
return /^play\/[^/]+\/run\/[^/]+/.test(target.trim());
|
|
7979
8111
|
}
|
|
7980
|
-
function formatPlayCommandReceivedRunIdError(
|
|
7981
|
-
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.
|
|
7982
8114
|
Use:
|
|
7983
|
-
deepline runs get ${
|
|
7984
|
-
deepline runs logs ${
|
|
7985
|
-
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`;
|
|
7986
8118
|
}
|
|
7987
8119
|
function looksLikeFilePath(target) {
|
|
7988
8120
|
if (target.trim().toLowerCase().startsWith("prebuilt/")) {
|
|
@@ -8036,9 +8168,9 @@ function parseInputFlagValue(raw) {
|
|
|
8036
8168
|
}
|
|
8037
8169
|
return raw;
|
|
8038
8170
|
}
|
|
8039
|
-
function getDottedInputValue(
|
|
8171
|
+
function getDottedInputValue(input2, path) {
|
|
8040
8172
|
const parts = path.split(".").map((part) => part.trim()).filter(Boolean);
|
|
8041
|
-
let cursor =
|
|
8173
|
+
let cursor = input2;
|
|
8042
8174
|
for (const part of parts) {
|
|
8043
8175
|
if (!cursor || typeof cursor !== "object" || Array.isArray(cursor)) {
|
|
8044
8176
|
return void 0;
|
|
@@ -8047,12 +8179,12 @@ function getDottedInputValue(input, path) {
|
|
|
8047
8179
|
}
|
|
8048
8180
|
return cursor;
|
|
8049
8181
|
}
|
|
8050
|
-
function setDottedInputValue(
|
|
8182
|
+
function setDottedInputValue(input2, path, value) {
|
|
8051
8183
|
const parts = path.split(".").map((part) => part.trim()).filter(Boolean);
|
|
8052
8184
|
if (parts.length === 0) {
|
|
8053
8185
|
throw new Error(`Invalid play input flag path: ${path}`);
|
|
8054
8186
|
}
|
|
8055
|
-
let cursor =
|
|
8187
|
+
let cursor = input2;
|
|
8056
8188
|
for (const part of parts.slice(0, -1)) {
|
|
8057
8189
|
const existing = cursor[part];
|
|
8058
8190
|
if (existing !== void 0 && (!existing || typeof existing !== "object" || Array.isArray(existing))) {
|
|
@@ -8119,17 +8251,17 @@ function inputContainsLocalFilePath(value) {
|
|
|
8119
8251
|
}
|
|
8120
8252
|
return false;
|
|
8121
8253
|
}
|
|
8122
|
-
function namedRunNeedsPlayDefinition(
|
|
8123
|
-
return
|
|
8254
|
+
function namedRunNeedsPlayDefinition(input2) {
|
|
8255
|
+
return input2.revisionSelector === "latest" || inputContainsLocalFilePath(input2.runtimeInput);
|
|
8124
8256
|
}
|
|
8125
|
-
async function stageFileInputArgs(
|
|
8257
|
+
async function stageFileInputArgs(input2) {
|
|
8126
8258
|
const uniqueBindings = [
|
|
8127
8259
|
...new Map(
|
|
8128
|
-
|
|
8260
|
+
input2.bindings.map((binding) => [binding.inputPath, binding])
|
|
8129
8261
|
).values()
|
|
8130
8262
|
];
|
|
8131
8263
|
const localFiles = uniqueBindings.flatMap((binding) => {
|
|
8132
|
-
const value = getDottedInputValue(
|
|
8264
|
+
const value = getDottedInputValue(input2.runtimeInput, binding.inputPath);
|
|
8133
8265
|
if (!isLocalFilePathValue(value)) return [];
|
|
8134
8266
|
const absolutePath = (0, import_node_path12.resolve)(value);
|
|
8135
8267
|
return [{ binding, absolutePath, logicalPath: (0, import_node_path12.basename)(absolutePath) }];
|
|
@@ -8137,22 +8269,22 @@ async function stageFileInputArgs(input) {
|
|
|
8137
8269
|
if (localFiles.length === 0) {
|
|
8138
8270
|
return { inputFile: null, packagedFiles: [] };
|
|
8139
8271
|
}
|
|
8140
|
-
|
|
8272
|
+
input2.progress.phase(
|
|
8141
8273
|
localFiles.length === 1 ? "staging input file" : "staging input files"
|
|
8142
8274
|
);
|
|
8143
|
-
const staged = await
|
|
8275
|
+
const staged = await input2.client.stagePlayFiles(
|
|
8144
8276
|
localFiles.map((file) => stageFile(file.logicalPath, file.absolutePath))
|
|
8145
8277
|
);
|
|
8146
8278
|
for (const [index, file] of localFiles.entries()) {
|
|
8147
8279
|
setDottedInputValue(
|
|
8148
|
-
|
|
8280
|
+
input2.runtimeInput,
|
|
8149
8281
|
file.binding.inputPath,
|
|
8150
8282
|
file.logicalPath
|
|
8151
8283
|
);
|
|
8152
8284
|
const stagedFile = staged[index];
|
|
8153
8285
|
if (stagedFile && stagedFile.logicalPath !== file.logicalPath) {
|
|
8154
8286
|
setDottedInputValue(
|
|
8155
|
-
|
|
8287
|
+
input2.runtimeInput,
|
|
8156
8288
|
file.binding.inputPath,
|
|
8157
8289
|
stagedFile.logicalPath
|
|
8158
8290
|
);
|
|
@@ -8437,16 +8569,16 @@ function buildStepReceiptsDebugCommand(runId) {
|
|
|
8437
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`;
|
|
8438
8570
|
return buildDebugDbQueryCommand(sql);
|
|
8439
8571
|
}
|
|
8440
|
-
function buildMapTableDebugCommand(
|
|
8572
|
+
function buildMapTableDebugCommand(input2) {
|
|
8441
8573
|
try {
|
|
8442
8574
|
const tableName = validatePlaySheetTableName(
|
|
8443
|
-
|
|
8444
|
-
|
|
8575
|
+
input2.playName,
|
|
8576
|
+
input2.tableNamespace
|
|
8445
8577
|
);
|
|
8446
8578
|
const table = `${quoteSqlIdentifier(
|
|
8447
8579
|
PLAY_CUSTOMER_STORAGE_SCHEMA_NAME
|
|
8448
8580
|
)}.${quoteSqlIdentifier(tableName)}`;
|
|
8449
|
-
const sql = `select * from ${table} where _run_id = ${quoteSqlLiteral(
|
|
8581
|
+
const sql = `select * from ${table} where _run_id = ${quoteSqlLiteral(input2.runId)} limit 20`;
|
|
8450
8582
|
return buildDebugDbQueryCommand(sql);
|
|
8451
8583
|
} catch {
|
|
8452
8584
|
return null;
|
|
@@ -8466,37 +8598,37 @@ function extractTableNamespaceFromLiveEvent(event) {
|
|
|
8466
8598
|
}
|
|
8467
8599
|
return null;
|
|
8468
8600
|
}
|
|
8469
|
-
function emitLiveDebugTableHints(
|
|
8470
|
-
if (
|
|
8601
|
+
function emitLiveDebugTableHints(input2) {
|
|
8602
|
+
if (input2.jsonOutput || !input2.runId || input2.runId === "pending") {
|
|
8471
8603
|
return;
|
|
8472
8604
|
}
|
|
8473
|
-
|
|
8474
|
-
const receiptsKey = `receipts:${
|
|
8475
|
-
if (!
|
|
8476
|
-
|
|
8477
|
-
|
|
8478
|
-
`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)}`,
|
|
8479
8611
|
process.stdout
|
|
8480
8612
|
);
|
|
8481
8613
|
}
|
|
8482
|
-
const tableNamespace = extractTableNamespaceFromLiveEvent(
|
|
8614
|
+
const tableNamespace = extractTableNamespaceFromLiveEvent(input2.event);
|
|
8483
8615
|
if (!tableNamespace) {
|
|
8484
8616
|
return;
|
|
8485
8617
|
}
|
|
8486
|
-
const tableKey = `table:${
|
|
8487
|
-
if (
|
|
8618
|
+
const tableKey = `table:${input2.runId}:${tableNamespace}`;
|
|
8619
|
+
if (input2.state.emittedDebugKeys.has(tableKey)) {
|
|
8488
8620
|
return;
|
|
8489
8621
|
}
|
|
8490
8622
|
const command = buildMapTableDebugCommand({
|
|
8491
|
-
playName:
|
|
8492
|
-
runId:
|
|
8623
|
+
playName: input2.playName,
|
|
8624
|
+
runId: input2.runId,
|
|
8493
8625
|
tableNamespace
|
|
8494
8626
|
});
|
|
8495
8627
|
if (!command) {
|
|
8496
8628
|
return;
|
|
8497
8629
|
}
|
|
8498
|
-
|
|
8499
|
-
|
|
8630
|
+
input2.state.emittedDebugKeys.add(tableKey);
|
|
8631
|
+
input2.progress.writeLine(
|
|
8500
8632
|
`Debug rows for ${tableNamespace}: ${command}`,
|
|
8501
8633
|
process.stdout
|
|
8502
8634
|
);
|
|
@@ -8529,9 +8661,9 @@ function formatProgressLabel(raw) {
|
|
|
8529
8661
|
const value = typeof raw === "string" && raw.trim() ? raw.trim() : "step";
|
|
8530
8662
|
return value.replace(/^map:/, "").replace(/^tool:/, "");
|
|
8531
8663
|
}
|
|
8532
|
-
function formatProgressCounts(
|
|
8533
|
-
const completed = typeof
|
|
8534
|
-
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;
|
|
8535
8667
|
if (completed === null || total === null || total <= 0) {
|
|
8536
8668
|
return null;
|
|
8537
8669
|
}
|
|
@@ -8539,7 +8671,7 @@ function formatProgressCounts(input) {
|
|
|
8539
8671
|
0,
|
|
8540
8672
|
Math.min(100, Math.round(completed / total * 100))
|
|
8541
8673
|
);
|
|
8542
|
-
const failed = typeof
|
|
8674
|
+
const failed = typeof input2.failed === "number" && Number.isFinite(input2.failed) && input2.failed > 0 ? `, failed ${formatInteger(input2.failed)}` : "";
|
|
8543
8675
|
return `${formatInteger(completed)}/${formatInteger(total)} (${percent}%)${failed}`;
|
|
8544
8676
|
}
|
|
8545
8677
|
function getProgressLinesFromLiveEvent(event) {
|
|
@@ -8581,14 +8713,14 @@ function getProgressLinesFromLiveEvent(event) {
|
|
|
8581
8713
|
}
|
|
8582
8714
|
return lines;
|
|
8583
8715
|
}
|
|
8584
|
-
function printPlayProgressLines(
|
|
8585
|
-
for (const line of
|
|
8716
|
+
function printPlayProgressLines(input2) {
|
|
8717
|
+
for (const line of input2.lines) {
|
|
8586
8718
|
const signature = line.trim();
|
|
8587
|
-
if (!signature ||
|
|
8719
|
+
if (!signature || input2.state.lastProgressSignature === signature) {
|
|
8588
8720
|
continue;
|
|
8589
8721
|
}
|
|
8590
|
-
|
|
8591
|
-
|
|
8722
|
+
input2.state.lastProgressSignature = signature;
|
|
8723
|
+
input2.progress.writeLine(line);
|
|
8592
8724
|
}
|
|
8593
8725
|
}
|
|
8594
8726
|
function buildPlayDashboardUrl(baseUrl, playName) {
|
|
@@ -8596,102 +8728,102 @@ function buildPlayDashboardUrl(baseUrl, playName) {
|
|
|
8596
8728
|
const encodedPlayName = encodeURIComponent(playName);
|
|
8597
8729
|
return `${trimmedBase}/dashboard/plays/${encodedPlayName}`;
|
|
8598
8730
|
}
|
|
8599
|
-
function openPlayDashboard(
|
|
8600
|
-
if (
|
|
8731
|
+
function openPlayDashboard(input2) {
|
|
8732
|
+
if (input2.jsonOutput || input2.noOpen || !input2.dashboardUrl) {
|
|
8601
8733
|
return;
|
|
8602
8734
|
}
|
|
8603
|
-
openInBrowser(
|
|
8735
|
+
openInBrowser(input2.dashboardUrl);
|
|
8604
8736
|
}
|
|
8605
|
-
function printPlayLogLines(
|
|
8606
|
-
for (const line of
|
|
8607
|
-
if (
|
|
8737
|
+
function printPlayLogLines(input2) {
|
|
8738
|
+
for (const line of input2.lines) {
|
|
8739
|
+
if (input2.emitLogs) {
|
|
8608
8740
|
const formatted = formatPlayLogLine(
|
|
8609
8741
|
line,
|
|
8610
|
-
|
|
8611
|
-
|
|
8742
|
+
input2.status ?? void 0,
|
|
8743
|
+
input2.state
|
|
8612
8744
|
);
|
|
8613
8745
|
if (formatted) {
|
|
8614
|
-
|
|
8746
|
+
input2.progress.writeLogLine(formatted);
|
|
8615
8747
|
}
|
|
8616
8748
|
}
|
|
8617
|
-
|
|
8749
|
+
input2.state.lastLogIndex += 1;
|
|
8618
8750
|
}
|
|
8619
8751
|
}
|
|
8620
|
-
function assertPlayWaitNotTimedOut(
|
|
8621
|
-
if (
|
|
8622
|
-
const hasRealRunId =
|
|
8623
|
-
const phaseSuffix =
|
|
8624
|
-
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.`;
|
|
8625
8757
|
throw new DeeplineError(
|
|
8626
|
-
`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}`,
|
|
8627
8759
|
void 0,
|
|
8628
8760
|
"PLAY_WAIT_TIMEOUT",
|
|
8629
8761
|
{
|
|
8630
|
-
...hasRealRunId ? { runId:
|
|
8631
|
-
...
|
|
8632
|
-
timeoutMs:
|
|
8762
|
+
...hasRealRunId ? { runId: input2.workflowId, workflowId: input2.workflowId } : {},
|
|
8763
|
+
...input2.lastPhase ? { phase: input2.lastPhase } : {},
|
|
8764
|
+
timeoutMs: input2.waitTimeoutMs
|
|
8633
8765
|
}
|
|
8634
8766
|
);
|
|
8635
8767
|
}
|
|
8636
8768
|
}
|
|
8637
|
-
async function waitForPlayCompletionByStream(
|
|
8769
|
+
async function waitForPlayCompletionByStream(input2) {
|
|
8638
8770
|
const controller = new AbortController();
|
|
8639
8771
|
let timedOut = false;
|
|
8640
8772
|
let lastPhase = null;
|
|
8641
|
-
const timeout =
|
|
8773
|
+
const timeout = input2.waitTimeoutMs === null ? null : setTimeout(
|
|
8642
8774
|
() => {
|
|
8643
8775
|
timedOut = true;
|
|
8644
8776
|
controller.abort();
|
|
8645
8777
|
},
|
|
8646
|
-
Math.max(1,
|
|
8778
|
+
Math.max(1, input2.waitTimeoutMs - (Date.now() - input2.startedAt))
|
|
8647
8779
|
);
|
|
8648
8780
|
try {
|
|
8649
|
-
for await (const event of
|
|
8650
|
-
|
|
8781
|
+
for await (const event of input2.client.streamPlayRunEvents(
|
|
8782
|
+
input2.workflowId,
|
|
8651
8783
|
{ signal: controller.signal }
|
|
8652
8784
|
)) {
|
|
8653
|
-
assertPlayWaitNotTimedOut({ ...
|
|
8785
|
+
assertPlayWaitNotTimedOut({ ...input2, lastPhase });
|
|
8654
8786
|
const phase = describeLiveEventPhase(event);
|
|
8655
8787
|
if (phase) {
|
|
8656
8788
|
lastPhase = phase;
|
|
8657
|
-
|
|
8789
|
+
input2.progress.phase(phase);
|
|
8658
8790
|
}
|
|
8659
8791
|
emitLiveDebugTableHints({
|
|
8660
8792
|
event,
|
|
8661
|
-
playName:
|
|
8662
|
-
runId:
|
|
8663
|
-
jsonOutput:
|
|
8664
|
-
state:
|
|
8665
|
-
progress:
|
|
8793
|
+
playName: input2.playName,
|
|
8794
|
+
runId: input2.workflowId,
|
|
8795
|
+
jsonOutput: input2.jsonOutput,
|
|
8796
|
+
state: input2.state,
|
|
8797
|
+
progress: input2.progress
|
|
8666
8798
|
});
|
|
8667
8799
|
printPlayLogLines({
|
|
8668
8800
|
lines: getLogLinesFromLiveEvent(event),
|
|
8669
8801
|
status: null,
|
|
8670
|
-
jsonOutput:
|
|
8671
|
-
emitLogs:
|
|
8672
|
-
state:
|
|
8673
|
-
progress:
|
|
8802
|
+
jsonOutput: input2.jsonOutput,
|
|
8803
|
+
emitLogs: input2.emitLogs,
|
|
8804
|
+
state: input2.state,
|
|
8805
|
+
progress: input2.progress
|
|
8674
8806
|
});
|
|
8675
|
-
if (!
|
|
8807
|
+
if (!input2.jsonOutput) {
|
|
8676
8808
|
printPlayProgressLines({
|
|
8677
8809
|
lines: getProgressLinesFromLiveEvent(event),
|
|
8678
|
-
state:
|
|
8679
|
-
progress:
|
|
8810
|
+
state: input2.state,
|
|
8811
|
+
progress: input2.progress
|
|
8680
8812
|
});
|
|
8681
8813
|
}
|
|
8682
8814
|
const status = getStatusFromLiveEvent(event);
|
|
8683
8815
|
if (status && TERMINAL_PLAY_STATUSES2.has(status)) {
|
|
8684
|
-
const finalStatus = await
|
|
8816
|
+
const finalStatus = await input2.client.getPlayStatus(input2.workflowId, {
|
|
8685
8817
|
billing: false
|
|
8686
8818
|
});
|
|
8687
8819
|
if (TERMINAL_PLAY_STATUSES2.has(finalStatus.status)) {
|
|
8688
|
-
return
|
|
8820
|
+
return input2.dashboardUrl ? { ...finalStatus, dashboardUrl: input2.dashboardUrl } : finalStatus;
|
|
8689
8821
|
}
|
|
8690
8822
|
}
|
|
8691
8823
|
}
|
|
8692
8824
|
} catch (error) {
|
|
8693
8825
|
if (timedOut) {
|
|
8694
|
-
assertPlayWaitNotTimedOut({ ...
|
|
8826
|
+
assertPlayWaitNotTimedOut({ ...input2, lastPhase });
|
|
8695
8827
|
}
|
|
8696
8828
|
throw error;
|
|
8697
8829
|
} finally {
|
|
@@ -8701,25 +8833,25 @@ async function waitForPlayCompletionByStream(input) {
|
|
|
8701
8833
|
}
|
|
8702
8834
|
const phaseSuffix = lastPhase && lastPhase.trim() ? ` (last observed phase: ${lastPhase.trim()})` : "";
|
|
8703
8835
|
throw new DeeplineError(
|
|
8704
|
-
`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}.`,
|
|
8705
8837
|
void 0,
|
|
8706
8838
|
"PLAY_LIVE_STREAM_ENDED",
|
|
8707
8839
|
{
|
|
8708
|
-
runId:
|
|
8709
|
-
workflowId:
|
|
8840
|
+
runId: input2.workflowId,
|
|
8841
|
+
workflowId: input2.workflowId,
|
|
8710
8842
|
...lastPhase ? { phase: lastPhase } : {}
|
|
8711
8843
|
}
|
|
8712
8844
|
);
|
|
8713
8845
|
}
|
|
8714
|
-
async function startAndWaitForPlayCompletionByStream(
|
|
8846
|
+
async function startAndWaitForPlayCompletionByStream(input2) {
|
|
8715
8847
|
for (let attempt = 0; attempt <= PLAY_START_TRANSIENT_RETRY_DELAYS_MS.length; attempt += 1) {
|
|
8716
|
-
const status = await startAndWaitForPlayCompletionByStreamOnce(
|
|
8848
|
+
const status = await startAndWaitForPlayCompletionByStreamOnce(input2);
|
|
8717
8849
|
const retryDelayMs = PLAY_START_TRANSIENT_RETRY_DELAYS_MS[attempt];
|
|
8718
8850
|
if (retryDelayMs === void 0 || !isRetryablePendingStartFailure(status)) {
|
|
8719
8851
|
return status;
|
|
8720
8852
|
}
|
|
8721
|
-
if (!
|
|
8722
|
-
|
|
8853
|
+
if (!input2.jsonOutput) {
|
|
8854
|
+
input2.progress.writeLine(
|
|
8723
8855
|
`[play watch] start failed before run id with a transient error; retrying (${playStatusErrorText(status)})`
|
|
8724
8856
|
);
|
|
8725
8857
|
}
|
|
@@ -8727,23 +8859,23 @@ async function startAndWaitForPlayCompletionByStream(input) {
|
|
|
8727
8859
|
phase: "cli.play_start_stream_retry",
|
|
8728
8860
|
ms: 0,
|
|
8729
8861
|
ok: true,
|
|
8730
|
-
playName:
|
|
8862
|
+
playName: input2.playName,
|
|
8731
8863
|
attempt: attempt + 1,
|
|
8732
8864
|
reason: playStatusErrorText(status)
|
|
8733
8865
|
});
|
|
8734
8866
|
await sleep4(retryDelayMs);
|
|
8735
8867
|
}
|
|
8736
8868
|
throw new DeeplineError(
|
|
8737
|
-
`Play ${
|
|
8869
|
+
`Play ${input2.playName} did not start after retrying transient start failures.`,
|
|
8738
8870
|
void 0,
|
|
8739
8871
|
"PLAY_START_RETRY_EXHAUSTED"
|
|
8740
8872
|
);
|
|
8741
8873
|
}
|
|
8742
|
-
async function startAndWaitForPlayCompletionByStreamOnce(
|
|
8874
|
+
async function startAndWaitForPlayCompletionByStreamOnce(input2) {
|
|
8743
8875
|
const startedAt = Date.now();
|
|
8744
8876
|
const dashboardUrl = buildPlayDashboardUrl(
|
|
8745
|
-
|
|
8746
|
-
|
|
8877
|
+
input2.client.baseUrl,
|
|
8878
|
+
input2.playName
|
|
8747
8879
|
);
|
|
8748
8880
|
const state = {
|
|
8749
8881
|
lastLogIndex: 0,
|
|
@@ -8757,15 +8889,15 @@ async function startAndWaitForPlayCompletionByStreamOnce(input) {
|
|
|
8757
8889
|
let eventCount = 0;
|
|
8758
8890
|
let firstRunIdMs = null;
|
|
8759
8891
|
let lastPhase = null;
|
|
8760
|
-
const timeout =
|
|
8892
|
+
const timeout = input2.waitTimeoutMs === null ? null : setTimeout(
|
|
8761
8893
|
() => {
|
|
8762
8894
|
timedOut = true;
|
|
8763
8895
|
controller.abort();
|
|
8764
8896
|
},
|
|
8765
|
-
Math.max(1,
|
|
8897
|
+
Math.max(1, input2.waitTimeoutMs)
|
|
8766
8898
|
);
|
|
8767
8899
|
try {
|
|
8768
|
-
for await (const event of
|
|
8900
|
+
for await (const event of input2.client.startPlayRunStream(input2.request, {
|
|
8769
8901
|
signal: controller.signal
|
|
8770
8902
|
})) {
|
|
8771
8903
|
eventCount += 1;
|
|
@@ -8776,55 +8908,55 @@ async function startAndWaitForPlayCompletionByStreamOnce(input) {
|
|
|
8776
8908
|
}
|
|
8777
8909
|
const workflowId = lastKnownWorkflowId || "pending";
|
|
8778
8910
|
if (workflowId !== "pending" && !emittedDashboardUrl) {
|
|
8779
|
-
if (!
|
|
8911
|
+
if (!input2.jsonOutput) {
|
|
8780
8912
|
writeStartedPlayRun({
|
|
8781
8913
|
runId: workflowId,
|
|
8782
|
-
playName:
|
|
8914
|
+
playName: input2.playName,
|
|
8783
8915
|
dashboardUrl,
|
|
8784
8916
|
jsonOutput: false,
|
|
8785
|
-
progress:
|
|
8917
|
+
progress: input2.progress
|
|
8786
8918
|
});
|
|
8787
8919
|
}
|
|
8788
8920
|
openPlayDashboard({
|
|
8789
8921
|
dashboardUrl,
|
|
8790
|
-
jsonOutput:
|
|
8791
|
-
noOpen:
|
|
8922
|
+
jsonOutput: input2.jsonOutput,
|
|
8923
|
+
noOpen: input2.noOpen
|
|
8792
8924
|
});
|
|
8793
|
-
|
|
8925
|
+
input2.progress.phase(`loading play on ${dashboardUrl}`);
|
|
8794
8926
|
emittedDashboardUrl = true;
|
|
8795
8927
|
}
|
|
8796
8928
|
assertPlayWaitNotTimedOut({
|
|
8797
8929
|
workflowId,
|
|
8798
8930
|
startedAt,
|
|
8799
|
-
waitTimeoutMs:
|
|
8931
|
+
waitTimeoutMs: input2.waitTimeoutMs,
|
|
8800
8932
|
lastPhase
|
|
8801
8933
|
});
|
|
8802
8934
|
const phase = describeLiveEventPhase(event);
|
|
8803
8935
|
if (phase) {
|
|
8804
8936
|
lastPhase = phase;
|
|
8805
|
-
|
|
8937
|
+
input2.progress.phase(phase);
|
|
8806
8938
|
}
|
|
8807
8939
|
printPlayLogLines({
|
|
8808
8940
|
lines: getLogLinesFromLiveEvent(event),
|
|
8809
8941
|
status: null,
|
|
8810
|
-
jsonOutput:
|
|
8811
|
-
emitLogs:
|
|
8942
|
+
jsonOutput: input2.jsonOutput,
|
|
8943
|
+
emitLogs: input2.emitLogs,
|
|
8812
8944
|
state,
|
|
8813
|
-
progress:
|
|
8945
|
+
progress: input2.progress
|
|
8814
8946
|
});
|
|
8815
8947
|
emitLiveDebugTableHints({
|
|
8816
8948
|
event,
|
|
8817
|
-
playName:
|
|
8949
|
+
playName: input2.playName,
|
|
8818
8950
|
runId: workflowId,
|
|
8819
|
-
jsonOutput:
|
|
8951
|
+
jsonOutput: input2.jsonOutput,
|
|
8820
8952
|
state,
|
|
8821
|
-
progress:
|
|
8953
|
+
progress: input2.progress
|
|
8822
8954
|
});
|
|
8823
|
-
if (!
|
|
8955
|
+
if (!input2.jsonOutput) {
|
|
8824
8956
|
printPlayProgressLines({
|
|
8825
8957
|
lines: getProgressLinesFromLiveEvent(event),
|
|
8826
8958
|
state,
|
|
8827
|
-
progress:
|
|
8959
|
+
progress: input2.progress
|
|
8828
8960
|
});
|
|
8829
8961
|
}
|
|
8830
8962
|
const finalStatus = getFinalStatusFromLiveEvent(event);
|
|
@@ -8833,7 +8965,7 @@ async function startAndWaitForPlayCompletionByStreamOnce(input) {
|
|
|
8833
8965
|
phase: "cli.play_start_stream_terminal",
|
|
8834
8966
|
ms: Date.now() - startedAt,
|
|
8835
8967
|
ok: true,
|
|
8836
|
-
playName:
|
|
8968
|
+
playName: input2.playName,
|
|
8837
8969
|
workflowId: finalStatus.runId || lastKnownWorkflowId || null,
|
|
8838
8970
|
eventCount,
|
|
8839
8971
|
firstRunIdMs,
|
|
@@ -8847,7 +8979,7 @@ async function startAndWaitForPlayCompletionByStreamOnce(input) {
|
|
|
8847
8979
|
assertPlayWaitNotTimedOut({
|
|
8848
8980
|
workflowId: lastKnownWorkflowId,
|
|
8849
8981
|
startedAt,
|
|
8850
|
-
waitTimeoutMs:
|
|
8982
|
+
waitTimeoutMs: input2.waitTimeoutMs,
|
|
8851
8983
|
lastPhase
|
|
8852
8984
|
});
|
|
8853
8985
|
}
|
|
@@ -8856,7 +8988,7 @@ async function startAndWaitForPlayCompletionByStreamOnce(input) {
|
|
|
8856
8988
|
clearTimeout(timeout);
|
|
8857
8989
|
}
|
|
8858
8990
|
const reason = error instanceof Error ? error.message : String(error);
|
|
8859
|
-
if (!
|
|
8991
|
+
if (!input2.jsonOutput) {
|
|
8860
8992
|
process.stderr.write(
|
|
8861
8993
|
`[play watch] start stream failed after run ${lastKnownWorkflowId}; reconnecting to run stream (${reason})
|
|
8862
8994
|
`
|
|
@@ -8866,7 +8998,7 @@ async function startAndWaitForPlayCompletionByStreamOnce(input) {
|
|
|
8866
8998
|
phase: "cli.play_start_stream_reconnect",
|
|
8867
8999
|
ms: Date.now() - startedAt,
|
|
8868
9000
|
ok: true,
|
|
8869
|
-
playName:
|
|
9001
|
+
playName: input2.playName,
|
|
8870
9002
|
workflowId: lastKnownWorkflowId,
|
|
8871
9003
|
eventCount,
|
|
8872
9004
|
firstRunIdMs,
|
|
@@ -8874,16 +9006,16 @@ async function startAndWaitForPlayCompletionByStreamOnce(input) {
|
|
|
8874
9006
|
reason
|
|
8875
9007
|
});
|
|
8876
9008
|
return waitForPlayCompletionByStream({
|
|
8877
|
-
client:
|
|
8878
|
-
playName:
|
|
9009
|
+
client: input2.client,
|
|
9010
|
+
playName: input2.playName,
|
|
8879
9011
|
workflowId: lastKnownWorkflowId,
|
|
8880
9012
|
dashboardUrl,
|
|
8881
|
-
jsonOutput:
|
|
8882
|
-
emitLogs:
|
|
8883
|
-
waitTimeoutMs:
|
|
9013
|
+
jsonOutput: input2.jsonOutput,
|
|
9014
|
+
emitLogs: input2.emitLogs,
|
|
9015
|
+
waitTimeoutMs: input2.waitTimeoutMs,
|
|
8884
9016
|
startedAt,
|
|
8885
9017
|
state,
|
|
8886
|
-
progress:
|
|
9018
|
+
progress: input2.progress
|
|
8887
9019
|
});
|
|
8888
9020
|
}
|
|
8889
9021
|
throw error;
|
|
@@ -8893,8 +9025,8 @@ async function startAndWaitForPlayCompletionByStreamOnce(input) {
|
|
|
8893
9025
|
}
|
|
8894
9026
|
}
|
|
8895
9027
|
if (lastKnownWorkflowId) {
|
|
8896
|
-
if (!
|
|
8897
|
-
|
|
9028
|
+
if (!input2.jsonOutput) {
|
|
9029
|
+
input2.progress.writeLine(
|
|
8898
9030
|
`[play watch] start stream ended after run ${lastKnownWorkflowId}; reconnecting to run stream`
|
|
8899
9031
|
);
|
|
8900
9032
|
}
|
|
@@ -8902,7 +9034,7 @@ async function startAndWaitForPlayCompletionByStreamOnce(input) {
|
|
|
8902
9034
|
phase: "cli.play_start_stream_reconnect",
|
|
8903
9035
|
ms: Date.now() - startedAt,
|
|
8904
9036
|
ok: true,
|
|
8905
|
-
playName:
|
|
9037
|
+
playName: input2.playName,
|
|
8906
9038
|
workflowId: lastKnownWorkflowId,
|
|
8907
9039
|
eventCount,
|
|
8908
9040
|
firstRunIdMs,
|
|
@@ -8910,16 +9042,16 @@ async function startAndWaitForPlayCompletionByStreamOnce(input) {
|
|
|
8910
9042
|
reason: "stream ended before terminal event"
|
|
8911
9043
|
});
|
|
8912
9044
|
return waitForPlayCompletionByStream({
|
|
8913
|
-
client:
|
|
8914
|
-
playName:
|
|
9045
|
+
client: input2.client,
|
|
9046
|
+
playName: input2.playName,
|
|
8915
9047
|
workflowId: lastKnownWorkflowId,
|
|
8916
9048
|
dashboardUrl,
|
|
8917
|
-
jsonOutput:
|
|
8918
|
-
emitLogs:
|
|
8919
|
-
waitTimeoutMs:
|
|
9049
|
+
jsonOutput: input2.jsonOutput,
|
|
9050
|
+
emitLogs: input2.emitLogs,
|
|
9051
|
+
waitTimeoutMs: input2.waitTimeoutMs,
|
|
8920
9052
|
startedAt,
|
|
8921
9053
|
state,
|
|
8922
|
-
progress:
|
|
9054
|
+
progress: input2.progress
|
|
8923
9055
|
});
|
|
8924
9056
|
}
|
|
8925
9057
|
const phaseSuffix = lastPhase && lastPhase.trim() ? ` (last observed phase: ${lastPhase.trim()})` : "";
|
|
@@ -9000,7 +9132,7 @@ function compactReturnValue(value, depth = 0) {
|
|
|
9000
9132
|
if (!value || typeof value !== "object") {
|
|
9001
9133
|
return value;
|
|
9002
9134
|
}
|
|
9003
|
-
const
|
|
9135
|
+
const output2 = {};
|
|
9004
9136
|
for (const [key, entry] of Object.entries(value)) {
|
|
9005
9137
|
if (depth === 0 && key === "_metadata") {
|
|
9006
9138
|
continue;
|
|
@@ -9011,9 +9143,9 @@ function compactReturnValue(value, depth = 0) {
|
|
|
9011
9143
|
if (key === "access") {
|
|
9012
9144
|
continue;
|
|
9013
9145
|
}
|
|
9014
|
-
|
|
9146
|
+
output2[key] = compactReturnValue(entry, depth + 1);
|
|
9015
9147
|
}
|
|
9016
|
-
return
|
|
9148
|
+
return output2;
|
|
9017
9149
|
}
|
|
9018
9150
|
function formatJsonPreview(value) {
|
|
9019
9151
|
const json = JSON.stringify(value, null, 2);
|
|
@@ -9222,22 +9354,22 @@ function extractBillingForStatus(status, error) {
|
|
|
9222
9354
|
const progressError = getStringField(status.progress, "error");
|
|
9223
9355
|
return extractBillingFromText(error) ?? extractBillingFromText(progressError) ?? getObjectField(status, "billing");
|
|
9224
9356
|
}
|
|
9225
|
-
function formatInsufficientCreditsMessage(
|
|
9226
|
-
const operation = getStringField(
|
|
9227
|
-
const balance = formatCreditAmount(
|
|
9228
|
-
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);
|
|
9229
9361
|
const recommended = formatCreditAmount(
|
|
9230
|
-
|
|
9362
|
+
input2.billing.recommended_add_credits ?? input2.billing.needed_credits
|
|
9231
9363
|
);
|
|
9232
|
-
const billingUrl = getStringField(
|
|
9233
|
-
const workspace = getStringField(
|
|
9364
|
+
const billingUrl = getStringField(input2.billing, "billing_url");
|
|
9365
|
+
const workspace = getStringField(input2.billing, "workspace_id") ?? getStringField(input2.billing, "workspaceId");
|
|
9234
9366
|
const workspaceSuffix = workspace ? ` (workspace=${workspace})` : "";
|
|
9235
9367
|
const addSuffix = billingUrl && recommended !== "-" ? ` Add >=${recommended} at ${billingUrl}.` : billingUrl ? ` Add credits at ${billingUrl}.` : "";
|
|
9236
9368
|
return `Workspace balance ${balance} < required ${required} for ${operation}${workspaceSuffix}.${addSuffix}`;
|
|
9237
9369
|
}
|
|
9238
|
-
function buildInsufficientCreditsSummaryLines(
|
|
9239
|
-
const progress =
|
|
9240
|
-
const rowsInfo = extractCanonicalRowsInfo(
|
|
9370
|
+
function buildInsufficientCreditsSummaryLines(input2) {
|
|
9371
|
+
const progress = input2.status.progress;
|
|
9372
|
+
const rowsInfo = extractCanonicalRowsInfo(input2.status);
|
|
9241
9373
|
const completed = getNumericField(progress, "completed") ?? getNumericField(progress, "completedRows") ?? rowsInfo?.rows.length ?? null;
|
|
9242
9374
|
const total = getNumericField(progress, "total") ?? getNumericField(progress, "totalRows") ?? rowsInfo?.totalRows ?? null;
|
|
9243
9375
|
const lines = [
|
|
@@ -9245,16 +9377,16 @@ function buildInsufficientCreditsSummaryLines(input) {
|
|
|
9245
9377
|
completed === null ? " completed rows: unknown" : ` completed rows: ${formatInteger(completed)}${total !== null ? ` of ${formatInteger(total)}` : ""}`,
|
|
9246
9378
|
" reusable receipts: yes; rerun after adding credits to continue from completed provider work"
|
|
9247
9379
|
];
|
|
9248
|
-
const billingUrl = getStringField(
|
|
9380
|
+
const billingUrl = getStringField(input2.billing, "billing_url");
|
|
9249
9381
|
const recommended = formatCreditAmount(
|
|
9250
|
-
|
|
9382
|
+
input2.billing.recommended_add_credits ?? input2.billing.needed_credits
|
|
9251
9383
|
);
|
|
9252
9384
|
if (billingUrl) {
|
|
9253
9385
|
lines.push(
|
|
9254
9386
|
recommended !== "-" ? ` add credits: add >=${recommended} at ${billingUrl}` : ` add credits: ${billingUrl}`
|
|
9255
9387
|
);
|
|
9256
9388
|
}
|
|
9257
|
-
const runId =
|
|
9389
|
+
const runId = input2.status.runId?.trim();
|
|
9258
9390
|
if (runId) {
|
|
9259
9391
|
lines.push(` inspect: deepline runs get ${runId} --json`);
|
|
9260
9392
|
lines.push(
|
|
@@ -9589,8 +9721,8 @@ function actionToCommand(action) {
|
|
|
9589
9721
|
}
|
|
9590
9722
|
function readFirstDatasetActions(packaged) {
|
|
9591
9723
|
for (const step of readRecordArray(packaged.steps)) {
|
|
9592
|
-
const
|
|
9593
|
-
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;
|
|
9594
9726
|
if (actions) {
|
|
9595
9727
|
return actions;
|
|
9596
9728
|
}
|
|
@@ -9612,12 +9744,12 @@ function buildRunPackageTextLines(packaged) {
|
|
|
9612
9744
|
const id = typeof step.id === "string" ? step.id : "step";
|
|
9613
9745
|
const kind = typeof step.kind === "string" ? step.kind : "step";
|
|
9614
9746
|
const stepStatus = typeof step.status === "string" ? step.status : status;
|
|
9615
|
-
const
|
|
9616
|
-
const rowCount =
|
|
9617
|
-
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;
|
|
9618
9750
|
const previewRows = Array.isArray(preview?.rows) ? preview.rows.length : null;
|
|
9619
9751
|
lines.push(` ${kind} ${id}: ${stepStatus}${rowCount}`);
|
|
9620
|
-
lines.push(...formatPackageDatasetSummaryLines(
|
|
9752
|
+
lines.push(...formatPackageDatasetSummaryLines(output2?.summary));
|
|
9621
9753
|
if (previewRows !== null) {
|
|
9622
9754
|
lines.push(
|
|
9623
9755
|
` preview=${previewRows}${preview?.truncated ? " truncated" : ""}`
|
|
@@ -9700,19 +9832,19 @@ function writePlayResult(status, jsonOutput, options) {
|
|
|
9700
9832
|
` }
|
|
9701
9833
|
);
|
|
9702
9834
|
}
|
|
9703
|
-
async function resolvePlayRunOutputStatus(
|
|
9704
|
-
if (!getPlayRunPackage(
|
|
9705
|
-
return
|
|
9835
|
+
async function resolvePlayRunOutputStatus(input2) {
|
|
9836
|
+
if (!getPlayRunPackage(input2.status)) {
|
|
9837
|
+
return input2.status;
|
|
9706
9838
|
}
|
|
9707
|
-
const runId =
|
|
9839
|
+
const runId = input2.status.runId;
|
|
9708
9840
|
if (!runId) {
|
|
9709
|
-
return
|
|
9841
|
+
return input2.status;
|
|
9710
9842
|
}
|
|
9711
|
-
const refreshedStatus = await
|
|
9843
|
+
const refreshedStatus = await input2.client.getPlayStatus(runId, {
|
|
9712
9844
|
billing: false,
|
|
9713
|
-
full:
|
|
9845
|
+
full: input2.fullJson
|
|
9714
9846
|
});
|
|
9715
|
-
const dashboardUrl =
|
|
9847
|
+
const dashboardUrl = input2.status.dashboardUrl;
|
|
9716
9848
|
return typeof dashboardUrl === "string" ? { ...refreshedStatus, dashboardUrl } : refreshedStatus;
|
|
9717
9849
|
}
|
|
9718
9850
|
var RUN_EXPORT_PAGE_SIZE = 5e3;
|
|
@@ -9743,21 +9875,21 @@ function extractRunPlayName(status) {
|
|
|
9743
9875
|
function normalizeCustomerDbIdentifier(value) {
|
|
9744
9876
|
return value.split("/").pop().replace(/[^A-Za-z0-9]+/g, "_").replace(/^_+|_+$/g, "").toLowerCase();
|
|
9745
9877
|
}
|
|
9746
|
-
function buildCustomerDbQueryPlan(
|
|
9747
|
-
const playName = extractRunPlayName(
|
|
9748
|
-
const tableNamespace =
|
|
9749
|
-
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) {
|
|
9750
9882
|
return null;
|
|
9751
9883
|
}
|
|
9752
9884
|
const tableName = `${normalizeCustomerDbIdentifier(playName)}_${normalizeCustomerDbIdentifier(
|
|
9753
9885
|
tableNamespace
|
|
9754
9886
|
)}`;
|
|
9755
|
-
const sql = `select * from "storage"."${tableName}" where _run_id = ${sqlStringLiteral(
|
|
9756
|
-
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}`;
|
|
9757
9889
|
return {
|
|
9758
9890
|
sql,
|
|
9759
9891
|
json: `${base} --json`,
|
|
9760
|
-
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))}`
|
|
9761
9893
|
};
|
|
9762
9894
|
}
|
|
9763
9895
|
function exportableSheetRow(row) {
|
|
@@ -9808,20 +9940,20 @@ function mergeExportColumns(preferredColumns, rows) {
|
|
|
9808
9940
|
}
|
|
9809
9941
|
return columns;
|
|
9810
9942
|
}
|
|
9811
|
-
async function fetchBackingDatasetRows(
|
|
9812
|
-
const playName = extractRunPlayName(
|
|
9813
|
-
const tableNamespace =
|
|
9943
|
+
async function fetchBackingDatasetRows(input2) {
|
|
9944
|
+
const playName = extractRunPlayName(input2.status);
|
|
9945
|
+
const tableNamespace = input2.rowsInfo.tableNamespace?.trim();
|
|
9814
9946
|
if (!playName || !tableNamespace) {
|
|
9815
9947
|
return null;
|
|
9816
9948
|
}
|
|
9817
9949
|
const sheetRows = [];
|
|
9818
9950
|
let offset = 0;
|
|
9819
|
-
let expectedTotal =
|
|
9951
|
+
let expectedTotal = input2.rowsInfo.totalRows;
|
|
9820
9952
|
while (true) {
|
|
9821
|
-
const page = await
|
|
9953
|
+
const page = await input2.client.runs.exportDatasetRows({
|
|
9822
9954
|
playName,
|
|
9823
9955
|
tableNamespace,
|
|
9824
|
-
runId:
|
|
9956
|
+
runId: input2.status.runId,
|
|
9825
9957
|
limit: RUN_EXPORT_PAGE_SIZE,
|
|
9826
9958
|
offset
|
|
9827
9959
|
});
|
|
@@ -9836,20 +9968,20 @@ async function fetchBackingDatasetRows(input) {
|
|
|
9836
9968
|
offset += page.rows.length;
|
|
9837
9969
|
}
|
|
9838
9970
|
const rows = sheetRows.map(exportableSheetRow).filter((row) => Boolean(row));
|
|
9839
|
-
if (rows.length <
|
|
9971
|
+
if (rows.length < input2.rowsInfo.totalRows) {
|
|
9840
9972
|
return null;
|
|
9841
9973
|
}
|
|
9842
9974
|
const columns = mergeExportColumns(
|
|
9843
|
-
|
|
9975
|
+
input2.rowsInfo.columnsExplicit ? input2.rowsInfo.columns : [],
|
|
9844
9976
|
rows
|
|
9845
9977
|
);
|
|
9846
9978
|
return {
|
|
9847
|
-
...
|
|
9979
|
+
...input2.rowsInfo,
|
|
9848
9980
|
rows,
|
|
9849
9981
|
columns,
|
|
9850
9982
|
totalRows: rows.length,
|
|
9851
9983
|
complete: true,
|
|
9852
|
-
source: `${
|
|
9984
|
+
source: `${input2.rowsInfo.source ?? "result.rows"} -> /api/v2/plays/${playName}/sheet?tableNamespace=${tableNamespace}`
|
|
9853
9985
|
};
|
|
9854
9986
|
}
|
|
9855
9987
|
async function exportPlayStatusRows(client, status, outPath, options = {}) {
|
|
@@ -9951,11 +10083,11 @@ function extractActiveRunsFromError(error) {
|
|
|
9951
10083
|
function activeRunId(run) {
|
|
9952
10084
|
return getStringField(run, "workflowId") ?? getStringField(run, "runId");
|
|
9953
10085
|
}
|
|
9954
|
-
function formatActiveRunConflictError(
|
|
10086
|
+
function formatActiveRunConflictError(input2) {
|
|
9955
10087
|
const lines = [
|
|
9956
|
-
`Active run exists for ${
|
|
10088
|
+
`Active run exists for ${input2.playName}. Use --force to supersede, or inspect/stop the active run first.`
|
|
9957
10089
|
];
|
|
9958
|
-
for (const run of
|
|
10090
|
+
for (const run of input2.activeRuns.slice(0, 3)) {
|
|
9959
10091
|
const runId = activeRunId(run);
|
|
9960
10092
|
if (!runId) {
|
|
9961
10093
|
continue;
|
|
@@ -10069,49 +10201,49 @@ function renderServerResultView(value) {
|
|
|
10069
10201
|
}
|
|
10070
10202
|
return { lines: lines.length > 1 ? lines : [], actions: [] };
|
|
10071
10203
|
}
|
|
10072
|
-
function writeStartedPlayRun(
|
|
10073
|
-
if (
|
|
10074
|
-
if (
|
|
10075
|
-
printCommandEnvelope(
|
|
10204
|
+
function writeStartedPlayRun(input2) {
|
|
10205
|
+
if (input2.package && isPlayRunPackageValue(input2.package)) {
|
|
10206
|
+
if (input2.jsonOutput) {
|
|
10207
|
+
printCommandEnvelope(input2.package, { json: true });
|
|
10076
10208
|
return;
|
|
10077
10209
|
}
|
|
10078
|
-
const lines2 = buildRunPackageTextLines(
|
|
10079
|
-
const
|
|
10080
|
-
if (
|
|
10081
|
-
|
|
10210
|
+
const lines2 = buildRunPackageTextLines(input2.package);
|
|
10211
|
+
const output3 = lines2.join("\n");
|
|
10212
|
+
if (input2.progress) {
|
|
10213
|
+
input2.progress.writeLine(output3, process.stdout);
|
|
10082
10214
|
return;
|
|
10083
10215
|
}
|
|
10084
|
-
printCommandEnvelope(
|
|
10216
|
+
printCommandEnvelope(input2.package, {
|
|
10085
10217
|
json: false,
|
|
10086
|
-
text: `${
|
|
10218
|
+
text: `${output3}
|
|
10087
10219
|
`
|
|
10088
10220
|
});
|
|
10089
10221
|
return;
|
|
10090
10222
|
}
|
|
10091
10223
|
const payload = {
|
|
10092
|
-
runId:
|
|
10093
|
-
workflowId:
|
|
10094
|
-
name:
|
|
10095
|
-
status:
|
|
10096
|
-
dashboardUrl:
|
|
10224
|
+
runId: input2.runId,
|
|
10225
|
+
workflowId: input2.runId,
|
|
10226
|
+
name: input2.playName,
|
|
10227
|
+
status: input2.status ?? "started",
|
|
10228
|
+
dashboardUrl: input2.dashboardUrl,
|
|
10097
10229
|
next: {
|
|
10098
|
-
inspect: `deepline runs get ${
|
|
10099
|
-
full: `deepline runs get ${
|
|
10100
|
-
logs: `deepline runs logs ${
|
|
10101
|
-
export: `deepline runs export ${
|
|
10102
|
-
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`
|
|
10103
10235
|
}
|
|
10104
10236
|
};
|
|
10105
10237
|
const lines = [
|
|
10106
|
-
`Started ${
|
|
10107
|
-
` run id: ${
|
|
10108
|
-
` inspect: deepline runs get ${
|
|
10109
|
-
` full debug: deepline runs get ${
|
|
10110
|
-
` logs: deepline runs logs ${
|
|
10111
|
-
` export after completion: deepline runs export ${
|
|
10112
|
-
` 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`
|
|
10113
10245
|
];
|
|
10114
|
-
if (
|
|
10246
|
+
if (input2.jsonOutput) {
|
|
10115
10247
|
printCommandEnvelope(
|
|
10116
10248
|
{
|
|
10117
10249
|
...payload,
|
|
@@ -10121,12 +10253,12 @@ function writeStartedPlayRun(input) {
|
|
|
10121
10253
|
);
|
|
10122
10254
|
return;
|
|
10123
10255
|
}
|
|
10124
|
-
if (
|
|
10125
|
-
lines.push(` play page: ${
|
|
10256
|
+
if (input2.dashboardUrl) {
|
|
10257
|
+
lines.push(` play page: ${input2.dashboardUrl}`);
|
|
10126
10258
|
}
|
|
10127
|
-
const
|
|
10128
|
-
if (
|
|
10129
|
-
|
|
10259
|
+
const output2 = lines.join("\n");
|
|
10260
|
+
if (input2.progress) {
|
|
10261
|
+
input2.progress.writeLine(output2, process.stdout);
|
|
10130
10262
|
return;
|
|
10131
10263
|
}
|
|
10132
10264
|
printCommandEnvelope(
|
|
@@ -10134,7 +10266,7 @@ function writeStartedPlayRun(input) {
|
|
|
10134
10266
|
...payload,
|
|
10135
10267
|
render: { sections: [{ title: "play run", lines }] }
|
|
10136
10268
|
},
|
|
10137
|
-
{ json: false, text: `${
|
|
10269
|
+
{ json: false, text: `${output2}
|
|
10138
10270
|
` }
|
|
10139
10271
|
);
|
|
10140
10272
|
}
|
|
@@ -10142,7 +10274,7 @@ function parsePlayRunOptions(args) {
|
|
|
10142
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.";
|
|
10143
10275
|
let filePath = null;
|
|
10144
10276
|
let playName = null;
|
|
10145
|
-
let
|
|
10277
|
+
let input2 = null;
|
|
10146
10278
|
let revisionId = null;
|
|
10147
10279
|
let revisionSelector = null;
|
|
10148
10280
|
const watch = !args.includes("--no-wait");
|
|
@@ -10163,7 +10295,7 @@ function parsePlayRunOptions(args) {
|
|
|
10163
10295
|
continue;
|
|
10164
10296
|
}
|
|
10165
10297
|
if ((arg === "--input" || arg === "-i") && args[index + 1]) {
|
|
10166
|
-
|
|
10298
|
+
input2 = parseJsonInput(args[++index]);
|
|
10167
10299
|
continue;
|
|
10168
10300
|
}
|
|
10169
10301
|
if (arg === "--revision-id" && args[index + 1]) {
|
|
@@ -10212,8 +10344,8 @@ function parsePlayRunOptions(args) {
|
|
|
10212
10344
|
}
|
|
10213
10345
|
if (arg.startsWith("--")) {
|
|
10214
10346
|
const { path, value } = parseInputFieldFlag(arg, args[index + 1]);
|
|
10215
|
-
|
|
10216
|
-
setDottedInputValue(
|
|
10347
|
+
input2 ??= {};
|
|
10348
|
+
setDottedInputValue(input2, path, parseInputFlagValue(value));
|
|
10217
10349
|
if (!arg.includes("=")) {
|
|
10218
10350
|
index += 1;
|
|
10219
10351
|
}
|
|
@@ -10248,7 +10380,7 @@ function parsePlayRunOptions(args) {
|
|
|
10248
10380
|
}
|
|
10249
10381
|
return {
|
|
10250
10382
|
target: filePath ? { kind: "file", path: filePath } : { kind: "name", name: playName },
|
|
10251
|
-
input,
|
|
10383
|
+
input: input2,
|
|
10252
10384
|
revisionId,
|
|
10253
10385
|
revisionSelector,
|
|
10254
10386
|
watch,
|
|
@@ -10615,15 +10747,15 @@ async function handleFileBackedRun(options) {
|
|
|
10615
10747
|
});
|
|
10616
10748
|
return 0;
|
|
10617
10749
|
}
|
|
10618
|
-
async function resolveNamedRunRevisionId(
|
|
10619
|
-
if (
|
|
10620
|
-
return
|
|
10750
|
+
async function resolveNamedRunRevisionId(input2) {
|
|
10751
|
+
if (input2.revisionId) {
|
|
10752
|
+
return input2.revisionId;
|
|
10621
10753
|
}
|
|
10622
|
-
if (
|
|
10623
|
-
const versions = await
|
|
10754
|
+
if (input2.selector === "latest") {
|
|
10755
|
+
const versions = await input2.client.listPlayVersions(input2.playName);
|
|
10624
10756
|
const latest = versions[0];
|
|
10625
10757
|
if (!latest?._id) {
|
|
10626
|
-
throw new Error(`No saved revisions found for ${
|
|
10758
|
+
throw new Error(`No saved revisions found for ${input2.playName}.`);
|
|
10627
10759
|
}
|
|
10628
10760
|
return latest._id;
|
|
10629
10761
|
}
|
|
@@ -12096,6 +12228,543 @@ Examples:
|
|
|
12096
12228
|
...options.json ? ["--json"] : []
|
|
12097
12229
|
]);
|
|
12098
12230
|
});
|
|
12231
|
+
const share = play.command("share").description(
|
|
12232
|
+
"Manage a play's public, unlisted share page (advanced \u2014 exposes play code)."
|
|
12233
|
+
).addHelpText(
|
|
12234
|
+
"after",
|
|
12235
|
+
`
|
|
12236
|
+
Concepts:
|
|
12237
|
+
A share page is a public, unlisted, SEO-indexable landing page for a play,
|
|
12238
|
+
pinned to one revision. Publish only after the play has run successfully.
|
|
12239
|
+
|
|
12240
|
+
NOT RECOMMENDED by default. Only publish when the user has explicitly asked
|
|
12241
|
+
to share this play AND has confirmed they accept the risks below. When in
|
|
12242
|
+
doubt, leave the play unpublished.
|
|
12243
|
+
|
|
12244
|
+
What is exposed:
|
|
12245
|
+
Run results and row-level data are NEVER exposed. But the page renders the
|
|
12246
|
+
play's STRUCTURE and anything baked into its source code: step names,
|
|
12247
|
+
input/output field names, tool ids, step descriptions/prompts, and any
|
|
12248
|
+
hardcoded string literals or comments in the play file. If the source
|
|
12249
|
+
contains PII, internal domains/emails, secrets-by-mistake, or proprietary
|
|
12250
|
+
business logic, publishing makes it publicly viewable and search-indexable.
|
|
12251
|
+
|
|
12252
|
+
Review the play source for sensitive content before publishing. Use
|
|
12253
|
+
--seo noindex to keep the page out of search engines if you must share it.
|
|
12254
|
+
|
|
12255
|
+
Examples:
|
|
12256
|
+
deepline plays share status company-to-contact --json
|
|
12257
|
+
deepline plays share publish company-to-contact --yes
|
|
12258
|
+
deepline plays share publish company-to-contact --version 3 --seo noindex --yes
|
|
12259
|
+
deepline plays share update company-to-contact --show-latency --json
|
|
12260
|
+
deepline plays share regenerate company-to-contact --json
|
|
12261
|
+
deepline plays share unpublish company-to-contact --yes
|
|
12262
|
+
`
|
|
12263
|
+
);
|
|
12264
|
+
share.command("status <play>").description("Show a play's share-page status and revision picker.").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (playName, options) => {
|
|
12265
|
+
process.exitCode = await handlePlayShareStatus([
|
|
12266
|
+
playName,
|
|
12267
|
+
...options.json ? ["--json"] : []
|
|
12268
|
+
]);
|
|
12269
|
+
});
|
|
12270
|
+
share.command("publish <play>").description(
|
|
12271
|
+
"Publish/repoint a PUBLIC page to a revision. Advanced; not recommended unless explicitly requested and risks confirmed."
|
|
12272
|
+
).option("--latest", "Publish the newest revision (default).").option("--version <n>", "Publish a specific version number.").option("--revision-id <id>", "Publish a specific revision id.").option("--seo <mode>", "SEO indexing: index | noindex.").option("--show-cost", "Show average Deepline credit cost on the page.").option("--show-latency", "Show average latency on the page.").option("--no-run-check", 'Skip the "must have a completed run" gate.').option(
|
|
12273
|
+
"-y, --yes",
|
|
12274
|
+
"Confirm public exposure of the play code/structure (required)."
|
|
12275
|
+
).option("--dry-run", "Show the planned publish without writing.").option("--json", "Emit JSON output. Also automatic when stdout is piped").addHelpText(
|
|
12276
|
+
"after",
|
|
12277
|
+
`
|
|
12278
|
+
WARNING \u2014 not recommended by default.
|
|
12279
|
+
Only run when the user has explicitly asked to share this play AND has
|
|
12280
|
+
confirmed they accept the exposure risks. Otherwise, do not publish.
|
|
12281
|
+
|
|
12282
|
+
Mutates cloud state. Creates a PUBLIC, SEO-indexable (unless --seo noindex),
|
|
12283
|
+
unlisted page; requires --yes to acknowledge it is publicly viewable.
|
|
12284
|
+
|
|
12285
|
+
Run results and row data are NEVER exposed. The page DOES expose the play's
|
|
12286
|
+
code/structure: step names, input/output field names, tool ids, step
|
|
12287
|
+
descriptions/prompts, and any hardcoded literals or comments in the source.
|
|
12288
|
+
This may reveal PII, internal domains/emails, or proprietary logic if such
|
|
12289
|
+
content lives in the play file. Review the source before publishing.
|
|
12290
|
+
|
|
12291
|
+
Exit codes: 0 ok; 2 usage/missing --yes; 4 play or version not found;
|
|
12292
|
+
7 no successful run for the play.
|
|
12293
|
+
|
|
12294
|
+
Examples:
|
|
12295
|
+
deepline plays share publish company-to-contact --yes
|
|
12296
|
+
deepline plays share publish company-to-contact --version 3 --seo noindex --yes --json
|
|
12297
|
+
`
|
|
12298
|
+
).action(async (playName, options) => {
|
|
12299
|
+
process.exitCode = await handlePlaySharePublish([
|
|
12300
|
+
playName,
|
|
12301
|
+
...options.latest ? ["--latest"] : [],
|
|
12302
|
+
...options.version ? ["--version", String(options.version)] : [],
|
|
12303
|
+
...options.revisionId ? ["--revision-id", options.revisionId] : [],
|
|
12304
|
+
...options.seo ? ["--seo", options.seo] : [],
|
|
12305
|
+
...options.showCost ? ["--show-cost"] : [],
|
|
12306
|
+
...options.showLatency ? ["--show-latency"] : [],
|
|
12307
|
+
...options.runCheck === false ? ["--no-run-check"] : [],
|
|
12308
|
+
...options.yes ? ["--yes"] : [],
|
|
12309
|
+
...options.dryRun ? ["--dry-run"] : [],
|
|
12310
|
+
...options.json ? ["--json"] : []
|
|
12311
|
+
]);
|
|
12312
|
+
});
|
|
12313
|
+
share.command("update <play>").description("Update share-page settings without moving the pointer.").option("--seo <mode>", "SEO indexing: index | noindex.").option("--show-cost", "Show average Deepline credit cost.").option("--hide-cost", "Hide average Deepline credit cost.").option("--show-latency", "Show average latency.").option("--hide-latency", "Hide average latency.").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (playName, options) => {
|
|
12314
|
+
process.exitCode = await handlePlayShareUpdate([
|
|
12315
|
+
playName,
|
|
12316
|
+
...options.seo ? ["--seo", options.seo] : [],
|
|
12317
|
+
...options.showCost ? ["--show-cost"] : [],
|
|
12318
|
+
...options.hideCost ? ["--hide-cost"] : [],
|
|
12319
|
+
...options.showLatency ? ["--show-latency"] : [],
|
|
12320
|
+
...options.hideLatency ? ["--hide-latency"] : [],
|
|
12321
|
+
...options.json ? ["--json"] : []
|
|
12322
|
+
]);
|
|
12323
|
+
});
|
|
12324
|
+
share.command("regenerate <play>").description("Regenerate the public page's LLM copy for a revision.").option("--version <n>", "Regenerate a specific version number.").option("--revision-id <id>", "Regenerate a specific revision id.").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (playName, options) => {
|
|
12325
|
+
process.exitCode = await handlePlayShareRegenerate([
|
|
12326
|
+
playName,
|
|
12327
|
+
...options.version ? ["--version", String(options.version)] : [],
|
|
12328
|
+
...options.revisionId ? ["--revision-id", options.revisionId] : [],
|
|
12329
|
+
...options.json ? ["--json"] : []
|
|
12330
|
+
]);
|
|
12331
|
+
});
|
|
12332
|
+
share.command("unpublish <play>").description(
|
|
12333
|
+
"Unshare: permanently delete the public page (frees it). Requires --yes."
|
|
12334
|
+
).option("-y, --yes", "Confirm taking the public page down (required).").option("--json", "Emit JSON output. Also automatic when stdout is piped").addHelpText(
|
|
12335
|
+
"after",
|
|
12336
|
+
`
|
|
12337
|
+
Mutates cloud state. Hard-deletes the page + its generated cards; the URL stops
|
|
12338
|
+
resolving. Org-admin only. Exit codes: 0 ok; 2 usage/missing --yes; 4 play not
|
|
12339
|
+
found.
|
|
12340
|
+
|
|
12341
|
+
Examples:
|
|
12342
|
+
deepline plays share unpublish company-to-contact --yes
|
|
12343
|
+
`
|
|
12344
|
+
).action(async (playName, options) => {
|
|
12345
|
+
process.exitCode = await handlePlayShareUnpublish([
|
|
12346
|
+
playName,
|
|
12347
|
+
...options.yes ? ["--yes"] : [],
|
|
12348
|
+
...options.json ? ["--json"] : []
|
|
12349
|
+
]);
|
|
12350
|
+
});
|
|
12351
|
+
}
|
|
12352
|
+
function shareFlagValue(args, flag) {
|
|
12353
|
+
const i = args.indexOf(flag);
|
|
12354
|
+
return i >= 0 && i + 1 < args.length ? args[i + 1] : void 0;
|
|
12355
|
+
}
|
|
12356
|
+
async function handlePlayShareStatus(args) {
|
|
12357
|
+
const target = args[0];
|
|
12358
|
+
if (!target) {
|
|
12359
|
+
console.error("Usage: deepline plays share status <play> [--json]");
|
|
12360
|
+
return 2;
|
|
12361
|
+
}
|
|
12362
|
+
const name = parseReferencedPlayTarget2(target).playName;
|
|
12363
|
+
const status = await new DeeplineClient().getSharePage(name);
|
|
12364
|
+
if (argsWantJson(args)) {
|
|
12365
|
+
process.stdout.write(`${JSON.stringify(status)}
|
|
12366
|
+
`);
|
|
12367
|
+
return 0;
|
|
12368
|
+
}
|
|
12369
|
+
if (!status.share) {
|
|
12370
|
+
console.log(`${status.playName}: not published.`);
|
|
12371
|
+
console.log(
|
|
12372
|
+
` Publish: deepline plays share publish ${status.playName} --yes`
|
|
12373
|
+
);
|
|
12374
|
+
return 0;
|
|
12375
|
+
}
|
|
12376
|
+
console.log(`${status.playName}: published v${status.share.publishedVersion}`);
|
|
12377
|
+
console.log(` url: ${status.share.publicPath}`);
|
|
12378
|
+
console.log(` seo: ${status.share.seoIndexing}`);
|
|
12379
|
+
console.log(
|
|
12380
|
+
` show: cost=${status.share.showAverageDeeplineCost} latency=${status.share.showAverageLatency}`
|
|
12381
|
+
);
|
|
12382
|
+
return 0;
|
|
12383
|
+
}
|
|
12384
|
+
async function handlePlaySharePublish(args) {
|
|
12385
|
+
const target = args[0];
|
|
12386
|
+
if (!target) {
|
|
12387
|
+
console.error(
|
|
12388
|
+
"Usage: deepline plays share publish <play> (--latest | --version <n> | --revision-id <id>) --yes [--seo index|noindex] [--show-cost] [--show-latency] [--json]"
|
|
12389
|
+
);
|
|
12390
|
+
return 2;
|
|
12391
|
+
}
|
|
12392
|
+
if (!args.includes("--yes")) {
|
|
12393
|
+
console.error(
|
|
12394
|
+
"Publishing creates a PUBLIC, SEO-indexable page. NOT recommended unless\nyou explicitly intend to share this play and accept the risks.\nRun results stay private, but the page exposes the play CODE: step names,\nfield names, tool ids, prompts/descriptions, and any hardcoded literals or\ncomments in the source \u2014 which may reveal PII or proprietary logic.\nReview the play source, then re-run with --yes to confirm."
|
|
12395
|
+
);
|
|
12396
|
+
return 2;
|
|
12397
|
+
}
|
|
12398
|
+
const name = parseReferencedPlayTarget2(target).playName;
|
|
12399
|
+
const client = new DeeplineClient();
|
|
12400
|
+
let revisionId = shareFlagValue(args, "--revision-id");
|
|
12401
|
+
let resolvedVersion;
|
|
12402
|
+
if (!revisionId) {
|
|
12403
|
+
const versions = await client.listPlayVersions(name);
|
|
12404
|
+
if (versions.length === 0) {
|
|
12405
|
+
console.error(
|
|
12406
|
+
`No saved revisions for ${name}. Run \`deepline plays set-live ${name}\` first.`
|
|
12407
|
+
);
|
|
12408
|
+
return 4;
|
|
12409
|
+
}
|
|
12410
|
+
const versionFlag = shareFlagValue(args, "--version");
|
|
12411
|
+
const chosen = versionFlag ? versions.find((r) => r.version === Number(versionFlag)) : versions[0];
|
|
12412
|
+
if (!chosen) {
|
|
12413
|
+
console.error(`Version ${versionFlag} not found for ${name}.`);
|
|
12414
|
+
return 4;
|
|
12415
|
+
}
|
|
12416
|
+
if (!chosen._id) {
|
|
12417
|
+
console.error("Resolved revision is missing an id.");
|
|
12418
|
+
return 5;
|
|
12419
|
+
}
|
|
12420
|
+
revisionId = chosen._id;
|
|
12421
|
+
resolvedVersion = chosen.version;
|
|
12422
|
+
}
|
|
12423
|
+
if (!args.includes("--no-run-check")) {
|
|
12424
|
+
const runs = await client.listRuns({ play: name });
|
|
12425
|
+
const hasCompleted = runs.some(
|
|
12426
|
+
(r) => String(r.status).toLowerCase() === "completed"
|
|
12427
|
+
);
|
|
12428
|
+
if (!hasCompleted) {
|
|
12429
|
+
const message = `No completed run for ${name}. Publish a play only after it has run successfully. (Override with --no-run-check.)`;
|
|
12430
|
+
if (argsWantJson(args)) {
|
|
12431
|
+
process.stdout.write(
|
|
12432
|
+
`${JSON.stringify({ ok: false, code: "NO_SUCCESSFUL_RUN", message, next: `deepline plays run ${name} --wait` })}
|
|
12433
|
+
`
|
|
12434
|
+
);
|
|
12435
|
+
} else {
|
|
12436
|
+
console.error(message);
|
|
12437
|
+
console.error(` deepline plays run ${name} --wait`);
|
|
12438
|
+
}
|
|
12439
|
+
return 7;
|
|
12440
|
+
}
|
|
12441
|
+
}
|
|
12442
|
+
const seo = shareFlagValue(args, "--seo");
|
|
12443
|
+
const seoIndexing = seo === "index" ? "index" : seo === "noindex" ? "noindex" : void 0;
|
|
12444
|
+
const request = {
|
|
12445
|
+
revisionId,
|
|
12446
|
+
acknowledgedUnlisted: true,
|
|
12447
|
+
showAverageDeeplineCost: args.includes("--show-cost"),
|
|
12448
|
+
showAverageLatency: args.includes("--show-latency"),
|
|
12449
|
+
...seoIndexing ? { seoIndexing } : {}
|
|
12450
|
+
};
|
|
12451
|
+
if (args.includes("--dry-run")) {
|
|
12452
|
+
const plan = { dryRun: true, name, version: resolvedVersion, ...request };
|
|
12453
|
+
if (argsWantJson(args)) {
|
|
12454
|
+
process.stdout.write(`${JSON.stringify(plan)}
|
|
12455
|
+
`);
|
|
12456
|
+
} else {
|
|
12457
|
+
console.log(
|
|
12458
|
+
`Would publish ${name}${resolvedVersion ? ` v${resolvedVersion}` : ""} (revision ${revisionId}).`
|
|
12459
|
+
);
|
|
12460
|
+
}
|
|
12461
|
+
return 0;
|
|
12462
|
+
}
|
|
12463
|
+
const status = await client.publishSharePage(name, request);
|
|
12464
|
+
if (argsWantJson(args)) {
|
|
12465
|
+
process.stdout.write(`${JSON.stringify(status)}
|
|
12466
|
+
`);
|
|
12467
|
+
return 0;
|
|
12468
|
+
}
|
|
12469
|
+
console.log(
|
|
12470
|
+
`Published ${name}${status.share ? ` v${status.share.publishedVersion}` : ""}: ${status.share?.publicPath ?? ""}`
|
|
12471
|
+
);
|
|
12472
|
+
if (status.warning) {
|
|
12473
|
+
console.error(`warning: ${status.warning}`);
|
|
12474
|
+
}
|
|
12475
|
+
return 0;
|
|
12476
|
+
}
|
|
12477
|
+
async function handlePlayShareUpdate(args) {
|
|
12478
|
+
const target = args[0];
|
|
12479
|
+
if (!target) {
|
|
12480
|
+
console.error(
|
|
12481
|
+
"Usage: deepline plays share update <play> [--seo index|noindex] [--show-cost|--hide-cost] [--show-latency|--hide-latency] [--json]"
|
|
12482
|
+
);
|
|
12483
|
+
return 2;
|
|
12484
|
+
}
|
|
12485
|
+
const name = parseReferencedPlayTarget2(target).playName;
|
|
12486
|
+
const seo = shareFlagValue(args, "--seo");
|
|
12487
|
+
const seoIndexing = seo === "index" ? "index" : seo === "noindex" ? "noindex" : void 0;
|
|
12488
|
+
const request = {
|
|
12489
|
+
...args.includes("--show-cost") ? { showAverageDeeplineCost: true } : args.includes("--hide-cost") ? { showAverageDeeplineCost: false } : {},
|
|
12490
|
+
...args.includes("--show-latency") ? { showAverageLatency: true } : args.includes("--hide-latency") ? { showAverageLatency: false } : {},
|
|
12491
|
+
...seoIndexing ? { seoIndexing } : {}
|
|
12492
|
+
};
|
|
12493
|
+
const status = await new DeeplineClient().updateSharePage(name, request);
|
|
12494
|
+
if (argsWantJson(args)) {
|
|
12495
|
+
process.stdout.write(`${JSON.stringify(status)}
|
|
12496
|
+
`);
|
|
12497
|
+
return 0;
|
|
12498
|
+
}
|
|
12499
|
+
console.log(`Updated ${name} share settings.`);
|
|
12500
|
+
return 0;
|
|
12501
|
+
}
|
|
12502
|
+
async function handlePlayShareRegenerate(args) {
|
|
12503
|
+
const target = args[0];
|
|
12504
|
+
if (!target) {
|
|
12505
|
+
console.error(
|
|
12506
|
+
"Usage: deepline plays share regenerate <play> [--version <n> | --revision-id <id>] [--json]"
|
|
12507
|
+
);
|
|
12508
|
+
return 2;
|
|
12509
|
+
}
|
|
12510
|
+
const name = parseReferencedPlayTarget2(target).playName;
|
|
12511
|
+
const client = new DeeplineClient();
|
|
12512
|
+
let revisionId = shareFlagValue(args, "--revision-id");
|
|
12513
|
+
const versionFlag = shareFlagValue(args, "--version");
|
|
12514
|
+
if (!revisionId && versionFlag) {
|
|
12515
|
+
const versions = await client.listPlayVersions(name);
|
|
12516
|
+
const chosen = versions.find((r) => r.version === Number(versionFlag));
|
|
12517
|
+
if (!chosen?._id) {
|
|
12518
|
+
console.error(`Version ${versionFlag} not found for ${name}.`);
|
|
12519
|
+
return 4;
|
|
12520
|
+
}
|
|
12521
|
+
revisionId = chosen._id;
|
|
12522
|
+
}
|
|
12523
|
+
const status = await client.regenerateSharePage(
|
|
12524
|
+
name,
|
|
12525
|
+
revisionId ? { revisionId } : {}
|
|
12526
|
+
);
|
|
12527
|
+
if (argsWantJson(args)) {
|
|
12528
|
+
process.stdout.write(`${JSON.stringify(status)}
|
|
12529
|
+
`);
|
|
12530
|
+
return 0;
|
|
12531
|
+
}
|
|
12532
|
+
console.log(`Regenerated public copy for ${name}.`);
|
|
12533
|
+
return 0;
|
|
12534
|
+
}
|
|
12535
|
+
async function handlePlayShareUnpublish(args) {
|
|
12536
|
+
const target = args[0];
|
|
12537
|
+
if (!target) {
|
|
12538
|
+
console.error("Usage: deepline plays share unpublish <play> --yes [--json]");
|
|
12539
|
+
return 2;
|
|
12540
|
+
}
|
|
12541
|
+
if (!args.includes("--yes")) {
|
|
12542
|
+
console.error(
|
|
12543
|
+
"Unpublishing permanently deletes the public page and frees its URL.\nRe-run with --yes to confirm."
|
|
12544
|
+
);
|
|
12545
|
+
return 2;
|
|
12546
|
+
}
|
|
12547
|
+
const name = parseReferencedPlayTarget2(target).playName;
|
|
12548
|
+
const status = await new DeeplineClient().unpublishSharePage(name);
|
|
12549
|
+
if (argsWantJson(args)) {
|
|
12550
|
+
process.stdout.write(`${JSON.stringify(status)}
|
|
12551
|
+
`);
|
|
12552
|
+
return 0;
|
|
12553
|
+
}
|
|
12554
|
+
console.log(`Unpublished ${name}; the public page has been removed.`);
|
|
12555
|
+
return 0;
|
|
12556
|
+
}
|
|
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
|
+
);
|
|
12099
12768
|
}
|
|
12100
12769
|
|
|
12101
12770
|
// src/cli/commands/tools.ts
|
|
@@ -13303,25 +13972,25 @@ function shellQuote(value) {
|
|
|
13303
13972
|
function powerShellQuote(value) {
|
|
13304
13973
|
return `'${value.replace(/'/g, "''")}'`;
|
|
13305
13974
|
}
|
|
13306
|
-
function seedToolListScript(
|
|
13307
|
-
const stem = safeFileStem(
|
|
13975
|
+
function seedToolListScript(input2) {
|
|
13976
|
+
const stem = safeFileStem(input2.toolId);
|
|
13308
13977
|
const fileName = `${stem}-workflow-seed-${Date.now()}.play.ts`;
|
|
13309
13978
|
const scriptDir = (0, import_node_fs12.mkdtempSync)((0, import_node_path14.join)((0, import_node_os8.tmpdir)(), "deepline-workflow-seed-"));
|
|
13310
13979
|
(0, import_node_fs12.chmodSync)(scriptDir, 448);
|
|
13311
13980
|
const scriptPath = (0, import_node_path14.join)(scriptDir, fileName);
|
|
13312
13981
|
const projectDir = `deepline/projects/${stem}-workflow`;
|
|
13313
13982
|
const playName = `${stem}-workflow`;
|
|
13314
|
-
const sampleRows =
|
|
13315
|
-
const columns = Object.keys(
|
|
13316
|
-
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)";
|
|
13317
13986
|
const script = `import { definePlay } from 'deepline';
|
|
13318
13987
|
|
|
13319
13988
|
export default definePlay(${JSON.stringify(playName)}, async (ctx) => {
|
|
13320
13989
|
const result = await ctx.tools.execute({
|
|
13321
|
-
id: ${JSON.stringify(
|
|
13322
|
-
tool: ${JSON.stringify(
|
|
13323
|
-
input: ${JSON.stringify(
|
|
13324
|
-
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.`)},
|
|
13325
13994
|
});
|
|
13326
13995
|
|
|
13327
13996
|
const list = Object.values(result.extractedLists)[0];
|
|
@@ -13353,23 +14022,23 @@ export default definePlay(${JSON.stringify(playName)}, async (ctx) => {
|
|
|
13353
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}`)}`
|
|
13354
14023
|
};
|
|
13355
14024
|
}
|
|
13356
|
-
function buildToolExecuteBaseEnvelope(
|
|
13357
|
-
const envelope = commandEnvelopeFromRawResponse(
|
|
13358
|
-
const summaryEntries = Object.entries(
|
|
13359
|
-
const outputPreview =
|
|
14025
|
+
function buildToolExecuteBaseEnvelope(input2) {
|
|
14026
|
+
const envelope = commandEnvelopeFromRawResponse(input2.rawResponse);
|
|
14027
|
+
const summaryEntries = Object.entries(input2.summary);
|
|
14028
|
+
const outputPreview = input2.listConversion ? {
|
|
13360
14029
|
kind: "list",
|
|
13361
|
-
rowCount:
|
|
13362
|
-
columns: Object.keys(
|
|
13363
|
-
preview:
|
|
13364
|
-
listStrategy:
|
|
13365
|
-
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
|
|
13366
14035
|
} : {
|
|
13367
14036
|
kind: summaryEntries.length > 0 ? "object" : "raw",
|
|
13368
|
-
summary:
|
|
14037
|
+
summary: input2.summary
|
|
13369
14038
|
};
|
|
13370
14039
|
const envelopeHasCanonicalOutput = isRecord5(envelope.toolResponse) && Object.prototype.hasOwnProperty.call(envelope.toolResponse, "raw");
|
|
13371
|
-
const inspectCommand = `deepline tools execute ${
|
|
13372
|
-
const actions =
|
|
14040
|
+
const inspectCommand = `deepline tools execute ${input2.toolId} --input ${shellQuote(JSON.stringify(input2.params))} --json`;
|
|
14041
|
+
const actions = input2.listConversion ? [
|
|
13373
14042
|
{
|
|
13374
14043
|
label: "next",
|
|
13375
14044
|
command: "move starter script into a project folder and expand it into a Deepline play"
|
|
@@ -13378,24 +14047,24 @@ function buildToolExecuteBaseEnvelope(input) {
|
|
|
13378
14047
|
return {
|
|
13379
14048
|
...envelope,
|
|
13380
14049
|
...envelopeHasCanonicalOutput ? { output_preview: outputPreview } : { output: outputPreview },
|
|
13381
|
-
...summaryEntries.length > 0 ? { summary:
|
|
14050
|
+
...summaryEntries.length > 0 ? { summary: input2.summary } : {},
|
|
13382
14051
|
next: {
|
|
13383
14052
|
inspect: inspectCommand,
|
|
13384
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.",
|
|
13385
|
-
...
|
|
14054
|
+
...input2.listConversion ? {
|
|
13386
14055
|
expandToPlay: "Use stable map and step keys so reruns are idempotent: completed rows are reused, and only missing or stale work runs again.",
|
|
13387
|
-
listSourcePath:
|
|
14056
|
+
listSourcePath: input2.listConversion.sourcePath ?? "auto-detected list in the CLI response preview"
|
|
13388
14057
|
} : {}
|
|
13389
14058
|
},
|
|
13390
14059
|
render: {
|
|
13391
|
-
sections:
|
|
14060
|
+
sections: input2.listConversion ? [
|
|
13392
14061
|
{
|
|
13393
14062
|
title: "output",
|
|
13394
14063
|
lines: [
|
|
13395
|
-
`${
|
|
14064
|
+
`${input2.listConversion.rows.length} row(s) extracted from ${input2.listConversion.sourcePath ?? "auto-detected list"}`,
|
|
13396
14065
|
"paths above are observed from this execute response; use run table rows to debug play getters",
|
|
13397
|
-
`columns: ${JSON.stringify(Object.keys(
|
|
13398
|
-
`preview: ${JSON.stringify(
|
|
14066
|
+
`columns: ${JSON.stringify(Object.keys(input2.listConversion.rows[0] ?? {}))}`,
|
|
14067
|
+
`preview: ${JSON.stringify(input2.listConversion.rows.slice(0, 5))}`
|
|
13399
14068
|
]
|
|
13400
14069
|
}
|
|
13401
14070
|
] : [
|
|
@@ -13403,7 +14072,7 @@ function buildToolExecuteBaseEnvelope(input) {
|
|
|
13403
14072
|
title: "result",
|
|
13404
14073
|
lines: summaryEntries.length > 0 ? summaryEntries.map(
|
|
13405
14074
|
([key, value]) => `${key}=${String(value)}`
|
|
13406
|
-
) : [JSON.stringify(
|
|
14075
|
+
) : [JSON.stringify(input2.rawResponse, null, 2)]
|
|
13407
14076
|
}
|
|
13408
14077
|
],
|
|
13409
14078
|
actions
|
|
@@ -13724,6 +14393,174 @@ Examples:
|
|
|
13724
14393
|
});
|
|
13725
14394
|
}
|
|
13726
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
|
+
|
|
13727
14564
|
// src/cli/skills-sync.ts
|
|
13728
14565
|
var import_node_child_process2 = require("child_process");
|
|
13729
14566
|
var import_node_fs14 = require("fs");
|
|
@@ -13731,7 +14568,6 @@ var import_node_os9 = require("os");
|
|
|
13731
14568
|
var import_node_path16 = require("path");
|
|
13732
14569
|
var CHECK_TIMEOUT_MS2 = 3e3;
|
|
13733
14570
|
var SDK_SKILL_NAME = "deepline-sdk";
|
|
13734
|
-
var SKILL_AGENTS = ["codex", "claude-code", "cursor"];
|
|
13735
14571
|
var attemptedSync = false;
|
|
13736
14572
|
function shouldSkipSkillsSync() {
|
|
13737
14573
|
const value = process.env.DEEPLINE_SKIP_SKILLS_SYNC?.trim().toLowerCase();
|
|
@@ -13828,42 +14664,10 @@ async function fetchSkillsUpdate(baseUrl, localVersion) {
|
|
|
13828
14664
|
}
|
|
13829
14665
|
}
|
|
13830
14666
|
function buildSkillsInstallArgs(baseUrl) {
|
|
13831
|
-
|
|
13832
|
-
"/.well-known/skills/index.json",
|
|
13833
|
-
baseUrl
|
|
13834
|
-
).toString();
|
|
13835
|
-
return [
|
|
13836
|
-
"--yes",
|
|
13837
|
-
"skills",
|
|
13838
|
-
"add",
|
|
13839
|
-
packageUrl,
|
|
13840
|
-
"--agent",
|
|
13841
|
-
...SKILL_AGENTS,
|
|
13842
|
-
"--global",
|
|
13843
|
-
"--yes",
|
|
13844
|
-
"--skill",
|
|
13845
|
-
SDK_SKILL_NAME,
|
|
13846
|
-
"--full-depth"
|
|
13847
|
-
];
|
|
14667
|
+
return buildSkillsAddArgs(baseUrl, SDK_SKILL_NAME);
|
|
13848
14668
|
}
|
|
13849
14669
|
function buildBunxSkillsInstallArgs(baseUrl) {
|
|
13850
|
-
|
|
13851
|
-
"/.well-known/skills/index.json",
|
|
13852
|
-
baseUrl
|
|
13853
|
-
).toString();
|
|
13854
|
-
return [
|
|
13855
|
-
"--bun",
|
|
13856
|
-
"skills",
|
|
13857
|
-
"add",
|
|
13858
|
-
packageUrl,
|
|
13859
|
-
"--agent",
|
|
13860
|
-
...SKILL_AGENTS,
|
|
13861
|
-
"--global",
|
|
13862
|
-
"--yes",
|
|
13863
|
-
"--skill",
|
|
13864
|
-
SDK_SKILL_NAME,
|
|
13865
|
-
"--full-depth"
|
|
13866
|
-
];
|
|
14670
|
+
return buildSkillsAddArgs(baseUrl, SDK_SKILL_NAME, { firstArg: "--bun" });
|
|
13867
14671
|
}
|
|
13868
14672
|
function hasCommand(command) {
|
|
13869
14673
|
const result = (0, import_node_child_process2.spawnSync)(command, ["--version"], {
|
|
@@ -13975,6 +14779,13 @@ async function syncSdkSkillsIfNeeded(baseUrl) {
|
|
|
13975
14779
|
}
|
|
13976
14780
|
|
|
13977
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
|
+
}
|
|
13978
14789
|
function shouldPrintStartupPhase() {
|
|
13979
14790
|
if (process.argv.includes("--json")) {
|
|
13980
14791
|
return false;
|
|
@@ -14060,7 +14871,7 @@ async function main() {
|
|
|
14060
14871
|
progress?.phase("loading deepline cli");
|
|
14061
14872
|
}
|
|
14062
14873
|
const program = new import_commander3.Command();
|
|
14063
|
-
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(
|
|
14064
14875
|
"after",
|
|
14065
14876
|
`
|
|
14066
14877
|
Common commands:
|
|
@@ -14069,6 +14880,7 @@ Common commands:
|
|
|
14069
14880
|
deepline plays search email --json
|
|
14070
14881
|
deepline plays describe person-linkedin-to-email --json
|
|
14071
14882
|
deepline plays run my.play.ts --input '{"domain":"stripe.com"}'
|
|
14883
|
+
deepline secrets check HUBSPOT_TOKEN
|
|
14072
14884
|
deepline tools execute hunter_email_verifier --input '{"email":"a@b.com"}'
|
|
14073
14885
|
deepline update
|
|
14074
14886
|
|
|
@@ -14118,6 +14930,7 @@ Exit codes:
|
|
|
14118
14930
|
registerAuthCommands(program);
|
|
14119
14931
|
registerToolsCommands(program);
|
|
14120
14932
|
registerPlayCommands(program);
|
|
14933
|
+
registerSecretsCommands(program);
|
|
14121
14934
|
registerBillingCommands(program);
|
|
14122
14935
|
registerOrgCommands(program);
|
|
14123
14936
|
registerCsvCommands(program);
|
|
@@ -14187,6 +15000,7 @@ Examples:
|
|
|
14187
15000
|
ok: true
|
|
14188
15001
|
});
|
|
14189
15002
|
} catch (error) {
|
|
15003
|
+
const commanderError = asCommanderError(error);
|
|
14190
15004
|
recordCliTrace({
|
|
14191
15005
|
phase: "cli.main_total",
|
|
14192
15006
|
ms: Date.now() - mainStartedAt,
|
|
@@ -14194,7 +15008,26 @@ Examples:
|
|
|
14194
15008
|
error: error instanceof Error ? error.message : String(error)
|
|
14195
15009
|
});
|
|
14196
15010
|
progress?.fail();
|
|
14197
|
-
|
|
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) {
|
|
14198
15031
|
printJsonError(error);
|
|
14199
15032
|
} else if (error instanceof Error) {
|
|
14200
15033
|
console.error(`Error: ${error.message}`);
|