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.mjs
CHANGED
|
@@ -206,10 +206,10 @@ import { join as join2 } from "path";
|
|
|
206
206
|
|
|
207
207
|
// src/release.ts
|
|
208
208
|
var SDK_RELEASE = {
|
|
209
|
-
version: "0.1.
|
|
209
|
+
version: "0.1.69",
|
|
210
210
|
apiContract: "2026-05-play-bootstrap-dataset-summary",
|
|
211
211
|
supportPolicy: {
|
|
212
|
-
latest: "0.1.
|
|
212
|
+
latest: "0.1.69",
|
|
213
213
|
minimumSupported: "0.1.53",
|
|
214
214
|
deprecatedBelow: "0.1.53"
|
|
215
215
|
}
|
|
@@ -460,6 +460,9 @@ var HttpClient = class {
|
|
|
460
460
|
headers
|
|
461
461
|
});
|
|
462
462
|
}
|
|
463
|
+
async patch(path, body, headers) {
|
|
464
|
+
return this.request(path, { method: "PATCH", body, headers });
|
|
465
|
+
}
|
|
463
466
|
/**
|
|
464
467
|
* Send a DELETE request.
|
|
465
468
|
*
|
|
@@ -713,7 +716,7 @@ var DeeplineClient = class {
|
|
|
713
716
|
list: (options2) => this.listRuns(options2),
|
|
714
717
|
tail: (runId, options2) => this.tailRun(runId, options2),
|
|
715
718
|
logs: (runId, options2) => this.getRunLogs(runId, options2),
|
|
716
|
-
exportDatasetRows: (
|
|
719
|
+
exportDatasetRows: (input2) => this.getPlaySheetRows(input2),
|
|
717
720
|
stop: (runId, options2) => this.stopRun(runId, options2)
|
|
718
721
|
};
|
|
719
722
|
}
|
|
@@ -800,6 +803,22 @@ var DeeplineClient = class {
|
|
|
800
803
|
};
|
|
801
804
|
}
|
|
802
805
|
// ——————————————————————————————————————————————————————————
|
|
806
|
+
// Secrets
|
|
807
|
+
// ——————————————————————————————————————————————————————————
|
|
808
|
+
async listSecrets() {
|
|
809
|
+
const response = await this.http.get(
|
|
810
|
+
"/api/v2/secrets"
|
|
811
|
+
);
|
|
812
|
+
return Array.isArray(response.secrets) ? response.secrets : [];
|
|
813
|
+
}
|
|
814
|
+
async checkSecret(name) {
|
|
815
|
+
const normalized = name.trim().toUpperCase();
|
|
816
|
+
const secrets = await this.listSecrets();
|
|
817
|
+
return secrets.find(
|
|
818
|
+
(secret) => secret.name === normalized && secret.status === "active" && secret.hasValue
|
|
819
|
+
) ?? null;
|
|
820
|
+
}
|
|
821
|
+
// ——————————————————————————————————————————————————————————
|
|
803
822
|
// Tools
|
|
804
823
|
// ——————————————————————————————————————————————————————————
|
|
805
824
|
/**
|
|
@@ -892,24 +911,24 @@ var DeeplineClient = class {
|
|
|
892
911
|
* Top-level fields such as `status`, `job_id`, and `billing` describe the
|
|
893
912
|
* Deepline execution envelope.
|
|
894
913
|
*/
|
|
895
|
-
async executeTool(toolId,
|
|
914
|
+
async executeTool(toolId, input2, options) {
|
|
896
915
|
const headers = {
|
|
897
916
|
[EXECUTE_RESPONSE_CONTRACT_HEADER]: V2_EXECUTE_RESPONSE_CONTRACT,
|
|
898
917
|
...options?.includeToolMetadata ? { [INCLUDE_TOOL_METADATA_HEADER]: "true" } : {}
|
|
899
918
|
};
|
|
900
919
|
return this.http.post(
|
|
901
920
|
`/api/v2/integrations/${encodeURIComponent(toolId)}/execute`,
|
|
902
|
-
{ payload:
|
|
921
|
+
{ payload: input2 },
|
|
903
922
|
headers
|
|
904
923
|
);
|
|
905
924
|
}
|
|
906
|
-
async executeToolRaw(toolId,
|
|
907
|
-
return this.executeTool(toolId,
|
|
925
|
+
async executeToolRaw(toolId, input2, options) {
|
|
926
|
+
return this.executeTool(toolId, input2, options);
|
|
908
927
|
}
|
|
909
|
-
async queryCustomerDb(
|
|
928
|
+
async queryCustomerDb(input2) {
|
|
910
929
|
return this.http.post("/api/v2/db/query", {
|
|
911
|
-
sql:
|
|
912
|
-
...
|
|
930
|
+
sql: input2.sql,
|
|
931
|
+
...input2.maxRows ? { max_rows: input2.maxRows } : {}
|
|
913
932
|
});
|
|
914
933
|
}
|
|
915
934
|
// ——————————————————————————————————————————————————————————
|
|
@@ -1016,15 +1035,15 @@ var DeeplineClient = class {
|
|
|
1016
1035
|
* Internal/advanced primitive used by packaging flows. Public callers should
|
|
1017
1036
|
* prefer the CLI, {@link submitPlay}, or {@link runPlay}.
|
|
1018
1037
|
*/
|
|
1019
|
-
async registerPlayArtifact(
|
|
1020
|
-
const compilerManifest =
|
|
1021
|
-
name:
|
|
1022
|
-
sourceCode:
|
|
1023
|
-
sourceFiles:
|
|
1024
|
-
artifact:
|
|
1038
|
+
async registerPlayArtifact(input2) {
|
|
1039
|
+
const compilerManifest = input2.compilerManifest ?? await this.compilePlayManifest({
|
|
1040
|
+
name: input2.name,
|
|
1041
|
+
sourceCode: input2.sourceCode,
|
|
1042
|
+
sourceFiles: input2.sourceFiles,
|
|
1043
|
+
artifact: input2.artifact
|
|
1025
1044
|
});
|
|
1026
1045
|
return this.http.post("/api/v2/plays/artifacts", {
|
|
1027
|
-
...
|
|
1046
|
+
...input2,
|
|
1028
1047
|
compilerManifest
|
|
1029
1048
|
});
|
|
1030
1049
|
}
|
|
@@ -1044,14 +1063,14 @@ var DeeplineClient = class {
|
|
|
1044
1063
|
artifacts: compiledArtifacts
|
|
1045
1064
|
});
|
|
1046
1065
|
}
|
|
1047
|
-
async compilePlayManifest(
|
|
1066
|
+
async compilePlayManifest(input2) {
|
|
1048
1067
|
const retryDelays = COMPILE_MANIFEST_RETRY_DELAYS_MS.slice(
|
|
1049
1068
|
0,
|
|
1050
1069
|
Math.max(0, this.config.maxRetries)
|
|
1051
1070
|
);
|
|
1052
1071
|
for (let attempt = 0; ; attempt += 1) {
|
|
1053
1072
|
try {
|
|
1054
|
-
const response = await this.http.post("/api/v2/plays/compile-manifest",
|
|
1073
|
+
const response = await this.http.post("/api/v2/plays/compile-manifest", input2);
|
|
1055
1074
|
return response.compilerManifest;
|
|
1056
1075
|
} catch (error) {
|
|
1057
1076
|
const delayMs = retryDelays[attempt];
|
|
@@ -1069,21 +1088,21 @@ var DeeplineClient = class {
|
|
|
1069
1088
|
* publish a revision, or start a run. It is the authoritative cloud validation
|
|
1070
1089
|
* path used by `deepline play check`.
|
|
1071
1090
|
*/
|
|
1072
|
-
async checkPlayArtifact(
|
|
1073
|
-
return this.http.post("/api/v2/plays/check",
|
|
1074
|
-
}
|
|
1075
|
-
async startPlayRunFromBundle(
|
|
1076
|
-
const compilerManifest =
|
|
1077
|
-
name:
|
|
1078
|
-
sourceCode:
|
|
1079
|
-
sourceFiles:
|
|
1080
|
-
artifact:
|
|
1091
|
+
async checkPlayArtifact(input2) {
|
|
1092
|
+
return this.http.post("/api/v2/plays/check", input2);
|
|
1093
|
+
}
|
|
1094
|
+
async startPlayRunFromBundle(input2) {
|
|
1095
|
+
const compilerManifest = input2.compilerManifest ?? await this.compilePlayManifest({
|
|
1096
|
+
name: input2.name,
|
|
1097
|
+
sourceCode: input2.sourceCode,
|
|
1098
|
+
sourceFiles: input2.sourceFiles,
|
|
1099
|
+
artifact: input2.artifact
|
|
1081
1100
|
});
|
|
1082
1101
|
const registeredArtifact = await this.registerPlayArtifact({
|
|
1083
|
-
name:
|
|
1084
|
-
sourceCode:
|
|
1085
|
-
sourceFiles:
|
|
1086
|
-
artifact:
|
|
1102
|
+
name: input2.name,
|
|
1103
|
+
sourceCode: input2.sourceCode,
|
|
1104
|
+
sourceFiles: input2.sourceFiles,
|
|
1105
|
+
artifact: input2.artifact,
|
|
1087
1106
|
compilerManifest,
|
|
1088
1107
|
publish: false
|
|
1089
1108
|
});
|
|
@@ -1093,13 +1112,13 @@ var DeeplineClient = class {
|
|
|
1093
1112
|
);
|
|
1094
1113
|
}
|
|
1095
1114
|
return this.startPlayRun({
|
|
1096
|
-
name:
|
|
1115
|
+
name: input2.name,
|
|
1097
1116
|
artifactStorageKey: registeredArtifact.artifactStorageKey,
|
|
1098
1117
|
compilerManifest,
|
|
1099
|
-
...
|
|
1100
|
-
...
|
|
1101
|
-
...
|
|
1102
|
-
...
|
|
1118
|
+
...input2.input ? { input: input2.input } : {},
|
|
1119
|
+
...input2.inputFile ? { inputFile: input2.inputFile } : {},
|
|
1120
|
+
...input2.packagedFiles?.length ? { packagedFiles: input2.packagedFiles } : {},
|
|
1121
|
+
...input2.force ? { force: true } : {}
|
|
1103
1122
|
});
|
|
1104
1123
|
}
|
|
1105
1124
|
/**
|
|
@@ -1444,17 +1463,17 @@ var DeeplineClient = class {
|
|
|
1444
1463
|
entries
|
|
1445
1464
|
};
|
|
1446
1465
|
}
|
|
1447
|
-
async getPlaySheetRows(
|
|
1466
|
+
async getPlaySheetRows(input2) {
|
|
1448
1467
|
const params = new URLSearchParams({
|
|
1449
|
-
tableNamespace:
|
|
1450
|
-
limit: String(
|
|
1451
|
-
offset: String(
|
|
1468
|
+
tableNamespace: input2.tableNamespace,
|
|
1469
|
+
limit: String(input2.limit ?? 5e3),
|
|
1470
|
+
offset: String(input2.offset ?? 0)
|
|
1452
1471
|
});
|
|
1453
|
-
if (
|
|
1454
|
-
params.set("runId",
|
|
1472
|
+
if (input2.runId?.trim()) {
|
|
1473
|
+
params.set("runId", input2.runId.trim());
|
|
1455
1474
|
}
|
|
1456
1475
|
return await this.http.get(
|
|
1457
|
-
`/api/v2/plays/${encodeURIComponent(
|
|
1476
|
+
`/api/v2/plays/${encodeURIComponent(input2.playName)}/sheet?${params.toString()}`
|
|
1458
1477
|
);
|
|
1459
1478
|
}
|
|
1460
1479
|
/**
|
|
@@ -1583,6 +1602,61 @@ var DeeplineClient = class {
|
|
|
1583
1602
|
return this.http.delete(`/api/v2/plays/${encodedName}`);
|
|
1584
1603
|
}
|
|
1585
1604
|
// ——————————————————————————————————————————————————————————
|
|
1605
|
+
// Plays — public share pages
|
|
1606
|
+
// ——————————————————————————————————————————————————————————
|
|
1607
|
+
/**
|
|
1608
|
+
* Current share status for a play: the public page (if any), the published
|
|
1609
|
+
* copy, and the revision picker. Read-only.
|
|
1610
|
+
*/
|
|
1611
|
+
async getSharePage(name) {
|
|
1612
|
+
const encodedName = encodeURIComponent(name);
|
|
1613
|
+
return this.http.get(`/api/v2/plays/${encodedName}/share`);
|
|
1614
|
+
}
|
|
1615
|
+
/**
|
|
1616
|
+
* Publish (or repoint) the play's public share page to a revision. Requires
|
|
1617
|
+
* `acknowledgedUnlisted: true` — the page is publicly viewable. Org-admin only.
|
|
1618
|
+
*/
|
|
1619
|
+
async publishSharePage(name, request) {
|
|
1620
|
+
const encodedName = encodeURIComponent(name);
|
|
1621
|
+
return this.http.post(
|
|
1622
|
+
`/api/v2/plays/${encodedName}/share`,
|
|
1623
|
+
request
|
|
1624
|
+
);
|
|
1625
|
+
}
|
|
1626
|
+
/**
|
|
1627
|
+
* Update share-page settings (SEO indexing, credit-cost / latency display)
|
|
1628
|
+
* without moving the published pointer. Org-admin only.
|
|
1629
|
+
*/
|
|
1630
|
+
async updateSharePage(name, request) {
|
|
1631
|
+
const encodedName = encodeURIComponent(name);
|
|
1632
|
+
return this.http.patch(
|
|
1633
|
+
`/api/v2/plays/${encodedName}/share`,
|
|
1634
|
+
request
|
|
1635
|
+
);
|
|
1636
|
+
}
|
|
1637
|
+
/**
|
|
1638
|
+
* Unshare: hard-delete the play's public page and its cards. Returns the
|
|
1639
|
+
* fresh status (now `share: null`). Org-admin only. Idempotent — a no-op when
|
|
1640
|
+
* the play was never published.
|
|
1641
|
+
*/
|
|
1642
|
+
async unpublishSharePage(name) {
|
|
1643
|
+
const encodedName = encodeURIComponent(name);
|
|
1644
|
+
return this.http.delete(
|
|
1645
|
+
`/api/v2/plays/${encodedName}/share`
|
|
1646
|
+
);
|
|
1647
|
+
}
|
|
1648
|
+
/**
|
|
1649
|
+
* Regenerate the LLM landing-page copy for a revision (defaults to the
|
|
1650
|
+
* published one). Org-admin only.
|
|
1651
|
+
*/
|
|
1652
|
+
async regenerateSharePage(name, request = {}) {
|
|
1653
|
+
const encodedName = encodeURIComponent(name);
|
|
1654
|
+
return this.http.post(
|
|
1655
|
+
`/api/v2/plays/${encodedName}/share/regenerate`,
|
|
1656
|
+
request
|
|
1657
|
+
);
|
|
1658
|
+
}
|
|
1659
|
+
// ——————————————————————————————————————————————————————————
|
|
1586
1660
|
// Plays — high-level orchestration
|
|
1587
1661
|
// ——————————————————————————————————————————————————————————
|
|
1588
1662
|
/**
|
|
@@ -1848,7 +1922,7 @@ function browserAppNameFromBundleId(bundleId) {
|
|
|
1848
1922
|
}
|
|
1849
1923
|
function readDefaultMacBrowserBundleId(runner = defaultBrowserCommandRunner) {
|
|
1850
1924
|
try {
|
|
1851
|
-
const
|
|
1925
|
+
const output2 = runner.execFileSync(
|
|
1852
1926
|
"/usr/bin/defaults",
|
|
1853
1927
|
[
|
|
1854
1928
|
"read",
|
|
@@ -1857,10 +1931,10 @@ function readDefaultMacBrowserBundleId(runner = defaultBrowserCommandRunner) {
|
|
|
1857
1931
|
],
|
|
1858
1932
|
{ encoding: "utf-8", stdio: ["ignore", "pipe", "ignore"] }
|
|
1859
1933
|
);
|
|
1860
|
-
const httpsMatch =
|
|
1934
|
+
const httpsMatch = output2.match(
|
|
1861
1935
|
/LSHandlerURLScheme\s*=\s*https;[\s\S]*?LSHandlerRole(?:All|Viewer|Editor)\s*=\s*"([^"]+)"/
|
|
1862
1936
|
);
|
|
1863
|
-
const httpMatch =
|
|
1937
|
+
const httpMatch = output2.match(
|
|
1864
1938
|
/LSHandlerURLScheme\s*=\s*http;[\s\S]*?LSHandlerRole(?:All|Viewer|Editor)\s*=\s*"([^"]+)"/
|
|
1865
1939
|
);
|
|
1866
1940
|
return (httpsMatch?.[1] ?? httpMatch?.[1] ?? "").trim();
|
|
@@ -3305,9 +3379,9 @@ function stripCsvProjectionColumns(columns, rows) {
|
|
|
3305
3379
|
(column) => column !== CSV_PROJECTED_FIELDS_KEY && !projectedFields.has(column)
|
|
3306
3380
|
);
|
|
3307
3381
|
}
|
|
3308
|
-
function sanitizeCsvProjectionInfo(
|
|
3309
|
-
const columns = stripCsvProjectionColumns(
|
|
3310
|
-
const rows =
|
|
3382
|
+
function sanitizeCsvProjectionInfo(input2) {
|
|
3383
|
+
const columns = stripCsvProjectionColumns(input2.columns, input2.rows);
|
|
3384
|
+
const rows = input2.rows.map(stripCsvProjectionFields);
|
|
3311
3385
|
return { rows, columns };
|
|
3312
3386
|
}
|
|
3313
3387
|
function isRecord2(value) {
|
|
@@ -3363,8 +3437,8 @@ function inferColumns(rows) {
|
|
|
3363
3437
|
}
|
|
3364
3438
|
return columns;
|
|
3365
3439
|
}
|
|
3366
|
-
function canonicalRowsInfoFromCandidate(
|
|
3367
|
-
const candidate =
|
|
3440
|
+
function canonicalRowsInfoFromCandidate(input2) {
|
|
3441
|
+
const candidate = input2;
|
|
3368
3442
|
if (isSerializedDataset(candidate.value)) {
|
|
3369
3443
|
const rawRows = rowArray(candidate.value.preview) ?? [];
|
|
3370
3444
|
const totalRows2 = readNumber(candidate.value.count) ?? rawRows.length;
|
|
@@ -3405,31 +3479,31 @@ function canonicalRowsInfoFromCandidate(input) {
|
|
|
3405
3479
|
source: candidate.source
|
|
3406
3480
|
};
|
|
3407
3481
|
}
|
|
3408
|
-
function collectDatasetCandidates(
|
|
3409
|
-
if (
|
|
3482
|
+
function collectDatasetCandidates(input2) {
|
|
3483
|
+
if (input2.depth && input2.depth > 16) {
|
|
3410
3484
|
return;
|
|
3411
3485
|
}
|
|
3412
|
-
if (isSerializedDataset(
|
|
3413
|
-
|
|
3414
|
-
source:
|
|
3415
|
-
value:
|
|
3416
|
-
total:
|
|
3486
|
+
if (isSerializedDataset(input2.value)) {
|
|
3487
|
+
input2.output.push({
|
|
3488
|
+
source: input2.path,
|
|
3489
|
+
value: input2.value,
|
|
3490
|
+
total: input2.total
|
|
3417
3491
|
});
|
|
3418
3492
|
return;
|
|
3419
3493
|
}
|
|
3420
|
-
if (!isRecord2(
|
|
3494
|
+
if (!isRecord2(input2.value)) {
|
|
3421
3495
|
return;
|
|
3422
3496
|
}
|
|
3423
|
-
for (const [key, child] of Object.entries(
|
|
3497
|
+
for (const [key, child] of Object.entries(input2.value)) {
|
|
3424
3498
|
if (key === "preview" || key === "access") {
|
|
3425
3499
|
continue;
|
|
3426
3500
|
}
|
|
3427
3501
|
collectDatasetCandidates({
|
|
3428
3502
|
value: child,
|
|
3429
|
-
path: `${
|
|
3430
|
-
total: totalRowsForDataset(
|
|
3431
|
-
output:
|
|
3432
|
-
depth: (
|
|
3503
|
+
path: `${input2.path}.${key}`,
|
|
3504
|
+
total: totalRowsForDataset(input2.value, `${input2.path}.${key}`),
|
|
3505
|
+
output: input2.output,
|
|
3506
|
+
depth: (input2.depth ?? 0) + 1
|
|
3433
3507
|
});
|
|
3434
3508
|
}
|
|
3435
3509
|
}
|
|
@@ -3947,26 +4021,26 @@ function writeCustomerDbCsv(result, outPath) {
|
|
|
3947
4021
|
);
|
|
3948
4022
|
return resolved;
|
|
3949
4023
|
}
|
|
3950
|
-
function dbQueryExportEnvelope(
|
|
3951
|
-
const destination =
|
|
4024
|
+
function dbQueryExportEnvelope(input2) {
|
|
4025
|
+
const destination = input2.outPath ?? "stdout";
|
|
3952
4026
|
return {
|
|
3953
|
-
command:
|
|
3954
|
-
format:
|
|
3955
|
-
row_count:
|
|
3956
|
-
row_count_returned:
|
|
3957
|
-
truncated:
|
|
3958
|
-
...
|
|
3959
|
-
next: { toolEquivalent:
|
|
4027
|
+
command: input2.result.command,
|
|
4028
|
+
format: input2.format,
|
|
4029
|
+
row_count: input2.result.row_count,
|
|
4030
|
+
row_count_returned: input2.result.row_count_returned,
|
|
4031
|
+
truncated: input2.result.truncated,
|
|
4032
|
+
...input2.outPath ? { file: input2.outPath, local: { file: input2.outPath } } : {},
|
|
4033
|
+
next: { toolEquivalent: input2.toolCommand },
|
|
3960
4034
|
render: {
|
|
3961
4035
|
sections: [
|
|
3962
4036
|
{
|
|
3963
4037
|
title: "customer db export",
|
|
3964
4038
|
lines: [
|
|
3965
|
-
`Rendered ${
|
|
4039
|
+
`Rendered ${input2.result.row_count_returned} row(s) as ${input2.format} to ${destination}`
|
|
3966
4040
|
]
|
|
3967
4041
|
}
|
|
3968
4042
|
],
|
|
3969
|
-
actions: [{ label: "Tool equivalent", command:
|
|
4043
|
+
actions: [{ label: "Tool equivalent", command: input2.toolCommand }]
|
|
3970
4044
|
}
|
|
3971
4045
|
};
|
|
3972
4046
|
}
|
|
@@ -4417,16 +4491,63 @@ var PLAY_RUNTIME_FEATURES = [
|
|
|
4417
4491
|
"durable_sleep",
|
|
4418
4492
|
"packaged_files"
|
|
4419
4493
|
];
|
|
4420
|
-
function buildPlayContractCompatibility(
|
|
4494
|
+
function buildPlayContractCompatibility(input2) {
|
|
4421
4495
|
return {
|
|
4422
4496
|
apiVersion: PLAY_PUBLIC_API_VERSION,
|
|
4423
4497
|
artifactVersion: PLAY_ARTIFACT_VERSION,
|
|
4424
4498
|
minRunnerVersion: PLAY_MIN_RUNNER_VERSION,
|
|
4425
4499
|
runtimeFeatures: [...PLAY_RUNTIME_FEATURES],
|
|
4426
|
-
runtimeBackend:
|
|
4500
|
+
runtimeBackend: input2?.runtimeBackend ?? null
|
|
4427
4501
|
};
|
|
4428
4502
|
}
|
|
4429
4503
|
|
|
4504
|
+
// ../shared_libs/plays/secret-guardrails.ts
|
|
4505
|
+
var SECRET_ENV_PATTERN = /\bprocess(?:\.env|\[['"]env['"]\])(?:\.|\[['"])([A-Z0-9_]*(?:API[_-]?KEY|TOKEN|SECRET|PASSWORD|PRIVATE[_-]?KEY|ACCESS[_-]?KEY)[A-Z0-9_]*)(?:['"]\])?/g;
|
|
4506
|
+
var PRIVATE_KEY_PATTERN = /-----BEGIN (?:RSA |EC |OPENSSH |PGP )?PRIVATE KEY-----/;
|
|
4507
|
+
var BEARER_LITERAL_PATTERN = /\bBearer\s+[A-Za-z0-9._~+/=-]{16,}/i;
|
|
4508
|
+
var ASSIGNMENT_SECRET_LITERAL_PATTERN = /\b(?:api[_-]?key|token|secret|password)\b\s*[:=]\s*['"][^'"]{12,}['"]/i;
|
|
4509
|
+
var HIGH_ENTROPY_LITERAL_PATTERN = /['"]([A-Za-z0-9+/=_-]{32,})['"]/g;
|
|
4510
|
+
function shannonEntropy(value) {
|
|
4511
|
+
const counts = /* @__PURE__ */ new Map();
|
|
4512
|
+
for (const char of value) counts.set(char, (counts.get(char) ?? 0) + 1);
|
|
4513
|
+
return [...counts.values()].reduce((entropy, count) => {
|
|
4514
|
+
const p = count / value.length;
|
|
4515
|
+
return entropy - p * Math.log2(p);
|
|
4516
|
+
}, 0);
|
|
4517
|
+
}
|
|
4518
|
+
function validatePlaySourceHasNoInlineSecrets(input2) {
|
|
4519
|
+
const findings = [];
|
|
4520
|
+
for (const match of input2.sourceCode.matchAll(SECRET_ENV_PATTERN)) {
|
|
4521
|
+
findings.push(`process.env.${match[1]}`);
|
|
4522
|
+
}
|
|
4523
|
+
if (PRIVATE_KEY_PATTERN.test(input2.sourceCode)) findings.push("private key block");
|
|
4524
|
+
if (BEARER_LITERAL_PATTERN.test(input2.sourceCode)) findings.push("bearer token literal");
|
|
4525
|
+
if (ASSIGNMENT_SECRET_LITERAL_PATTERN.test(input2.sourceCode)) {
|
|
4526
|
+
findings.push("secret-looking assignment literal");
|
|
4527
|
+
}
|
|
4528
|
+
for (const match of input2.sourceCode.matchAll(HIGH_ENTROPY_LITERAL_PATTERN)) {
|
|
4529
|
+
const literal = match[1] ?? "";
|
|
4530
|
+
if (literal.length >= 40 && shannonEntropy(literal) >= 4.2) {
|
|
4531
|
+
findings.push("high-entropy string literal");
|
|
4532
|
+
break;
|
|
4533
|
+
}
|
|
4534
|
+
}
|
|
4535
|
+
if (!findings.length) return;
|
|
4536
|
+
throw new Error(
|
|
4537
|
+
[
|
|
4538
|
+
`Play source ${input2.filePath} appears to contain inline secret material: ${[
|
|
4539
|
+
...new Set(findings)
|
|
4540
|
+
].join(", ")}.`,
|
|
4541
|
+
'Author secrets in the dashboard and use ctx.secrets.get("NAME") with an approved helper such as ctx.secrets.bearer(handle).'
|
|
4542
|
+
].join(" ")
|
|
4543
|
+
);
|
|
4544
|
+
}
|
|
4545
|
+
function validatePlaySourceFilesHaveNoInlineSecrets(sourceFiles) {
|
|
4546
|
+
for (const [filePath, sourceCode] of Object.entries(sourceFiles)) {
|
|
4547
|
+
validatePlaySourceHasNoInlineSecrets({ filePath, sourceCode });
|
|
4548
|
+
}
|
|
4549
|
+
}
|
|
4550
|
+
|
|
4430
4551
|
// ../shared_libs/plays/bundling/index.ts
|
|
4431
4552
|
var PLAY_BUNDLE_CACHE_VERSION = 24;
|
|
4432
4553
|
var MAX_PLAY_BUNDLE_BYTES = 30 * 1024 * 1024;
|
|
@@ -4488,12 +4609,12 @@ function createPlayWorkspace(entryFile) {
|
|
|
4488
4609
|
function isPathInsideDirectory(filePath, directory) {
|
|
4489
4610
|
return filePath === directory || filePath.startsWith(`${directory}/`);
|
|
4490
4611
|
}
|
|
4491
|
-
function assertWithinPlayWorkspace(
|
|
4492
|
-
if (isPathInsideDirectory(
|
|
4612
|
+
function assertWithinPlayWorkspace(input2) {
|
|
4613
|
+
if (isPathInsideDirectory(input2.resolvedPath, input2.workspace.rootDir)) {
|
|
4493
4614
|
return;
|
|
4494
4615
|
}
|
|
4495
4616
|
throw new Error(
|
|
4496
|
-
`${
|
|
4617
|
+
`${input2.importer}:${input2.line}:${input2.column} Local play imports must stay inside the play workspace (${input2.workspace.rootDir}). Import "${input2.specifier}" resolved to ${input2.resolvedPath}, which crosses into app/backend code. Use the public SDK/API surface or move shared helpers into the play workspace.`
|
|
4497
4618
|
);
|
|
4498
4619
|
}
|
|
4499
4620
|
function getPackageName(specifier) {
|
|
@@ -5348,6 +5469,15 @@ entry-export:${exportName}`
|
|
|
5348
5469
|
workers-harness:${harnessFingerprint}`
|
|
5349
5470
|
);
|
|
5350
5471
|
}
|
|
5472
|
+
try {
|
|
5473
|
+
validatePlaySourceFilesHaveNoInlineSecrets(analysis.sourceFiles);
|
|
5474
|
+
} catch (error) {
|
|
5475
|
+
return {
|
|
5476
|
+
success: false,
|
|
5477
|
+
filePath: absolutePath,
|
|
5478
|
+
errors: [error instanceof Error ? error.message : String(error)]
|
|
5479
|
+
};
|
|
5480
|
+
}
|
|
5351
5481
|
const typecheckErrors = [
|
|
5352
5482
|
...await adapter.typecheckPlaySource?.({
|
|
5353
5483
|
sourceCode: analysis.sourceCode,
|
|
@@ -5957,11 +6087,13 @@ function createSdkPlayBundlingAdapter() {
|
|
|
5957
6087
|
};
|
|
5958
6088
|
}
|
|
5959
6089
|
async function bundlePlayFile2(filePath, options = {}) {
|
|
5960
|
-
|
|
6090
|
+
const result = await bundlePlayFile(filePath, {
|
|
5961
6091
|
target: options.target ?? defaultPlayBundleTarget(),
|
|
5962
6092
|
exportName: options.exportName,
|
|
5963
6093
|
adapter: createSdkPlayBundlingAdapter()
|
|
5964
6094
|
});
|
|
6095
|
+
if (result.success) validatePlaySourceFilesHaveNoInlineSecrets(result.sourceFiles);
|
|
6096
|
+
return result;
|
|
5965
6097
|
}
|
|
5966
6098
|
|
|
5967
6099
|
// src/cli/commands/plays/bootstrap.ts
|
|
@@ -6555,28 +6687,28 @@ function objectPropertySchema(schema, property) {
|
|
|
6555
6687
|
function finderResultTypeName(finder) {
|
|
6556
6688
|
return finder === "email_finder" ? "EmailFinderPlayResult" : "PhoneFinderPlayResult";
|
|
6557
6689
|
}
|
|
6558
|
-
function renderFinderPlayResultType(
|
|
6559
|
-
if (!
|
|
6560
|
-
const outputField = PLAY_BOOTSTRAP_OUTPUT_FIELD_BY_FINDER[
|
|
6690
|
+
function renderFinderPlayResultType(input2) {
|
|
6691
|
+
if (!input2.play) return null;
|
|
6692
|
+
const outputField = PLAY_BOOTSTRAP_OUTPUT_FIELD_BY_FINDER[input2.finder];
|
|
6561
6693
|
const fieldSchema = objectPropertySchema(
|
|
6562
|
-
|
|
6694
|
+
input2.play.outputSchema,
|
|
6563
6695
|
outputField
|
|
6564
6696
|
);
|
|
6565
6697
|
const fieldType = fieldSchema ? jsonSchemaTypeExpression(fieldSchema) : "string | null";
|
|
6566
|
-
return `type ${finderResultTypeName(
|
|
6698
|
+
return `type ${finderResultTypeName(input2.finder)} =
|
|
6567
6699
|
| string
|
|
6568
6700
|
| null
|
|
6569
6701
|
| {
|
|
6570
6702
|
${outputField}?: ${fieldType};
|
|
6571
6703
|
};`;
|
|
6572
6704
|
}
|
|
6573
|
-
function generatedFinderPlayResultTypes(
|
|
6705
|
+
function generatedFinderPlayResultTypes(input2) {
|
|
6574
6706
|
return ["email_finder", "phone_finder"].flatMap((finder) => {
|
|
6575
|
-
const stage = finderStage(
|
|
6707
|
+
const stage = finderStage(input2.options, finder);
|
|
6576
6708
|
if (stage?.kind !== "play") return [];
|
|
6577
6709
|
const typeDefinition = renderFinderPlayResultType({
|
|
6578
6710
|
finder,
|
|
6579
|
-
play:
|
|
6711
|
+
play: input2.finderPlays[finder]
|
|
6580
6712
|
});
|
|
6581
6713
|
return typeDefinition ? [typeDefinition] : [];
|
|
6582
6714
|
}).join("\n\n");
|
|
@@ -6634,8 +6766,8 @@ function generateCompanyInputObjectFromSchema(schema, indent, label, fallbackFie
|
|
|
6634
6766
|
${lines.join("\n")}
|
|
6635
6767
|
${indent.slice(2)}}`;
|
|
6636
6768
|
}
|
|
6637
|
-
function generateSourceProviderInputObject(
|
|
6638
|
-
const { tool, indent, label, entity } =
|
|
6769
|
+
function generateSourceProviderInputObject(input2) {
|
|
6770
|
+
const { tool, indent, label, entity } = input2;
|
|
6639
6771
|
const properties = inputPropertyNames(tool?.inputSchema);
|
|
6640
6772
|
const details = schemaFieldDetails(tool?.inputSchema);
|
|
6641
6773
|
const required = details.required;
|
|
@@ -6693,8 +6825,8 @@ function generateSourceProviderInputObject(input) {
|
|
|
6693
6825
|
${lines.join("\n")}
|
|
6694
6826
|
${indent.slice(2)}}`;
|
|
6695
6827
|
}
|
|
6696
|
-
function generatePlayInputObject(
|
|
6697
|
-
const { schema, indent, label, entity } =
|
|
6828
|
+
function generatePlayInputObject(input2) {
|
|
6829
|
+
const { schema, indent, label, entity } = input2;
|
|
6698
6830
|
const details = schemaFieldDetails(schema);
|
|
6699
6831
|
const fallback = entity === "company" ? ["domain", "company_name"] : ["first_name", "last_name", "domain"];
|
|
6700
6832
|
const required = details.required.length ? details.required : fallback;
|
|
@@ -6761,80 +6893,80 @@ function needsWhenImport(options) {
|
|
|
6761
6893
|
function sourceCollectionTypeName(entity) {
|
|
6762
6894
|
return entity === "company" ? "CompanySourceRow" : "ContactSourceRow";
|
|
6763
6895
|
}
|
|
6764
|
-
function renderPartialRowType(
|
|
6765
|
-
if (
|
|
6766
|
-
return `type ${
|
|
6896
|
+
function renderPartialRowType(input2) {
|
|
6897
|
+
if (input2.fields.length === 0) {
|
|
6898
|
+
return `type ${input2.typeName} = Record<string, unknown>;`;
|
|
6767
6899
|
}
|
|
6768
|
-
const properties =
|
|
6769
|
-
return `type ${
|
|
6770
|
-
// ${
|
|
6900
|
+
const properties = input2.fields.map((field) => ` ${jsString(field)}?: unknown;`).join("\n");
|
|
6901
|
+
return `type ${input2.typeName} = Record<string, unknown> & Partial<{
|
|
6902
|
+
// ${input2.comment}
|
|
6771
6903
|
${properties}
|
|
6772
6904
|
}>;`;
|
|
6773
6905
|
}
|
|
6774
|
-
function fieldsFromSchemaDetails(
|
|
6906
|
+
function fieldsFromSchemaDetails(input2) {
|
|
6775
6907
|
return [
|
|
6776
|
-
...
|
|
6777
|
-
...
|
|
6908
|
+
...input2.details.required.length ? input2.details.required : input2.fallbackFields,
|
|
6909
|
+
...input2.details.optional
|
|
6778
6910
|
];
|
|
6779
6911
|
}
|
|
6780
|
-
function schemaFieldsForStage(stage,
|
|
6912
|
+
function schemaFieldsForStage(stage, input2) {
|
|
6781
6913
|
switch (stage?.kind) {
|
|
6782
6914
|
case void 0:
|
|
6783
6915
|
return [];
|
|
6784
6916
|
case "play":
|
|
6785
6917
|
return fieldsFromSchemaDetails({
|
|
6786
|
-
details: schemaFieldDetails(
|
|
6787
|
-
fallbackFields:
|
|
6918
|
+
details: schemaFieldDetails(input2.play?.inputSchema),
|
|
6919
|
+
fallbackFields: input2.fallbackFields
|
|
6788
6920
|
});
|
|
6789
6921
|
case "providers":
|
|
6790
|
-
return
|
|
6922
|
+
return input2.tools.flatMap(
|
|
6791
6923
|
(tool) => fieldsFromSchemaDetails({
|
|
6792
6924
|
details: schemaFieldDetails(tool.inputSchema),
|
|
6793
|
-
fallbackFields:
|
|
6925
|
+
fallbackFields: input2.fallbackFields
|
|
6794
6926
|
})
|
|
6795
6927
|
);
|
|
6796
6928
|
}
|
|
6797
6929
|
}
|
|
6798
|
-
function sourceRowTypeDefinition(
|
|
6799
|
-
switch (
|
|
6930
|
+
function sourceRowTypeDefinition(input2) {
|
|
6931
|
+
switch (input2.options.from.kind) {
|
|
6800
6932
|
case "csv":
|
|
6801
|
-
return `type ${
|
|
6933
|
+
return `type ${input2.sourceTypeName} = SourceCsvRow;`;
|
|
6802
6934
|
case "providers":
|
|
6803
6935
|
return renderPartialRowType({
|
|
6804
|
-
typeName:
|
|
6936
|
+
typeName: input2.sourceTypeName,
|
|
6805
6937
|
fields: [
|
|
6806
|
-
...new Set(
|
|
6938
|
+
...new Set(input2.sourceTools.flatMap(listRowCandidateKeysFromTool))
|
|
6807
6939
|
].sort(),
|
|
6808
6940
|
comment: "Candidate source row keys from described list getters; confirm the actual provider keys with source_*.extractedLists.*.keys before mapping."
|
|
6809
6941
|
});
|
|
6810
6942
|
case "play": {
|
|
6811
|
-
const details = schemaFieldDetails(
|
|
6943
|
+
const details = schemaFieldDetails(input2.sourcePlay?.outputSchema);
|
|
6812
6944
|
return renderPartialRowType({
|
|
6813
|
-
typeName:
|
|
6945
|
+
typeName: input2.sourceTypeName,
|
|
6814
6946
|
fields: [...details.required, ...details.optional].sort(),
|
|
6815
6947
|
comment: "Candidate source play output fields; confirm the selected rows field before mapping."
|
|
6816
6948
|
});
|
|
6817
6949
|
}
|
|
6818
6950
|
}
|
|
6819
6951
|
}
|
|
6820
|
-
function contactBridgeRowTypeDefinition(
|
|
6821
|
-
const config = playBootstrapTemplateConfig(
|
|
6822
|
-
if (config.sourceEntity !== "company" || !
|
|
6823
|
-
const emailFields = schemaFieldsForStage(
|
|
6824
|
-
tools:
|
|
6825
|
-
play:
|
|
6952
|
+
function contactBridgeRowTypeDefinition(input2) {
|
|
6953
|
+
const config = playBootstrapTemplateConfig(input2.options.template);
|
|
6954
|
+
if (config.sourceEntity !== "company" || !input2.options.people) return null;
|
|
6955
|
+
const emailFields = schemaFieldsForStage(input2.options.email, {
|
|
6956
|
+
tools: input2.finderTools.email_finder ?? [],
|
|
6957
|
+
play: input2.finderPlays.email_finder,
|
|
6826
6958
|
fallbackFields: ["first_name", "last_name", "domain"]
|
|
6827
6959
|
});
|
|
6828
|
-
const phoneFields = schemaFieldsForStage(
|
|
6829
|
-
tools:
|
|
6830
|
-
play:
|
|
6960
|
+
const phoneFields = schemaFieldsForStage(input2.options.phone, {
|
|
6961
|
+
tools: input2.finderTools.phone_finder ?? [],
|
|
6962
|
+
play: input2.finderPlays.phone_finder,
|
|
6831
6963
|
fallbackFields: ["first_name", "last_name", "domain"]
|
|
6832
6964
|
});
|
|
6833
6965
|
return renderPartialRowType({
|
|
6834
6966
|
typeName: "ContactSourceRow",
|
|
6835
6967
|
fields: [
|
|
6836
6968
|
.../* @__PURE__ */ new Set([
|
|
6837
|
-
...inputPropertyNames(
|
|
6969
|
+
...inputPropertyNames(input2.peoplePlay?.outputSchema),
|
|
6838
6970
|
...emailFields,
|
|
6839
6971
|
...phoneFields
|
|
6840
6972
|
])
|
|
@@ -6842,27 +6974,27 @@ function contactBridgeRowTypeDefinition(input) {
|
|
|
6842
6974
|
comment: "Fields the people play or later finder stages may need; the generated code still requires explicit mapping."
|
|
6843
6975
|
});
|
|
6844
6976
|
}
|
|
6845
|
-
function generateRowTypeDefinitions(
|
|
6846
|
-
const config = playBootstrapTemplateConfig(
|
|
6977
|
+
function generateRowTypeDefinitions(input2) {
|
|
6978
|
+
const config = playBootstrapTemplateConfig(input2.options.template);
|
|
6847
6979
|
const sourceTypeName = sourceCollectionTypeName(config.sourceEntity);
|
|
6848
6980
|
const definitions = [
|
|
6849
6981
|
sourceRowTypeDefinition({
|
|
6850
|
-
options:
|
|
6982
|
+
options: input2.options,
|
|
6851
6983
|
sourceTypeName,
|
|
6852
|
-
sourceTools:
|
|
6853
|
-
sourcePlay:
|
|
6984
|
+
sourceTools: input2.sourceTools,
|
|
6985
|
+
sourcePlay: input2.sourcePlay
|
|
6854
6986
|
}),
|
|
6855
|
-
contactBridgeRowTypeDefinition(
|
|
6987
|
+
contactBridgeRowTypeDefinition(input2)
|
|
6856
6988
|
];
|
|
6857
6989
|
return definitions.filter(Boolean).join("\n\n");
|
|
6858
6990
|
}
|
|
6859
|
-
function validateBootstrapRoutes(
|
|
6860
|
-
const config = playBootstrapTemplateConfig(
|
|
6991
|
+
function validateBootstrapRoutes(input2) {
|
|
6992
|
+
const config = playBootstrapTemplateConfig(input2.options.template);
|
|
6861
6993
|
const sourceCategory = config.sourceEntity === "company" ? PLAY_BOOTSTRAP_COMPANY_PROVIDER_CATEGORY : PLAY_BOOTSTRAP_PEOPLE_PROVIDER_CATEGORY;
|
|
6862
|
-
for (const tool of
|
|
6994
|
+
for (const tool of input2.sourceTools) {
|
|
6863
6995
|
if (!tool.categories.includes(sourceCategory)) {
|
|
6864
6996
|
throw new PlayBootstrapValidationError(
|
|
6865
|
-
`Cannot use ${tool.toolId} as a ${config.sourceEntity} source for ${
|
|
6997
|
+
`Cannot use ${tool.toolId} as a ${config.sourceEntity} source for ${input2.options.template}: expected category ${sourceCategory}, got ${tool.categories.join(", ") || "none"}. Run: deepline tools grep ${sourceCategory} --categories ${sourceCategory} --json`
|
|
6866
6998
|
);
|
|
6867
6999
|
}
|
|
6868
7000
|
if (getterNamesFromTool(tool, "list").length === 0) {
|
|
@@ -6871,14 +7003,14 @@ function validateBootstrapRoutes(input) {
|
|
|
6871
7003
|
);
|
|
6872
7004
|
}
|
|
6873
7005
|
}
|
|
6874
|
-
if (
|
|
7006
|
+
if (input2.options.people?.kind === "providers") {
|
|
6875
7007
|
throw new PlayBootstrapValidationError(
|
|
6876
7008
|
"Company-to-people bootstrap only accepts --people play:<play-ref> for now. Providers are too task-specific; choose or create a people play so the generated file can show the mapping contract."
|
|
6877
7009
|
);
|
|
6878
7010
|
}
|
|
6879
7011
|
for (const finder of ["email_finder", "phone_finder"]) {
|
|
6880
7012
|
const requiredCategory = PLAY_BOOTSTRAP_PROVIDER_CATEGORY_BY_FINDER[finder];
|
|
6881
|
-
for (const tool of
|
|
7013
|
+
for (const tool of input2.finderTools[finder] ?? []) {
|
|
6882
7014
|
if (!tool.categories.includes(requiredCategory)) {
|
|
6883
7015
|
throw new PlayBootstrapValidationError(
|
|
6884
7016
|
`Cannot use ${tool.toolId} for ${finder}: expected category ${requiredCategory}, got ${tool.categories.join(", ") || "none"}. Run: deepline tools grep ${requiredCategory} --categories ${requiredCategory} --json`
|
|
@@ -6900,118 +7032,118 @@ function sourceCollectionName(entity) {
|
|
|
6900
7032
|
return "contacts";
|
|
6901
7033
|
}
|
|
6902
7034
|
}
|
|
6903
|
-
function requiredGetterName(
|
|
6904
|
-
const getter = getterNamesFromTool(
|
|
7035
|
+
function requiredGetterName(input2) {
|
|
7036
|
+
const getter = getterNamesFromTool(input2.tool, input2.kind)[0];
|
|
6905
7037
|
if (!getter) {
|
|
6906
|
-
switch (
|
|
7038
|
+
switch (input2.kind) {
|
|
6907
7039
|
case "list":
|
|
6908
7040
|
throw new PlayBootstrapValidationError(
|
|
6909
|
-
`Cannot use ${
|
|
7041
|
+
`Cannot use ${input2.label} as a source: it exposes no extracted list getters.`
|
|
6910
7042
|
);
|
|
6911
7043
|
case "value":
|
|
6912
7044
|
throw new PlayBootstrapValidationError(
|
|
6913
|
-
`Cannot use ${
|
|
7045
|
+
`Cannot use ${input2.label} as a finder: it exposes no extracted value getters.`
|
|
6914
7046
|
);
|
|
6915
7047
|
}
|
|
6916
7048
|
}
|
|
6917
7049
|
return getter;
|
|
6918
7050
|
}
|
|
6919
|
-
function generateCsvSourceRowsBlock(
|
|
6920
|
-
return `const sourceDataset = await ctx.csv<SourceCsvRow>(${jsString(
|
|
6921
|
-
const ${
|
|
7051
|
+
function generateCsvSourceRowsBlock(input2) {
|
|
7052
|
+
return `const sourceDataset = await ctx.csv<SourceCsvRow>(${jsString(input2.packagedSourceCsvPath ?? input2.source.value)});
|
|
7053
|
+
const ${input2.collection}: ${input2.collectionType}[] = await sourceDataset.peek(limit);`;
|
|
6922
7054
|
}
|
|
6923
|
-
function generatePlaySourceRowsBlock(
|
|
7055
|
+
function generatePlaySourceRowsBlock(input2) {
|
|
6924
7056
|
const playInput = generatePlayInputObject({
|
|
6925
|
-
schema:
|
|
7057
|
+
schema: input2.sourcePlay?.inputSchema,
|
|
6926
7058
|
indent: " ",
|
|
6927
|
-
label:
|
|
6928
|
-
entity:
|
|
7059
|
+
label: input2.source.value,
|
|
7060
|
+
entity: input2.entity
|
|
6929
7061
|
});
|
|
6930
7062
|
return `const sourceInput = ${playInput};
|
|
6931
|
-
throw new Error(${jsString(`TODO: map sourceInput for ${
|
|
6932
|
-
const sourceResult = await ctx.runPlay('source_play', ${jsString(
|
|
6933
|
-
description: ${jsString(`Seed ${
|
|
7063
|
+
throw new Error(${jsString(`TODO: map sourceInput for ${input2.source.value}, choose the play output rows field, then delete this throw.`)});
|
|
7064
|
+
const sourceResult = await ctx.runPlay('source_play', ${jsString(input2.source.value)}, sourceInput, {
|
|
7065
|
+
description: ${jsString(`Seed ${input2.entity} rows from the selected play.`)},
|
|
6934
7066
|
});
|
|
6935
7067
|
// TODO: Replace sourceResult.rows with the selected play's actual row output field.
|
|
6936
|
-
const ${
|
|
7068
|
+
const ${input2.collection}: ${input2.collectionType}[] = (sourceResult.rows ?? []) as ${input2.collectionType}[];`;
|
|
6937
7069
|
}
|
|
6938
|
-
function generateProviderSourceBlock(
|
|
7070
|
+
function generateProviderSourceBlock(input2) {
|
|
6939
7071
|
const getter = requiredGetterName({
|
|
6940
|
-
tool:
|
|
7072
|
+
tool: input2.tool,
|
|
6941
7073
|
kind: "list",
|
|
6942
|
-
label:
|
|
7074
|
+
label: input2.provider
|
|
6943
7075
|
});
|
|
6944
|
-
const inputName = `${
|
|
6945
|
-
return `// ${
|
|
7076
|
+
const inputName = `${input2.entity}Input_${input2.index}`;
|
|
7077
|
+
return `// ${input2.entity === "company" ? "Company" : "People"} source provider: ${input2.provider}
|
|
6946
7078
|
const ${inputName}: Record<string, unknown> = ${generateSourceProviderInputObject(
|
|
6947
7079
|
{
|
|
6948
|
-
tool:
|
|
7080
|
+
tool: input2.tool,
|
|
6949
7081
|
indent: " ",
|
|
6950
|
-
label:
|
|
6951
|
-
entity:
|
|
7082
|
+
label: input2.provider,
|
|
7083
|
+
entity: input2.entity
|
|
6952
7084
|
}
|
|
6953
7085
|
)};
|
|
6954
|
-
throw new Error(${jsString(`TODO: fill ${inputName} for ${
|
|
6955
|
-
const source_${
|
|
6956
|
-
id: ${jsString(`${
|
|
6957
|
-
tool: ${jsString(
|
|
7086
|
+
throw new Error(${jsString(`TODO: fill ${inputName} for ${input2.provider}, then delete this throw.`)});
|
|
7087
|
+
const source_${input2.index} = await ctx.tools.execute({
|
|
7088
|
+
id: ${jsString(`${input2.entity}_source_${input2.index}`)},
|
|
7089
|
+
tool: ${jsString(input2.provider)},
|
|
6958
7090
|
input: ${inputName},
|
|
6959
|
-
description: ${jsString(`Seed ${
|
|
7091
|
+
description: ${jsString(`Seed ${input2.entity} rows from ${input2.provider}.`)},
|
|
6960
7092
|
});
|
|
6961
7093
|
// extractedLists.${getter}.get() returns provider-shaped rows. Do not assume canonical fields;
|
|
6962
|
-
// inspect source_${
|
|
6963
|
-
const sourceRows_${
|
|
7094
|
+
// inspect source_${input2.index}.extractedLists.${getter}.keys or the provider output schema, then map explicitly below.
|
|
7095
|
+
const sourceRows_${input2.index} = ${accessorExpression(`source_${input2.index}.extractedLists`, getter)}.get() as ${input2.collectionType}[];`;
|
|
6964
7096
|
}
|
|
6965
|
-
function generateProviderSourceRowsBlock(
|
|
6966
|
-
const blocks =
|
|
7097
|
+
function generateProviderSourceRowsBlock(input2) {
|
|
7098
|
+
const blocks = input2.source.values.map(
|
|
6967
7099
|
(provider, index) => generateProviderSourceBlock({
|
|
6968
7100
|
provider,
|
|
6969
7101
|
index,
|
|
6970
|
-
tool:
|
|
6971
|
-
entity:
|
|
6972
|
-
collectionType:
|
|
7102
|
+
tool: input2.sourceTools[index] ?? null,
|
|
7103
|
+
entity: input2.entity,
|
|
7104
|
+
collectionType: input2.collectionType
|
|
6973
7105
|
})
|
|
6974
7106
|
);
|
|
6975
7107
|
return `${blocks.join("\n\n ")}
|
|
6976
|
-
const ${
|
|
7108
|
+
const ${input2.collection}: ${input2.collectionType}[] = [${input2.source.values.map((_, index) => `...sourceRows_${index}`).join(", ")}];`;
|
|
6977
7109
|
}
|
|
6978
|
-
function generateSourceRowsBlock(
|
|
6979
|
-
const config = playBootstrapTemplateConfig(
|
|
7110
|
+
function generateSourceRowsBlock(input2) {
|
|
7111
|
+
const config = playBootstrapTemplateConfig(input2.options.template);
|
|
6980
7112
|
const entity = config.sourceEntity;
|
|
6981
7113
|
const collection = sourceCollectionName(entity);
|
|
6982
7114
|
const collectionType = sourceCollectionTypeName(entity);
|
|
6983
|
-
switch (
|
|
7115
|
+
switch (input2.options.from.kind) {
|
|
6984
7116
|
case "csv":
|
|
6985
7117
|
return generateCsvSourceRowsBlock({
|
|
6986
|
-
source:
|
|
7118
|
+
source: input2.options.from,
|
|
6987
7119
|
collection,
|
|
6988
7120
|
collectionType,
|
|
6989
|
-
packagedSourceCsvPath:
|
|
7121
|
+
packagedSourceCsvPath: input2.packagedSourceCsvPath
|
|
6990
7122
|
});
|
|
6991
7123
|
case "play":
|
|
6992
7124
|
return generatePlaySourceRowsBlock({
|
|
6993
|
-
source:
|
|
6994
|
-
sourcePlay:
|
|
7125
|
+
source: input2.options.from,
|
|
7126
|
+
sourcePlay: input2.sourcePlay,
|
|
6995
7127
|
entity,
|
|
6996
7128
|
collection,
|
|
6997
7129
|
collectionType
|
|
6998
7130
|
});
|
|
6999
7131
|
case "providers":
|
|
7000
7132
|
return generateProviderSourceRowsBlock({
|
|
7001
|
-
source:
|
|
7002
|
-
sourceTools:
|
|
7133
|
+
source: input2.options.from,
|
|
7134
|
+
sourceTools: input2.sourceTools,
|
|
7003
7135
|
entity,
|
|
7004
7136
|
collection,
|
|
7005
7137
|
collectionType
|
|
7006
7138
|
});
|
|
7007
7139
|
}
|
|
7008
7140
|
}
|
|
7009
|
-
function generateSourceSeedBlock(
|
|
7010
|
-
const sourceRows = generateSourceRowsBlock(
|
|
7011
|
-
const peoplePlayRef = stagePlayRef(
|
|
7141
|
+
function generateSourceSeedBlock(input2) {
|
|
7142
|
+
const sourceRows = generateSourceRowsBlock(input2);
|
|
7143
|
+
const peoplePlayRef = stagePlayRef(input2.options.people);
|
|
7012
7144
|
if (!peoplePlayRef) return sourceRows;
|
|
7013
7145
|
const peopleInput = generateCompanyInputObjectFromSchema(
|
|
7014
|
-
|
|
7146
|
+
input2.peoplePlay?.inputSchema,
|
|
7015
7147
|
" ",
|
|
7016
7148
|
peoplePlayRef,
|
|
7017
7149
|
["domain", "company_name"]
|
|
@@ -7033,15 +7165,15 @@ function generateSourceSeedBlock(input) {
|
|
|
7033
7165
|
contacts.push(...((peopleResult.rows ?? []) as ContactSourceRow[]));
|
|
7034
7166
|
}`;
|
|
7035
7167
|
}
|
|
7036
|
-
function finderProviderStepName(
|
|
7037
|
-
return `${
|
|
7168
|
+
function finderProviderStepName(input2) {
|
|
7169
|
+
return `${input2.aggregateStepName}${input2.index}_${safeIdentifier(input2.provider)}`;
|
|
7038
7170
|
}
|
|
7039
|
-
function finderValueGetter(
|
|
7040
|
-
const getters = getterNamesFromTool(
|
|
7041
|
-
const getter = getters.find((name) => name ===
|
|
7042
|
-
tool:
|
|
7171
|
+
function finderValueGetter(input2) {
|
|
7172
|
+
const getters = getterNamesFromTool(input2.tool, "value");
|
|
7173
|
+
const getter = getters.find((name) => name === input2.outputField) ?? requiredGetterName({
|
|
7174
|
+
tool: input2.tool,
|
|
7043
7175
|
kind: "value",
|
|
7044
|
-
label:
|
|
7176
|
+
label: input2.provider
|
|
7045
7177
|
});
|
|
7046
7178
|
return getter;
|
|
7047
7179
|
}
|
|
@@ -7049,157 +7181,157 @@ function optionalFinderValueExpression(candidateExpression, outputField) {
|
|
|
7049
7181
|
const valueExpression = /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(outputField) ? `${candidateExpression}?.${outputField}` : `${candidateExpression}?.[${jsString(outputField)}]`;
|
|
7050
7182
|
return `${valueExpression}?.trim()`;
|
|
7051
7183
|
}
|
|
7052
|
-
function generateFinderPlayStep(
|
|
7053
|
-
const outputField = PLAY_BOOTSTRAP_OUTPUT_FIELD_BY_FINDER[
|
|
7054
|
-
const resultTypeName = finderResultTypeName(
|
|
7184
|
+
function generateFinderPlayStep(input2) {
|
|
7185
|
+
const outputField = PLAY_BOOTSTRAP_OUTPUT_FIELD_BY_FINDER[input2.finder];
|
|
7186
|
+
const resultTypeName = finderResultTypeName(input2.finder);
|
|
7055
7187
|
const payload = generateContactInputObjectFromSchema(
|
|
7056
|
-
|
|
7188
|
+
input2.play?.inputSchema,
|
|
7057
7189
|
" ",
|
|
7058
|
-
|
|
7190
|
+
input2.stage.value
|
|
7059
7191
|
);
|
|
7060
7192
|
return `.step(${jsString(outputField)}, async (row, rowCtx) => {
|
|
7061
|
-
const ${
|
|
7062
|
-
throw new Error(${jsString(`TODO: map ${
|
|
7063
|
-
const ${
|
|
7064
|
-
${jsString(`${
|
|
7065
|
-
${jsString(
|
|
7066
|
-
${
|
|
7193
|
+
const ${input2.aggregateStepName}Input = ${payload};
|
|
7194
|
+
throw new Error(${jsString(`TODO: map ${input2.aggregateStepName}Input for ${input2.stage.value}, then delete this throw.`)});
|
|
7195
|
+
const ${input2.aggregateStepName}Result = await rowCtx.runPlay<${resultTypeName}>(
|
|
7196
|
+
${jsString(`${input2.aggregateStepName}Play`)},
|
|
7197
|
+
${jsString(input2.stage.value)},
|
|
7198
|
+
${input2.aggregateStepName}Input,
|
|
7067
7199
|
{
|
|
7068
|
-
description: ${jsString(`Run ${
|
|
7200
|
+
description: ${jsString(`Run ${input2.finder} play.`)},
|
|
7069
7201
|
},
|
|
7070
7202
|
);
|
|
7071
|
-
return typeof ${
|
|
7072
|
-
? ${
|
|
7073
|
-
: ${
|
|
7203
|
+
return typeof ${input2.aggregateStepName}Result === 'string'
|
|
7204
|
+
? ${input2.aggregateStepName}Result.trim() || null
|
|
7205
|
+
: ${input2.aggregateStepName}Result?.${outputField} ?? null;
|
|
7074
7206
|
})`;
|
|
7075
7207
|
}
|
|
7076
|
-
function generateFinderProviderResolver(
|
|
7208
|
+
function generateFinderProviderResolver(input2) {
|
|
7077
7209
|
const payload = generateContactInputObjectFromSchema(
|
|
7078
|
-
|
|
7210
|
+
input2.tool?.inputSchema,
|
|
7079
7211
|
" ",
|
|
7080
|
-
|
|
7212
|
+
input2.provider
|
|
7081
7213
|
);
|
|
7082
7214
|
const getter = finderValueGetter({
|
|
7083
|
-
tool:
|
|
7084
|
-
provider:
|
|
7085
|
-
outputField:
|
|
7215
|
+
tool: input2.tool,
|
|
7216
|
+
provider: input2.provider,
|
|
7217
|
+
outputField: input2.outputField
|
|
7086
7218
|
});
|
|
7087
7219
|
return `async (row, rowCtx) => {
|
|
7088
7220
|
const providerInput = ${payload};
|
|
7089
|
-
throw new Error(${jsString(`TODO: map providerInput for ${
|
|
7221
|
+
throw new Error(${jsString(`TODO: map providerInput for ${input2.provider}, then delete this throw.`)});
|
|
7090
7222
|
const result = await rowCtx.tools.execute({
|
|
7091
|
-
id: ${jsString(`${
|
|
7092
|
-
tool: ${jsString(
|
|
7223
|
+
id: ${jsString(`${input2.aggregateStepName}_${input2.providerIndex}`)},
|
|
7224
|
+
tool: ${jsString(input2.provider)},
|
|
7093
7225
|
input: providerInput,
|
|
7094
|
-
description: ${jsString(`Try ${
|
|
7226
|
+
description: ${jsString(`Try ${input2.provider} as a ${input2.finder}.`)},
|
|
7095
7227
|
});
|
|
7096
7228
|
return {
|
|
7097
|
-
${
|
|
7229
|
+
${input2.outputField}: (${accessorExpression("result.extractedValues", getter)}.get() as string | null) ?? null,
|
|
7098
7230
|
result,
|
|
7099
7231
|
};
|
|
7100
7232
|
}`;
|
|
7101
7233
|
}
|
|
7102
|
-
function generateFinderProviderStep(
|
|
7103
|
-
const stepName =
|
|
7104
|
-
switch (
|
|
7234
|
+
function generateFinderProviderStep(input2) {
|
|
7235
|
+
const stepName = input2.stepNames[input2.index];
|
|
7236
|
+
switch (input2.index) {
|
|
7105
7237
|
case 0:
|
|
7106
|
-
return `.step(${jsString(stepName)}, ${
|
|
7238
|
+
return `.step(${jsString(stepName)}, ${input2.resolver})`;
|
|
7107
7239
|
default: {
|
|
7108
|
-
const priorCandidates =
|
|
7240
|
+
const priorCandidates = input2.stepNames.slice(0, input2.index).map((name) => `row.${name}`).join(", ");
|
|
7109
7241
|
return `.step(
|
|
7110
7242
|
${jsString(stepName)},
|
|
7111
7243
|
when(
|
|
7112
|
-
(row) => ![${priorCandidates}].some((candidate) => ${optionalFinderValueExpression("candidate",
|
|
7113
|
-
${
|
|
7244
|
+
(row) => ![${priorCandidates}].some((candidate) => ${optionalFinderValueExpression("candidate", input2.outputField)}),
|
|
7245
|
+
${input2.resolver},
|
|
7114
7246
|
),
|
|
7115
7247
|
)`;
|
|
7116
7248
|
}
|
|
7117
7249
|
}
|
|
7118
7250
|
}
|
|
7119
|
-
function generateFinderProviderWaterfall(
|
|
7120
|
-
const legPrefix = finderProviderStepPrefix(
|
|
7121
|
-
const stepNames =
|
|
7251
|
+
function generateFinderProviderWaterfall(input2) {
|
|
7252
|
+
const legPrefix = finderProviderStepPrefix(input2.finder);
|
|
7253
|
+
const stepNames = input2.stage.values.map(
|
|
7122
7254
|
(provider, index) => finderProviderStepName({
|
|
7123
7255
|
aggregateStepName: legPrefix,
|
|
7124
7256
|
provider,
|
|
7125
7257
|
index
|
|
7126
7258
|
})
|
|
7127
7259
|
);
|
|
7128
|
-
const providerSteps =
|
|
7260
|
+
const providerSteps = input2.stage.values.map(
|
|
7129
7261
|
(provider, index) => generateFinderProviderStep({
|
|
7130
7262
|
index,
|
|
7131
7263
|
stepNames,
|
|
7132
|
-
outputField:
|
|
7264
|
+
outputField: input2.outputField,
|
|
7133
7265
|
resolver: generateFinderProviderResolver({
|
|
7134
|
-
finder:
|
|
7266
|
+
finder: input2.finder,
|
|
7135
7267
|
provider,
|
|
7136
7268
|
providerIndex: index,
|
|
7137
|
-
tool:
|
|
7138
|
-
aggregateStepName:
|
|
7139
|
-
outputField:
|
|
7269
|
+
tool: input2.tools[index] ?? null,
|
|
7270
|
+
aggregateStepName: input2.aggregateStepName,
|
|
7271
|
+
outputField: input2.outputField
|
|
7140
7272
|
})
|
|
7141
7273
|
})
|
|
7142
7274
|
);
|
|
7143
7275
|
const candidateNames = stepNames.map((name) => `row.${name}`).join(", ");
|
|
7144
|
-
return `// ${
|
|
7276
|
+
return `// ${input2.aggregateStepName} provider waterfall. Each provider leg is active once its TODO throw is removed;
|
|
7145
7277
|
// delete or comment out legs you do not want before running. Later legs are gated with when(...).
|
|
7146
7278
|
${providerSteps.join("\n ")}
|
|
7147
|
-
.step(${jsString(
|
|
7279
|
+
.step(${jsString(input2.aggregateStepName)}, (row) => {
|
|
7148
7280
|
const candidates = [${candidateNames}];
|
|
7149
|
-
const match = candidates.find((candidate) => ${optionalFinderValueExpression("candidate",
|
|
7150
|
-
return ${optionalFinderValueExpression("match",
|
|
7281
|
+
const match = candidates.find((candidate) => ${optionalFinderValueExpression("candidate", input2.outputField)});
|
|
7282
|
+
return ${optionalFinderValueExpression("match", input2.outputField)} ?? null;
|
|
7151
7283
|
})`;
|
|
7152
7284
|
}
|
|
7153
|
-
function generateFinderStageSteps(
|
|
7154
|
-
const outputField = PLAY_BOOTSTRAP_OUTPUT_FIELD_BY_FINDER[
|
|
7155
|
-
const aggregateStepName = stepFieldName(
|
|
7156
|
-
switch (
|
|
7285
|
+
function generateFinderStageSteps(input2) {
|
|
7286
|
+
const outputField = PLAY_BOOTSTRAP_OUTPUT_FIELD_BY_FINDER[input2.finder];
|
|
7287
|
+
const aggregateStepName = stepFieldName(input2.finder);
|
|
7288
|
+
switch (input2.stage.kind) {
|
|
7157
7289
|
case "play":
|
|
7158
7290
|
return generateFinderPlayStep({
|
|
7159
|
-
finder:
|
|
7160
|
-
stage:
|
|
7161
|
-
play:
|
|
7291
|
+
finder: input2.finder,
|
|
7292
|
+
stage: input2.stage,
|
|
7293
|
+
play: input2.finderPlays[input2.finder],
|
|
7162
7294
|
aggregateStepName
|
|
7163
7295
|
});
|
|
7164
7296
|
case "providers":
|
|
7165
7297
|
return generateFinderProviderWaterfall({
|
|
7166
|
-
finder:
|
|
7167
|
-
stage:
|
|
7168
|
-
tools:
|
|
7298
|
+
finder: input2.finder,
|
|
7299
|
+
stage: input2.stage,
|
|
7300
|
+
tools: input2.finderTools[input2.finder] ?? [],
|
|
7169
7301
|
aggregateStepName,
|
|
7170
7302
|
outputField
|
|
7171
7303
|
});
|
|
7172
7304
|
}
|
|
7173
7305
|
}
|
|
7174
|
-
function generateFinderSteps(
|
|
7306
|
+
function generateFinderSteps(input2) {
|
|
7175
7307
|
return ["email_finder", "phone_finder"].flatMap((finder) => {
|
|
7176
|
-
const stage = finderStage(
|
|
7308
|
+
const stage = finderStage(input2.options, finder);
|
|
7177
7309
|
return stage ? [
|
|
7178
7310
|
generateFinderStageSteps({
|
|
7179
|
-
...
|
|
7311
|
+
...input2,
|
|
7180
7312
|
finder,
|
|
7181
7313
|
stage
|
|
7182
7314
|
})
|
|
7183
7315
|
] : [];
|
|
7184
7316
|
}).join("\n ");
|
|
7185
7317
|
}
|
|
7186
|
-
function generateBootstrapPlaySource(
|
|
7187
|
-
const config = playBootstrapTemplateConfig(
|
|
7188
|
-
const sourceSeedBlock = generateSourceSeedBlock(
|
|
7189
|
-
const finderSteps = generateFinderSteps(
|
|
7190
|
-
const hasPeople = config.sourceEntity === "people" || Boolean(
|
|
7318
|
+
function generateBootstrapPlaySource(input2) {
|
|
7319
|
+
const config = playBootstrapTemplateConfig(input2.options.template);
|
|
7320
|
+
const sourceSeedBlock = generateSourceSeedBlock(input2);
|
|
7321
|
+
const finderSteps = generateFinderSteps(input2);
|
|
7322
|
+
const hasPeople = config.sourceEntity === "people" || Boolean(input2.options.people);
|
|
7191
7323
|
const sourceCollection = hasPeople ? "contacts" : "companies";
|
|
7192
7324
|
const mapSteps = finderSteps ? `
|
|
7193
7325
|
${finderSteps}` : "";
|
|
7194
|
-
const sourceCsvRowType =
|
|
7195
|
-
const rowTypeDefinitions = generateRowTypeDefinitions(
|
|
7196
|
-
const finderPlayResultTypes = generatedFinderPlayResultTypes(
|
|
7326
|
+
const sourceCsvRowType = input2.options.from.kind === "csv" ? renderSourceCsvRowType(input2.sourceCsvColumns) : "";
|
|
7327
|
+
const rowTypeDefinitions = generateRowTypeDefinitions(input2);
|
|
7328
|
+
const finderPlayResultTypes = generatedFinderPlayResultTypes(input2);
|
|
7197
7329
|
const typeDefinitions = [
|
|
7198
7330
|
sourceCsvRowType.trimEnd(),
|
|
7199
7331
|
rowTypeDefinitions,
|
|
7200
7332
|
finderPlayResultTypes
|
|
7201
7333
|
].filter((definition) => definition.trim().length > 0).join("\n\n");
|
|
7202
|
-
const importNames = needsWhenImport(
|
|
7334
|
+
const importNames = needsWhenImport(input2.options) ? "definePlay, when" : "definePlay";
|
|
7203
7335
|
return `import { ${importNames} } from 'deepline';
|
|
7204
7336
|
|
|
7205
7337
|
${typeDefinitions}
|
|
@@ -7208,8 +7340,8 @@ type Input = {
|
|
|
7208
7340
|
limit?: number;
|
|
7209
7341
|
};
|
|
7210
7342
|
|
|
7211
|
-
export default definePlay(${jsString(
|
|
7212
|
-
const limit = Math.max(1, Math.min(Number(input.limit ?? ${
|
|
7343
|
+
export default definePlay(${jsString(input2.options.name)}, async (ctx, input: Input = {}) => {
|
|
7344
|
+
const limit = Math.max(1, Math.min(Number(input.limit ?? ${input2.options.limit}), ${input2.options.limit}));
|
|
7213
7345
|
${sourceSeedBlock}
|
|
7214
7346
|
|
|
7215
7347
|
const rowsToProcess = ${sourceCollection}.slice(0, limit);
|
|
@@ -7221,7 +7353,7 @@ export default definePlay(${jsString(input.options.name)}, async (ctx, input: In
|
|
|
7221
7353
|
.map('bootstrap_rows', rowsToProcess)${mapSteps}
|
|
7222
7354
|
.run({
|
|
7223
7355
|
key: (_row, index) => index,
|
|
7224
|
-
description: ${jsString(`Bootstrap ${
|
|
7356
|
+
description: ${jsString(`Bootstrap ${input2.options.template}: seed source rows, run requested stages, then return the mapped rows.`)},
|
|
7225
7357
|
});
|
|
7226
7358
|
|
|
7227
7359
|
return {
|
|
@@ -7629,8 +7761,8 @@ var SHA256_ROUND_CONSTANTS = [
|
|
|
7629
7761
|
function rightRotate32(value, bits) {
|
|
7630
7762
|
return value >>> bits | value << 32 - bits;
|
|
7631
7763
|
}
|
|
7632
|
-
function sha256Hex(
|
|
7633
|
-
const bytes = Array.from(new TextEncoder().encode(
|
|
7764
|
+
function sha256Hex(input2) {
|
|
7765
|
+
const bytes = Array.from(new TextEncoder().encode(input2));
|
|
7634
7766
|
const bitLength = bytes.length * 8;
|
|
7635
7767
|
bytes.push(128);
|
|
7636
7768
|
while (bytes.length % 64 !== 56) {
|
|
@@ -7804,10 +7936,10 @@ function looksLikeInvalidExtractedGetter(error, sourceLine) {
|
|
|
7804
7936
|
if (!/Property '[^']+' does not exist on type/.test(error)) return false;
|
|
7805
7937
|
return /\bextracted(?:Values|Lists)\s*\./.test(sourceLine);
|
|
7806
7938
|
}
|
|
7807
|
-
function addPlayCheckRepairHints(
|
|
7939
|
+
function addPlayCheckRepairHints(input2) {
|
|
7808
7940
|
let addedHint = false;
|
|
7809
|
-
return
|
|
7810
|
-
const line = sourceLineForError(
|
|
7941
|
+
return input2.errors.map((error) => {
|
|
7942
|
+
const line = sourceLineForError(input2.sourceCode, error);
|
|
7811
7943
|
if (addedHint || !looksLikeInvalidExtractedGetter(error, line) || error.includes(EXTRACTED_GETTER_ERROR_HINT)) {
|
|
7812
7944
|
return error;
|
|
7813
7945
|
}
|
|
@@ -7869,9 +8001,9 @@ function parseReferencedPlayTarget2(target) {
|
|
|
7869
8001
|
function isPrebuiltReferenceTarget(target) {
|
|
7870
8002
|
return target.trim().toLowerCase().startsWith("prebuilt/");
|
|
7871
8003
|
}
|
|
7872
|
-
function buildBarePrebuiltReferenceError(
|
|
8004
|
+
function buildBarePrebuiltReferenceError(input2) {
|
|
7873
8005
|
return new Error(
|
|
7874
|
-
`Prebuilt play "${
|
|
8006
|
+
`Prebuilt play "${input2.requested}" must be referenced as "${input2.reference}". Use the prebuilt/ namespace anywhere you run, describe, get, or link to Deepline-managed plays.`
|
|
7875
8007
|
);
|
|
7876
8008
|
}
|
|
7877
8009
|
async function assertCanonicalNamedPlayReference(client, target) {
|
|
@@ -7914,23 +8046,23 @@ function buildCloneEditStarter(play) {
|
|
|
7914
8046
|
checkCommand: `deepline plays check ${path}`
|
|
7915
8047
|
};
|
|
7916
8048
|
}
|
|
7917
|
-
function materializeRemotePlaySource(
|
|
7918
|
-
if (isFileTarget(
|
|
8049
|
+
function materializeRemotePlaySource(input2) {
|
|
8050
|
+
if (isFileTarget(input2.target)) {
|
|
7919
8051
|
return null;
|
|
7920
8052
|
}
|
|
7921
|
-
if (!
|
|
8053
|
+
if (!input2.sourceCode.trim()) {
|
|
7922
8054
|
return null;
|
|
7923
8055
|
}
|
|
7924
|
-
const outputPath =
|
|
8056
|
+
const outputPath = input2.outPath ?? defaultMaterializedPlayPath(input2.playName);
|
|
7925
8057
|
if (existsSync7(outputPath)) {
|
|
7926
8058
|
const existingSource = readFileSync6(outputPath, "utf-8");
|
|
7927
|
-
if (existingSource ===
|
|
8059
|
+
if (existingSource === input2.sourceCode) {
|
|
7928
8060
|
return { path: outputPath, status: "unchanged", created: false };
|
|
7929
8061
|
}
|
|
7930
|
-
writeFileSync6(outputPath,
|
|
8062
|
+
writeFileSync6(outputPath, input2.sourceCode, "utf-8");
|
|
7931
8063
|
return { path: outputPath, status: "updated", created: false };
|
|
7932
8064
|
}
|
|
7933
|
-
writeFileSync6(outputPath,
|
|
8065
|
+
writeFileSync6(outputPath, input2.sourceCode, "utf-8");
|
|
7934
8066
|
return { path: outputPath, status: "created", created: true };
|
|
7935
8067
|
}
|
|
7936
8068
|
function formatLoadedPlayMessage(materializedFile) {
|
|
@@ -7980,12 +8112,12 @@ function isFileTarget(target) {
|
|
|
7980
8112
|
function looksLikeRunId(target) {
|
|
7981
8113
|
return /^play\/[^/]+\/run\/[^/]+/.test(target.trim());
|
|
7982
8114
|
}
|
|
7983
|
-
function formatPlayCommandReceivedRunIdError(
|
|
7984
|
-
return `\`deepline plays ${
|
|
8115
|
+
function formatPlayCommandReceivedRunIdError(input2) {
|
|
8116
|
+
return `\`deepline plays ${input2.command} <run-id>\` expects a play name, but this looks like a run id.
|
|
7985
8117
|
Use:
|
|
7986
|
-
deepline runs get ${
|
|
7987
|
-
deepline runs logs ${
|
|
7988
|
-
deepline runs export ${
|
|
8118
|
+
deepline runs get ${input2.runId} --json
|
|
8119
|
+
deepline runs logs ${input2.runId} --json
|
|
8120
|
+
deepline runs export ${input2.runId} --out output.csv`;
|
|
7989
8121
|
}
|
|
7990
8122
|
function looksLikeFilePath(target) {
|
|
7991
8123
|
if (target.trim().toLowerCase().startsWith("prebuilt/")) {
|
|
@@ -8039,9 +8171,9 @@ function parseInputFlagValue(raw) {
|
|
|
8039
8171
|
}
|
|
8040
8172
|
return raw;
|
|
8041
8173
|
}
|
|
8042
|
-
function getDottedInputValue(
|
|
8174
|
+
function getDottedInputValue(input2, path) {
|
|
8043
8175
|
const parts = path.split(".").map((part) => part.trim()).filter(Boolean);
|
|
8044
|
-
let cursor =
|
|
8176
|
+
let cursor = input2;
|
|
8045
8177
|
for (const part of parts) {
|
|
8046
8178
|
if (!cursor || typeof cursor !== "object" || Array.isArray(cursor)) {
|
|
8047
8179
|
return void 0;
|
|
@@ -8050,12 +8182,12 @@ function getDottedInputValue(input, path) {
|
|
|
8050
8182
|
}
|
|
8051
8183
|
return cursor;
|
|
8052
8184
|
}
|
|
8053
|
-
function setDottedInputValue(
|
|
8185
|
+
function setDottedInputValue(input2, path, value) {
|
|
8054
8186
|
const parts = path.split(".").map((part) => part.trim()).filter(Boolean);
|
|
8055
8187
|
if (parts.length === 0) {
|
|
8056
8188
|
throw new Error(`Invalid play input flag path: ${path}`);
|
|
8057
8189
|
}
|
|
8058
|
-
let cursor =
|
|
8190
|
+
let cursor = input2;
|
|
8059
8191
|
for (const part of parts.slice(0, -1)) {
|
|
8060
8192
|
const existing = cursor[part];
|
|
8061
8193
|
if (existing !== void 0 && (!existing || typeof existing !== "object" || Array.isArray(existing))) {
|
|
@@ -8122,17 +8254,17 @@ function inputContainsLocalFilePath(value) {
|
|
|
8122
8254
|
}
|
|
8123
8255
|
return false;
|
|
8124
8256
|
}
|
|
8125
|
-
function namedRunNeedsPlayDefinition(
|
|
8126
|
-
return
|
|
8257
|
+
function namedRunNeedsPlayDefinition(input2) {
|
|
8258
|
+
return input2.revisionSelector === "latest" || inputContainsLocalFilePath(input2.runtimeInput);
|
|
8127
8259
|
}
|
|
8128
|
-
async function stageFileInputArgs(
|
|
8260
|
+
async function stageFileInputArgs(input2) {
|
|
8129
8261
|
const uniqueBindings = [
|
|
8130
8262
|
...new Map(
|
|
8131
|
-
|
|
8263
|
+
input2.bindings.map((binding) => [binding.inputPath, binding])
|
|
8132
8264
|
).values()
|
|
8133
8265
|
];
|
|
8134
8266
|
const localFiles = uniqueBindings.flatMap((binding) => {
|
|
8135
|
-
const value = getDottedInputValue(
|
|
8267
|
+
const value = getDottedInputValue(input2.runtimeInput, binding.inputPath);
|
|
8136
8268
|
if (!isLocalFilePathValue(value)) return [];
|
|
8137
8269
|
const absolutePath = resolve10(value);
|
|
8138
8270
|
return [{ binding, absolutePath, logicalPath: basename3(absolutePath) }];
|
|
@@ -8140,22 +8272,22 @@ async function stageFileInputArgs(input) {
|
|
|
8140
8272
|
if (localFiles.length === 0) {
|
|
8141
8273
|
return { inputFile: null, packagedFiles: [] };
|
|
8142
8274
|
}
|
|
8143
|
-
|
|
8275
|
+
input2.progress.phase(
|
|
8144
8276
|
localFiles.length === 1 ? "staging input file" : "staging input files"
|
|
8145
8277
|
);
|
|
8146
|
-
const staged = await
|
|
8278
|
+
const staged = await input2.client.stagePlayFiles(
|
|
8147
8279
|
localFiles.map((file) => stageFile(file.logicalPath, file.absolutePath))
|
|
8148
8280
|
);
|
|
8149
8281
|
for (const [index, file] of localFiles.entries()) {
|
|
8150
8282
|
setDottedInputValue(
|
|
8151
|
-
|
|
8283
|
+
input2.runtimeInput,
|
|
8152
8284
|
file.binding.inputPath,
|
|
8153
8285
|
file.logicalPath
|
|
8154
8286
|
);
|
|
8155
8287
|
const stagedFile = staged[index];
|
|
8156
8288
|
if (stagedFile && stagedFile.logicalPath !== file.logicalPath) {
|
|
8157
8289
|
setDottedInputValue(
|
|
8158
|
-
|
|
8290
|
+
input2.runtimeInput,
|
|
8159
8291
|
file.binding.inputPath,
|
|
8160
8292
|
stagedFile.logicalPath
|
|
8161
8293
|
);
|
|
@@ -8440,16 +8572,16 @@ function buildStepReceiptsDebugCommand(runId) {
|
|
|
8440
8572
|
const sql = `select convert_from(k, 'UTF8') as receipt_key, case status when 0 then 'pending' when 1 then 'running' when 2 then 'completed' when 3 then 'failed' when 4 then 'skipped' else status::text end as status, output, error, updated_at from ${table} where run_id = ${quoteSqlLiteral(runId)} order by updated_at asc, receipt_key asc limit 20`;
|
|
8441
8573
|
return buildDebugDbQueryCommand(sql);
|
|
8442
8574
|
}
|
|
8443
|
-
function buildMapTableDebugCommand(
|
|
8575
|
+
function buildMapTableDebugCommand(input2) {
|
|
8444
8576
|
try {
|
|
8445
8577
|
const tableName = validatePlaySheetTableName(
|
|
8446
|
-
|
|
8447
|
-
|
|
8578
|
+
input2.playName,
|
|
8579
|
+
input2.tableNamespace
|
|
8448
8580
|
);
|
|
8449
8581
|
const table = `${quoteSqlIdentifier(
|
|
8450
8582
|
PLAY_CUSTOMER_STORAGE_SCHEMA_NAME
|
|
8451
8583
|
)}.${quoteSqlIdentifier(tableName)}`;
|
|
8452
|
-
const sql = `select * from ${table} where _run_id = ${quoteSqlLiteral(
|
|
8584
|
+
const sql = `select * from ${table} where _run_id = ${quoteSqlLiteral(input2.runId)} limit 20`;
|
|
8453
8585
|
return buildDebugDbQueryCommand(sql);
|
|
8454
8586
|
} catch {
|
|
8455
8587
|
return null;
|
|
@@ -8469,37 +8601,37 @@ function extractTableNamespaceFromLiveEvent(event) {
|
|
|
8469
8601
|
}
|
|
8470
8602
|
return null;
|
|
8471
8603
|
}
|
|
8472
|
-
function emitLiveDebugTableHints(
|
|
8473
|
-
if (
|
|
8604
|
+
function emitLiveDebugTableHints(input2) {
|
|
8605
|
+
if (input2.jsonOutput || !input2.runId || input2.runId === "pending") {
|
|
8474
8606
|
return;
|
|
8475
8607
|
}
|
|
8476
|
-
|
|
8477
|
-
const receiptsKey = `receipts:${
|
|
8478
|
-
if (!
|
|
8479
|
-
|
|
8480
|
-
|
|
8481
|
-
`Debug top-level outputs: ${buildStepReceiptsDebugCommand(
|
|
8608
|
+
input2.state.emittedDebugKeys ??= /* @__PURE__ */ new Set();
|
|
8609
|
+
const receiptsKey = `receipts:${input2.runId}`;
|
|
8610
|
+
if (!input2.state.emittedDebugKeys.has(receiptsKey)) {
|
|
8611
|
+
input2.state.emittedDebugKeys.add(receiptsKey);
|
|
8612
|
+
input2.progress.writeLine(
|
|
8613
|
+
`Debug top-level outputs: ${buildStepReceiptsDebugCommand(input2.runId)}`,
|
|
8482
8614
|
process.stdout
|
|
8483
8615
|
);
|
|
8484
8616
|
}
|
|
8485
|
-
const tableNamespace = extractTableNamespaceFromLiveEvent(
|
|
8617
|
+
const tableNamespace = extractTableNamespaceFromLiveEvent(input2.event);
|
|
8486
8618
|
if (!tableNamespace) {
|
|
8487
8619
|
return;
|
|
8488
8620
|
}
|
|
8489
|
-
const tableKey = `table:${
|
|
8490
|
-
if (
|
|
8621
|
+
const tableKey = `table:${input2.runId}:${tableNamespace}`;
|
|
8622
|
+
if (input2.state.emittedDebugKeys.has(tableKey)) {
|
|
8491
8623
|
return;
|
|
8492
8624
|
}
|
|
8493
8625
|
const command = buildMapTableDebugCommand({
|
|
8494
|
-
playName:
|
|
8495
|
-
runId:
|
|
8626
|
+
playName: input2.playName,
|
|
8627
|
+
runId: input2.runId,
|
|
8496
8628
|
tableNamespace
|
|
8497
8629
|
});
|
|
8498
8630
|
if (!command) {
|
|
8499
8631
|
return;
|
|
8500
8632
|
}
|
|
8501
|
-
|
|
8502
|
-
|
|
8633
|
+
input2.state.emittedDebugKeys.add(tableKey);
|
|
8634
|
+
input2.progress.writeLine(
|
|
8503
8635
|
`Debug rows for ${tableNamespace}: ${command}`,
|
|
8504
8636
|
process.stdout
|
|
8505
8637
|
);
|
|
@@ -8532,9 +8664,9 @@ function formatProgressLabel(raw) {
|
|
|
8532
8664
|
const value = typeof raw === "string" && raw.trim() ? raw.trim() : "step";
|
|
8533
8665
|
return value.replace(/^map:/, "").replace(/^tool:/, "");
|
|
8534
8666
|
}
|
|
8535
|
-
function formatProgressCounts(
|
|
8536
|
-
const completed = typeof
|
|
8537
|
-
const total = typeof
|
|
8667
|
+
function formatProgressCounts(input2) {
|
|
8668
|
+
const completed = typeof input2.completed === "number" && Number.isFinite(input2.completed) ? input2.completed : null;
|
|
8669
|
+
const total = typeof input2.total === "number" && Number.isFinite(input2.total) ? input2.total : null;
|
|
8538
8670
|
if (completed === null || total === null || total <= 0) {
|
|
8539
8671
|
return null;
|
|
8540
8672
|
}
|
|
@@ -8542,7 +8674,7 @@ function formatProgressCounts(input) {
|
|
|
8542
8674
|
0,
|
|
8543
8675
|
Math.min(100, Math.round(completed / total * 100))
|
|
8544
8676
|
);
|
|
8545
|
-
const failed = typeof
|
|
8677
|
+
const failed = typeof input2.failed === "number" && Number.isFinite(input2.failed) && input2.failed > 0 ? `, failed ${formatInteger(input2.failed)}` : "";
|
|
8546
8678
|
return `${formatInteger(completed)}/${formatInteger(total)} (${percent}%)${failed}`;
|
|
8547
8679
|
}
|
|
8548
8680
|
function getProgressLinesFromLiveEvent(event) {
|
|
@@ -8584,14 +8716,14 @@ function getProgressLinesFromLiveEvent(event) {
|
|
|
8584
8716
|
}
|
|
8585
8717
|
return lines;
|
|
8586
8718
|
}
|
|
8587
|
-
function printPlayProgressLines(
|
|
8588
|
-
for (const line of
|
|
8719
|
+
function printPlayProgressLines(input2) {
|
|
8720
|
+
for (const line of input2.lines) {
|
|
8589
8721
|
const signature = line.trim();
|
|
8590
|
-
if (!signature ||
|
|
8722
|
+
if (!signature || input2.state.lastProgressSignature === signature) {
|
|
8591
8723
|
continue;
|
|
8592
8724
|
}
|
|
8593
|
-
|
|
8594
|
-
|
|
8725
|
+
input2.state.lastProgressSignature = signature;
|
|
8726
|
+
input2.progress.writeLine(line);
|
|
8595
8727
|
}
|
|
8596
8728
|
}
|
|
8597
8729
|
function buildPlayDashboardUrl(baseUrl, playName) {
|
|
@@ -8599,102 +8731,102 @@ function buildPlayDashboardUrl(baseUrl, playName) {
|
|
|
8599
8731
|
const encodedPlayName = encodeURIComponent(playName);
|
|
8600
8732
|
return `${trimmedBase}/dashboard/plays/${encodedPlayName}`;
|
|
8601
8733
|
}
|
|
8602
|
-
function openPlayDashboard(
|
|
8603
|
-
if (
|
|
8734
|
+
function openPlayDashboard(input2) {
|
|
8735
|
+
if (input2.jsonOutput || input2.noOpen || !input2.dashboardUrl) {
|
|
8604
8736
|
return;
|
|
8605
8737
|
}
|
|
8606
|
-
openInBrowser(
|
|
8738
|
+
openInBrowser(input2.dashboardUrl);
|
|
8607
8739
|
}
|
|
8608
|
-
function printPlayLogLines(
|
|
8609
|
-
for (const line of
|
|
8610
|
-
if (
|
|
8740
|
+
function printPlayLogLines(input2) {
|
|
8741
|
+
for (const line of input2.lines) {
|
|
8742
|
+
if (input2.emitLogs) {
|
|
8611
8743
|
const formatted = formatPlayLogLine(
|
|
8612
8744
|
line,
|
|
8613
|
-
|
|
8614
|
-
|
|
8745
|
+
input2.status ?? void 0,
|
|
8746
|
+
input2.state
|
|
8615
8747
|
);
|
|
8616
8748
|
if (formatted) {
|
|
8617
|
-
|
|
8749
|
+
input2.progress.writeLogLine(formatted);
|
|
8618
8750
|
}
|
|
8619
8751
|
}
|
|
8620
|
-
|
|
8752
|
+
input2.state.lastLogIndex += 1;
|
|
8621
8753
|
}
|
|
8622
8754
|
}
|
|
8623
|
-
function assertPlayWaitNotTimedOut(
|
|
8624
|
-
if (
|
|
8625
|
-
const hasRealRunId =
|
|
8626
|
-
const phaseSuffix =
|
|
8627
|
-
const tailHint = hasRealRunId ? ` Run 'deepline runs tail ${
|
|
8755
|
+
function assertPlayWaitNotTimedOut(input2) {
|
|
8756
|
+
if (input2.waitTimeoutMs !== null && Date.now() - input2.startedAt >= input2.waitTimeoutMs) {
|
|
8757
|
+
const hasRealRunId = input2.workflowId.length > 0 && input2.workflowId !== "pending";
|
|
8758
|
+
const phaseSuffix = input2.lastPhase && input2.lastPhase.trim() ? ` (last observed phase: ${input2.lastPhase.trim()})` : "";
|
|
8759
|
+
const tailHint = hasRealRunId ? ` Run 'deepline runs tail ${input2.workflowId} --json' to inspect it, or rerun with a larger --tail-timeout-ms.` : ` The run never reported a workflow id \u2014 the start request likely failed before reaching the scheduler. Check server logs and rerun with a larger --tail-timeout-ms.`;
|
|
8628
8760
|
throw new DeeplineError(
|
|
8629
|
-
`Timed out waiting for play ${hasRealRunId ?
|
|
8761
|
+
`Timed out waiting for play ${hasRealRunId ? input2.workflowId : "<no run id>"} after ${Math.ceil(input2.waitTimeoutMs / 1e3)}s${phaseSuffix}.${tailHint}`,
|
|
8630
8762
|
void 0,
|
|
8631
8763
|
"PLAY_WAIT_TIMEOUT",
|
|
8632
8764
|
{
|
|
8633
|
-
...hasRealRunId ? { runId:
|
|
8634
|
-
...
|
|
8635
|
-
timeoutMs:
|
|
8765
|
+
...hasRealRunId ? { runId: input2.workflowId, workflowId: input2.workflowId } : {},
|
|
8766
|
+
...input2.lastPhase ? { phase: input2.lastPhase } : {},
|
|
8767
|
+
timeoutMs: input2.waitTimeoutMs
|
|
8636
8768
|
}
|
|
8637
8769
|
);
|
|
8638
8770
|
}
|
|
8639
8771
|
}
|
|
8640
|
-
async function waitForPlayCompletionByStream(
|
|
8772
|
+
async function waitForPlayCompletionByStream(input2) {
|
|
8641
8773
|
const controller = new AbortController();
|
|
8642
8774
|
let timedOut = false;
|
|
8643
8775
|
let lastPhase = null;
|
|
8644
|
-
const timeout =
|
|
8776
|
+
const timeout = input2.waitTimeoutMs === null ? null : setTimeout(
|
|
8645
8777
|
() => {
|
|
8646
8778
|
timedOut = true;
|
|
8647
8779
|
controller.abort();
|
|
8648
8780
|
},
|
|
8649
|
-
Math.max(1,
|
|
8781
|
+
Math.max(1, input2.waitTimeoutMs - (Date.now() - input2.startedAt))
|
|
8650
8782
|
);
|
|
8651
8783
|
try {
|
|
8652
|
-
for await (const event of
|
|
8653
|
-
|
|
8784
|
+
for await (const event of input2.client.streamPlayRunEvents(
|
|
8785
|
+
input2.workflowId,
|
|
8654
8786
|
{ signal: controller.signal }
|
|
8655
8787
|
)) {
|
|
8656
|
-
assertPlayWaitNotTimedOut({ ...
|
|
8788
|
+
assertPlayWaitNotTimedOut({ ...input2, lastPhase });
|
|
8657
8789
|
const phase = describeLiveEventPhase(event);
|
|
8658
8790
|
if (phase) {
|
|
8659
8791
|
lastPhase = phase;
|
|
8660
|
-
|
|
8792
|
+
input2.progress.phase(phase);
|
|
8661
8793
|
}
|
|
8662
8794
|
emitLiveDebugTableHints({
|
|
8663
8795
|
event,
|
|
8664
|
-
playName:
|
|
8665
|
-
runId:
|
|
8666
|
-
jsonOutput:
|
|
8667
|
-
state:
|
|
8668
|
-
progress:
|
|
8796
|
+
playName: input2.playName,
|
|
8797
|
+
runId: input2.workflowId,
|
|
8798
|
+
jsonOutput: input2.jsonOutput,
|
|
8799
|
+
state: input2.state,
|
|
8800
|
+
progress: input2.progress
|
|
8669
8801
|
});
|
|
8670
8802
|
printPlayLogLines({
|
|
8671
8803
|
lines: getLogLinesFromLiveEvent(event),
|
|
8672
8804
|
status: null,
|
|
8673
|
-
jsonOutput:
|
|
8674
|
-
emitLogs:
|
|
8675
|
-
state:
|
|
8676
|
-
progress:
|
|
8805
|
+
jsonOutput: input2.jsonOutput,
|
|
8806
|
+
emitLogs: input2.emitLogs,
|
|
8807
|
+
state: input2.state,
|
|
8808
|
+
progress: input2.progress
|
|
8677
8809
|
});
|
|
8678
|
-
if (!
|
|
8810
|
+
if (!input2.jsonOutput) {
|
|
8679
8811
|
printPlayProgressLines({
|
|
8680
8812
|
lines: getProgressLinesFromLiveEvent(event),
|
|
8681
|
-
state:
|
|
8682
|
-
progress:
|
|
8813
|
+
state: input2.state,
|
|
8814
|
+
progress: input2.progress
|
|
8683
8815
|
});
|
|
8684
8816
|
}
|
|
8685
8817
|
const status = getStatusFromLiveEvent(event);
|
|
8686
8818
|
if (status && TERMINAL_PLAY_STATUSES2.has(status)) {
|
|
8687
|
-
const finalStatus = await
|
|
8819
|
+
const finalStatus = await input2.client.getPlayStatus(input2.workflowId, {
|
|
8688
8820
|
billing: false
|
|
8689
8821
|
});
|
|
8690
8822
|
if (TERMINAL_PLAY_STATUSES2.has(finalStatus.status)) {
|
|
8691
|
-
return
|
|
8823
|
+
return input2.dashboardUrl ? { ...finalStatus, dashboardUrl: input2.dashboardUrl } : finalStatus;
|
|
8692
8824
|
}
|
|
8693
8825
|
}
|
|
8694
8826
|
}
|
|
8695
8827
|
} catch (error) {
|
|
8696
8828
|
if (timedOut) {
|
|
8697
|
-
assertPlayWaitNotTimedOut({ ...
|
|
8829
|
+
assertPlayWaitNotTimedOut({ ...input2, lastPhase });
|
|
8698
8830
|
}
|
|
8699
8831
|
throw error;
|
|
8700
8832
|
} finally {
|
|
@@ -8704,25 +8836,25 @@ async function waitForPlayCompletionByStream(input) {
|
|
|
8704
8836
|
}
|
|
8705
8837
|
const phaseSuffix = lastPhase && lastPhase.trim() ? ` (last observed phase: ${lastPhase.trim()})` : "";
|
|
8706
8838
|
throw new DeeplineError(
|
|
8707
|
-
`Play live stream ended before the run reached a terminal state runId=${
|
|
8839
|
+
`Play live stream ended before the run reached a terminal state runId=${input2.workflowId}${phaseSuffix}.`,
|
|
8708
8840
|
void 0,
|
|
8709
8841
|
"PLAY_LIVE_STREAM_ENDED",
|
|
8710
8842
|
{
|
|
8711
|
-
runId:
|
|
8712
|
-
workflowId:
|
|
8843
|
+
runId: input2.workflowId,
|
|
8844
|
+
workflowId: input2.workflowId,
|
|
8713
8845
|
...lastPhase ? { phase: lastPhase } : {}
|
|
8714
8846
|
}
|
|
8715
8847
|
);
|
|
8716
8848
|
}
|
|
8717
|
-
async function startAndWaitForPlayCompletionByStream(
|
|
8849
|
+
async function startAndWaitForPlayCompletionByStream(input2) {
|
|
8718
8850
|
for (let attempt = 0; attempt <= PLAY_START_TRANSIENT_RETRY_DELAYS_MS.length; attempt += 1) {
|
|
8719
|
-
const status = await startAndWaitForPlayCompletionByStreamOnce(
|
|
8851
|
+
const status = await startAndWaitForPlayCompletionByStreamOnce(input2);
|
|
8720
8852
|
const retryDelayMs = PLAY_START_TRANSIENT_RETRY_DELAYS_MS[attempt];
|
|
8721
8853
|
if (retryDelayMs === void 0 || !isRetryablePendingStartFailure(status)) {
|
|
8722
8854
|
return status;
|
|
8723
8855
|
}
|
|
8724
|
-
if (!
|
|
8725
|
-
|
|
8856
|
+
if (!input2.jsonOutput) {
|
|
8857
|
+
input2.progress.writeLine(
|
|
8726
8858
|
`[play watch] start failed before run id with a transient error; retrying (${playStatusErrorText(status)})`
|
|
8727
8859
|
);
|
|
8728
8860
|
}
|
|
@@ -8730,23 +8862,23 @@ async function startAndWaitForPlayCompletionByStream(input) {
|
|
|
8730
8862
|
phase: "cli.play_start_stream_retry",
|
|
8731
8863
|
ms: 0,
|
|
8732
8864
|
ok: true,
|
|
8733
|
-
playName:
|
|
8865
|
+
playName: input2.playName,
|
|
8734
8866
|
attempt: attempt + 1,
|
|
8735
8867
|
reason: playStatusErrorText(status)
|
|
8736
8868
|
});
|
|
8737
8869
|
await sleep4(retryDelayMs);
|
|
8738
8870
|
}
|
|
8739
8871
|
throw new DeeplineError(
|
|
8740
|
-
`Play ${
|
|
8872
|
+
`Play ${input2.playName} did not start after retrying transient start failures.`,
|
|
8741
8873
|
void 0,
|
|
8742
8874
|
"PLAY_START_RETRY_EXHAUSTED"
|
|
8743
8875
|
);
|
|
8744
8876
|
}
|
|
8745
|
-
async function startAndWaitForPlayCompletionByStreamOnce(
|
|
8877
|
+
async function startAndWaitForPlayCompletionByStreamOnce(input2) {
|
|
8746
8878
|
const startedAt = Date.now();
|
|
8747
8879
|
const dashboardUrl = buildPlayDashboardUrl(
|
|
8748
|
-
|
|
8749
|
-
|
|
8880
|
+
input2.client.baseUrl,
|
|
8881
|
+
input2.playName
|
|
8750
8882
|
);
|
|
8751
8883
|
const state = {
|
|
8752
8884
|
lastLogIndex: 0,
|
|
@@ -8760,15 +8892,15 @@ async function startAndWaitForPlayCompletionByStreamOnce(input) {
|
|
|
8760
8892
|
let eventCount = 0;
|
|
8761
8893
|
let firstRunIdMs = null;
|
|
8762
8894
|
let lastPhase = null;
|
|
8763
|
-
const timeout =
|
|
8895
|
+
const timeout = input2.waitTimeoutMs === null ? null : setTimeout(
|
|
8764
8896
|
() => {
|
|
8765
8897
|
timedOut = true;
|
|
8766
8898
|
controller.abort();
|
|
8767
8899
|
},
|
|
8768
|
-
Math.max(1,
|
|
8900
|
+
Math.max(1, input2.waitTimeoutMs)
|
|
8769
8901
|
);
|
|
8770
8902
|
try {
|
|
8771
|
-
for await (const event of
|
|
8903
|
+
for await (const event of input2.client.startPlayRunStream(input2.request, {
|
|
8772
8904
|
signal: controller.signal
|
|
8773
8905
|
})) {
|
|
8774
8906
|
eventCount += 1;
|
|
@@ -8779,55 +8911,55 @@ async function startAndWaitForPlayCompletionByStreamOnce(input) {
|
|
|
8779
8911
|
}
|
|
8780
8912
|
const workflowId = lastKnownWorkflowId || "pending";
|
|
8781
8913
|
if (workflowId !== "pending" && !emittedDashboardUrl) {
|
|
8782
|
-
if (!
|
|
8914
|
+
if (!input2.jsonOutput) {
|
|
8783
8915
|
writeStartedPlayRun({
|
|
8784
8916
|
runId: workflowId,
|
|
8785
|
-
playName:
|
|
8917
|
+
playName: input2.playName,
|
|
8786
8918
|
dashboardUrl,
|
|
8787
8919
|
jsonOutput: false,
|
|
8788
|
-
progress:
|
|
8920
|
+
progress: input2.progress
|
|
8789
8921
|
});
|
|
8790
8922
|
}
|
|
8791
8923
|
openPlayDashboard({
|
|
8792
8924
|
dashboardUrl,
|
|
8793
|
-
jsonOutput:
|
|
8794
|
-
noOpen:
|
|
8925
|
+
jsonOutput: input2.jsonOutput,
|
|
8926
|
+
noOpen: input2.noOpen
|
|
8795
8927
|
});
|
|
8796
|
-
|
|
8928
|
+
input2.progress.phase(`loading play on ${dashboardUrl}`);
|
|
8797
8929
|
emittedDashboardUrl = true;
|
|
8798
8930
|
}
|
|
8799
8931
|
assertPlayWaitNotTimedOut({
|
|
8800
8932
|
workflowId,
|
|
8801
8933
|
startedAt,
|
|
8802
|
-
waitTimeoutMs:
|
|
8934
|
+
waitTimeoutMs: input2.waitTimeoutMs,
|
|
8803
8935
|
lastPhase
|
|
8804
8936
|
});
|
|
8805
8937
|
const phase = describeLiveEventPhase(event);
|
|
8806
8938
|
if (phase) {
|
|
8807
8939
|
lastPhase = phase;
|
|
8808
|
-
|
|
8940
|
+
input2.progress.phase(phase);
|
|
8809
8941
|
}
|
|
8810
8942
|
printPlayLogLines({
|
|
8811
8943
|
lines: getLogLinesFromLiveEvent(event),
|
|
8812
8944
|
status: null,
|
|
8813
|
-
jsonOutput:
|
|
8814
|
-
emitLogs:
|
|
8945
|
+
jsonOutput: input2.jsonOutput,
|
|
8946
|
+
emitLogs: input2.emitLogs,
|
|
8815
8947
|
state,
|
|
8816
|
-
progress:
|
|
8948
|
+
progress: input2.progress
|
|
8817
8949
|
});
|
|
8818
8950
|
emitLiveDebugTableHints({
|
|
8819
8951
|
event,
|
|
8820
|
-
playName:
|
|
8952
|
+
playName: input2.playName,
|
|
8821
8953
|
runId: workflowId,
|
|
8822
|
-
jsonOutput:
|
|
8954
|
+
jsonOutput: input2.jsonOutput,
|
|
8823
8955
|
state,
|
|
8824
|
-
progress:
|
|
8956
|
+
progress: input2.progress
|
|
8825
8957
|
});
|
|
8826
|
-
if (!
|
|
8958
|
+
if (!input2.jsonOutput) {
|
|
8827
8959
|
printPlayProgressLines({
|
|
8828
8960
|
lines: getProgressLinesFromLiveEvent(event),
|
|
8829
8961
|
state,
|
|
8830
|
-
progress:
|
|
8962
|
+
progress: input2.progress
|
|
8831
8963
|
});
|
|
8832
8964
|
}
|
|
8833
8965
|
const finalStatus = getFinalStatusFromLiveEvent(event);
|
|
@@ -8836,7 +8968,7 @@ async function startAndWaitForPlayCompletionByStreamOnce(input) {
|
|
|
8836
8968
|
phase: "cli.play_start_stream_terminal",
|
|
8837
8969
|
ms: Date.now() - startedAt,
|
|
8838
8970
|
ok: true,
|
|
8839
|
-
playName:
|
|
8971
|
+
playName: input2.playName,
|
|
8840
8972
|
workflowId: finalStatus.runId || lastKnownWorkflowId || null,
|
|
8841
8973
|
eventCount,
|
|
8842
8974
|
firstRunIdMs,
|
|
@@ -8850,7 +8982,7 @@ async function startAndWaitForPlayCompletionByStreamOnce(input) {
|
|
|
8850
8982
|
assertPlayWaitNotTimedOut({
|
|
8851
8983
|
workflowId: lastKnownWorkflowId,
|
|
8852
8984
|
startedAt,
|
|
8853
|
-
waitTimeoutMs:
|
|
8985
|
+
waitTimeoutMs: input2.waitTimeoutMs,
|
|
8854
8986
|
lastPhase
|
|
8855
8987
|
});
|
|
8856
8988
|
}
|
|
@@ -8859,7 +8991,7 @@ async function startAndWaitForPlayCompletionByStreamOnce(input) {
|
|
|
8859
8991
|
clearTimeout(timeout);
|
|
8860
8992
|
}
|
|
8861
8993
|
const reason = error instanceof Error ? error.message : String(error);
|
|
8862
|
-
if (!
|
|
8994
|
+
if (!input2.jsonOutput) {
|
|
8863
8995
|
process.stderr.write(
|
|
8864
8996
|
`[play watch] start stream failed after run ${lastKnownWorkflowId}; reconnecting to run stream (${reason})
|
|
8865
8997
|
`
|
|
@@ -8869,7 +9001,7 @@ async function startAndWaitForPlayCompletionByStreamOnce(input) {
|
|
|
8869
9001
|
phase: "cli.play_start_stream_reconnect",
|
|
8870
9002
|
ms: Date.now() - startedAt,
|
|
8871
9003
|
ok: true,
|
|
8872
|
-
playName:
|
|
9004
|
+
playName: input2.playName,
|
|
8873
9005
|
workflowId: lastKnownWorkflowId,
|
|
8874
9006
|
eventCount,
|
|
8875
9007
|
firstRunIdMs,
|
|
@@ -8877,16 +9009,16 @@ async function startAndWaitForPlayCompletionByStreamOnce(input) {
|
|
|
8877
9009
|
reason
|
|
8878
9010
|
});
|
|
8879
9011
|
return waitForPlayCompletionByStream({
|
|
8880
|
-
client:
|
|
8881
|
-
playName:
|
|
9012
|
+
client: input2.client,
|
|
9013
|
+
playName: input2.playName,
|
|
8882
9014
|
workflowId: lastKnownWorkflowId,
|
|
8883
9015
|
dashboardUrl,
|
|
8884
|
-
jsonOutput:
|
|
8885
|
-
emitLogs:
|
|
8886
|
-
waitTimeoutMs:
|
|
9016
|
+
jsonOutput: input2.jsonOutput,
|
|
9017
|
+
emitLogs: input2.emitLogs,
|
|
9018
|
+
waitTimeoutMs: input2.waitTimeoutMs,
|
|
8887
9019
|
startedAt,
|
|
8888
9020
|
state,
|
|
8889
|
-
progress:
|
|
9021
|
+
progress: input2.progress
|
|
8890
9022
|
});
|
|
8891
9023
|
}
|
|
8892
9024
|
throw error;
|
|
@@ -8896,8 +9028,8 @@ async function startAndWaitForPlayCompletionByStreamOnce(input) {
|
|
|
8896
9028
|
}
|
|
8897
9029
|
}
|
|
8898
9030
|
if (lastKnownWorkflowId) {
|
|
8899
|
-
if (!
|
|
8900
|
-
|
|
9031
|
+
if (!input2.jsonOutput) {
|
|
9032
|
+
input2.progress.writeLine(
|
|
8901
9033
|
`[play watch] start stream ended after run ${lastKnownWorkflowId}; reconnecting to run stream`
|
|
8902
9034
|
);
|
|
8903
9035
|
}
|
|
@@ -8905,7 +9037,7 @@ async function startAndWaitForPlayCompletionByStreamOnce(input) {
|
|
|
8905
9037
|
phase: "cli.play_start_stream_reconnect",
|
|
8906
9038
|
ms: Date.now() - startedAt,
|
|
8907
9039
|
ok: true,
|
|
8908
|
-
playName:
|
|
9040
|
+
playName: input2.playName,
|
|
8909
9041
|
workflowId: lastKnownWorkflowId,
|
|
8910
9042
|
eventCount,
|
|
8911
9043
|
firstRunIdMs,
|
|
@@ -8913,16 +9045,16 @@ async function startAndWaitForPlayCompletionByStreamOnce(input) {
|
|
|
8913
9045
|
reason: "stream ended before terminal event"
|
|
8914
9046
|
});
|
|
8915
9047
|
return waitForPlayCompletionByStream({
|
|
8916
|
-
client:
|
|
8917
|
-
playName:
|
|
9048
|
+
client: input2.client,
|
|
9049
|
+
playName: input2.playName,
|
|
8918
9050
|
workflowId: lastKnownWorkflowId,
|
|
8919
9051
|
dashboardUrl,
|
|
8920
|
-
jsonOutput:
|
|
8921
|
-
emitLogs:
|
|
8922
|
-
waitTimeoutMs:
|
|
9052
|
+
jsonOutput: input2.jsonOutput,
|
|
9053
|
+
emitLogs: input2.emitLogs,
|
|
9054
|
+
waitTimeoutMs: input2.waitTimeoutMs,
|
|
8923
9055
|
startedAt,
|
|
8924
9056
|
state,
|
|
8925
|
-
progress:
|
|
9057
|
+
progress: input2.progress
|
|
8926
9058
|
});
|
|
8927
9059
|
}
|
|
8928
9060
|
const phaseSuffix = lastPhase && lastPhase.trim() ? ` (last observed phase: ${lastPhase.trim()})` : "";
|
|
@@ -9003,7 +9135,7 @@ function compactReturnValue(value, depth = 0) {
|
|
|
9003
9135
|
if (!value || typeof value !== "object") {
|
|
9004
9136
|
return value;
|
|
9005
9137
|
}
|
|
9006
|
-
const
|
|
9138
|
+
const output2 = {};
|
|
9007
9139
|
for (const [key, entry] of Object.entries(value)) {
|
|
9008
9140
|
if (depth === 0 && key === "_metadata") {
|
|
9009
9141
|
continue;
|
|
@@ -9014,9 +9146,9 @@ function compactReturnValue(value, depth = 0) {
|
|
|
9014
9146
|
if (key === "access") {
|
|
9015
9147
|
continue;
|
|
9016
9148
|
}
|
|
9017
|
-
|
|
9149
|
+
output2[key] = compactReturnValue(entry, depth + 1);
|
|
9018
9150
|
}
|
|
9019
|
-
return
|
|
9151
|
+
return output2;
|
|
9020
9152
|
}
|
|
9021
9153
|
function formatJsonPreview(value) {
|
|
9022
9154
|
const json = JSON.stringify(value, null, 2);
|
|
@@ -9225,22 +9357,22 @@ function extractBillingForStatus(status, error) {
|
|
|
9225
9357
|
const progressError = getStringField(status.progress, "error");
|
|
9226
9358
|
return extractBillingFromText(error) ?? extractBillingFromText(progressError) ?? getObjectField(status, "billing");
|
|
9227
9359
|
}
|
|
9228
|
-
function formatInsufficientCreditsMessage(
|
|
9229
|
-
const operation = getStringField(
|
|
9230
|
-
const balance = formatCreditAmount(
|
|
9231
|
-
const required = formatCreditAmount(
|
|
9360
|
+
function formatInsufficientCreditsMessage(input2) {
|
|
9361
|
+
const operation = getStringField(input2.billing, "operation_id") ?? getStringField(input2.billing, "operation") ?? extractToolIdFromErrorText(input2.error) ?? getStringField(input2.billing, "provider") ?? "tool call";
|
|
9362
|
+
const balance = formatCreditAmount(input2.billing.balance_credits);
|
|
9363
|
+
const required = formatCreditAmount(input2.billing.required_credits);
|
|
9232
9364
|
const recommended = formatCreditAmount(
|
|
9233
|
-
|
|
9365
|
+
input2.billing.recommended_add_credits ?? input2.billing.needed_credits
|
|
9234
9366
|
);
|
|
9235
|
-
const billingUrl = getStringField(
|
|
9236
|
-
const workspace = getStringField(
|
|
9367
|
+
const billingUrl = getStringField(input2.billing, "billing_url");
|
|
9368
|
+
const workspace = getStringField(input2.billing, "workspace_id") ?? getStringField(input2.billing, "workspaceId");
|
|
9237
9369
|
const workspaceSuffix = workspace ? ` (workspace=${workspace})` : "";
|
|
9238
9370
|
const addSuffix = billingUrl && recommended !== "-" ? ` Add >=${recommended} at ${billingUrl}.` : billingUrl ? ` Add credits at ${billingUrl}.` : "";
|
|
9239
9371
|
return `Workspace balance ${balance} < required ${required} for ${operation}${workspaceSuffix}.${addSuffix}`;
|
|
9240
9372
|
}
|
|
9241
|
-
function buildInsufficientCreditsSummaryLines(
|
|
9242
|
-
const progress =
|
|
9243
|
-
const rowsInfo = extractCanonicalRowsInfo(
|
|
9373
|
+
function buildInsufficientCreditsSummaryLines(input2) {
|
|
9374
|
+
const progress = input2.status.progress;
|
|
9375
|
+
const rowsInfo = extractCanonicalRowsInfo(input2.status);
|
|
9244
9376
|
const completed = getNumericField(progress, "completed") ?? getNumericField(progress, "completedRows") ?? rowsInfo?.rows.length ?? null;
|
|
9245
9377
|
const total = getNumericField(progress, "total") ?? getNumericField(progress, "totalRows") ?? rowsInfo?.totalRows ?? null;
|
|
9246
9378
|
const lines = [
|
|
@@ -9248,16 +9380,16 @@ function buildInsufficientCreditsSummaryLines(input) {
|
|
|
9248
9380
|
completed === null ? " completed rows: unknown" : ` completed rows: ${formatInteger(completed)}${total !== null ? ` of ${formatInteger(total)}` : ""}`,
|
|
9249
9381
|
" reusable receipts: yes; rerun after adding credits to continue from completed provider work"
|
|
9250
9382
|
];
|
|
9251
|
-
const billingUrl = getStringField(
|
|
9383
|
+
const billingUrl = getStringField(input2.billing, "billing_url");
|
|
9252
9384
|
const recommended = formatCreditAmount(
|
|
9253
|
-
|
|
9385
|
+
input2.billing.recommended_add_credits ?? input2.billing.needed_credits
|
|
9254
9386
|
);
|
|
9255
9387
|
if (billingUrl) {
|
|
9256
9388
|
lines.push(
|
|
9257
9389
|
recommended !== "-" ? ` add credits: add >=${recommended} at ${billingUrl}` : ` add credits: ${billingUrl}`
|
|
9258
9390
|
);
|
|
9259
9391
|
}
|
|
9260
|
-
const runId =
|
|
9392
|
+
const runId = input2.status.runId?.trim();
|
|
9261
9393
|
if (runId) {
|
|
9262
9394
|
lines.push(` inspect: deepline runs get ${runId} --json`);
|
|
9263
9395
|
lines.push(
|
|
@@ -9592,8 +9724,8 @@ function actionToCommand(action) {
|
|
|
9592
9724
|
}
|
|
9593
9725
|
function readFirstDatasetActions(packaged) {
|
|
9594
9726
|
for (const step of readRecordArray(packaged.steps)) {
|
|
9595
|
-
const
|
|
9596
|
-
const actions =
|
|
9727
|
+
const output2 = step.output && typeof step.output === "object" && !Array.isArray(step.output) ? step.output : null;
|
|
9728
|
+
const actions = output2?.actions && typeof output2.actions === "object" && !Array.isArray(output2.actions) ? output2.actions : null;
|
|
9597
9729
|
if (actions) {
|
|
9598
9730
|
return actions;
|
|
9599
9731
|
}
|
|
@@ -9615,12 +9747,12 @@ function buildRunPackageTextLines(packaged) {
|
|
|
9615
9747
|
const id = typeof step.id === "string" ? step.id : "step";
|
|
9616
9748
|
const kind = typeof step.kind === "string" ? step.kind : "step";
|
|
9617
9749
|
const stepStatus = typeof step.status === "string" ? step.status : status;
|
|
9618
|
-
const
|
|
9619
|
-
const rowCount =
|
|
9620
|
-
const preview =
|
|
9750
|
+
const output2 = step.output && typeof step.output === "object" && !Array.isArray(step.output) ? step.output : null;
|
|
9751
|
+
const rowCount = output2 && typeof output2.rowCount === "number" ? ` rows=${formatInteger(output2.rowCount)}` : "";
|
|
9752
|
+
const preview = output2?.preview && typeof output2.preview === "object" && !Array.isArray(output2.preview) ? output2.preview : null;
|
|
9621
9753
|
const previewRows = Array.isArray(preview?.rows) ? preview.rows.length : null;
|
|
9622
9754
|
lines.push(` ${kind} ${id}: ${stepStatus}${rowCount}`);
|
|
9623
|
-
lines.push(...formatPackageDatasetSummaryLines(
|
|
9755
|
+
lines.push(...formatPackageDatasetSummaryLines(output2?.summary));
|
|
9624
9756
|
if (previewRows !== null) {
|
|
9625
9757
|
lines.push(
|
|
9626
9758
|
` preview=${previewRows}${preview?.truncated ? " truncated" : ""}`
|
|
@@ -9703,19 +9835,19 @@ function writePlayResult(status, jsonOutput, options) {
|
|
|
9703
9835
|
` }
|
|
9704
9836
|
);
|
|
9705
9837
|
}
|
|
9706
|
-
async function resolvePlayRunOutputStatus(
|
|
9707
|
-
if (!getPlayRunPackage(
|
|
9708
|
-
return
|
|
9838
|
+
async function resolvePlayRunOutputStatus(input2) {
|
|
9839
|
+
if (!getPlayRunPackage(input2.status)) {
|
|
9840
|
+
return input2.status;
|
|
9709
9841
|
}
|
|
9710
|
-
const runId =
|
|
9842
|
+
const runId = input2.status.runId;
|
|
9711
9843
|
if (!runId) {
|
|
9712
|
-
return
|
|
9844
|
+
return input2.status;
|
|
9713
9845
|
}
|
|
9714
|
-
const refreshedStatus = await
|
|
9846
|
+
const refreshedStatus = await input2.client.getPlayStatus(runId, {
|
|
9715
9847
|
billing: false,
|
|
9716
|
-
full:
|
|
9848
|
+
full: input2.fullJson
|
|
9717
9849
|
});
|
|
9718
|
-
const dashboardUrl =
|
|
9850
|
+
const dashboardUrl = input2.status.dashboardUrl;
|
|
9719
9851
|
return typeof dashboardUrl === "string" ? { ...refreshedStatus, dashboardUrl } : refreshedStatus;
|
|
9720
9852
|
}
|
|
9721
9853
|
var RUN_EXPORT_PAGE_SIZE = 5e3;
|
|
@@ -9746,21 +9878,21 @@ function extractRunPlayName(status) {
|
|
|
9746
9878
|
function normalizeCustomerDbIdentifier(value) {
|
|
9747
9879
|
return value.split("/").pop().replace(/[^A-Za-z0-9]+/g, "_").replace(/^_+|_+$/g, "").toLowerCase();
|
|
9748
9880
|
}
|
|
9749
|
-
function buildCustomerDbQueryPlan(
|
|
9750
|
-
const playName = extractRunPlayName(
|
|
9751
|
-
const tableNamespace =
|
|
9752
|
-
if (!playName || !tableNamespace ||
|
|
9881
|
+
function buildCustomerDbQueryPlan(input2) {
|
|
9882
|
+
const playName = extractRunPlayName(input2.status);
|
|
9883
|
+
const tableNamespace = input2.rowsInfo.tableNamespace?.trim();
|
|
9884
|
+
if (!playName || !tableNamespace || input2.rowsInfo.totalRows <= 0) {
|
|
9753
9885
|
return null;
|
|
9754
9886
|
}
|
|
9755
9887
|
const tableName = `${normalizeCustomerDbIdentifier(playName)}_${normalizeCustomerDbIdentifier(
|
|
9756
9888
|
tableNamespace
|
|
9757
9889
|
)}`;
|
|
9758
|
-
const sql = `select * from "storage"."${tableName}" where _run_id = ${sqlStringLiteral(
|
|
9759
|
-
const base = `deepline customer-db query --sql ${shellSingleQuote(sql)} --max-rows ${
|
|
9890
|
+
const sql = `select * from "storage"."${tableName}" where _run_id = ${sqlStringLiteral(input2.status.runId)} limit ${input2.rowsInfo.totalRows}`;
|
|
9891
|
+
const base = `deepline customer-db query --sql ${shellSingleQuote(sql)} --max-rows ${input2.rowsInfo.totalRows}`;
|
|
9760
9892
|
return {
|
|
9761
9893
|
sql,
|
|
9762
9894
|
json: `${base} --json`,
|
|
9763
|
-
csv: `${base} --format csv --out ${shellSingleQuote(resolve10(
|
|
9895
|
+
csv: `${base} --format csv --out ${shellSingleQuote(resolve10(input2.outPath))}`
|
|
9764
9896
|
};
|
|
9765
9897
|
}
|
|
9766
9898
|
function exportableSheetRow(row) {
|
|
@@ -9811,20 +9943,20 @@ function mergeExportColumns(preferredColumns, rows) {
|
|
|
9811
9943
|
}
|
|
9812
9944
|
return columns;
|
|
9813
9945
|
}
|
|
9814
|
-
async function fetchBackingDatasetRows(
|
|
9815
|
-
const playName = extractRunPlayName(
|
|
9816
|
-
const tableNamespace =
|
|
9946
|
+
async function fetchBackingDatasetRows(input2) {
|
|
9947
|
+
const playName = extractRunPlayName(input2.status);
|
|
9948
|
+
const tableNamespace = input2.rowsInfo.tableNamespace?.trim();
|
|
9817
9949
|
if (!playName || !tableNamespace) {
|
|
9818
9950
|
return null;
|
|
9819
9951
|
}
|
|
9820
9952
|
const sheetRows = [];
|
|
9821
9953
|
let offset = 0;
|
|
9822
|
-
let expectedTotal =
|
|
9954
|
+
let expectedTotal = input2.rowsInfo.totalRows;
|
|
9823
9955
|
while (true) {
|
|
9824
|
-
const page = await
|
|
9956
|
+
const page = await input2.client.runs.exportDatasetRows({
|
|
9825
9957
|
playName,
|
|
9826
9958
|
tableNamespace,
|
|
9827
|
-
runId:
|
|
9959
|
+
runId: input2.status.runId,
|
|
9828
9960
|
limit: RUN_EXPORT_PAGE_SIZE,
|
|
9829
9961
|
offset
|
|
9830
9962
|
});
|
|
@@ -9839,20 +9971,20 @@ async function fetchBackingDatasetRows(input) {
|
|
|
9839
9971
|
offset += page.rows.length;
|
|
9840
9972
|
}
|
|
9841
9973
|
const rows = sheetRows.map(exportableSheetRow).filter((row) => Boolean(row));
|
|
9842
|
-
if (rows.length <
|
|
9974
|
+
if (rows.length < input2.rowsInfo.totalRows) {
|
|
9843
9975
|
return null;
|
|
9844
9976
|
}
|
|
9845
9977
|
const columns = mergeExportColumns(
|
|
9846
|
-
|
|
9978
|
+
input2.rowsInfo.columnsExplicit ? input2.rowsInfo.columns : [],
|
|
9847
9979
|
rows
|
|
9848
9980
|
);
|
|
9849
9981
|
return {
|
|
9850
|
-
...
|
|
9982
|
+
...input2.rowsInfo,
|
|
9851
9983
|
rows,
|
|
9852
9984
|
columns,
|
|
9853
9985
|
totalRows: rows.length,
|
|
9854
9986
|
complete: true,
|
|
9855
|
-
source: `${
|
|
9987
|
+
source: `${input2.rowsInfo.source ?? "result.rows"} -> /api/v2/plays/${playName}/sheet?tableNamespace=${tableNamespace}`
|
|
9856
9988
|
};
|
|
9857
9989
|
}
|
|
9858
9990
|
async function exportPlayStatusRows(client, status, outPath, options = {}) {
|
|
@@ -9954,11 +10086,11 @@ function extractActiveRunsFromError(error) {
|
|
|
9954
10086
|
function activeRunId(run) {
|
|
9955
10087
|
return getStringField(run, "workflowId") ?? getStringField(run, "runId");
|
|
9956
10088
|
}
|
|
9957
|
-
function formatActiveRunConflictError(
|
|
10089
|
+
function formatActiveRunConflictError(input2) {
|
|
9958
10090
|
const lines = [
|
|
9959
|
-
`Active run exists for ${
|
|
10091
|
+
`Active run exists for ${input2.playName}. Use --force to supersede, or inspect/stop the active run first.`
|
|
9960
10092
|
];
|
|
9961
|
-
for (const run of
|
|
10093
|
+
for (const run of input2.activeRuns.slice(0, 3)) {
|
|
9962
10094
|
const runId = activeRunId(run);
|
|
9963
10095
|
if (!runId) {
|
|
9964
10096
|
continue;
|
|
@@ -10072,49 +10204,49 @@ function renderServerResultView(value) {
|
|
|
10072
10204
|
}
|
|
10073
10205
|
return { lines: lines.length > 1 ? lines : [], actions: [] };
|
|
10074
10206
|
}
|
|
10075
|
-
function writeStartedPlayRun(
|
|
10076
|
-
if (
|
|
10077
|
-
if (
|
|
10078
|
-
printCommandEnvelope(
|
|
10207
|
+
function writeStartedPlayRun(input2) {
|
|
10208
|
+
if (input2.package && isPlayRunPackageValue(input2.package)) {
|
|
10209
|
+
if (input2.jsonOutput) {
|
|
10210
|
+
printCommandEnvelope(input2.package, { json: true });
|
|
10079
10211
|
return;
|
|
10080
10212
|
}
|
|
10081
|
-
const lines2 = buildRunPackageTextLines(
|
|
10082
|
-
const
|
|
10083
|
-
if (
|
|
10084
|
-
|
|
10213
|
+
const lines2 = buildRunPackageTextLines(input2.package);
|
|
10214
|
+
const output3 = lines2.join("\n");
|
|
10215
|
+
if (input2.progress) {
|
|
10216
|
+
input2.progress.writeLine(output3, process.stdout);
|
|
10085
10217
|
return;
|
|
10086
10218
|
}
|
|
10087
|
-
printCommandEnvelope(
|
|
10219
|
+
printCommandEnvelope(input2.package, {
|
|
10088
10220
|
json: false,
|
|
10089
|
-
text: `${
|
|
10221
|
+
text: `${output3}
|
|
10090
10222
|
`
|
|
10091
10223
|
});
|
|
10092
10224
|
return;
|
|
10093
10225
|
}
|
|
10094
10226
|
const payload = {
|
|
10095
|
-
runId:
|
|
10096
|
-
workflowId:
|
|
10097
|
-
name:
|
|
10098
|
-
status:
|
|
10099
|
-
dashboardUrl:
|
|
10227
|
+
runId: input2.runId,
|
|
10228
|
+
workflowId: input2.runId,
|
|
10229
|
+
name: input2.playName,
|
|
10230
|
+
status: input2.status ?? "started",
|
|
10231
|
+
dashboardUrl: input2.dashboardUrl,
|
|
10100
10232
|
next: {
|
|
10101
|
-
inspect: `deepline runs get ${
|
|
10102
|
-
full: `deepline runs get ${
|
|
10103
|
-
logs: `deepline runs logs ${
|
|
10104
|
-
export: `deepline runs export ${
|
|
10105
|
-
stop: `deepline runs stop ${
|
|
10233
|
+
inspect: `deepline runs get ${input2.runId} --json`,
|
|
10234
|
+
full: `deepline runs get ${input2.runId} --full --json`,
|
|
10235
|
+
logs: `deepline runs logs ${input2.runId} --json`,
|
|
10236
|
+
export: `deepline runs export ${input2.runId} --out output.csv`,
|
|
10237
|
+
stop: `deepline runs stop ${input2.runId} --reason "stale lock" --json`
|
|
10106
10238
|
}
|
|
10107
10239
|
};
|
|
10108
10240
|
const lines = [
|
|
10109
|
-
`Started ${
|
|
10110
|
-
` run id: ${
|
|
10111
|
-
` inspect: deepline runs get ${
|
|
10112
|
-
` full debug: deepline runs get ${
|
|
10113
|
-
` logs: deepline runs logs ${
|
|
10114
|
-
` export after completion: deepline runs export ${
|
|
10115
|
-
` stop run: deepline runs stop ${
|
|
10241
|
+
`Started ${input2.playName}`,
|
|
10242
|
+
` run id: ${input2.runId}`,
|
|
10243
|
+
` inspect: deepline runs get ${input2.runId} --json`,
|
|
10244
|
+
` full debug: deepline runs get ${input2.runId} --full --json`,
|
|
10245
|
+
` logs: deepline runs logs ${input2.runId} --json`,
|
|
10246
|
+
` export after completion: deepline runs export ${input2.runId} --out output.csv`,
|
|
10247
|
+
` stop run: deepline runs stop ${input2.runId} --reason "stale lock" --json`
|
|
10116
10248
|
];
|
|
10117
|
-
if (
|
|
10249
|
+
if (input2.jsonOutput) {
|
|
10118
10250
|
printCommandEnvelope(
|
|
10119
10251
|
{
|
|
10120
10252
|
...payload,
|
|
@@ -10124,12 +10256,12 @@ function writeStartedPlayRun(input) {
|
|
|
10124
10256
|
);
|
|
10125
10257
|
return;
|
|
10126
10258
|
}
|
|
10127
|
-
if (
|
|
10128
|
-
lines.push(` play page: ${
|
|
10259
|
+
if (input2.dashboardUrl) {
|
|
10260
|
+
lines.push(` play page: ${input2.dashboardUrl}`);
|
|
10129
10261
|
}
|
|
10130
|
-
const
|
|
10131
|
-
if (
|
|
10132
|
-
|
|
10262
|
+
const output2 = lines.join("\n");
|
|
10263
|
+
if (input2.progress) {
|
|
10264
|
+
input2.progress.writeLine(output2, process.stdout);
|
|
10133
10265
|
return;
|
|
10134
10266
|
}
|
|
10135
10267
|
printCommandEnvelope(
|
|
@@ -10137,7 +10269,7 @@ function writeStartedPlayRun(input) {
|
|
|
10137
10269
|
...payload,
|
|
10138
10270
|
render: { sections: [{ title: "play run", lines }] }
|
|
10139
10271
|
},
|
|
10140
|
-
{ json: false, text: `${
|
|
10272
|
+
{ json: false, text: `${output2}
|
|
10141
10273
|
` }
|
|
10142
10274
|
);
|
|
10143
10275
|
}
|
|
@@ -10145,7 +10277,7 @@ function parsePlayRunOptions(args) {
|
|
|
10145
10277
|
const usage = "Usage: deepline plays run <play-name> [--input '{...}'] [--no-wait] [--tail-timeout-ms 30000] [--force] [--full] [--<input> value]\n deepline plays run <play-file.ts> [--input '{...}'] [--no-wait] [--tail-timeout-ms 30000] [--force] [--full] [--<input> value]\n deepline plays run --file <play-file.ts> [--input '{...}'] [--no-wait] [--tail-timeout-ms 30000] [--force] [--full] [--<input> value]\n deepline plays run --name <name> [--input '{...}'] [--live|--latest|--revision-id <id>] [--no-wait] [--tail-timeout-ms 30000] [--force] [--no-open] [--json] [--full] [--<input> value]\n Unknown --<input> value flags, such as --limit 5, are passed into play input.\nRun `deepline plays run --help` for idempotency, tool call id, and ctx.map guidance.";
|
|
10146
10278
|
let filePath = null;
|
|
10147
10279
|
let playName = null;
|
|
10148
|
-
let
|
|
10280
|
+
let input2 = null;
|
|
10149
10281
|
let revisionId = null;
|
|
10150
10282
|
let revisionSelector = null;
|
|
10151
10283
|
const watch = !args.includes("--no-wait");
|
|
@@ -10166,7 +10298,7 @@ function parsePlayRunOptions(args) {
|
|
|
10166
10298
|
continue;
|
|
10167
10299
|
}
|
|
10168
10300
|
if ((arg === "--input" || arg === "-i") && args[index + 1]) {
|
|
10169
|
-
|
|
10301
|
+
input2 = parseJsonInput(args[++index]);
|
|
10170
10302
|
continue;
|
|
10171
10303
|
}
|
|
10172
10304
|
if (arg === "--revision-id" && args[index + 1]) {
|
|
@@ -10215,8 +10347,8 @@ function parsePlayRunOptions(args) {
|
|
|
10215
10347
|
}
|
|
10216
10348
|
if (arg.startsWith("--")) {
|
|
10217
10349
|
const { path, value } = parseInputFieldFlag(arg, args[index + 1]);
|
|
10218
|
-
|
|
10219
|
-
setDottedInputValue(
|
|
10350
|
+
input2 ??= {};
|
|
10351
|
+
setDottedInputValue(input2, path, parseInputFlagValue(value));
|
|
10220
10352
|
if (!arg.includes("=")) {
|
|
10221
10353
|
index += 1;
|
|
10222
10354
|
}
|
|
@@ -10251,7 +10383,7 @@ function parsePlayRunOptions(args) {
|
|
|
10251
10383
|
}
|
|
10252
10384
|
return {
|
|
10253
10385
|
target: filePath ? { kind: "file", path: filePath } : { kind: "name", name: playName },
|
|
10254
|
-
input,
|
|
10386
|
+
input: input2,
|
|
10255
10387
|
revisionId,
|
|
10256
10388
|
revisionSelector,
|
|
10257
10389
|
watch,
|
|
@@ -10618,15 +10750,15 @@ async function handleFileBackedRun(options) {
|
|
|
10618
10750
|
});
|
|
10619
10751
|
return 0;
|
|
10620
10752
|
}
|
|
10621
|
-
async function resolveNamedRunRevisionId(
|
|
10622
|
-
if (
|
|
10623
|
-
return
|
|
10753
|
+
async function resolveNamedRunRevisionId(input2) {
|
|
10754
|
+
if (input2.revisionId) {
|
|
10755
|
+
return input2.revisionId;
|
|
10624
10756
|
}
|
|
10625
|
-
if (
|
|
10626
|
-
const versions = await
|
|
10757
|
+
if (input2.selector === "latest") {
|
|
10758
|
+
const versions = await input2.client.listPlayVersions(input2.playName);
|
|
10627
10759
|
const latest = versions[0];
|
|
10628
10760
|
if (!latest?._id) {
|
|
10629
|
-
throw new Error(`No saved revisions found for ${
|
|
10761
|
+
throw new Error(`No saved revisions found for ${input2.playName}.`);
|
|
10630
10762
|
}
|
|
10631
10763
|
return latest._id;
|
|
10632
10764
|
}
|
|
@@ -12099,6 +12231,543 @@ Examples:
|
|
|
12099
12231
|
...options.json ? ["--json"] : []
|
|
12100
12232
|
]);
|
|
12101
12233
|
});
|
|
12234
|
+
const share = play.command("share").description(
|
|
12235
|
+
"Manage a play's public, unlisted share page (advanced \u2014 exposes play code)."
|
|
12236
|
+
).addHelpText(
|
|
12237
|
+
"after",
|
|
12238
|
+
`
|
|
12239
|
+
Concepts:
|
|
12240
|
+
A share page is a public, unlisted, SEO-indexable landing page for a play,
|
|
12241
|
+
pinned to one revision. Publish only after the play has run successfully.
|
|
12242
|
+
|
|
12243
|
+
NOT RECOMMENDED by default. Only publish when the user has explicitly asked
|
|
12244
|
+
to share this play AND has confirmed they accept the risks below. When in
|
|
12245
|
+
doubt, leave the play unpublished.
|
|
12246
|
+
|
|
12247
|
+
What is exposed:
|
|
12248
|
+
Run results and row-level data are NEVER exposed. But the page renders the
|
|
12249
|
+
play's STRUCTURE and anything baked into its source code: step names,
|
|
12250
|
+
input/output field names, tool ids, step descriptions/prompts, and any
|
|
12251
|
+
hardcoded string literals or comments in the play file. If the source
|
|
12252
|
+
contains PII, internal domains/emails, secrets-by-mistake, or proprietary
|
|
12253
|
+
business logic, publishing makes it publicly viewable and search-indexable.
|
|
12254
|
+
|
|
12255
|
+
Review the play source for sensitive content before publishing. Use
|
|
12256
|
+
--seo noindex to keep the page out of search engines if you must share it.
|
|
12257
|
+
|
|
12258
|
+
Examples:
|
|
12259
|
+
deepline plays share status company-to-contact --json
|
|
12260
|
+
deepline plays share publish company-to-contact --yes
|
|
12261
|
+
deepline plays share publish company-to-contact --version 3 --seo noindex --yes
|
|
12262
|
+
deepline plays share update company-to-contact --show-latency --json
|
|
12263
|
+
deepline plays share regenerate company-to-contact --json
|
|
12264
|
+
deepline plays share unpublish company-to-contact --yes
|
|
12265
|
+
`
|
|
12266
|
+
);
|
|
12267
|
+
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) => {
|
|
12268
|
+
process.exitCode = await handlePlayShareStatus([
|
|
12269
|
+
playName,
|
|
12270
|
+
...options.json ? ["--json"] : []
|
|
12271
|
+
]);
|
|
12272
|
+
});
|
|
12273
|
+
share.command("publish <play>").description(
|
|
12274
|
+
"Publish/repoint a PUBLIC page to a revision. Advanced; not recommended unless explicitly requested and risks confirmed."
|
|
12275
|
+
).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(
|
|
12276
|
+
"-y, --yes",
|
|
12277
|
+
"Confirm public exposure of the play code/structure (required)."
|
|
12278
|
+
).option("--dry-run", "Show the planned publish without writing.").option("--json", "Emit JSON output. Also automatic when stdout is piped").addHelpText(
|
|
12279
|
+
"after",
|
|
12280
|
+
`
|
|
12281
|
+
WARNING \u2014 not recommended by default.
|
|
12282
|
+
Only run when the user has explicitly asked to share this play AND has
|
|
12283
|
+
confirmed they accept the exposure risks. Otherwise, do not publish.
|
|
12284
|
+
|
|
12285
|
+
Mutates cloud state. Creates a PUBLIC, SEO-indexable (unless --seo noindex),
|
|
12286
|
+
unlisted page; requires --yes to acknowledge it is publicly viewable.
|
|
12287
|
+
|
|
12288
|
+
Run results and row data are NEVER exposed. The page DOES expose the play's
|
|
12289
|
+
code/structure: step names, input/output field names, tool ids, step
|
|
12290
|
+
descriptions/prompts, and any hardcoded literals or comments in the source.
|
|
12291
|
+
This may reveal PII, internal domains/emails, or proprietary logic if such
|
|
12292
|
+
content lives in the play file. Review the source before publishing.
|
|
12293
|
+
|
|
12294
|
+
Exit codes: 0 ok; 2 usage/missing --yes; 4 play or version not found;
|
|
12295
|
+
7 no successful run for the play.
|
|
12296
|
+
|
|
12297
|
+
Examples:
|
|
12298
|
+
deepline plays share publish company-to-contact --yes
|
|
12299
|
+
deepline plays share publish company-to-contact --version 3 --seo noindex --yes --json
|
|
12300
|
+
`
|
|
12301
|
+
).action(async (playName, options) => {
|
|
12302
|
+
process.exitCode = await handlePlaySharePublish([
|
|
12303
|
+
playName,
|
|
12304
|
+
...options.latest ? ["--latest"] : [],
|
|
12305
|
+
...options.version ? ["--version", String(options.version)] : [],
|
|
12306
|
+
...options.revisionId ? ["--revision-id", options.revisionId] : [],
|
|
12307
|
+
...options.seo ? ["--seo", options.seo] : [],
|
|
12308
|
+
...options.showCost ? ["--show-cost"] : [],
|
|
12309
|
+
...options.showLatency ? ["--show-latency"] : [],
|
|
12310
|
+
...options.runCheck === false ? ["--no-run-check"] : [],
|
|
12311
|
+
...options.yes ? ["--yes"] : [],
|
|
12312
|
+
...options.dryRun ? ["--dry-run"] : [],
|
|
12313
|
+
...options.json ? ["--json"] : []
|
|
12314
|
+
]);
|
|
12315
|
+
});
|
|
12316
|
+
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) => {
|
|
12317
|
+
process.exitCode = await handlePlayShareUpdate([
|
|
12318
|
+
playName,
|
|
12319
|
+
...options.seo ? ["--seo", options.seo] : [],
|
|
12320
|
+
...options.showCost ? ["--show-cost"] : [],
|
|
12321
|
+
...options.hideCost ? ["--hide-cost"] : [],
|
|
12322
|
+
...options.showLatency ? ["--show-latency"] : [],
|
|
12323
|
+
...options.hideLatency ? ["--hide-latency"] : [],
|
|
12324
|
+
...options.json ? ["--json"] : []
|
|
12325
|
+
]);
|
|
12326
|
+
});
|
|
12327
|
+
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) => {
|
|
12328
|
+
process.exitCode = await handlePlayShareRegenerate([
|
|
12329
|
+
playName,
|
|
12330
|
+
...options.version ? ["--version", String(options.version)] : [],
|
|
12331
|
+
...options.revisionId ? ["--revision-id", options.revisionId] : [],
|
|
12332
|
+
...options.json ? ["--json"] : []
|
|
12333
|
+
]);
|
|
12334
|
+
});
|
|
12335
|
+
share.command("unpublish <play>").description(
|
|
12336
|
+
"Unshare: permanently delete the public page (frees it). Requires --yes."
|
|
12337
|
+
).option("-y, --yes", "Confirm taking the public page down (required).").option("--json", "Emit JSON output. Also automatic when stdout is piped").addHelpText(
|
|
12338
|
+
"after",
|
|
12339
|
+
`
|
|
12340
|
+
Mutates cloud state. Hard-deletes the page + its generated cards; the URL stops
|
|
12341
|
+
resolving. Org-admin only. Exit codes: 0 ok; 2 usage/missing --yes; 4 play not
|
|
12342
|
+
found.
|
|
12343
|
+
|
|
12344
|
+
Examples:
|
|
12345
|
+
deepline plays share unpublish company-to-contact --yes
|
|
12346
|
+
`
|
|
12347
|
+
).action(async (playName, options) => {
|
|
12348
|
+
process.exitCode = await handlePlayShareUnpublish([
|
|
12349
|
+
playName,
|
|
12350
|
+
...options.yes ? ["--yes"] : [],
|
|
12351
|
+
...options.json ? ["--json"] : []
|
|
12352
|
+
]);
|
|
12353
|
+
});
|
|
12354
|
+
}
|
|
12355
|
+
function shareFlagValue(args, flag) {
|
|
12356
|
+
const i = args.indexOf(flag);
|
|
12357
|
+
return i >= 0 && i + 1 < args.length ? args[i + 1] : void 0;
|
|
12358
|
+
}
|
|
12359
|
+
async function handlePlayShareStatus(args) {
|
|
12360
|
+
const target = args[0];
|
|
12361
|
+
if (!target) {
|
|
12362
|
+
console.error("Usage: deepline plays share status <play> [--json]");
|
|
12363
|
+
return 2;
|
|
12364
|
+
}
|
|
12365
|
+
const name = parseReferencedPlayTarget2(target).playName;
|
|
12366
|
+
const status = await new DeeplineClient().getSharePage(name);
|
|
12367
|
+
if (argsWantJson(args)) {
|
|
12368
|
+
process.stdout.write(`${JSON.stringify(status)}
|
|
12369
|
+
`);
|
|
12370
|
+
return 0;
|
|
12371
|
+
}
|
|
12372
|
+
if (!status.share) {
|
|
12373
|
+
console.log(`${status.playName}: not published.`);
|
|
12374
|
+
console.log(
|
|
12375
|
+
` Publish: deepline plays share publish ${status.playName} --yes`
|
|
12376
|
+
);
|
|
12377
|
+
return 0;
|
|
12378
|
+
}
|
|
12379
|
+
console.log(`${status.playName}: published v${status.share.publishedVersion}`);
|
|
12380
|
+
console.log(` url: ${status.share.publicPath}`);
|
|
12381
|
+
console.log(` seo: ${status.share.seoIndexing}`);
|
|
12382
|
+
console.log(
|
|
12383
|
+
` show: cost=${status.share.showAverageDeeplineCost} latency=${status.share.showAverageLatency}`
|
|
12384
|
+
);
|
|
12385
|
+
return 0;
|
|
12386
|
+
}
|
|
12387
|
+
async function handlePlaySharePublish(args) {
|
|
12388
|
+
const target = args[0];
|
|
12389
|
+
if (!target) {
|
|
12390
|
+
console.error(
|
|
12391
|
+
"Usage: deepline plays share publish <play> (--latest | --version <n> | --revision-id <id>) --yes [--seo index|noindex] [--show-cost] [--show-latency] [--json]"
|
|
12392
|
+
);
|
|
12393
|
+
return 2;
|
|
12394
|
+
}
|
|
12395
|
+
if (!args.includes("--yes")) {
|
|
12396
|
+
console.error(
|
|
12397
|
+
"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."
|
|
12398
|
+
);
|
|
12399
|
+
return 2;
|
|
12400
|
+
}
|
|
12401
|
+
const name = parseReferencedPlayTarget2(target).playName;
|
|
12402
|
+
const client = new DeeplineClient();
|
|
12403
|
+
let revisionId = shareFlagValue(args, "--revision-id");
|
|
12404
|
+
let resolvedVersion;
|
|
12405
|
+
if (!revisionId) {
|
|
12406
|
+
const versions = await client.listPlayVersions(name);
|
|
12407
|
+
if (versions.length === 0) {
|
|
12408
|
+
console.error(
|
|
12409
|
+
`No saved revisions for ${name}. Run \`deepline plays set-live ${name}\` first.`
|
|
12410
|
+
);
|
|
12411
|
+
return 4;
|
|
12412
|
+
}
|
|
12413
|
+
const versionFlag = shareFlagValue(args, "--version");
|
|
12414
|
+
const chosen = versionFlag ? versions.find((r) => r.version === Number(versionFlag)) : versions[0];
|
|
12415
|
+
if (!chosen) {
|
|
12416
|
+
console.error(`Version ${versionFlag} not found for ${name}.`);
|
|
12417
|
+
return 4;
|
|
12418
|
+
}
|
|
12419
|
+
if (!chosen._id) {
|
|
12420
|
+
console.error("Resolved revision is missing an id.");
|
|
12421
|
+
return 5;
|
|
12422
|
+
}
|
|
12423
|
+
revisionId = chosen._id;
|
|
12424
|
+
resolvedVersion = chosen.version;
|
|
12425
|
+
}
|
|
12426
|
+
if (!args.includes("--no-run-check")) {
|
|
12427
|
+
const runs = await client.listRuns({ play: name });
|
|
12428
|
+
const hasCompleted = runs.some(
|
|
12429
|
+
(r) => String(r.status).toLowerCase() === "completed"
|
|
12430
|
+
);
|
|
12431
|
+
if (!hasCompleted) {
|
|
12432
|
+
const message = `No completed run for ${name}. Publish a play only after it has run successfully. (Override with --no-run-check.)`;
|
|
12433
|
+
if (argsWantJson(args)) {
|
|
12434
|
+
process.stdout.write(
|
|
12435
|
+
`${JSON.stringify({ ok: false, code: "NO_SUCCESSFUL_RUN", message, next: `deepline plays run ${name} --wait` })}
|
|
12436
|
+
`
|
|
12437
|
+
);
|
|
12438
|
+
} else {
|
|
12439
|
+
console.error(message);
|
|
12440
|
+
console.error(` deepline plays run ${name} --wait`);
|
|
12441
|
+
}
|
|
12442
|
+
return 7;
|
|
12443
|
+
}
|
|
12444
|
+
}
|
|
12445
|
+
const seo = shareFlagValue(args, "--seo");
|
|
12446
|
+
const seoIndexing = seo === "index" ? "index" : seo === "noindex" ? "noindex" : void 0;
|
|
12447
|
+
const request = {
|
|
12448
|
+
revisionId,
|
|
12449
|
+
acknowledgedUnlisted: true,
|
|
12450
|
+
showAverageDeeplineCost: args.includes("--show-cost"),
|
|
12451
|
+
showAverageLatency: args.includes("--show-latency"),
|
|
12452
|
+
...seoIndexing ? { seoIndexing } : {}
|
|
12453
|
+
};
|
|
12454
|
+
if (args.includes("--dry-run")) {
|
|
12455
|
+
const plan = { dryRun: true, name, version: resolvedVersion, ...request };
|
|
12456
|
+
if (argsWantJson(args)) {
|
|
12457
|
+
process.stdout.write(`${JSON.stringify(plan)}
|
|
12458
|
+
`);
|
|
12459
|
+
} else {
|
|
12460
|
+
console.log(
|
|
12461
|
+
`Would publish ${name}${resolvedVersion ? ` v${resolvedVersion}` : ""} (revision ${revisionId}).`
|
|
12462
|
+
);
|
|
12463
|
+
}
|
|
12464
|
+
return 0;
|
|
12465
|
+
}
|
|
12466
|
+
const status = await client.publishSharePage(name, request);
|
|
12467
|
+
if (argsWantJson(args)) {
|
|
12468
|
+
process.stdout.write(`${JSON.stringify(status)}
|
|
12469
|
+
`);
|
|
12470
|
+
return 0;
|
|
12471
|
+
}
|
|
12472
|
+
console.log(
|
|
12473
|
+
`Published ${name}${status.share ? ` v${status.share.publishedVersion}` : ""}: ${status.share?.publicPath ?? ""}`
|
|
12474
|
+
);
|
|
12475
|
+
if (status.warning) {
|
|
12476
|
+
console.error(`warning: ${status.warning}`);
|
|
12477
|
+
}
|
|
12478
|
+
return 0;
|
|
12479
|
+
}
|
|
12480
|
+
async function handlePlayShareUpdate(args) {
|
|
12481
|
+
const target = args[0];
|
|
12482
|
+
if (!target) {
|
|
12483
|
+
console.error(
|
|
12484
|
+
"Usage: deepline plays share update <play> [--seo index|noindex] [--show-cost|--hide-cost] [--show-latency|--hide-latency] [--json]"
|
|
12485
|
+
);
|
|
12486
|
+
return 2;
|
|
12487
|
+
}
|
|
12488
|
+
const name = parseReferencedPlayTarget2(target).playName;
|
|
12489
|
+
const seo = shareFlagValue(args, "--seo");
|
|
12490
|
+
const seoIndexing = seo === "index" ? "index" : seo === "noindex" ? "noindex" : void 0;
|
|
12491
|
+
const request = {
|
|
12492
|
+
...args.includes("--show-cost") ? { showAverageDeeplineCost: true } : args.includes("--hide-cost") ? { showAverageDeeplineCost: false } : {},
|
|
12493
|
+
...args.includes("--show-latency") ? { showAverageLatency: true } : args.includes("--hide-latency") ? { showAverageLatency: false } : {},
|
|
12494
|
+
...seoIndexing ? { seoIndexing } : {}
|
|
12495
|
+
};
|
|
12496
|
+
const status = await new DeeplineClient().updateSharePage(name, request);
|
|
12497
|
+
if (argsWantJson(args)) {
|
|
12498
|
+
process.stdout.write(`${JSON.stringify(status)}
|
|
12499
|
+
`);
|
|
12500
|
+
return 0;
|
|
12501
|
+
}
|
|
12502
|
+
console.log(`Updated ${name} share settings.`);
|
|
12503
|
+
return 0;
|
|
12504
|
+
}
|
|
12505
|
+
async function handlePlayShareRegenerate(args) {
|
|
12506
|
+
const target = args[0];
|
|
12507
|
+
if (!target) {
|
|
12508
|
+
console.error(
|
|
12509
|
+
"Usage: deepline plays share regenerate <play> [--version <n> | --revision-id <id>] [--json]"
|
|
12510
|
+
);
|
|
12511
|
+
return 2;
|
|
12512
|
+
}
|
|
12513
|
+
const name = parseReferencedPlayTarget2(target).playName;
|
|
12514
|
+
const client = new DeeplineClient();
|
|
12515
|
+
let revisionId = shareFlagValue(args, "--revision-id");
|
|
12516
|
+
const versionFlag = shareFlagValue(args, "--version");
|
|
12517
|
+
if (!revisionId && versionFlag) {
|
|
12518
|
+
const versions = await client.listPlayVersions(name);
|
|
12519
|
+
const chosen = versions.find((r) => r.version === Number(versionFlag));
|
|
12520
|
+
if (!chosen?._id) {
|
|
12521
|
+
console.error(`Version ${versionFlag} not found for ${name}.`);
|
|
12522
|
+
return 4;
|
|
12523
|
+
}
|
|
12524
|
+
revisionId = chosen._id;
|
|
12525
|
+
}
|
|
12526
|
+
const status = await client.regenerateSharePage(
|
|
12527
|
+
name,
|
|
12528
|
+
revisionId ? { revisionId } : {}
|
|
12529
|
+
);
|
|
12530
|
+
if (argsWantJson(args)) {
|
|
12531
|
+
process.stdout.write(`${JSON.stringify(status)}
|
|
12532
|
+
`);
|
|
12533
|
+
return 0;
|
|
12534
|
+
}
|
|
12535
|
+
console.log(`Regenerated public copy for ${name}.`);
|
|
12536
|
+
return 0;
|
|
12537
|
+
}
|
|
12538
|
+
async function handlePlayShareUnpublish(args) {
|
|
12539
|
+
const target = args[0];
|
|
12540
|
+
if (!target) {
|
|
12541
|
+
console.error("Usage: deepline plays share unpublish <play> --yes [--json]");
|
|
12542
|
+
return 2;
|
|
12543
|
+
}
|
|
12544
|
+
if (!args.includes("--yes")) {
|
|
12545
|
+
console.error(
|
|
12546
|
+
"Unpublishing permanently deletes the public page and frees its URL.\nRe-run with --yes to confirm."
|
|
12547
|
+
);
|
|
12548
|
+
return 2;
|
|
12549
|
+
}
|
|
12550
|
+
const name = parseReferencedPlayTarget2(target).playName;
|
|
12551
|
+
const status = await new DeeplineClient().unpublishSharePage(name);
|
|
12552
|
+
if (argsWantJson(args)) {
|
|
12553
|
+
process.stdout.write(`${JSON.stringify(status)}
|
|
12554
|
+
`);
|
|
12555
|
+
return 0;
|
|
12556
|
+
}
|
|
12557
|
+
console.log(`Unpublished ${name}; the public page has been removed.`);
|
|
12558
|
+
return 0;
|
|
12559
|
+
}
|
|
12560
|
+
|
|
12561
|
+
// src/cli/commands/secrets.ts
|
|
12562
|
+
import { stdin as input, stdout as output } from "process";
|
|
12563
|
+
var hiddenInputBuffer = "";
|
|
12564
|
+
function normalizeSecretName(value) {
|
|
12565
|
+
const normalized = value.trim().toUpperCase();
|
|
12566
|
+
if (!/^[A-Z][A-Z0-9_]{1,63}$/.test(normalized)) {
|
|
12567
|
+
throw new Error(
|
|
12568
|
+
"Secret names must be 2-64 characters and use uppercase letters, numbers, and underscores."
|
|
12569
|
+
);
|
|
12570
|
+
}
|
|
12571
|
+
return normalized;
|
|
12572
|
+
}
|
|
12573
|
+
function renderSecret(secret) {
|
|
12574
|
+
const scope = secret.scope === "play" && secret.playName ? `play:${secret.playName}` : secret.scope;
|
|
12575
|
+
return `${secret.name} (${scope}) - ${secret.status}${secret.hasValue ? ", set" : ", empty"}`;
|
|
12576
|
+
}
|
|
12577
|
+
async function readHiddenLine(prompt) {
|
|
12578
|
+
if (!input.isTTY || !output.isTTY) {
|
|
12579
|
+
throw new Error(
|
|
12580
|
+
"Secret values must be entered from an interactive TTY. Do not pipe, pass, or script secret values."
|
|
12581
|
+
);
|
|
12582
|
+
}
|
|
12583
|
+
output.write(prompt);
|
|
12584
|
+
const previousRawMode = input.isRaw;
|
|
12585
|
+
if (typeof input.setRawMode === "function") input.setRawMode(true);
|
|
12586
|
+
let value = "";
|
|
12587
|
+
input.resume();
|
|
12588
|
+
return await new Promise((resolve12, reject) => {
|
|
12589
|
+
let settled = false;
|
|
12590
|
+
const cleanup = () => {
|
|
12591
|
+
input.off("data", onData);
|
|
12592
|
+
input.off("end", onEnd);
|
|
12593
|
+
input.off("error", onError);
|
|
12594
|
+
if (typeof input.setRawMode === "function") {
|
|
12595
|
+
input.setRawMode(previousRawMode);
|
|
12596
|
+
}
|
|
12597
|
+
};
|
|
12598
|
+
const finish = (line) => {
|
|
12599
|
+
if (settled) return;
|
|
12600
|
+
settled = true;
|
|
12601
|
+
output.write("\n");
|
|
12602
|
+
cleanup();
|
|
12603
|
+
resolve12(line);
|
|
12604
|
+
};
|
|
12605
|
+
const fail = (error) => {
|
|
12606
|
+
if (settled) return;
|
|
12607
|
+
settled = true;
|
|
12608
|
+
output.write("\n");
|
|
12609
|
+
cleanup();
|
|
12610
|
+
reject(error);
|
|
12611
|
+
};
|
|
12612
|
+
const processText = (text) => {
|
|
12613
|
+
for (let index = 0; index < text.length; index++) {
|
|
12614
|
+
const char = text[index];
|
|
12615
|
+
const code = char.charCodeAt(0);
|
|
12616
|
+
if (char === "\r" || char === "\n") {
|
|
12617
|
+
hiddenInputBuffer = text.slice(index + 1);
|
|
12618
|
+
finish(value);
|
|
12619
|
+
return;
|
|
12620
|
+
}
|
|
12621
|
+
if (code === 3) {
|
|
12622
|
+
fail(new Error("Secret input cancelled."));
|
|
12623
|
+
return;
|
|
12624
|
+
}
|
|
12625
|
+
if (code === 8 || code === 127) {
|
|
12626
|
+
value = value.slice(0, -1);
|
|
12627
|
+
continue;
|
|
12628
|
+
}
|
|
12629
|
+
if (code >= 32) {
|
|
12630
|
+
value += char;
|
|
12631
|
+
}
|
|
12632
|
+
}
|
|
12633
|
+
hiddenInputBuffer = "";
|
|
12634
|
+
};
|
|
12635
|
+
const onData = (chunk) => {
|
|
12636
|
+
processText(chunk.toString());
|
|
12637
|
+
};
|
|
12638
|
+
const onEnd = () => fail(new Error("Secret input ended before a value was entered."));
|
|
12639
|
+
const onError = (error) => fail(error);
|
|
12640
|
+
input.on("data", onData);
|
|
12641
|
+
input.once("end", onEnd);
|
|
12642
|
+
input.once("error", onError);
|
|
12643
|
+
if (hiddenInputBuffer) {
|
|
12644
|
+
const buffered = hiddenInputBuffer;
|
|
12645
|
+
hiddenInputBuffer = "";
|
|
12646
|
+
processText(buffered);
|
|
12647
|
+
}
|
|
12648
|
+
});
|
|
12649
|
+
}
|
|
12650
|
+
async function readSecretValue() {
|
|
12651
|
+
const first = await readHiddenLine("Secret value: ");
|
|
12652
|
+
if (!first) throw new Error("Secret value is required.");
|
|
12653
|
+
const second = await readHiddenLine("Confirm secret value: ");
|
|
12654
|
+
if (first !== second) {
|
|
12655
|
+
throw new Error("Secret values did not match.");
|
|
12656
|
+
}
|
|
12657
|
+
return first;
|
|
12658
|
+
}
|
|
12659
|
+
function preventShellHistoryLeak(forbidden) {
|
|
12660
|
+
if (forbidden.length > 0) {
|
|
12661
|
+
throw new Error(
|
|
12662
|
+
"Do not pass secret values as command arguments. Run `deepline secrets set NAME` and enter the value at the hidden prompt."
|
|
12663
|
+
);
|
|
12664
|
+
}
|
|
12665
|
+
}
|
|
12666
|
+
async function handleList(options) {
|
|
12667
|
+
const client = new DeeplineClient();
|
|
12668
|
+
const secrets = await client.listSecrets();
|
|
12669
|
+
printCommandEnvelope(
|
|
12670
|
+
{
|
|
12671
|
+
secrets,
|
|
12672
|
+
count: secrets.length,
|
|
12673
|
+
render: {
|
|
12674
|
+
sections: [
|
|
12675
|
+
{
|
|
12676
|
+
title: "secrets",
|
|
12677
|
+
lines: secrets.length ? secrets.map(renderSecret) : ["No play secrets are configured."]
|
|
12678
|
+
}
|
|
12679
|
+
]
|
|
12680
|
+
}
|
|
12681
|
+
},
|
|
12682
|
+
{ json: options.json }
|
|
12683
|
+
);
|
|
12684
|
+
}
|
|
12685
|
+
async function handleCheck(nameInput, options) {
|
|
12686
|
+
const name = normalizeSecretName(nameInput);
|
|
12687
|
+
const client = new DeeplineClient();
|
|
12688
|
+
const secret = await client.checkSecret(name);
|
|
12689
|
+
printCommandEnvelope(
|
|
12690
|
+
{
|
|
12691
|
+
ok: Boolean(secret),
|
|
12692
|
+
name,
|
|
12693
|
+
secret: secret ?? null,
|
|
12694
|
+
render: {
|
|
12695
|
+
sections: [
|
|
12696
|
+
{
|
|
12697
|
+
title: "secret check",
|
|
12698
|
+
lines: [
|
|
12699
|
+
secret ? `${name}: active` : `${name}: missing, disabled, or empty`
|
|
12700
|
+
]
|
|
12701
|
+
}
|
|
12702
|
+
]
|
|
12703
|
+
}
|
|
12704
|
+
},
|
|
12705
|
+
{ json: options.json }
|
|
12706
|
+
);
|
|
12707
|
+
if (!secret) process.exitCode = 4;
|
|
12708
|
+
}
|
|
12709
|
+
async function handleSet(nameInput, forbidden, options) {
|
|
12710
|
+
preventShellHistoryLeak(forbidden);
|
|
12711
|
+
const name = normalizeSecretName(nameInput);
|
|
12712
|
+
const scope = options.scope === "play" ? "play" : "org";
|
|
12713
|
+
const playName = options.play?.trim();
|
|
12714
|
+
if (scope === "play" && !playName) {
|
|
12715
|
+
throw new Error("--play <name> is required when --scope play is used.");
|
|
12716
|
+
}
|
|
12717
|
+
const value = await readSecretValue();
|
|
12718
|
+
const { http } = getAuthedHttpClient();
|
|
12719
|
+
const response = await http.post(
|
|
12720
|
+
"/api/v2/secrets",
|
|
12721
|
+
{
|
|
12722
|
+
name,
|
|
12723
|
+
value,
|
|
12724
|
+
scope,
|
|
12725
|
+
...playName ? { playName } : {}
|
|
12726
|
+
}
|
|
12727
|
+
);
|
|
12728
|
+
const secret = response.secret;
|
|
12729
|
+
printCommandEnvelope(
|
|
12730
|
+
{
|
|
12731
|
+
ok: true,
|
|
12732
|
+
secret,
|
|
12733
|
+
render: {
|
|
12734
|
+
sections: [
|
|
12735
|
+
{
|
|
12736
|
+
title: "secret saved",
|
|
12737
|
+
lines: [`${secret.name}: saved (${secret.scope})`]
|
|
12738
|
+
}
|
|
12739
|
+
]
|
|
12740
|
+
}
|
|
12741
|
+
},
|
|
12742
|
+
{ json: options.json }
|
|
12743
|
+
);
|
|
12744
|
+
}
|
|
12745
|
+
function registerSecretsCommands(program) {
|
|
12746
|
+
const secrets = program.command("secrets").description("Manage play secrets without revealing values.").addHelpText(
|
|
12747
|
+
"after",
|
|
12748
|
+
`
|
|
12749
|
+
Notes:
|
|
12750
|
+
Secret values are never accepted as command arguments, stdin pipes, env vars,
|
|
12751
|
+
or files. Use deepline secrets set NAME and type the value at the hidden TTY
|
|
12752
|
+
prompt. Agents can list/check metadata but should not enter secret values.
|
|
12753
|
+
|
|
12754
|
+
Examples:
|
|
12755
|
+
deepline secrets list
|
|
12756
|
+
deepline secrets check HUBSPOT_TOKEN
|
|
12757
|
+
deepline secrets set HUBSPOT_TOKEN
|
|
12758
|
+
`
|
|
12759
|
+
);
|
|
12760
|
+
secrets.command("list").description("List secret metadata only.").option("--json", "Emit JSON output").action(async (options) => {
|
|
12761
|
+
await handleList(options);
|
|
12762
|
+
});
|
|
12763
|
+
secrets.command("check").description("Check whether a secret exists and is active.").argument("<name>", "Secret name").option("--json", "Emit JSON output").action(async (name, options) => {
|
|
12764
|
+
await handleCheck(name, options);
|
|
12765
|
+
});
|
|
12766
|
+
secrets.command("set").description("Set or rotate a secret through a hidden interactive prompt.").argument("<name>", "Secret name").argument("[forbidden...]", "Do not pass secret values here").option("--json", "Emit JSON output").option("--scope <scope>", "Secret scope: org or play", "org").option("--play <name>", "Play name for play-scoped secrets").action(
|
|
12767
|
+
async (name, forbidden, options) => {
|
|
12768
|
+
await handleSet(name, forbidden ?? [], options);
|
|
12769
|
+
}
|
|
12770
|
+
);
|
|
12102
12771
|
}
|
|
12103
12772
|
|
|
12104
12773
|
// src/cli/commands/tools.ts
|
|
@@ -13306,25 +13975,25 @@ function shellQuote(value) {
|
|
|
13306
13975
|
function powerShellQuote(value) {
|
|
13307
13976
|
return `'${value.replace(/'/g, "''")}'`;
|
|
13308
13977
|
}
|
|
13309
|
-
function seedToolListScript(
|
|
13310
|
-
const stem = safeFileStem(
|
|
13978
|
+
function seedToolListScript(input2) {
|
|
13979
|
+
const stem = safeFileStem(input2.toolId);
|
|
13311
13980
|
const fileName = `${stem}-workflow-seed-${Date.now()}.play.ts`;
|
|
13312
13981
|
const scriptDir = mkdtempSync(join9(tmpdir3(), "deepline-workflow-seed-"));
|
|
13313
13982
|
chmodSync(scriptDir, 448);
|
|
13314
13983
|
const scriptPath = join9(scriptDir, fileName);
|
|
13315
13984
|
const projectDir = `deepline/projects/${stem}-workflow`;
|
|
13316
13985
|
const playName = `${stem}-workflow`;
|
|
13317
|
-
const sampleRows =
|
|
13318
|
-
const columns = Object.keys(
|
|
13319
|
-
const rowKey = Object.prototype.hasOwnProperty.call(
|
|
13986
|
+
const sampleRows = input2.rows.length > 0 ? `${JSON.stringify(input2.rows.slice(0, 2)).replace(/\]$/, "")}, ...]` : "[]";
|
|
13987
|
+
const columns = Object.keys(input2.rows[0] ?? {}).join(", ");
|
|
13988
|
+
const rowKey = Object.prototype.hasOwnProperty.call(input2.rows[0] ?? {}, "id") ? '"id"' : "(row) => JSON.stringify(row)";
|
|
13320
13989
|
const script = `import { definePlay } from 'deepline';
|
|
13321
13990
|
|
|
13322
13991
|
export default definePlay(${JSON.stringify(playName)}, async (ctx) => {
|
|
13323
13992
|
const result = await ctx.tools.execute({
|
|
13324
|
-
id: ${JSON.stringify(
|
|
13325
|
-
tool: ${JSON.stringify(
|
|
13326
|
-
input: ${JSON.stringify(
|
|
13327
|
-
description: ${JSON.stringify(`Seed ${
|
|
13993
|
+
id: ${JSON.stringify(input2.toolId)},
|
|
13994
|
+
tool: ${JSON.stringify(input2.toolId)},
|
|
13995
|
+
input: ${JSON.stringify(input2.payload)},
|
|
13996
|
+
description: ${JSON.stringify(`Seed ${input2.toolId} rows for workflow expansion.`)},
|
|
13328
13997
|
});
|
|
13329
13998
|
|
|
13330
13999
|
const list = Object.values(result.extractedLists)[0];
|
|
@@ -13356,23 +14025,23 @@ export default definePlay(${JSON.stringify(playName)}, async (ctx) => {
|
|
|
13356
14025
|
windowsCopyCommand: `New-Item -ItemType Directory -Force -Path ${powerShellQuote(projectDir.replace(/\//g, "\\"))} | Out-Null; Copy-Item -LiteralPath ${powerShellQuote(scriptPath)} -Destination ${powerShellQuote(`${projectDir.replace(/\//g, "\\")}\\${fileName}`)}`
|
|
13357
14026
|
};
|
|
13358
14027
|
}
|
|
13359
|
-
function buildToolExecuteBaseEnvelope(
|
|
13360
|
-
const envelope = commandEnvelopeFromRawResponse(
|
|
13361
|
-
const summaryEntries = Object.entries(
|
|
13362
|
-
const outputPreview =
|
|
14028
|
+
function buildToolExecuteBaseEnvelope(input2) {
|
|
14029
|
+
const envelope = commandEnvelopeFromRawResponse(input2.rawResponse);
|
|
14030
|
+
const summaryEntries = Object.entries(input2.summary);
|
|
14031
|
+
const outputPreview = input2.listConversion ? {
|
|
13363
14032
|
kind: "list",
|
|
13364
|
-
rowCount:
|
|
13365
|
-
columns: Object.keys(
|
|
13366
|
-
preview:
|
|
13367
|
-
listStrategy:
|
|
13368
|
-
listSourcePath:
|
|
14033
|
+
rowCount: input2.listConversion.rows.length,
|
|
14034
|
+
columns: Object.keys(input2.listConversion.rows[0] ?? {}),
|
|
14035
|
+
preview: input2.listConversion.rows.slice(0, 5),
|
|
14036
|
+
listStrategy: input2.listConversion.strategy,
|
|
14037
|
+
listSourcePath: input2.listConversion.sourcePath
|
|
13369
14038
|
} : {
|
|
13370
14039
|
kind: summaryEntries.length > 0 ? "object" : "raw",
|
|
13371
|
-
summary:
|
|
14040
|
+
summary: input2.summary
|
|
13372
14041
|
};
|
|
13373
14042
|
const envelopeHasCanonicalOutput = isRecord5(envelope.toolResponse) && Object.prototype.hasOwnProperty.call(envelope.toolResponse, "raw");
|
|
13374
|
-
const inspectCommand = `deepline tools execute ${
|
|
13375
|
-
const actions =
|
|
14043
|
+
const inspectCommand = `deepline tools execute ${input2.toolId} --input ${shellQuote(JSON.stringify(input2.params))} --json`;
|
|
14044
|
+
const actions = input2.listConversion ? [
|
|
13376
14045
|
{
|
|
13377
14046
|
label: "next",
|
|
13378
14047
|
command: "move starter script into a project folder and expand it into a Deepline play"
|
|
@@ -13381,24 +14050,24 @@ function buildToolExecuteBaseEnvelope(input) {
|
|
|
13381
14050
|
return {
|
|
13382
14051
|
...envelope,
|
|
13383
14052
|
...envelopeHasCanonicalOutput ? { output_preview: outputPreview } : { output: outputPreview },
|
|
13384
|
-
...summaryEntries.length > 0 ? { summary:
|
|
14053
|
+
...summaryEntries.length > 0 ? { summary: input2.summary } : {},
|
|
13385
14054
|
next: {
|
|
13386
14055
|
inspect: inspectCommand,
|
|
13387
14056
|
playDebugging: "When fixing a play getter, inspect the actual play run table with runs get / inspect rows; do not copy CLI preview paths blindly.",
|
|
13388
|
-
...
|
|
14057
|
+
...input2.listConversion ? {
|
|
13389
14058
|
expandToPlay: "Use stable map and step keys so reruns are idempotent: completed rows are reused, and only missing or stale work runs again.",
|
|
13390
|
-
listSourcePath:
|
|
14059
|
+
listSourcePath: input2.listConversion.sourcePath ?? "auto-detected list in the CLI response preview"
|
|
13391
14060
|
} : {}
|
|
13392
14061
|
},
|
|
13393
14062
|
render: {
|
|
13394
|
-
sections:
|
|
14063
|
+
sections: input2.listConversion ? [
|
|
13395
14064
|
{
|
|
13396
14065
|
title: "output",
|
|
13397
14066
|
lines: [
|
|
13398
|
-
`${
|
|
14067
|
+
`${input2.listConversion.rows.length} row(s) extracted from ${input2.listConversion.sourcePath ?? "auto-detected list"}`,
|
|
13399
14068
|
"paths above are observed from this execute response; use run table rows to debug play getters",
|
|
13400
|
-
`columns: ${JSON.stringify(Object.keys(
|
|
13401
|
-
`preview: ${JSON.stringify(
|
|
14069
|
+
`columns: ${JSON.stringify(Object.keys(input2.listConversion.rows[0] ?? {}))}`,
|
|
14070
|
+
`preview: ${JSON.stringify(input2.listConversion.rows.slice(0, 5))}`
|
|
13402
14071
|
]
|
|
13403
14072
|
}
|
|
13404
14073
|
] : [
|
|
@@ -13406,7 +14075,7 @@ function buildToolExecuteBaseEnvelope(input) {
|
|
|
13406
14075
|
title: "result",
|
|
13407
14076
|
lines: summaryEntries.length > 0 ? summaryEntries.map(
|
|
13408
14077
|
([key, value]) => `${key}=${String(value)}`
|
|
13409
|
-
) : [JSON.stringify(
|
|
14078
|
+
) : [JSON.stringify(input2.rawResponse, null, 2)]
|
|
13410
14079
|
}
|
|
13411
14080
|
],
|
|
13412
14081
|
actions
|
|
@@ -13727,6 +14396,174 @@ Examples:
|
|
|
13727
14396
|
});
|
|
13728
14397
|
}
|
|
13729
14398
|
|
|
14399
|
+
// ../shared_libs/cli/command-compatibility.json
|
|
14400
|
+
var command_compatibility_default = {
|
|
14401
|
+
enrich: {
|
|
14402
|
+
family: "python",
|
|
14403
|
+
label: "a legacy Python CLI enrichment command",
|
|
14404
|
+
sdk_alternative: "Use `deepline plays ...` for durable workflows or `deepline tools execute ...` for one tool call."
|
|
14405
|
+
},
|
|
14406
|
+
session: {
|
|
14407
|
+
family: "python",
|
|
14408
|
+
label: "a legacy Python CLI session/playground command",
|
|
14409
|
+
sdk_alternative: "Use SDK play run output and run commands such as `deepline plays run ...`."
|
|
14410
|
+
},
|
|
14411
|
+
workflows: {
|
|
14412
|
+
family: "python",
|
|
14413
|
+
label: "a legacy Python CLI workflow command",
|
|
14414
|
+
sdk_alternative: "Use `deepline plays ...` in the SDK CLI."
|
|
14415
|
+
},
|
|
14416
|
+
backend: {
|
|
14417
|
+
family: "python",
|
|
14418
|
+
label: "a legacy Python CLI playground backend command"
|
|
14419
|
+
},
|
|
14420
|
+
events: {
|
|
14421
|
+
family: "python",
|
|
14422
|
+
label: "a legacy Python CLI event command"
|
|
14423
|
+
},
|
|
14424
|
+
plays: {
|
|
14425
|
+
family: "sdk",
|
|
14426
|
+
label: "an SDK CLI play command",
|
|
14427
|
+
python_alternative: "Use `deepline workflows ...` only for legacy workflows."
|
|
14428
|
+
},
|
|
14429
|
+
play: {
|
|
14430
|
+
family: "sdk",
|
|
14431
|
+
label: "an SDK CLI play command",
|
|
14432
|
+
python_alternative: "Use `deepline workflows ...` only for legacy workflows."
|
|
14433
|
+
},
|
|
14434
|
+
runs: {
|
|
14435
|
+
family: "sdk",
|
|
14436
|
+
label: "an SDK CLI run inspection command"
|
|
14437
|
+
},
|
|
14438
|
+
health: {
|
|
14439
|
+
family: "sdk",
|
|
14440
|
+
label: "an SDK CLI health command"
|
|
14441
|
+
}
|
|
14442
|
+
};
|
|
14443
|
+
|
|
14444
|
+
// ../shared_libs/cli/install-commands.json
|
|
14445
|
+
var install_commands_default = {
|
|
14446
|
+
skills: {
|
|
14447
|
+
index_path: "/.well-known/skills/index.json",
|
|
14448
|
+
default_agents: ["codex", "claude-code", "cursor"],
|
|
14449
|
+
npx_binary: "npx",
|
|
14450
|
+
npx_add_args_template: [
|
|
14451
|
+
"--yes",
|
|
14452
|
+
"skills",
|
|
14453
|
+
"add",
|
|
14454
|
+
"{skills_index_url}",
|
|
14455
|
+
"--agent",
|
|
14456
|
+
"{agents}",
|
|
14457
|
+
"--global",
|
|
14458
|
+
"--yes",
|
|
14459
|
+
"--skill",
|
|
14460
|
+
"{skill_name}",
|
|
14461
|
+
"--full-depth"
|
|
14462
|
+
]
|
|
14463
|
+
},
|
|
14464
|
+
cli: {
|
|
14465
|
+
legacy_python_shell_template: "curl -s {base_url}/api/v2/cli/install | bash",
|
|
14466
|
+
sdk_npm_global: "npm install -g deepline@latest"
|
|
14467
|
+
}
|
|
14468
|
+
};
|
|
14469
|
+
|
|
14470
|
+
// src/cli/install-commands.ts
|
|
14471
|
+
var INSTALL_COMMANDS = install_commands_default;
|
|
14472
|
+
function normalizeBaseUrl2(baseUrl) {
|
|
14473
|
+
return baseUrl.replace(/\/$/, "");
|
|
14474
|
+
}
|
|
14475
|
+
function renderTemplate(template, values) {
|
|
14476
|
+
return template.replace(/\{([a-z_]+)\}/g, (match, key) => {
|
|
14477
|
+
return values[key] ?? match;
|
|
14478
|
+
});
|
|
14479
|
+
}
|
|
14480
|
+
function shellJoin(args) {
|
|
14481
|
+
return args.join(" ");
|
|
14482
|
+
}
|
|
14483
|
+
function skillsIndexUrl(baseUrl) {
|
|
14484
|
+
return `${normalizeBaseUrl2(baseUrl)}${INSTALL_COMMANDS.skills.index_path}`;
|
|
14485
|
+
}
|
|
14486
|
+
function buildSkillsAddArgs(baseUrl, skillName, options = {}) {
|
|
14487
|
+
const values = {
|
|
14488
|
+
skills_index_url: skillsIndexUrl(baseUrl),
|
|
14489
|
+
agents: INSTALL_COMMANDS.skills.default_agents.join(" "),
|
|
14490
|
+
skill_name: skillName
|
|
14491
|
+
};
|
|
14492
|
+
const rendered = INSTALL_COMMANDS.skills.npx_add_args_template.flatMap(
|
|
14493
|
+
(arg, index) => {
|
|
14494
|
+
const next = index === 0 && options.firstArg ? options.firstArg : arg;
|
|
14495
|
+
const value = renderTemplate(next, values);
|
|
14496
|
+
return arg === "{agents}" ? INSTALL_COMMANDS.skills.default_agents : value;
|
|
14497
|
+
}
|
|
14498
|
+
);
|
|
14499
|
+
return rendered;
|
|
14500
|
+
}
|
|
14501
|
+
function skillsInstallCommand(baseUrl, skillName) {
|
|
14502
|
+
return `${INSTALL_COMMANDS.skills.npx_binary} ${shellJoin(
|
|
14503
|
+
buildSkillsAddArgs(baseUrl, skillName)
|
|
14504
|
+
)}`;
|
|
14505
|
+
}
|
|
14506
|
+
function legacyPythonInstallCommand(baseUrl) {
|
|
14507
|
+
return renderTemplate(INSTALL_COMMANDS.cli.legacy_python_shell_template, {
|
|
14508
|
+
base_url: normalizeBaseUrl2(baseUrl)
|
|
14509
|
+
});
|
|
14510
|
+
}
|
|
14511
|
+
function sdkNpmGlobalInstallCommand() {
|
|
14512
|
+
return INSTALL_COMMANDS.cli.sdk_npm_global;
|
|
14513
|
+
}
|
|
14514
|
+
|
|
14515
|
+
// src/cli/command-compatibility.ts
|
|
14516
|
+
var COMMAND_COMPATIBILITY = command_compatibility_default;
|
|
14517
|
+
function cliFamilyLabel(family) {
|
|
14518
|
+
return family === "sdk" ? "SDK CLI" : "legacy Python CLI";
|
|
14519
|
+
}
|
|
14520
|
+
function commandCompatibilityHint(currentFamily, commandName, baseUrl) {
|
|
14521
|
+
const compatibility = COMMAND_COMPATIBILITY[commandName];
|
|
14522
|
+
if (!compatibility || compatibility.family === currentFamily) {
|
|
14523
|
+
return null;
|
|
14524
|
+
}
|
|
14525
|
+
const expectedFamily = compatibility.family;
|
|
14526
|
+
const currentLabel = cliFamilyLabel(currentFamily);
|
|
14527
|
+
const expectedLabel = cliFamilyLabel(expectedFamily);
|
|
14528
|
+
const lines = [
|
|
14529
|
+
"",
|
|
14530
|
+
"Command compatibility:",
|
|
14531
|
+
` \`deepline ${commandName}\` is ${compatibility.label}.`,
|
|
14532
|
+
` Current binary: ${currentLabel}. Required binary: ${expectedLabel}.`,
|
|
14533
|
+
" If this came from an agent skill, the installed skill likely targets the other Deepline CLI."
|
|
14534
|
+
];
|
|
14535
|
+
if (currentFamily === "sdk") {
|
|
14536
|
+
lines.push(
|
|
14537
|
+
"",
|
|
14538
|
+
" To stay on the SDK CLI, install the SDK agent skill:",
|
|
14539
|
+
` ${skillsInstallCommand(baseUrl, "deepline-sdk")}`,
|
|
14540
|
+
" To use the legacy Python CLI instead:",
|
|
14541
|
+
` ${legacyPythonInstallCommand(baseUrl)}`,
|
|
14542
|
+
" `deepline update` updates this SDK CLI, but it will not switch CLI families."
|
|
14543
|
+
);
|
|
14544
|
+
if (compatibility.sdk_alternative) {
|
|
14545
|
+
lines.push(` SDK alternative: ${compatibility.sdk_alternative}`);
|
|
14546
|
+
}
|
|
14547
|
+
} else {
|
|
14548
|
+
lines.push(
|
|
14549
|
+
"",
|
|
14550
|
+
" To use SDK commands, install the SDK CLI and SDK agent skill:",
|
|
14551
|
+
` ${sdkNpmGlobalInstallCommand()}`,
|
|
14552
|
+
` ${skillsInstallCommand(baseUrl, "deepline-sdk")}`,
|
|
14553
|
+
" `deepline update` updates this Python CLI and its skills, but it will not switch CLI families."
|
|
14554
|
+
);
|
|
14555
|
+
if (compatibility.python_alternative) {
|
|
14556
|
+
lines.push(` Python alternative: ${compatibility.python_alternative}`);
|
|
14557
|
+
}
|
|
14558
|
+
}
|
|
14559
|
+
return lines.join("\n");
|
|
14560
|
+
}
|
|
14561
|
+
function unknownCommandNameFromMessage(message) {
|
|
14562
|
+
const match = message.match(/unknown command ['"]([^'"]+)['"]/i);
|
|
14563
|
+
const command = match?.[1]?.trim();
|
|
14564
|
+
return command ? command : null;
|
|
14565
|
+
}
|
|
14566
|
+
|
|
13730
14567
|
// src/cli/skills-sync.ts
|
|
13731
14568
|
import { spawn as spawn2, spawnSync } from "child_process";
|
|
13732
14569
|
import {
|
|
@@ -13741,7 +14578,6 @@ import { homedir as homedir5 } from "os";
|
|
|
13741
14578
|
import { dirname as dirname10, join as join11 } from "path";
|
|
13742
14579
|
var CHECK_TIMEOUT_MS2 = 3e3;
|
|
13743
14580
|
var SDK_SKILL_NAME = "deepline-sdk";
|
|
13744
|
-
var SKILL_AGENTS = ["codex", "claude-code", "cursor"];
|
|
13745
14581
|
var attemptedSync = false;
|
|
13746
14582
|
function shouldSkipSkillsSync() {
|
|
13747
14583
|
const value = process.env.DEEPLINE_SKIP_SKILLS_SYNC?.trim().toLowerCase();
|
|
@@ -13838,42 +14674,10 @@ async function fetchSkillsUpdate(baseUrl, localVersion) {
|
|
|
13838
14674
|
}
|
|
13839
14675
|
}
|
|
13840
14676
|
function buildSkillsInstallArgs(baseUrl) {
|
|
13841
|
-
|
|
13842
|
-
"/.well-known/skills/index.json",
|
|
13843
|
-
baseUrl
|
|
13844
|
-
).toString();
|
|
13845
|
-
return [
|
|
13846
|
-
"--yes",
|
|
13847
|
-
"skills",
|
|
13848
|
-
"add",
|
|
13849
|
-
packageUrl,
|
|
13850
|
-
"--agent",
|
|
13851
|
-
...SKILL_AGENTS,
|
|
13852
|
-
"--global",
|
|
13853
|
-
"--yes",
|
|
13854
|
-
"--skill",
|
|
13855
|
-
SDK_SKILL_NAME,
|
|
13856
|
-
"--full-depth"
|
|
13857
|
-
];
|
|
14677
|
+
return buildSkillsAddArgs(baseUrl, SDK_SKILL_NAME);
|
|
13858
14678
|
}
|
|
13859
14679
|
function buildBunxSkillsInstallArgs(baseUrl) {
|
|
13860
|
-
|
|
13861
|
-
"/.well-known/skills/index.json",
|
|
13862
|
-
baseUrl
|
|
13863
|
-
).toString();
|
|
13864
|
-
return [
|
|
13865
|
-
"--bun",
|
|
13866
|
-
"skills",
|
|
13867
|
-
"add",
|
|
13868
|
-
packageUrl,
|
|
13869
|
-
"--agent",
|
|
13870
|
-
...SKILL_AGENTS,
|
|
13871
|
-
"--global",
|
|
13872
|
-
"--yes",
|
|
13873
|
-
"--skill",
|
|
13874
|
-
SDK_SKILL_NAME,
|
|
13875
|
-
"--full-depth"
|
|
13876
|
-
];
|
|
14680
|
+
return buildSkillsAddArgs(baseUrl, SDK_SKILL_NAME, { firstArg: "--bun" });
|
|
13877
14681
|
}
|
|
13878
14682
|
function hasCommand(command) {
|
|
13879
14683
|
const result = spawnSync(command, ["--version"], {
|
|
@@ -13985,6 +14789,13 @@ async function syncSdkSkillsIfNeeded(baseUrl) {
|
|
|
13985
14789
|
}
|
|
13986
14790
|
|
|
13987
14791
|
// src/cli/index.ts
|
|
14792
|
+
function asCommanderError(error) {
|
|
14793
|
+
if (!(error instanceof Error) || !("code" in error)) {
|
|
14794
|
+
return null;
|
|
14795
|
+
}
|
|
14796
|
+
const code = error.code;
|
|
14797
|
+
return typeof code === "string" && code.startsWith("commander.") ? error : null;
|
|
14798
|
+
}
|
|
13988
14799
|
function shouldPrintStartupPhase() {
|
|
13989
14800
|
if (process.argv.includes("--json")) {
|
|
13990
14801
|
return false;
|
|
@@ -14070,7 +14881,7 @@ async function main() {
|
|
|
14070
14881
|
progress?.phase("loading deepline cli");
|
|
14071
14882
|
}
|
|
14072
14883
|
const program = new Command3();
|
|
14073
|
-
program.name("deepline").description("Deepline CLI (TypeScript SDK)").version(SDK_VERSION, "-v, --version", "Show version").showHelpAfterError().showSuggestionAfterError(true).addHelpText(
|
|
14884
|
+
program.name("deepline").description("Deepline CLI (TypeScript SDK)").version(SDK_VERSION, "-v, --version", "Show version").exitOverride().showHelpAfterError().showSuggestionAfterError(true).addHelpText(
|
|
14074
14885
|
"after",
|
|
14075
14886
|
`
|
|
14076
14887
|
Common commands:
|
|
@@ -14079,6 +14890,7 @@ Common commands:
|
|
|
14079
14890
|
deepline plays search email --json
|
|
14080
14891
|
deepline plays describe person-linkedin-to-email --json
|
|
14081
14892
|
deepline plays run my.play.ts --input '{"domain":"stripe.com"}'
|
|
14893
|
+
deepline secrets check HUBSPOT_TOKEN
|
|
14082
14894
|
deepline tools execute hunter_email_verifier --input '{"email":"a@b.com"}'
|
|
14083
14895
|
deepline update
|
|
14084
14896
|
|
|
@@ -14128,6 +14940,7 @@ Exit codes:
|
|
|
14128
14940
|
registerAuthCommands(program);
|
|
14129
14941
|
registerToolsCommands(program);
|
|
14130
14942
|
registerPlayCommands(program);
|
|
14943
|
+
registerSecretsCommands(program);
|
|
14131
14944
|
registerBillingCommands(program);
|
|
14132
14945
|
registerOrgCommands(program);
|
|
14133
14946
|
registerCsvCommands(program);
|
|
@@ -14197,6 +15010,7 @@ Examples:
|
|
|
14197
15010
|
ok: true
|
|
14198
15011
|
});
|
|
14199
15012
|
} catch (error) {
|
|
15013
|
+
const commanderError = asCommanderError(error);
|
|
14200
15014
|
recordCliTrace({
|
|
14201
15015
|
phase: "cli.main_total",
|
|
14202
15016
|
ms: Date.now() - mainStartedAt,
|
|
@@ -14204,7 +15018,26 @@ Examples:
|
|
|
14204
15018
|
error: error instanceof Error ? error.message : String(error)
|
|
14205
15019
|
});
|
|
14206
15020
|
progress?.fail();
|
|
14207
|
-
|
|
15021
|
+
const wantsJson = process.argv.includes("--json");
|
|
15022
|
+
if (commanderError) {
|
|
15023
|
+
if (commanderError.code === "commander.unknownCommand") {
|
|
15024
|
+
const commandName = unknownCommandNameFromMessage(
|
|
15025
|
+
commanderError.message
|
|
15026
|
+
);
|
|
15027
|
+
if (commandName && !wantsJson) {
|
|
15028
|
+
const hint = commandCompatibilityHint(
|
|
15029
|
+
"sdk",
|
|
15030
|
+
commandName,
|
|
15031
|
+
autoDetectBaseUrl()
|
|
15032
|
+
);
|
|
15033
|
+
if (hint) {
|
|
15034
|
+
console.error(hint);
|
|
15035
|
+
}
|
|
15036
|
+
}
|
|
15037
|
+
}
|
|
15038
|
+
process.exitCode = commanderError.code === "commander.unknownCommand" && !wantsJson ? 2 : commanderError.exitCode ?? 1;
|
|
15039
|
+
return;
|
|
15040
|
+
} else if (wantsJson) {
|
|
14208
15041
|
printJsonError(error);
|
|
14209
15042
|
} else if (error instanceof Error) {
|
|
14210
15043
|
console.error(`Error: ${error.message}`);
|