deepline 0.1.47 → 0.1.49
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/README.md +14 -14
- package/dist/cli/index.js +863 -260
- package/dist/cli/index.mjs +863 -260
- package/dist/index.d.mts +44 -34
- package/dist/index.d.ts +44 -34
- package/dist/index.js +57 -16
- package/dist/index.mjs +57 -16
- package/dist/repo/apps/play-runner-workers/src/coordinator-entry.ts +5 -2
- package/dist/repo/apps/play-runner-workers/src/entry.ts +383 -305
- package/dist/repo/apps/play-runner-workers/src/runtime/receipts.ts +51 -21
- package/dist/repo/sdk/src/client.ts +29 -4
- package/dist/repo/sdk/src/play.ts +35 -42
- package/dist/repo/sdk/src/plays/harness-stub.ts +1 -1
- package/dist/repo/sdk/src/version.ts +1 -1
- package/dist/repo/sdk/src/worker-play-entry.ts +17 -67
- package/dist/repo/shared_libs/play-runtime/tool-result.ts +34 -3
- package/dist/repo/shared_libs/plays/row-identity.ts +5 -59
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -24,7 +24,10 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
24
24
|
));
|
|
25
25
|
|
|
26
26
|
// src/cli/index.ts
|
|
27
|
-
var
|
|
27
|
+
var import_promises5 = require("fs/promises");
|
|
28
|
+
var import_node_path15 = require("path");
|
|
29
|
+
var import_node_os9 = require("os");
|
|
30
|
+
var import_commander3 = require("commander");
|
|
28
31
|
|
|
29
32
|
// src/config.ts
|
|
30
33
|
var import_node_fs = require("fs");
|
|
@@ -216,7 +219,7 @@ function resolveConfig(options) {
|
|
|
216
219
|
}
|
|
217
220
|
|
|
218
221
|
// src/version.ts
|
|
219
|
-
var SDK_VERSION = "0.1.
|
|
222
|
+
var SDK_VERSION = "0.1.49";
|
|
220
223
|
var SDK_API_CONTRACT = "2026-05-stripe-promo-checkout";
|
|
221
224
|
|
|
222
225
|
// ../shared_libs/play-runtime/coordinator-headers.ts
|
|
@@ -736,9 +739,18 @@ var DeeplineClient = class {
|
|
|
736
739
|
* console.log(`Found ${searchTools.length} search tools`);
|
|
737
740
|
* ```
|
|
738
741
|
*/
|
|
739
|
-
async listTools() {
|
|
742
|
+
async listTools(options) {
|
|
743
|
+
const params = new URLSearchParams();
|
|
744
|
+
if (options?.categories?.trim()) {
|
|
745
|
+
params.set("categories", options.categories.trim());
|
|
746
|
+
}
|
|
747
|
+
if (options?.grep?.trim()) {
|
|
748
|
+
params.set("grep", options.grep.trim());
|
|
749
|
+
params.set("grep_mode", options.grepMode ?? "all");
|
|
750
|
+
}
|
|
751
|
+
const suffix = params.toString() ? `?${params.toString()}` : "";
|
|
740
752
|
const res = await this.http.get(
|
|
741
|
-
|
|
753
|
+
`/api/v2/tools${suffix}`
|
|
742
754
|
);
|
|
743
755
|
return res.tools;
|
|
744
756
|
}
|
|
@@ -1373,9 +1385,17 @@ var DeeplineClient = class {
|
|
|
1373
1385
|
options?.reason ? { reason: options.reason } : {}
|
|
1374
1386
|
);
|
|
1375
1387
|
}
|
|
1376
|
-
async listPlays() {
|
|
1388
|
+
async listPlays(options) {
|
|
1389
|
+
const params = new URLSearchParams();
|
|
1390
|
+
if (options?.origin) params.set("origin", options.origin);
|
|
1391
|
+
if (options?.grep?.trim()) {
|
|
1392
|
+
params.set("grep", options.grep.trim());
|
|
1393
|
+
params.set("grep_mode", options.grepMode ?? "all");
|
|
1394
|
+
params.set("limit", "60");
|
|
1395
|
+
}
|
|
1396
|
+
const suffix = params.toString() ? `?${params.toString()}` : "";
|
|
1377
1397
|
const response = await this.http.get(
|
|
1378
|
-
|
|
1398
|
+
`/api/v2/plays${suffix}`
|
|
1379
1399
|
);
|
|
1380
1400
|
return response.plays ?? [];
|
|
1381
1401
|
}
|
|
@@ -2795,8 +2815,10 @@ async function handleCheckout(options) {
|
|
|
2795
2815
|
}
|
|
2796
2816
|
async function handleRedeemCode(code, options) {
|
|
2797
2817
|
const { http } = getAuthedHttpClient();
|
|
2798
|
-
const payload = await http.post("/api/v2/billing/checkout
|
|
2799
|
-
|
|
2818
|
+
const payload = await http.post("/api/v2/billing/checkout", {
|
|
2819
|
+
discountCode: code
|
|
2820
|
+
});
|
|
2821
|
+
const url = String(payload.url || payload.checkout_url || "");
|
|
2800
2822
|
if (!options.json && !options.noOpen && url) openInBrowser(url);
|
|
2801
2823
|
printCommandEnvelope({
|
|
2802
2824
|
...payload,
|
|
@@ -5681,6 +5703,16 @@ function extractPlayName(code, filePath) {
|
|
|
5681
5703
|
function isFileTarget(target) {
|
|
5682
5704
|
return (0, import_node_fs8.existsSync)((0, import_node_path10.resolve)(target));
|
|
5683
5705
|
}
|
|
5706
|
+
function looksLikeRunId(target) {
|
|
5707
|
+
return /^play\/[^/]+\/run\/[^/]+/.test(target.trim());
|
|
5708
|
+
}
|
|
5709
|
+
function formatPlayCommandReceivedRunIdError(input) {
|
|
5710
|
+
return `\`deepline plays ${input.command} <run-id>\` expects a play name, but this looks like a run id.
|
|
5711
|
+
Use:
|
|
5712
|
+
deepline runs get ${input.runId} --json
|
|
5713
|
+
deepline runs logs ${input.runId} --json
|
|
5714
|
+
deepline runs export ${input.runId} --out output.csv`;
|
|
5715
|
+
}
|
|
5684
5716
|
function looksLikeFilePath(target) {
|
|
5685
5717
|
if (target.trim().toLowerCase().startsWith("prebuilt/")) {
|
|
5686
5718
|
return false;
|
|
@@ -6107,6 +6139,69 @@ function describeLiveEventPhase(event) {
|
|
|
6107
6139
|
}
|
|
6108
6140
|
return null;
|
|
6109
6141
|
}
|
|
6142
|
+
function formatProgressLabel(raw) {
|
|
6143
|
+
const value = typeof raw === "string" && raw.trim() ? raw.trim() : "step";
|
|
6144
|
+
return value.replace(/^map:/, "").replace(/^tool:/, "");
|
|
6145
|
+
}
|
|
6146
|
+
function formatProgressCounts(input) {
|
|
6147
|
+
const completed = typeof input.completed === "number" && Number.isFinite(input.completed) ? input.completed : null;
|
|
6148
|
+
const total = typeof input.total === "number" && Number.isFinite(input.total) ? input.total : null;
|
|
6149
|
+
if (completed === null || total === null || total <= 0) {
|
|
6150
|
+
return null;
|
|
6151
|
+
}
|
|
6152
|
+
const percent = Math.max(0, Math.min(100, Math.round(completed / total * 100)));
|
|
6153
|
+
const failed = typeof input.failed === "number" && Number.isFinite(input.failed) && input.failed > 0 ? `, failed ${formatInteger(input.failed)}` : "";
|
|
6154
|
+
return `${formatInteger(completed)}/${formatInteger(total)} (${percent}%)${failed}`;
|
|
6155
|
+
}
|
|
6156
|
+
function getProgressLinesFromLiveEvent(event) {
|
|
6157
|
+
const payload = getEventPayload(event);
|
|
6158
|
+
if (event.type === "play.step.progress") {
|
|
6159
|
+
const counts = formatProgressCounts({
|
|
6160
|
+
completed: payload.completed,
|
|
6161
|
+
total: payload.total,
|
|
6162
|
+
failed: payload.failed
|
|
6163
|
+
});
|
|
6164
|
+
if (!counts) return [];
|
|
6165
|
+
return [`progress ${formatProgressLabel(payload.stepId)}: ${counts}`];
|
|
6166
|
+
}
|
|
6167
|
+
if (event.type !== "play.run.snapshot" && event.type !== "play.run.final_status") {
|
|
6168
|
+
return [];
|
|
6169
|
+
}
|
|
6170
|
+
const nodeStates = Array.isArray(payload.nodeStates) ? payload.nodeStates : Array.isArray(payload.steps) ? payload.steps : [];
|
|
6171
|
+
const lines = [];
|
|
6172
|
+
for (const state of nodeStates) {
|
|
6173
|
+
if (!state || typeof state !== "object" || Array.isArray(state)) {
|
|
6174
|
+
continue;
|
|
6175
|
+
}
|
|
6176
|
+
const record = state;
|
|
6177
|
+
const progress = record.progress && typeof record.progress === "object" && !Array.isArray(record.progress) ? record.progress : null;
|
|
6178
|
+
if (!progress) {
|
|
6179
|
+
continue;
|
|
6180
|
+
}
|
|
6181
|
+
const counts = formatProgressCounts({
|
|
6182
|
+
completed: progress.completed,
|
|
6183
|
+
total: progress.total,
|
|
6184
|
+
failed: progress.failed
|
|
6185
|
+
});
|
|
6186
|
+
if (!counts) {
|
|
6187
|
+
continue;
|
|
6188
|
+
}
|
|
6189
|
+
lines.push(
|
|
6190
|
+
`progress ${formatProgressLabel(record.nodeId ?? progress.artifactTableNamespace)}: ${counts}`
|
|
6191
|
+
);
|
|
6192
|
+
}
|
|
6193
|
+
return lines;
|
|
6194
|
+
}
|
|
6195
|
+
function printPlayProgressLines(input) {
|
|
6196
|
+
for (const line of input.lines) {
|
|
6197
|
+
const signature = line.trim();
|
|
6198
|
+
if (!signature || input.state.lastProgressSignature === signature) {
|
|
6199
|
+
continue;
|
|
6200
|
+
}
|
|
6201
|
+
input.state.lastProgressSignature = signature;
|
|
6202
|
+
input.progress.writeLine(line);
|
|
6203
|
+
}
|
|
6204
|
+
}
|
|
6110
6205
|
function buildPlayDashboardUrl(baseUrl, playName) {
|
|
6111
6206
|
const trimmedBase = baseUrl.replace(/\/$/, "");
|
|
6112
6207
|
const encodedPlayName = encodeURIComponent(playName);
|
|
@@ -6180,6 +6275,13 @@ async function waitForPlayCompletionByStream(input) {
|
|
|
6180
6275
|
state: input.state,
|
|
6181
6276
|
progress: input.progress
|
|
6182
6277
|
});
|
|
6278
|
+
if (!input.jsonOutput) {
|
|
6279
|
+
printPlayProgressLines({
|
|
6280
|
+
lines: getProgressLinesFromLiveEvent(event),
|
|
6281
|
+
state: input.state,
|
|
6282
|
+
progress: input.progress
|
|
6283
|
+
});
|
|
6284
|
+
}
|
|
6183
6285
|
const status = getStatusFromLiveEvent(event);
|
|
6184
6286
|
if (status && TERMINAL_PLAY_STATUSES2.has(status)) {
|
|
6185
6287
|
const finalStatus = await input.client.getPlayStatus(input.workflowId, {
|
|
@@ -6248,7 +6350,8 @@ async function startAndWaitForPlayCompletionByStreamOnce(input) {
|
|
|
6248
6350
|
);
|
|
6249
6351
|
const state = {
|
|
6250
6352
|
lastLogIndex: 0,
|
|
6251
|
-
emittedRunnerStarted: false
|
|
6353
|
+
emittedRunnerStarted: false,
|
|
6354
|
+
lastProgressSignature: null
|
|
6252
6355
|
};
|
|
6253
6356
|
const controller = new AbortController();
|
|
6254
6357
|
let timedOut = false;
|
|
@@ -6276,11 +6379,6 @@ async function startAndWaitForPlayCompletionByStreamOnce(input) {
|
|
|
6276
6379
|
}
|
|
6277
6380
|
const workflowId = lastKnownWorkflowId || "pending";
|
|
6278
6381
|
if (workflowId !== "pending" && !emittedDashboardUrl) {
|
|
6279
|
-
openPlayDashboard({
|
|
6280
|
-
dashboardUrl,
|
|
6281
|
-
jsonOutput: input.jsonOutput,
|
|
6282
|
-
noOpen: input.noOpen
|
|
6283
|
-
});
|
|
6284
6382
|
if (!input.jsonOutput) {
|
|
6285
6383
|
writeStartedPlayRun({
|
|
6286
6384
|
runId: workflowId,
|
|
@@ -6290,6 +6388,11 @@ async function startAndWaitForPlayCompletionByStreamOnce(input) {
|
|
|
6290
6388
|
progress: input.progress
|
|
6291
6389
|
});
|
|
6292
6390
|
}
|
|
6391
|
+
openPlayDashboard({
|
|
6392
|
+
dashboardUrl,
|
|
6393
|
+
jsonOutput: input.jsonOutput,
|
|
6394
|
+
noOpen: input.noOpen
|
|
6395
|
+
});
|
|
6293
6396
|
input.progress.phase(`loading play on ${dashboardUrl}`);
|
|
6294
6397
|
emittedDashboardUrl = true;
|
|
6295
6398
|
}
|
|
@@ -6312,6 +6415,13 @@ async function startAndWaitForPlayCompletionByStreamOnce(input) {
|
|
|
6312
6415
|
state,
|
|
6313
6416
|
progress: input.progress
|
|
6314
6417
|
});
|
|
6418
|
+
if (!input.jsonOutput) {
|
|
6419
|
+
printPlayProgressLines({
|
|
6420
|
+
lines: getProgressLinesFromLiveEvent(event),
|
|
6421
|
+
state,
|
|
6422
|
+
progress: input.progress
|
|
6423
|
+
});
|
|
6424
|
+
}
|
|
6315
6425
|
const finalStatus = getFinalStatusFromLiveEvent(event);
|
|
6316
6426
|
if (finalStatus) {
|
|
6317
6427
|
recordCliTrace({
|
|
@@ -6580,6 +6690,7 @@ function buildRunNextCommands(status) {
|
|
|
6580
6690
|
const commands = {
|
|
6581
6691
|
get: `deepline runs get ${runId} --json`,
|
|
6582
6692
|
full: `deepline runs get ${runId} --full --json`,
|
|
6693
|
+
export: `deepline runs export ${runId} --out output.csv`,
|
|
6583
6694
|
stop: `deepline runs stop ${runId} --reason "stale lock" --json`,
|
|
6584
6695
|
logs: `deepline runs logs ${runId} --out run.log --json`
|
|
6585
6696
|
};
|
|
@@ -6712,6 +6823,32 @@ function formatInsufficientCreditsMessage(input) {
|
|
|
6712
6823
|
const addSuffix = billingUrl && recommended !== "-" ? ` Add >=${recommended} at ${billingUrl}.` : billingUrl ? ` Add credits at ${billingUrl}.` : "";
|
|
6713
6824
|
return `Workspace balance ${balance} < required ${required} for ${operation}${workspaceSuffix}.${addSuffix}`;
|
|
6714
6825
|
}
|
|
6826
|
+
function buildInsufficientCreditsSummaryLines(input) {
|
|
6827
|
+
const progress = input.status.progress;
|
|
6828
|
+
const rowsInfo = extractCanonicalRowsInfo(input.status);
|
|
6829
|
+
const completed = getNumericField(progress, "completed") ?? getNumericField(progress, "completedRows") ?? rowsInfo?.rows.length ?? null;
|
|
6830
|
+
const total = getNumericField(progress, "total") ?? getNumericField(progress, "totalRows") ?? rowsInfo?.totalRows ?? null;
|
|
6831
|
+
const lines = [
|
|
6832
|
+
" status: stopped_insufficient_credits",
|
|
6833
|
+
completed === null ? " completed rows: unknown" : ` completed rows: ${formatInteger(completed)}${total !== null ? ` of ${formatInteger(total)}` : ""}`,
|
|
6834
|
+
" reusable receipts: yes; rerun after adding credits to continue from completed provider work"
|
|
6835
|
+
];
|
|
6836
|
+
const billingUrl = getStringField(input.billing, "billing_url");
|
|
6837
|
+
const recommended = formatCreditAmount(
|
|
6838
|
+
input.billing.recommended_add_credits ?? input.billing.needed_credits
|
|
6839
|
+
);
|
|
6840
|
+
if (billingUrl) {
|
|
6841
|
+
lines.push(
|
|
6842
|
+
recommended !== "-" ? ` add credits: add >=${recommended} at ${billingUrl}` : ` add credits: ${billingUrl}`
|
|
6843
|
+
);
|
|
6844
|
+
}
|
|
6845
|
+
const runId = input.status.runId?.trim();
|
|
6846
|
+
if (runId) {
|
|
6847
|
+
lines.push(` inspect: deepline runs get ${runId} --json`);
|
|
6848
|
+
lines.push(` export partial: deepline runs export ${runId} --out output.csv`);
|
|
6849
|
+
}
|
|
6850
|
+
return lines;
|
|
6851
|
+
}
|
|
6715
6852
|
function formatPlayErrorForDisplay(status, error) {
|
|
6716
6853
|
if (!error) {
|
|
6717
6854
|
return null;
|
|
@@ -6902,6 +7039,19 @@ function formatDatasetStatsLines(datasetStats) {
|
|
|
6902
7039
|
}
|
|
6903
7040
|
return lines;
|
|
6904
7041
|
}
|
|
7042
|
+
function buildJsonRunResultRenderLines(status) {
|
|
7043
|
+
const publicStatus = status.status ?? "running";
|
|
7044
|
+
const runId = status.runId ?? "unknown";
|
|
7045
|
+
const lines = [`${publicStatus} ${runId}`];
|
|
7046
|
+
const progressError = status.progress?.error;
|
|
7047
|
+
if (typeof progressError === "string") {
|
|
7048
|
+
const billing = extractBillingForStatus(status, progressError);
|
|
7049
|
+
if (isInsufficientCreditsBilling(billing)) {
|
|
7050
|
+
lines.push(...buildInsufficientCreditsSummaryLines({ status, billing }));
|
|
7051
|
+
}
|
|
7052
|
+
}
|
|
7053
|
+
return lines;
|
|
7054
|
+
}
|
|
6905
7055
|
function writePlayResult(status, jsonOutput, options) {
|
|
6906
7056
|
if (jsonOutput) {
|
|
6907
7057
|
const payload2 = options?.fullJson ? enrichPlayStatusWithDatasetStats(status) : compactPlayStatus(status);
|
|
@@ -6911,9 +7061,7 @@ function writePlayResult(status, jsonOutput, options) {
|
|
|
6911
7061
|
sections: [
|
|
6912
7062
|
{
|
|
6913
7063
|
title: "run result",
|
|
6914
|
-
lines:
|
|
6915
|
-
`${status.status ?? "running"} ${status.runId ?? "unknown"}`
|
|
6916
|
-
]
|
|
7064
|
+
lines: buildJsonRunResultRenderLines(status)
|
|
6917
7065
|
}
|
|
6918
7066
|
]
|
|
6919
7067
|
}
|
|
@@ -6940,6 +7088,10 @@ function writePlayResult(status, jsonOutput, options) {
|
|
|
6940
7088
|
lines.push(...formatDatasetStatsLines(datasetStats));
|
|
6941
7089
|
const progressError = status.progress?.error;
|
|
6942
7090
|
if (progressError && typeof progressError === "string") {
|
|
7091
|
+
const billing = extractBillingForStatus(status, progressError);
|
|
7092
|
+
if (isInsufficientCreditsBilling(billing)) {
|
|
7093
|
+
lines.push(...buildInsufficientCreditsSummaryLines({ status, billing }));
|
|
7094
|
+
}
|
|
6943
7095
|
const displayError = formatPlayErrorForDisplay(status, progressError) ?? progressError;
|
|
6944
7096
|
lines.push(` error: ${displayError.slice(0, 200)}`);
|
|
6945
7097
|
}
|
|
@@ -7319,24 +7471,31 @@ function writeStartedPlayRun(input) {
|
|
|
7319
7471
|
workflowId: input.runId,
|
|
7320
7472
|
name: input.playName,
|
|
7321
7473
|
status: input.status ?? "started",
|
|
7322
|
-
dashboardUrl: input.dashboardUrl
|
|
7474
|
+
dashboardUrl: input.dashboardUrl,
|
|
7475
|
+
next: {
|
|
7476
|
+
inspect: `deepline runs get ${input.runId} --json`,
|
|
7477
|
+
full: `deepline runs get ${input.runId} --full --json`,
|
|
7478
|
+
logs: `deepline runs logs ${input.runId} --json`,
|
|
7479
|
+
export: `deepline runs export ${input.runId} --out output.csv`,
|
|
7480
|
+
stop: `deepline runs stop ${input.runId} --reason "stale lock" --json`
|
|
7481
|
+
}
|
|
7323
7482
|
};
|
|
7483
|
+
const lines = [
|
|
7484
|
+
`Started ${input.playName}`,
|
|
7485
|
+
` run id: ${input.runId}`,
|
|
7486
|
+
` inspect: deepline runs get ${input.runId} --json`,
|
|
7487
|
+
` full debug: deepline runs get ${input.runId} --full --json`,
|
|
7488
|
+
` logs: deepline runs logs ${input.runId} --json`,
|
|
7489
|
+
` export after completion: deepline runs export ${input.runId} --out output.csv`,
|
|
7490
|
+
` stop run: deepline runs stop ${input.runId} --reason "stale lock" --json`
|
|
7491
|
+
];
|
|
7324
7492
|
if (input.jsonOutput) {
|
|
7325
7493
|
printCommandEnvelope({
|
|
7326
7494
|
...payload,
|
|
7327
|
-
render: { sections: [{ title: "play run", lines
|
|
7495
|
+
render: { sections: [{ title: "play run", lines }] }
|
|
7328
7496
|
}, { json: true });
|
|
7329
7497
|
return;
|
|
7330
7498
|
}
|
|
7331
|
-
const lines = [
|
|
7332
|
-
`Started ${input.playName}`,
|
|
7333
|
-
` run id: ${input.runId}`,
|
|
7334
|
-
` get status: deepline runs get ${input.runId} --json`,
|
|
7335
|
-
` logs: deepline runs logs ${input.runId} --json`,
|
|
7336
|
-
` stop run: deepline runs stop ${input.runId} --reason "stale lock" --json`,
|
|
7337
|
-
` result JSON: deepline runs get ${input.runId} --json`,
|
|
7338
|
-
` full debug JSON: deepline runs get ${input.runId} --full --json`
|
|
7339
|
-
];
|
|
7340
7499
|
if (input.dashboardUrl) {
|
|
7341
7500
|
lines.push(` play page: ${input.dashboardUrl}`);
|
|
7342
7501
|
}
|
|
@@ -7352,13 +7511,13 @@ function writeStartedPlayRun(input) {
|
|
|
7352
7511
|
` });
|
|
7353
7512
|
}
|
|
7354
7513
|
function parsePlayRunOptions(args) {
|
|
7355
|
-
const usage = "Usage: deepline plays run <play-name> [--input '{...}'] [--
|
|
7514
|
+
const usage = "Usage: deepline plays run <play-name> [--input '{...}'] [--no-wait] [--tail-timeout-ms 30000] [--force] [--<input> value]\n deepline plays run <play-file.ts> [--input '{...}'] [--no-wait] [--tail-timeout-ms 30000] [--force] [--<input> value]\n deepline plays run --file <play-file.ts> [--input '{...}'] [--no-wait] [--tail-timeout-ms 30000] [--force] [--<input> value]\n deepline plays run --name <name> [--input '{...}'] [--live|--latest|--revision-id <id>] [--no-wait] [--tail-timeout-ms 30000] [--force] [--no-open] [--json] [--<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.";
|
|
7356
7515
|
let filePath = null;
|
|
7357
7516
|
let playName = null;
|
|
7358
7517
|
let input = null;
|
|
7359
7518
|
let revisionId = null;
|
|
7360
7519
|
let revisionSelector = null;
|
|
7361
|
-
const watch = args.includes("--
|
|
7520
|
+
const watch = !args.includes("--no-wait");
|
|
7362
7521
|
let jsonOutput = watch ? args.includes("--json") : argsWantJson(args);
|
|
7363
7522
|
const emitLogs = !jsonOutput || args.includes("--logs");
|
|
7364
7523
|
const force = args.includes("--force");
|
|
@@ -7404,7 +7563,7 @@ function parsePlayRunOptions(args) {
|
|
|
7404
7563
|
waitTimeoutMs = parsePositiveInteger2(args[++index], arg);
|
|
7405
7564
|
continue;
|
|
7406
7565
|
}
|
|
7407
|
-
if (arg === "--json" || arg === "--wait" || arg === "--tail" || arg === "--watch" || arg === "--logs" || arg === "--force" || arg === "--no-open") {
|
|
7566
|
+
if (arg === "--json" || arg === "--wait" || arg === "--tail" || arg === "--watch" || arg === "--no-wait" || arg === "--logs" || arg === "--force" || arg === "--no-open") {
|
|
7408
7567
|
if (arg === "--watch") {
|
|
7409
7568
|
continue;
|
|
7410
7569
|
}
|
|
@@ -8260,6 +8419,12 @@ async function handlePlayGet(args) {
|
|
|
8260
8419
|
console.error("Usage: deepline play get <play-file.ts|play-name> [--json]");
|
|
8261
8420
|
return 1;
|
|
8262
8421
|
}
|
|
8422
|
+
if (looksLikeRunId(target)) {
|
|
8423
|
+
console.error(
|
|
8424
|
+
formatPlayCommandReceivedRunIdError({ command: "get", runId: target })
|
|
8425
|
+
);
|
|
8426
|
+
return 2;
|
|
8427
|
+
}
|
|
8263
8428
|
const client = new DeeplineClient();
|
|
8264
8429
|
const explicitJson = args.includes("--json");
|
|
8265
8430
|
const sourceOutput = args.includes("--source");
|
|
@@ -8374,8 +8539,20 @@ async function handlePlayVersions(args) {
|
|
|
8374
8539
|
}
|
|
8375
8540
|
async function handlePlayList(args) {
|
|
8376
8541
|
const jsonOutput = argsWantJson(args);
|
|
8542
|
+
const originArgIndex = args.findIndex((arg) => arg === "--origin");
|
|
8543
|
+
const rawOrigin = originArgIndex >= 0 ? args[originArgIndex + 1] : void 0;
|
|
8544
|
+
if (rawOrigin && rawOrigin !== "prebuilt" && rawOrigin !== "owned") {
|
|
8545
|
+
throw new Error(`Invalid value for --origin: ${rawOrigin}`);
|
|
8546
|
+
}
|
|
8547
|
+
const origin = rawOrigin;
|
|
8377
8548
|
const client = new DeeplineClient();
|
|
8378
|
-
const plays = await client.listPlays(
|
|
8549
|
+
const plays = (await client.listPlays({
|
|
8550
|
+
...origin ? { origin } : {}
|
|
8551
|
+
})).filter((play) => {
|
|
8552
|
+
if (!origin) return true;
|
|
8553
|
+
const isPrebuilt = play.origin === "prebuilt" || play.ownerType === "deepline";
|
|
8554
|
+
return origin === "prebuilt" ? isPrebuilt : !isPrebuilt;
|
|
8555
|
+
});
|
|
8379
8556
|
if (jsonOutput) {
|
|
8380
8557
|
process.stdout.write(`${JSON.stringify(plays)}
|
|
8381
8558
|
`);
|
|
@@ -8478,6 +8655,54 @@ function printPlayDescription(play) {
|
|
|
8478
8655
|
);
|
|
8479
8656
|
}
|
|
8480
8657
|
}
|
|
8658
|
+
function compactPlaySchema(schema) {
|
|
8659
|
+
if (!schema) return null;
|
|
8660
|
+
const fields = Array.isArray(schema.fields) ? schema.fields.map(
|
|
8661
|
+
(field) => field && typeof field === "object" ? {
|
|
8662
|
+
name: String(field.name ?? ""),
|
|
8663
|
+
type: field.type ?? void 0,
|
|
8664
|
+
required: field.required ?? void 0
|
|
8665
|
+
} : null
|
|
8666
|
+
).filter((field) => Boolean(field?.name)) : [];
|
|
8667
|
+
return fields.length > 0 ? { fields } : schema;
|
|
8668
|
+
}
|
|
8669
|
+
function playSchemaMetadata(schema, key) {
|
|
8670
|
+
if (!schema || typeof schema !== "object" || Array.isArray(schema)) return null;
|
|
8671
|
+
const value = schema[key];
|
|
8672
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
8673
|
+
}
|
|
8674
|
+
function playRunCommand(play, options) {
|
|
8675
|
+
const target = play.reference || play.name;
|
|
8676
|
+
if (options?.csvInput) {
|
|
8677
|
+
const inputField = typeof options.csvInput.inputField === "string" && options.csvInput.inputField.trim() ? options.csvInput.inputField.trim() : "csv";
|
|
8678
|
+
return `deepline plays run ${target} --input '${JSON.stringify({ [inputField]: "leads.csv" })}' --watch`;
|
|
8679
|
+
}
|
|
8680
|
+
return `deepline plays run ${target} --input '{...}' --watch`;
|
|
8681
|
+
}
|
|
8682
|
+
function summarizePlayListItemForCli(play, options) {
|
|
8683
|
+
const aliases = play.aliases?.length ? play.aliases : [play.name];
|
|
8684
|
+
const csvInput = playSchemaMetadata(play.inputSchema, "csvInput");
|
|
8685
|
+
const rowOutputSchema = playSchemaMetadata(play.outputSchema, "rowOutputSchema");
|
|
8686
|
+
const runCommand2 = playRunCommand(play, { csvInput });
|
|
8687
|
+
return {
|
|
8688
|
+
name: play.name,
|
|
8689
|
+
...play.reference ? { reference: play.reference } : {},
|
|
8690
|
+
...play.displayName ? { displayName: play.displayName } : {},
|
|
8691
|
+
origin: play.origin,
|
|
8692
|
+
ownerType: play.ownerType,
|
|
8693
|
+
canEdit: play.canEdit,
|
|
8694
|
+
canClone: play.canClone,
|
|
8695
|
+
aliases,
|
|
8696
|
+
inputSchema: options?.compact ? compactPlaySchema(play.inputSchema) : play.inputSchema ?? null,
|
|
8697
|
+
outputSchema: options?.compact ? compactPlaySchema(play.outputSchema) : play.outputSchema ?? null,
|
|
8698
|
+
...csvInput ? { csvInput } : {},
|
|
8699
|
+
...rowOutputSchema ? { rowOutputSchema } : {},
|
|
8700
|
+
runCommand: runCommand2,
|
|
8701
|
+
examples: [runCommand2],
|
|
8702
|
+
currentPublishedVersion: play.currentPublishedVersion ?? null,
|
|
8703
|
+
isDraftDirty: play.isDraftDirty
|
|
8704
|
+
};
|
|
8705
|
+
}
|
|
8481
8706
|
async function handlePlaySearch(args) {
|
|
8482
8707
|
let options;
|
|
8483
8708
|
try {
|
|
@@ -8499,6 +8724,100 @@ async function handlePlaySearch(args) {
|
|
|
8499
8724
|
}
|
|
8500
8725
|
process.stdout.write(`${plays.length} plays found:
|
|
8501
8726
|
|
|
8727
|
+
`);
|
|
8728
|
+
for (const play of plays) {
|
|
8729
|
+
printPlayDescription(play);
|
|
8730
|
+
console.log("");
|
|
8731
|
+
}
|
|
8732
|
+
return 0;
|
|
8733
|
+
}
|
|
8734
|
+
function normalizePlayGrepText(value) {
|
|
8735
|
+
if (value === null || value === void 0) return "";
|
|
8736
|
+
if (typeof value === "string") return value.toLowerCase();
|
|
8737
|
+
if (typeof value === "number" || typeof value === "boolean") {
|
|
8738
|
+
return String(value).toLowerCase();
|
|
8739
|
+
}
|
|
8740
|
+
if (Array.isArray(value)) return value.map(normalizePlayGrepText).join(" ");
|
|
8741
|
+
if (typeof value === "object") {
|
|
8742
|
+
return Object.values(value).map(normalizePlayGrepText).join(" ");
|
|
8743
|
+
}
|
|
8744
|
+
return "";
|
|
8745
|
+
}
|
|
8746
|
+
function parsePlayGrepTerms(query, mode) {
|
|
8747
|
+
const trimmed = query.trim().toLowerCase();
|
|
8748
|
+
if (!trimmed) return [];
|
|
8749
|
+
if (mode === "phrase") return [trimmed];
|
|
8750
|
+
const matches = trimmed.match(/"([^"]+)"|'([^']+)'|\S+/g) ?? [];
|
|
8751
|
+
return matches.map((term) => term.replace(/^["']|["']$/g, "").trim()).filter(Boolean);
|
|
8752
|
+
}
|
|
8753
|
+
function matchesPlayGrepQuery(value, query, mode) {
|
|
8754
|
+
const terms = parsePlayGrepTerms(query, mode);
|
|
8755
|
+
if (terms.length === 0) return true;
|
|
8756
|
+
const haystack = normalizePlayGrepText(value);
|
|
8757
|
+
if (mode === "any") return terms.some((term) => haystack.includes(term));
|
|
8758
|
+
return terms.every((term) => haystack.includes(term));
|
|
8759
|
+
}
|
|
8760
|
+
async function handlePlayGrep(args) {
|
|
8761
|
+
const query = args[0]?.trim();
|
|
8762
|
+
if (!query) {
|
|
8763
|
+
console.error("Usage: deepline plays grep <query> [--origin prebuilt|owned] [--compact] [--json]");
|
|
8764
|
+
return 1;
|
|
8765
|
+
}
|
|
8766
|
+
let origin;
|
|
8767
|
+
let mode = "all";
|
|
8768
|
+
for (let index = 1; index < args.length; index += 1) {
|
|
8769
|
+
const arg = args[index];
|
|
8770
|
+
if (arg === "--origin" && args[index + 1]) {
|
|
8771
|
+
const rawOrigin = args[++index].trim().toLowerCase();
|
|
8772
|
+
if (rawOrigin !== "prebuilt" && rawOrigin !== "owned") {
|
|
8773
|
+
throw new Error(`Invalid value for --origin: ${rawOrigin}`);
|
|
8774
|
+
}
|
|
8775
|
+
origin = rawOrigin;
|
|
8776
|
+
}
|
|
8777
|
+
if (arg === "--mode" && args[index + 1]) {
|
|
8778
|
+
const rawMode = args[++index].trim().toLowerCase();
|
|
8779
|
+
mode = rawMode === "any" || rawMode === "phrase" ? rawMode : "all";
|
|
8780
|
+
}
|
|
8781
|
+
}
|
|
8782
|
+
const compact = args.includes("--compact");
|
|
8783
|
+
const client = new DeeplineClient();
|
|
8784
|
+
const plays = (await client.listPlays({
|
|
8785
|
+
grep: query,
|
|
8786
|
+
grepMode: mode,
|
|
8787
|
+
...origin ? { origin } : {}
|
|
8788
|
+
})).filter((play) => {
|
|
8789
|
+
if (!origin) return true;
|
|
8790
|
+
const isPrebuilt = play.origin === "prebuilt" || play.ownerType === "deepline";
|
|
8791
|
+
return origin === "prebuilt" ? isPrebuilt : !isPrebuilt;
|
|
8792
|
+
}).filter(
|
|
8793
|
+
(play) => matchesPlayGrepQuery(
|
|
8794
|
+
{
|
|
8795
|
+
name: play.name,
|
|
8796
|
+
reference: play.reference,
|
|
8797
|
+
displayName: play.displayName,
|
|
8798
|
+
origin: play.origin,
|
|
8799
|
+
ownerType: play.ownerType,
|
|
8800
|
+
aliases: play.aliases,
|
|
8801
|
+
inputSchema: play.inputSchema,
|
|
8802
|
+
outputSchema: play.outputSchema
|
|
8803
|
+
},
|
|
8804
|
+
query,
|
|
8805
|
+
mode
|
|
8806
|
+
)
|
|
8807
|
+
).map((play) => summarizePlayListItemForCli(play, { compact }));
|
|
8808
|
+
if (argsWantJson(args)) {
|
|
8809
|
+
process.stdout.write(`${JSON.stringify({
|
|
8810
|
+
plays,
|
|
8811
|
+
count: plays.length,
|
|
8812
|
+
query,
|
|
8813
|
+
grep: { mode, terms: parsePlayGrepTerms(query, mode) },
|
|
8814
|
+
filters: { origin: origin ?? null }
|
|
8815
|
+
})}
|
|
8816
|
+
`);
|
|
8817
|
+
return 0;
|
|
8818
|
+
}
|
|
8819
|
+
process.stdout.write(`${plays.length} plays found:
|
|
8820
|
+
|
|
8502
8821
|
`);
|
|
8503
8822
|
for (const play of plays) {
|
|
8504
8823
|
printPlayDescription(play);
|
|
@@ -8514,6 +8833,15 @@ async function handlePlayDescribe(args) {
|
|
|
8514
8833
|
);
|
|
8515
8834
|
return 1;
|
|
8516
8835
|
}
|
|
8836
|
+
if (looksLikeRunId(playName)) {
|
|
8837
|
+
console.error(
|
|
8838
|
+
formatPlayCommandReceivedRunIdError({
|
|
8839
|
+
command: "describe",
|
|
8840
|
+
runId: playName
|
|
8841
|
+
})
|
|
8842
|
+
);
|
|
8843
|
+
return 2;
|
|
8844
|
+
}
|
|
8517
8845
|
const client = new DeeplineClient();
|
|
8518
8846
|
await assertCanonicalNamedPlayReference(client, playName);
|
|
8519
8847
|
const play = await client.describePlay(
|
|
@@ -8670,7 +8998,7 @@ Common commands:
|
|
|
8670
8998
|
deepline plays search email --json
|
|
8671
8999
|
deepline plays describe person-linkedin-to-email --json
|
|
8672
9000
|
deepline plays check my.play.ts
|
|
8673
|
-
deepline plays run my.play.ts --input '{"domain":"stripe.com"}'
|
|
9001
|
+
deepline plays run my.play.ts --input '{"domain":"stripe.com"}'
|
|
8674
9002
|
deepline plays set-live my.play.ts --json
|
|
8675
9003
|
deepline plays get person-linkedin-to-email --json
|
|
8676
9004
|
`
|
|
@@ -8701,8 +9029,10 @@ Notes:
|
|
|
8701
9029
|
Unknown --foo value and --foo.bar value flags are passed into play input.
|
|
8702
9030
|
Example: --limit 5 becomes input.limit = 5.
|
|
8703
9031
|
File args accept local paths; the CLI stages files before submit.
|
|
8704
|
-
|
|
8705
|
-
--wait
|
|
9032
|
+
By default, run waits for completion and prints logs, previews, stats, and
|
|
9033
|
+
next commands. --watch and --wait are accepted compatibility aliases for the
|
|
9034
|
+
default behavior. Use --no-wait only when you intentionally want
|
|
9035
|
+
a fire-and-forget run id.
|
|
8706
9036
|
The play page opens in your browser as soon as the run starts; use --no-open
|
|
8707
9037
|
to only print the URL.
|
|
8708
9038
|
--force supersedes active runs; it does not bypass completed reuse.
|
|
@@ -8730,17 +9060,18 @@ Idempotent execution:
|
|
|
8730
9060
|
.run({ key: 'domain', staleAfterSeconds: 86400 })
|
|
8731
9061
|
|
|
8732
9062
|
Examples:
|
|
8733
|
-
deepline plays run my.play.ts --input '{"domain":"stripe.com"}'
|
|
8734
|
-
deepline plays run my.play.ts --input @input.json --
|
|
8735
|
-
deepline plays run person-linkedin-to-email --input '{"linkedin_url":"..."}'
|
|
8736
|
-
deepline plays run cto-search.play.ts --limit 5
|
|
9063
|
+
deepline plays run my.play.ts --input '{"domain":"stripe.com"}'
|
|
9064
|
+
deepline plays run my.play.ts --input @input.json --json
|
|
9065
|
+
deepline plays run person-linkedin-to-email --input '{"linkedin_url":"..."}'
|
|
9066
|
+
deepline plays run cto-search.play.ts --limit 5
|
|
9067
|
+
deepline plays run long-background-play --no-wait
|
|
8737
9068
|
deepline runs export <run-id> --out output.csv
|
|
8738
9069
|
deepline runs get <run-id>
|
|
8739
9070
|
`
|
|
8740
9071
|
).option("--file <path>", "Local play file to run").option("--name <name>", "Saved play name to run").option("-i, --input <json>", "Input JSON object or @file path").option("--live", "Run the current live revision explicitly").option("--latest", "Run the newest saved revision, even if it is not live").option(
|
|
8741
9072
|
"--revision-id <id>",
|
|
8742
9073
|
"Run a specific saved revision instead of the live revision"
|
|
8743
|
-
).option("--watch", "
|
|
9074
|
+
).option("--watch", "Compatibility alias; run waits by default").option("--wait", "Compatibility alias; run waits by default").option("--no-wait", "Start the run and return immediately").option(
|
|
8744
9075
|
"--logs",
|
|
8745
9076
|
"When output is non-interactive, stream play logs to stderr while waiting"
|
|
8746
9077
|
).option("--tail-timeout-ms <ms>", "Timeout while watching the run stream").option("--force", "Supersede any active runs for this play").option("--no-open", "Print the play page URL without opening a browser").option("--json", "Emit JSON output").addHelpText(
|
|
@@ -8773,6 +9104,7 @@ Pass-through input flags:
|
|
|
8773
9104
|
...options.live ? ["--live"] : [],
|
|
8774
9105
|
...options.latest ? ["--latest"] : [],
|
|
8775
9106
|
...options.revisionId ? ["--revision-id", options.revisionId] : [],
|
|
9107
|
+
...options.wait === false ? ["--no-wait"] : [],
|
|
8776
9108
|
...options.watch || options.wait ? ["--watch"] : [],
|
|
8777
9109
|
...options.logs ? ["--logs"] : [],
|
|
8778
9110
|
...options.tailTimeoutMs ? ["--tail-timeout-ms", options.tailTimeoutMs] : [],
|
|
@@ -8813,24 +9145,27 @@ Notes:
|
|
|
8813
9145
|
|
|
8814
9146
|
Examples:
|
|
8815
9147
|
deepline plays list
|
|
8816
|
-
deepline plays list --json
|
|
9148
|
+
deepline plays list --origin prebuilt --json
|
|
8817
9149
|
deepline plays search email --origin prebuilt --json
|
|
8818
9150
|
`
|
|
8819
|
-
).option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (options) => {
|
|
9151
|
+
).option("--origin <origin>", "Filter to prebuilt or owned plays").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (options) => {
|
|
8820
9152
|
process.exitCode = await handlePlayList([
|
|
9153
|
+
...options.origin ? ["--origin", options.origin] : [],
|
|
8821
9154
|
...options.json ? ["--json"] : []
|
|
8822
9155
|
]);
|
|
8823
9156
|
});
|
|
8824
|
-
|
|
9157
|
+
const addPlaySearchCommand = (command) => command.description("Search saved and prebuilt plays.").addHelpText(
|
|
8825
9158
|
"after",
|
|
8826
9159
|
`
|
|
8827
9160
|
Notes:
|
|
8828
9161
|
Ranked discovery for workflows. Use --origin prebuilt or --origin owned when
|
|
8829
9162
|
you need to narrow results. Use describe on a result before running it.
|
|
9163
|
+
The grep alias is the same ranked retrieval surface with a more literal name
|
|
9164
|
+
for agents that are filtering the play registry.
|
|
8830
9165
|
|
|
8831
9166
|
Examples:
|
|
8832
9167
|
deepline plays search email
|
|
8833
|
-
deepline plays
|
|
9168
|
+
deepline plays grep "linkedin to email" --origin prebuilt --compact --json
|
|
8834
9169
|
deepline plays describe person-linkedin-to-email --json
|
|
8835
9170
|
`
|
|
8836
9171
|
).option("--origin <origin>", "Filter to prebuilt or owned plays").option("--compact", "Emit compact schemas").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (query, options) => {
|
|
@@ -8841,6 +9176,30 @@ Examples:
|
|
|
8841
9176
|
...options.json ? ["--json"] : []
|
|
8842
9177
|
]);
|
|
8843
9178
|
});
|
|
9179
|
+
addPlaySearchCommand(play.command("search <query>"));
|
|
9180
|
+
play.command("grep <query>").description("Literal grep over play names, aliases, schemas, and descriptions.").addHelpText(
|
|
9181
|
+
"after",
|
|
9182
|
+
`
|
|
9183
|
+
Notes:
|
|
9184
|
+
Literal registry filtering. Terms are matched case-insensitively against play
|
|
9185
|
+
names, references, display names, aliases, ownership, and schemas. Use
|
|
9186
|
+
--mode phrase for exact phrase matching, --mode any for OR, and the default
|
|
9187
|
+
--mode all for AND.
|
|
9188
|
+
|
|
9189
|
+
Examples:
|
|
9190
|
+
deepline plays grep email --origin prebuilt --json
|
|
9191
|
+
deepline plays grep "company contact" --origin prebuilt --mode all --json
|
|
9192
|
+
deepline plays describe prebuilt/company-to-contact --json
|
|
9193
|
+
`
|
|
9194
|
+
).option("--origin <origin>", "Filter to prebuilt or owned plays").option("--compact", "Emit compact schemas").option("--mode <mode>", "Grep matching mode: all, any, or phrase").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (query, options) => {
|
|
9195
|
+
process.exitCode = await handlePlayGrep([
|
|
9196
|
+
query,
|
|
9197
|
+
...options.origin ? ["--origin", options.origin] : [],
|
|
9198
|
+
...options.compact ? ["--compact"] : [],
|
|
9199
|
+
...options.mode ? ["--mode", options.mode] : [],
|
|
9200
|
+
...options.json ? ["--json"] : []
|
|
9201
|
+
]);
|
|
9202
|
+
});
|
|
8844
9203
|
play.command("describe <target>").description("Describe a play contract and how to run it.").addHelpText(
|
|
8845
9204
|
"after",
|
|
8846
9205
|
`
|
|
@@ -8869,7 +9228,7 @@ Notes:
|
|
|
8869
9228
|
Examples:
|
|
8870
9229
|
deepline plays versions --name my-play
|
|
8871
9230
|
deepline plays versions --name my-play --json
|
|
8872
|
-
deepline plays run my-play --revision-id <revision-id>
|
|
9231
|
+
deepline plays run my-play --revision-id <revision-id>
|
|
8873
9232
|
`
|
|
8874
9233
|
).option("--name <name>", "Saved play name").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (options) => {
|
|
8875
9234
|
process.exitCode = await handlePlayVersions([
|
|
@@ -9071,6 +9430,7 @@ Examples:
|
|
|
9071
9430
|
}
|
|
9072
9431
|
|
|
9073
9432
|
// src/cli/commands/tools.ts
|
|
9433
|
+
var import_commander2 = require("commander");
|
|
9074
9434
|
var import_node_fs10 = require("fs");
|
|
9075
9435
|
var import_node_os7 = require("os");
|
|
9076
9436
|
var import_node_path12 = require("path");
|
|
@@ -9255,9 +9615,42 @@ function toListedTool(tool) {
|
|
|
9255
9615
|
executeCommand: `deepline tools execute ${tool.toolId}`
|
|
9256
9616
|
};
|
|
9257
9617
|
}
|
|
9618
|
+
function normalizeGrepText(value) {
|
|
9619
|
+
if (value === null || value === void 0) return "";
|
|
9620
|
+
if (typeof value === "string") return value.toLowerCase();
|
|
9621
|
+
if (typeof value === "number" || typeof value === "boolean") {
|
|
9622
|
+
return String(value).toLowerCase();
|
|
9623
|
+
}
|
|
9624
|
+
if (Array.isArray(value)) return value.map(normalizeGrepText).join(" ");
|
|
9625
|
+
if (typeof value === "object") {
|
|
9626
|
+
return Object.values(value).map(normalizeGrepText).join(" ");
|
|
9627
|
+
}
|
|
9628
|
+
return "";
|
|
9629
|
+
}
|
|
9630
|
+
function parseGrepTerms(query, mode) {
|
|
9631
|
+
const trimmed = query.trim().toLowerCase();
|
|
9632
|
+
if (!trimmed) return [];
|
|
9633
|
+
if (mode === "phrase") return [trimmed];
|
|
9634
|
+
const matches = trimmed.match(/"([^"]+)"|'([^']+)'|\S+/g) ?? [];
|
|
9635
|
+
return matches.map((term) => term.replace(/^["']|["']$/g, "").trim()).filter(Boolean);
|
|
9636
|
+
}
|
|
9637
|
+
function matchesGrepQuery(value, query, mode) {
|
|
9638
|
+
const terms = parseGrepTerms(query, mode);
|
|
9639
|
+
if (terms.length === 0) return true;
|
|
9640
|
+
const haystack = normalizeGrepText(value);
|
|
9641
|
+
if (mode === "any") return terms.some((term) => haystack.includes(term));
|
|
9642
|
+
return terms.every((term) => haystack.includes(term));
|
|
9643
|
+
}
|
|
9258
9644
|
async function listTools(args) {
|
|
9259
9645
|
const client = new DeeplineClient();
|
|
9260
|
-
const
|
|
9646
|
+
const categoryArgIndex = args.findIndex((arg) => arg === "--categories");
|
|
9647
|
+
const categoryFilter = categoryArgIndex >= 0 ? args[categoryArgIndex + 1] : "";
|
|
9648
|
+
const requestedCategories = categoryFilter ? categoryFilter.split(",").map((item) => item.trim()).filter(Boolean) : [];
|
|
9649
|
+
const items = (await client.listTools({
|
|
9650
|
+
...categoryFilter ? { categories: categoryFilter } : {}
|
|
9651
|
+
})).map(toListedTool).filter(
|
|
9652
|
+
(item) => requestedCategories.length === 0 || requestedCategories.some((category) => item.categories.includes(category))
|
|
9653
|
+
);
|
|
9261
9654
|
const render = {
|
|
9262
9655
|
sections: [
|
|
9263
9656
|
{
|
|
@@ -9280,6 +9673,9 @@ async function listTools(args) {
|
|
|
9280
9673
|
{
|
|
9281
9674
|
tools: items,
|
|
9282
9675
|
count: items.length,
|
|
9676
|
+
filters: {
|
|
9677
|
+
categories: requestedCategories
|
|
9678
|
+
},
|
|
9283
9679
|
commandTemplates: TOOL_COMMAND_TEMPLATES,
|
|
9284
9680
|
render
|
|
9285
9681
|
},
|
|
@@ -9306,6 +9702,56 @@ async function searchTools(queryInput, options = {}) {
|
|
|
9306
9702
|
});
|
|
9307
9703
|
return 0;
|
|
9308
9704
|
}
|
|
9705
|
+
async function grepTools(queryInput, options = {}) {
|
|
9706
|
+
const query = queryInput.trim();
|
|
9707
|
+
if (!query) {
|
|
9708
|
+
console.error("Usage: deepline tools grep <query> [--json]");
|
|
9709
|
+
return 1;
|
|
9710
|
+
}
|
|
9711
|
+
const client = new DeeplineClient();
|
|
9712
|
+
const requestedCategories = options.categories ? options.categories.split(",").map((item) => item.trim()).filter(Boolean) : [];
|
|
9713
|
+
const mode = options.mode ?? "all";
|
|
9714
|
+
const tools = (await client.listTools({
|
|
9715
|
+
grep: query,
|
|
9716
|
+
grepMode: mode,
|
|
9717
|
+
...options.categories ? { categories: options.categories } : {}
|
|
9718
|
+
})).map(toListedTool).filter(
|
|
9719
|
+
(item) => requestedCategories.length === 0 || requestedCategories.some((category) => item.categories.includes(category))
|
|
9720
|
+
).filter(
|
|
9721
|
+
(item) => matchesGrepQuery(
|
|
9722
|
+
{
|
|
9723
|
+
id: item.toolId,
|
|
9724
|
+
toolId: item.toolId,
|
|
9725
|
+
provider: item.provider,
|
|
9726
|
+
displayName: item.displayName,
|
|
9727
|
+
description: item.description,
|
|
9728
|
+
categories: item.categories,
|
|
9729
|
+
operation: item.operation,
|
|
9730
|
+
operationAliases: item.operationAliases,
|
|
9731
|
+
inputFields: item.inputFields
|
|
9732
|
+
},
|
|
9733
|
+
query,
|
|
9734
|
+
mode
|
|
9735
|
+
)
|
|
9736
|
+
);
|
|
9737
|
+
printCommandEnvelope(
|
|
9738
|
+
{
|
|
9739
|
+
tools,
|
|
9740
|
+
count: tools.length,
|
|
9741
|
+
query,
|
|
9742
|
+
grep: {
|
|
9743
|
+
mode,
|
|
9744
|
+
terms: parseGrepTerms(query, mode)
|
|
9745
|
+
},
|
|
9746
|
+
filters: {
|
|
9747
|
+
categories: requestedCategories
|
|
9748
|
+
},
|
|
9749
|
+
commandTemplates: TOOL_COMMAND_TEMPLATES
|
|
9750
|
+
},
|
|
9751
|
+
{ json: options.json || shouldEmitJson() }
|
|
9752
|
+
);
|
|
9753
|
+
return 0;
|
|
9754
|
+
}
|
|
9309
9755
|
function playIdentifiers(play) {
|
|
9310
9756
|
return [play.name, play.reference, ...play.aliases ?? []].filter((value) => Boolean(value?.trim())).map((value) => value.trim());
|
|
9311
9757
|
}
|
|
@@ -9375,24 +9821,27 @@ Notes:
|
|
|
9375
9821
|
|
|
9376
9822
|
Examples:
|
|
9377
9823
|
deepline tools list
|
|
9378
|
-
deepline tools list --json
|
|
9824
|
+
deepline tools list --categories email_finder --json
|
|
9379
9825
|
deepline tools search email --json
|
|
9380
9826
|
`
|
|
9381
|
-
).option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (options) => {
|
|
9827
|
+
).option("--categories <categories>", "Comma-separated categories to filter inventory").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (options) => {
|
|
9382
9828
|
process.exitCode = await listTools([
|
|
9829
|
+
...options.categories ? ["--categories", options.categories] : [],
|
|
9383
9830
|
...options.json ? ["--json"] : []
|
|
9384
9831
|
]);
|
|
9385
9832
|
});
|
|
9386
|
-
|
|
9833
|
+
const addToolSearchCommand = (command) => command.description("Search available tools.").addHelpText(
|
|
9387
9834
|
"after",
|
|
9388
9835
|
`
|
|
9389
9836
|
Notes:
|
|
9390
9837
|
Ranked discovery for atomic provider/API operations. Results include tool ids
|
|
9391
9838
|
that can be passed to deepline tools describe or deepline tools execute.
|
|
9839
|
+
The grep alias is the same ranked retrieval surface with a more literal name
|
|
9840
|
+
for agents that are filtering a registry rather than choosing a workflow.
|
|
9392
9841
|
|
|
9393
9842
|
Examples:
|
|
9394
9843
|
deepline tools search email
|
|
9395
|
-
deepline tools
|
|
9844
|
+
deepline tools grep "company enrichment" --categories enrichment --json
|
|
9396
9845
|
deepline tools search verifier --search-mode v2 --json
|
|
9397
9846
|
`
|
|
9398
9847
|
).option("--categories <categories>", "Comma-separated categories to filter ranked search").option("--search_terms <terms>", "Structured search terms for ranked search").option("--search-terms <terms>", "Structured search terms for ranked search").option("--search-mode <mode>", "Ranked search mode: v1 or v2").option("--include-search-debug", "Include ranked search debug metadata").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (query, options) => {
|
|
@@ -9404,24 +9853,55 @@ Examples:
|
|
|
9404
9853
|
includeSearchDebug: Boolean(options.includeSearchDebug)
|
|
9405
9854
|
});
|
|
9406
9855
|
});
|
|
9856
|
+
addToolSearchCommand(tools.command("search <query>"));
|
|
9857
|
+
tools.command("grep <query>").description("Literal grep over tool ids, descriptions, categories, and input fields.").addHelpText(
|
|
9858
|
+
"after",
|
|
9859
|
+
`
|
|
9860
|
+
Notes:
|
|
9861
|
+
Literal registry filtering. Terms are matched case-insensitively against tool
|
|
9862
|
+
ids, provider, display name, description, categories, aliases, and input
|
|
9863
|
+
fields. Use --mode phrase for exact phrase matching, --mode any for OR, and
|
|
9864
|
+
the default --mode all for AND.
|
|
9865
|
+
|
|
9866
|
+
Examples:
|
|
9867
|
+
deepline tools grep email --categories email_finder --json
|
|
9868
|
+
deepline tools grep "phone validate" --mode all --json
|
|
9869
|
+
deepline tools grep hunter --mode phrase --json
|
|
9870
|
+
`
|
|
9871
|
+
).option("--categories <categories>", "Comma-separated categories to filter inventory").option("--mode <mode>", "Grep matching mode: all, any, or phrase").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (query, options) => {
|
|
9872
|
+
const mode = options.mode === "any" || options.mode === "phrase" ? options.mode : "all";
|
|
9873
|
+
process.exitCode = await grepTools(query, {
|
|
9874
|
+
json: options.json,
|
|
9875
|
+
categories: options.categories,
|
|
9876
|
+
mode
|
|
9877
|
+
});
|
|
9878
|
+
});
|
|
9407
9879
|
const addToolMetadataCommand = (command) => command.description("Show metadata for a tool.").addHelpText(
|
|
9408
9880
|
"after",
|
|
9409
9881
|
`
|
|
9410
9882
|
Notes:
|
|
9411
|
-
Shows the
|
|
9412
|
-
|
|
9413
|
-
|
|
9883
|
+
Shows the compact agent contract by default: what the tool does, cost,
|
|
9884
|
+
required inputs, play getters, and a runnable ctx.tools.execute snippet.
|
|
9885
|
+
Use --json for the full metadata/debug payload.
|
|
9414
9886
|
|
|
9415
9887
|
Examples:
|
|
9416
9888
|
deepline tools describe hunter_email_verifier
|
|
9417
|
-
deepline tools describe hunter_email_verifier --
|
|
9889
|
+
deepline tools describe hunter_email_verifier --pricing-only
|
|
9890
|
+
deepline tools describe hunter_email_verifier --schema-only
|
|
9891
|
+
deepline tools describe hunter_email_verifier --examples-only
|
|
9892
|
+
deepline tools describe hunter_email_verifier --json
|
|
9418
9893
|
deepline tools execute hunter_email_verifier --input '{"email":"a@b.com"}'
|
|
9419
9894
|
`
|
|
9420
|
-
).option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (toolId, options) => {
|
|
9421
|
-
process.exitCode = await getTool(
|
|
9422
|
-
|
|
9423
|
-
|
|
9424
|
-
|
|
9895
|
+
).option("--json", "Emit JSON output. Also automatic when stdout is piped").option("--pricing-only", "Only print pricing and billing semantics").option("--schema-only", "Only print input schema fields").option("--examples-only", "Only print runnable examples and sample payloads").option("--getters-only", "Only print extracted list/value getters").addOption(new import_commander2.Option("--compact", "Compatibility alias for the default compact view").hideHelp()).addOption(new import_commander2.Option("--contract-json", "Compatibility alias for compact contract JSON").hideHelp()).action(async (toolId, options) => {
|
|
9896
|
+
process.exitCode = await getTool(toolId, {
|
|
9897
|
+
json: Boolean(options.json),
|
|
9898
|
+
compact: Boolean(options.compact),
|
|
9899
|
+
contractJson: Boolean(options.contractJson),
|
|
9900
|
+
pricingOnly: Boolean(options.pricingOnly),
|
|
9901
|
+
schemaOnly: Boolean(options.schemaOnly),
|
|
9902
|
+
examplesOnly: Boolean(options.examplesOnly),
|
|
9903
|
+
gettersOnly: Boolean(options.gettersOnly)
|
|
9904
|
+
});
|
|
9425
9905
|
});
|
|
9426
9906
|
addToolMetadataCommand(tools.command("describe <toolId>"));
|
|
9427
9907
|
tools.command("get <toolId>").description("Deprecated. Use tools describe.").addHelpText(
|
|
@@ -9474,8 +9954,7 @@ Examples:
|
|
|
9474
9954
|
process.exitCode = await executeTool(args);
|
|
9475
9955
|
});
|
|
9476
9956
|
}
|
|
9477
|
-
async function getTool(
|
|
9478
|
-
const toolId = args[0];
|
|
9957
|
+
async function getTool(toolId, options = {}) {
|
|
9479
9958
|
if (!toolId) {
|
|
9480
9959
|
console.error("Usage: deepline tools get <toolId> [--json]");
|
|
9481
9960
|
return 1;
|
|
@@ -9492,14 +9971,264 @@ async function getTool(args) {
|
|
|
9492
9971
|
}
|
|
9493
9972
|
throw error;
|
|
9494
9973
|
}
|
|
9495
|
-
if (
|
|
9974
|
+
if (options.contractJson) {
|
|
9975
|
+
process.stdout.write(`${JSON.stringify(toolContractJsonForDescribe(tool, toolId))}
|
|
9976
|
+
`);
|
|
9977
|
+
return 0;
|
|
9978
|
+
}
|
|
9979
|
+
const emitJson = options.json === true;
|
|
9980
|
+
if (emitJson) {
|
|
9496
9981
|
process.stdout.write(`${JSON.stringify(toolMetadataJsonForDescribe(tool, toolId))}
|
|
9497
9982
|
`);
|
|
9498
9983
|
return 0;
|
|
9499
9984
|
}
|
|
9500
|
-
|
|
9985
|
+
const onlyModes = [
|
|
9986
|
+
options.pricingOnly,
|
|
9987
|
+
options.schemaOnly,
|
|
9988
|
+
options.examplesOnly,
|
|
9989
|
+
options.gettersOnly
|
|
9990
|
+
].filter(Boolean).length;
|
|
9991
|
+
if (onlyModes > 1) {
|
|
9992
|
+
console.error("Use only one of --pricing-only, --schema-only, --examples-only, or --getters-only.");
|
|
9993
|
+
return 2;
|
|
9994
|
+
}
|
|
9995
|
+
if (options.pricingOnly) {
|
|
9996
|
+
printToolPricingOnly(tool, toolId);
|
|
9997
|
+
return 0;
|
|
9998
|
+
}
|
|
9999
|
+
if (options.schemaOnly) {
|
|
10000
|
+
printToolSchemaOnly(tool, toolId);
|
|
10001
|
+
return 0;
|
|
10002
|
+
}
|
|
10003
|
+
if (options.examplesOnly) {
|
|
10004
|
+
printToolExamplesOnly(tool, toolId);
|
|
10005
|
+
return 0;
|
|
10006
|
+
}
|
|
10007
|
+
if (options.gettersOnly) {
|
|
10008
|
+
printToolGettersOnly(tool, toolId);
|
|
10009
|
+
return 0;
|
|
10010
|
+
}
|
|
10011
|
+
if (options.compact) {
|
|
10012
|
+
printCompactToolContract(tool, toolId);
|
|
10013
|
+
return 0;
|
|
10014
|
+
}
|
|
10015
|
+
if (shouldEmitJson()) {
|
|
10016
|
+
process.stdout.write(`${JSON.stringify(toolMetadataJsonForDescribe(tool, toolId))}
|
|
10017
|
+
`);
|
|
10018
|
+
return 0;
|
|
10019
|
+
}
|
|
10020
|
+
printCompactToolContract(tool, toolId);
|
|
9501
10021
|
return 0;
|
|
9502
10022
|
}
|
|
10023
|
+
function toolContractJsonForDescribe(tool, requestedToolId) {
|
|
10024
|
+
const toolId = String(tool.toolId || requestedToolId);
|
|
10025
|
+
const inputFields = toolInputFieldsForDisplay(recordField(tool, "inputSchema", "input_schema"));
|
|
10026
|
+
const usageGuidance = recordField(tool, "usageGuidance", "usage_guidance");
|
|
10027
|
+
const toolExecutionResult = recordField(usageGuidance, "toolExecutionResult", "tool_execution_result");
|
|
10028
|
+
const extractedLists = extractionContractEntries(
|
|
10029
|
+
arrayField(toolExecutionResult, "extractedLists", "extracted_lists")
|
|
10030
|
+
);
|
|
10031
|
+
const extractedValues = extractionContractEntries(
|
|
10032
|
+
arrayField(toolExecutionResult, "extractedValues", "extracted_values")
|
|
10033
|
+
);
|
|
10034
|
+
const cost = recordField(tool, "cost");
|
|
10035
|
+
const deeplineCredits = numberField(tool, "deeplineCreditsPerPricingUnit", "deepline_credits_per_pricing_unit");
|
|
10036
|
+
const deeplineUsdPerPricingUnit = numberField(tool, "deeplineUsdPerPricingUnit", "deepline_usd_per_pricing_unit");
|
|
10037
|
+
return {
|
|
10038
|
+
schemaVersion: 1,
|
|
10039
|
+
toolId,
|
|
10040
|
+
provider: tool.provider,
|
|
10041
|
+
displayName: tool.displayName,
|
|
10042
|
+
description: tool.description,
|
|
10043
|
+
categories: tool.categories,
|
|
10044
|
+
inputFields: inputFields.map((field) => ({
|
|
10045
|
+
name: field.name,
|
|
10046
|
+
type: field.type ?? "unknown",
|
|
10047
|
+
required: Boolean(field.required),
|
|
10048
|
+
...field.description ? { description: field.description } : {},
|
|
10049
|
+
...Object.prototype.hasOwnProperty.call(field, "default") ? { default: field.default } : {}
|
|
10050
|
+
})),
|
|
10051
|
+
cost: {
|
|
10052
|
+
pricingModel: stringField(cost, "pricingModel", "pricing_model") || null,
|
|
10053
|
+
billingMode: stringField(cost, "billingMode", "billing_mode") || null,
|
|
10054
|
+
deeplineCreditsPerPricingUnit: deeplineCredits,
|
|
10055
|
+
deeplineUsdPerPricingUnit
|
|
10056
|
+
},
|
|
10057
|
+
getters: {
|
|
10058
|
+
extractedLists,
|
|
10059
|
+
extractedValues
|
|
10060
|
+
},
|
|
10061
|
+
executeCommand: `deepline tools execute ${toolId} --input '{...}' --json`
|
|
10062
|
+
};
|
|
10063
|
+
}
|
|
10064
|
+
function extractionContractEntries(entries) {
|
|
10065
|
+
return entries.flatMap((entry) => {
|
|
10066
|
+
if (!isRecord4(entry)) return [];
|
|
10067
|
+
const name = stringField(entry, "name");
|
|
10068
|
+
const expression = stringField(entry, "expression");
|
|
10069
|
+
return name && expression ? [{ name, expression }] : [];
|
|
10070
|
+
});
|
|
10071
|
+
}
|
|
10072
|
+
function printCompactToolContract(tool, requestedToolId) {
|
|
10073
|
+
const contract = toolContractJsonForDescribe(tool, requestedToolId);
|
|
10074
|
+
const cost = isRecord4(contract.cost) ? contract.cost : {};
|
|
10075
|
+
const getters = isRecord4(contract.getters) ? contract.getters : {};
|
|
10076
|
+
const listGetters = Array.isArray(getters.extractedLists) ? getters.extractedLists : [];
|
|
10077
|
+
const valueGetters = Array.isArray(getters.extractedValues) ? getters.extractedValues : [];
|
|
10078
|
+
const inputFields = Array.isArray(contract.inputFields) ? contract.inputFields : [];
|
|
10079
|
+
console.log(String(contract.toolId));
|
|
10080
|
+
if (contract.displayName) console.log(`Best for: ${contract.displayName}`);
|
|
10081
|
+
if (typeof contract.description === "string" && contract.description.trim()) {
|
|
10082
|
+
console.log(`Description: ${contract.description.trim()}`);
|
|
10083
|
+
}
|
|
10084
|
+
if (Array.isArray(contract.categories) && contract.categories.length) {
|
|
10085
|
+
console.log(`Tags: ${contract.categories.join(", ")}`);
|
|
10086
|
+
}
|
|
10087
|
+
printToolPricingOnly(tool, requestedToolId, { heading: "Cost" });
|
|
10088
|
+
if (inputFields.length) {
|
|
10089
|
+
console.log("");
|
|
10090
|
+
console.log("Inputs:");
|
|
10091
|
+
for (const field of inputFields) {
|
|
10092
|
+
if (!isRecord4(field)) continue;
|
|
10093
|
+
const name = stringField(field, "name");
|
|
10094
|
+
if (!name) continue;
|
|
10095
|
+
const required = field.required ? "*" : "";
|
|
10096
|
+
const type = stringField(field, "type") || "unknown";
|
|
10097
|
+
const description = stringField(field, "description");
|
|
10098
|
+
console.log(`- ${name}${required}: ${type}${description ? ` - ${description}` : ""}`);
|
|
10099
|
+
}
|
|
10100
|
+
}
|
|
10101
|
+
console.log("");
|
|
10102
|
+
printToolExamplesOnly(tool, requestedToolId, { includeSamples: false });
|
|
10103
|
+
if (listGetters.length || valueGetters.length) {
|
|
10104
|
+
console.log("");
|
|
10105
|
+
console.log("Getters:");
|
|
10106
|
+
if (listGetters.length) console.log("Lists:");
|
|
10107
|
+
for (const entry of listGetters) {
|
|
10108
|
+
if (isRecord4(entry)) console.log(`- ${stringField(entry, "name")}: ${playResultExpression(entry)}`);
|
|
10109
|
+
}
|
|
10110
|
+
if (valueGetters.length) console.log("Values:");
|
|
10111
|
+
for (const entry of valueGetters) {
|
|
10112
|
+
if (isRecord4(entry)) console.log(`- ${stringField(entry, "name")}: ${playResultExpression(entry)}`);
|
|
10113
|
+
}
|
|
10114
|
+
}
|
|
10115
|
+
console.log("");
|
|
10116
|
+
console.log(`More: deepline tools describe ${contract.toolId} --pricing-only | --schema-only | --examples-only | --getters-only | --json`);
|
|
10117
|
+
}
|
|
10118
|
+
function printToolPricingOnly(tool, requestedToolId, options = {}) {
|
|
10119
|
+
const contract = toolContractJsonForDescribe(tool, requestedToolId);
|
|
10120
|
+
const cost = isRecord4(contract.cost) ? contract.cost : {};
|
|
10121
|
+
const pricingModel = stringField(cost, "pricingModel") || "unknown";
|
|
10122
|
+
const billingMode = stringField(cost, "billingMode") || "unknown";
|
|
10123
|
+
const unit = pricingModel === "per_page" ? "page" : pricingModel === "per_result" ? "result" : pricingModel === "fixed" ? "call" : pricingModel.replace(/^per_/, "") || "unit";
|
|
10124
|
+
const credits = numberField(cost, "deeplineCreditsPerPricingUnit");
|
|
10125
|
+
const usd = numberField(cost, "deeplineUsdPerPricingUnit");
|
|
10126
|
+
const price = credits !== null ? `${formatDecimal(credits)} Deepline credits${usd !== null ? ` / ${formatUsd(usd)}` : ""} per ${unit}` : "pricing unavailable";
|
|
10127
|
+
console.log(`${options.heading ?? `Pricing: ${contract.toolId}`}: ${price}`);
|
|
10128
|
+
console.log(`Billing: ${billingMode}`);
|
|
10129
|
+
}
|
|
10130
|
+
function printToolSchemaOnly(tool, requestedToolId) {
|
|
10131
|
+
const contract = toolContractJsonForDescribe(tool, requestedToolId);
|
|
10132
|
+
const inputFields = Array.isArray(contract.inputFields) ? contract.inputFields : [];
|
|
10133
|
+
console.log(`Schema: ${contract.toolId}`);
|
|
10134
|
+
if (!inputFields.length) {
|
|
10135
|
+
console.log("Inputs: none");
|
|
10136
|
+
return;
|
|
10137
|
+
}
|
|
10138
|
+
console.log("Inputs:");
|
|
10139
|
+
for (const field of inputFields) {
|
|
10140
|
+
if (!isRecord4(field)) continue;
|
|
10141
|
+
const name = stringField(field, "name");
|
|
10142
|
+
if (!name) continue;
|
|
10143
|
+
const required = field.required ? "*" : "";
|
|
10144
|
+
const type = stringField(field, "type") || "unknown";
|
|
10145
|
+
const description = stringField(field, "description");
|
|
10146
|
+
const defaultSuffix = Object.prototype.hasOwnProperty.call(field, "default") ? ` default=${JSON.stringify(field.default)}` : "";
|
|
10147
|
+
console.log(`- ${name}${required}: ${type}${defaultSuffix}${description ? ` - ${description}` : ""}`);
|
|
10148
|
+
}
|
|
10149
|
+
}
|
|
10150
|
+
function printToolExamplesOnly(tool, requestedToolId, options = {}) {
|
|
10151
|
+
const contract = toolContractJsonForDescribe(tool, requestedToolId);
|
|
10152
|
+
const toolId = String(contract.toolId);
|
|
10153
|
+
const inputFields = Array.isArray(contract.inputFields) ? contract.inputFields : [];
|
|
10154
|
+
const sampleInput = Object.fromEntries(
|
|
10155
|
+
inputFields.slice(0, 4).flatMap((field) => {
|
|
10156
|
+
if (!isRecord4(field)) return [];
|
|
10157
|
+
const name = stringField(field, "name");
|
|
10158
|
+
if (!name) return [];
|
|
10159
|
+
return [[name, sampleValueForField(field)]];
|
|
10160
|
+
})
|
|
10161
|
+
);
|
|
10162
|
+
console.log(`Use in a play:`);
|
|
10163
|
+
console.log("```ts");
|
|
10164
|
+
console.log("const result = await ctx.tools.execute({");
|
|
10165
|
+
console.log(` id: '${stableStepIdForTool(toolId)}',`);
|
|
10166
|
+
console.log(` tool: '${toolId}',`);
|
|
10167
|
+
console.log(` input: ${JSON.stringify(sampleInput || {}, null, 2).replace(/\n/g, "\n ")},`);
|
|
10168
|
+
console.log("});");
|
|
10169
|
+
const getters = isRecord4(contract.getters) ? contract.getters : {};
|
|
10170
|
+
const valueGetters = Array.isArray(getters.extractedValues) ? getters.extractedValues : [];
|
|
10171
|
+
const listGetters = Array.isArray(getters.extractedLists) ? getters.extractedLists : [];
|
|
10172
|
+
const firstGetter = [...valueGetters, ...listGetters].find(isRecord4);
|
|
10173
|
+
if (firstGetter) {
|
|
10174
|
+
const name = stringField(firstGetter, "name") || "value";
|
|
10175
|
+
const expression = stringField(firstGetter, "expression");
|
|
10176
|
+
if (expression) console.log(`const ${safeIdentifier(name)} = ${expression.replace(/^toolExecutionResult\./, "result.")};`);
|
|
10177
|
+
}
|
|
10178
|
+
console.log("```");
|
|
10179
|
+
if (options.includeSamples !== false) {
|
|
10180
|
+
const samples = recordField(tool, "samples");
|
|
10181
|
+
printSamples(samples);
|
|
10182
|
+
}
|
|
10183
|
+
}
|
|
10184
|
+
function printToolGettersOnly(tool, requestedToolId) {
|
|
10185
|
+
const contract = toolContractJsonForDescribe(tool, requestedToolId);
|
|
10186
|
+
const getters = isRecord4(contract.getters) ? contract.getters : {};
|
|
10187
|
+
const listGetters = Array.isArray(getters.extractedLists) ? getters.extractedLists : [];
|
|
10188
|
+
const valueGetters = Array.isArray(getters.extractedValues) ? getters.extractedValues : [];
|
|
10189
|
+
console.log(`Getters: ${contract.toolId}`);
|
|
10190
|
+
if (!listGetters.length && !valueGetters.length) {
|
|
10191
|
+
console.log("No generated getters declared. Use --json only if you need raw metadata.");
|
|
10192
|
+
return;
|
|
10193
|
+
}
|
|
10194
|
+
if (listGetters.length) {
|
|
10195
|
+
console.log("Lists:");
|
|
10196
|
+
for (const entry of listGetters) {
|
|
10197
|
+
if (isRecord4(entry)) console.log(`- ${stringField(entry, "name")}: ${playResultExpression(entry)}`);
|
|
10198
|
+
}
|
|
10199
|
+
}
|
|
10200
|
+
if (valueGetters.length) {
|
|
10201
|
+
console.log("Values:");
|
|
10202
|
+
for (const entry of valueGetters) {
|
|
10203
|
+
if (isRecord4(entry)) console.log(`- ${stringField(entry, "name")}: ${playResultExpression(entry)}`);
|
|
10204
|
+
}
|
|
10205
|
+
}
|
|
10206
|
+
}
|
|
10207
|
+
function sampleValueForField(field) {
|
|
10208
|
+
const name = stringField(field, "name").toLowerCase();
|
|
10209
|
+
const type = stringField(field, "type").toLowerCase();
|
|
10210
|
+
if (Object.prototype.hasOwnProperty.call(field, "default")) return field.default;
|
|
10211
|
+
if (name.includes("email")) return "ada@example.com";
|
|
10212
|
+
if (name.includes("domain") || name.includes("website")) return "example.com";
|
|
10213
|
+
if (name.includes("first")) return "Ada";
|
|
10214
|
+
if (name.includes("last")) return "Lovelace";
|
|
10215
|
+
if (name.includes("name")) return "Ada Lovelace";
|
|
10216
|
+
if (type === "integer" || type === "number") return 1;
|
|
10217
|
+
if (type === "boolean") return true;
|
|
10218
|
+
if (type === "array") return [];
|
|
10219
|
+
if (type === "object") return {};
|
|
10220
|
+
return "...";
|
|
10221
|
+
}
|
|
10222
|
+
function stableStepIdForTool(toolId) {
|
|
10223
|
+
return toolId.replace(/^[a-z0-9]+_/, "").replace(/[^a-z0-9_]+/gi, "_") || "tool_call";
|
|
10224
|
+
}
|
|
10225
|
+
function safeIdentifier(name) {
|
|
10226
|
+
const cleaned = name.replace(/[^a-zA-Z0-9_$]+/g, "_").replace(/^[^a-zA-Z_$]+/, "");
|
|
10227
|
+
return cleaned || "value";
|
|
10228
|
+
}
|
|
10229
|
+
function playResultExpression(entry) {
|
|
10230
|
+
return stringField(entry, "expression").replace(/^toolExecutionResult\./, "result.");
|
|
10231
|
+
}
|
|
9503
10232
|
function toolMetadataJsonForDescribe(tool, requestedToolId) {
|
|
9504
10233
|
const toolId = String(tool.toolId || requestedToolId);
|
|
9505
10234
|
const {
|
|
@@ -9530,152 +10259,6 @@ function toolMetadataJsonForDescribe(tool, requestedToolId) {
|
|
|
9530
10259
|
}
|
|
9531
10260
|
};
|
|
9532
10261
|
}
|
|
9533
|
-
function printToolDetails(tool, requestedToolId) {
|
|
9534
|
-
const toolId = String(tool.toolId || requestedToolId);
|
|
9535
|
-
const operation = typeof tool.operation === "string" ? tool.operation : "";
|
|
9536
|
-
const displayBase = operation && operation.startsWith(`${tool.provider}_`) ? operation.slice(String(tool.provider).length + 1) : operation ? `${tool.provider} ${operation}`.trim() : toolId;
|
|
9537
|
-
const displayName = titleCase(displayBase || String(tool.displayName || toolId));
|
|
9538
|
-
const cost = isRecord4(tool.cost) ? tool.cost : null;
|
|
9539
|
-
const pricing = recordField(tool, "pricing");
|
|
9540
|
-
const deeplineCredits = numberField(tool, "deeplineCreditsPerPricingUnit", "deepline_credits_per_pricing_unit");
|
|
9541
|
-
const deeplineUsdPerPricingUnit = numberField(tool, "deeplineUsdPerPricingUnit", "deepline_usd_per_pricing_unit");
|
|
9542
|
-
const billingSource = stringField(tool, "billingSource", "billing_source");
|
|
9543
|
-
const billingSourceLabel = stringField(tool, "billingSourceLabel", "billing_source_label");
|
|
9544
|
-
const estimatedCreditsRange = stringField(tool, "estimatedCreditsRange", "estimated_credits_range");
|
|
9545
|
-
const estimatedUsdRange = stringField(tool, "estimatedUsdRange", "estimated_usd_range");
|
|
9546
|
-
const estimateModelVersion = stringField(tool, "estimateModelVersion", "estimate_model_version");
|
|
9547
|
-
const estimateBasedOnTools = arrayField(tool, "estimateBasedOnTools", "estimate_based_on_tools").map((item) => String(item).trim()).filter(Boolean);
|
|
9548
|
-
const stepContributions = arrayField(tool, "stepContributions", "step_contributions");
|
|
9549
|
-
const playExpansion = recordField(tool, "playExpansion", "play_expansion");
|
|
9550
|
-
const samples = recordField(tool, "samples");
|
|
9551
|
-
const usageGuidance = recordField(tool, "usageGuidance", "usage_guidance");
|
|
9552
|
-
console.log(`Tool: ${toolId}`);
|
|
9553
|
-
console.log(" Runtime output help:");
|
|
9554
|
-
console.log(" describe shows declared schema/getters, not an observed provider response");
|
|
9555
|
-
console.log(` observe actual shape: deepline tools execute ${toolId} --input '{...}' --json`);
|
|
9556
|
-
console.log(" for play getter bugs: run the play, then use the db query commands printed by runs get");
|
|
9557
|
-
if (displayName) {
|
|
9558
|
-
console.log(" Display name:");
|
|
9559
|
-
console.log(` ${displayName}`);
|
|
9560
|
-
}
|
|
9561
|
-
if (tool.categories.length > 0) {
|
|
9562
|
-
console.log(" Categories:");
|
|
9563
|
-
console.log(` ${tool.categories.join(", ")}`);
|
|
9564
|
-
}
|
|
9565
|
-
const printedCost = printToolCost({
|
|
9566
|
-
pricing,
|
|
9567
|
-
cost,
|
|
9568
|
-
billingSource,
|
|
9569
|
-
deeplineCredits,
|
|
9570
|
-
deeplineUsdPerPricingUnit
|
|
9571
|
-
});
|
|
9572
|
-
if (!printedCost && ["run_javascript", "call_local_codex", "call_local_claude_code"].includes(toolId)) {
|
|
9573
|
-
console.log(" Cost: free");
|
|
9574
|
-
}
|
|
9575
|
-
if (billingSourceLabel) {
|
|
9576
|
-
console.log(` Billing source: ${billingSourceLabel}`);
|
|
9577
|
-
}
|
|
9578
|
-
if (estimatedCreditsRange) {
|
|
9579
|
-
const usdSuffix = estimatedUsdRange ? ` (~${estimatedUsdRange})` : "";
|
|
9580
|
-
console.log(` Estimated play spend: ${estimatedCreditsRange}${usdSuffix}`);
|
|
9581
|
-
if (estimateModelVersion) console.log(` model: ${estimateModelVersion}`);
|
|
9582
|
-
if (estimateBasedOnTools.length) console.log(` based on: ${estimateBasedOnTools.join(", ")}`);
|
|
9583
|
-
if (stepContributions.length) {
|
|
9584
|
-
console.log(" step contributions:");
|
|
9585
|
-
for (const item of stepContributions) {
|
|
9586
|
-
if (!isRecord4(item)) continue;
|
|
9587
|
-
const stepTool = typeof item.tool === "string" ? item.tool.trim() : "";
|
|
9588
|
-
const low = typeof item.lowCredits === "number" ? item.lowCredits : null;
|
|
9589
|
-
const high = typeof item.highCredits === "number" ? item.highCredits : null;
|
|
9590
|
-
const lowUsd = typeof item.lowUsd === "number" ? item.lowUsd : null;
|
|
9591
|
-
const highUsd = typeof item.highUsd === "number" ? item.highUsd : null;
|
|
9592
|
-
if (!stepTool || low === null || high === null) continue;
|
|
9593
|
-
const stepUsdSuffix = lowUsd !== null && highUsd !== null ? ` (~${formatUsd(lowUsd)}-${formatUsd(highUsd)})` : "";
|
|
9594
|
-
console.log(` - ${stepTool}: ${formatDecimal(low)}-${formatDecimal(high)} credits${stepUsdSuffix}`);
|
|
9595
|
-
}
|
|
9596
|
-
}
|
|
9597
|
-
}
|
|
9598
|
-
if (playExpansion && Object.keys(playExpansion).length > 0) {
|
|
9599
|
-
const group = typeof playExpansion.group === "string" ? playExpansion.group.trim() : "";
|
|
9600
|
-
console.log(" Play expansion:");
|
|
9601
|
-
if (group) console.log(` group: ${group}`);
|
|
9602
|
-
}
|
|
9603
|
-
const fields = toolInputFieldsForDisplay(recordField(tool, "inputSchema", "input_schema"));
|
|
9604
|
-
if (fields.length) {
|
|
9605
|
-
console.log(" Inputs (operation-specific):");
|
|
9606
|
-
for (const field of fields) {
|
|
9607
|
-
const name = String(field.name || "");
|
|
9608
|
-
const typeName = String(field.type || "unknown");
|
|
9609
|
-
const requiredLabel = field.required ? "required" : "optional";
|
|
9610
|
-
const defaultSuffix = Object.prototype.hasOwnProperty.call(field, "default") ? `, default: ${JSON.stringify(field.default)}` : "";
|
|
9611
|
-
const desc = typeof field.description === "string" && field.description.trim() ? ` - ${field.description.trim()}` : "";
|
|
9612
|
-
console.log(` - ${name} (${typeName}, ${requiredLabel}${defaultSuffix})${desc}`);
|
|
9613
|
-
}
|
|
9614
|
-
console.log(" Tip: pass --payload with a JSON object.");
|
|
9615
|
-
}
|
|
9616
|
-
printSamples(samples);
|
|
9617
|
-
printUsageGuidance(usageGuidance);
|
|
9618
|
-
if (isPlayTool(tool)) {
|
|
9619
|
-
console.log(" Play contract:");
|
|
9620
|
-
console.log(" - This is a deepline-native waterfall; the returned rows are extracted by target getters, not by hand-authored payload shape.");
|
|
9621
|
-
if (playExpansion && typeof playExpansion.group === "string" && playExpansion.group.trim()) {
|
|
9622
|
-
console.log(` - Output alias/runtime group is: ${playExpansion.group.trim()}`);
|
|
9623
|
-
}
|
|
9624
|
-
const toolExecutionResult = recordField(usageGuidance, "toolExecutionResult");
|
|
9625
|
-
const extractedValues = arrayField(toolExecutionResult, "extractedValues", "extracted_values");
|
|
9626
|
-
const targets = extractedValues.map((entry) => isRecord4(entry) && typeof entry.name === "string" ? entry.name : "").filter(Boolean).sort();
|
|
9627
|
-
if (targets.length) {
|
|
9628
|
-
console.log(` - Built-in extract targets: ${targets.join(", ")}`);
|
|
9629
|
-
}
|
|
9630
|
-
}
|
|
9631
|
-
console.log("");
|
|
9632
|
-
console.log("Usage:");
|
|
9633
|
-
const requestPayload = samplePayload(samples, "request");
|
|
9634
|
-
if (isPlayTool(tool)) {
|
|
9635
|
-
if (requestPayload !== void 0) {
|
|
9636
|
-
console.log(` deepline enrich --with '${JSON.stringify({ alias: "result", tool: toolId, payload: requestPayload })}'`);
|
|
9637
|
-
} else {
|
|
9638
|
-
console.log(` deepline enrich --with '{"alias":"result","tool":"${toolId}","payload":{...}}'`);
|
|
9639
|
-
}
|
|
9640
|
-
} else if (requestPayload !== void 0) {
|
|
9641
|
-
console.log(` deepline tools execute ${toolId} --payload '${JSON.stringify(requestPayload)}'`);
|
|
9642
|
-
} else {
|
|
9643
|
-
console.log(` deepline tools execute ${toolId} --payload '{...}'`);
|
|
9644
|
-
}
|
|
9645
|
-
console.log(" deepline tools describe <tool_id> --json");
|
|
9646
|
-
}
|
|
9647
|
-
function printUsageGuidance(usageGuidance) {
|
|
9648
|
-
if (Object.keys(usageGuidance).length === 0) return;
|
|
9649
|
-
const execute = stringField(usageGuidance, "execute");
|
|
9650
|
-
const toolExecutionResult = recordField(usageGuidance, "toolExecutionResult", "tool_execution_result");
|
|
9651
|
-
const toolResponse = recordField(toolExecutionResult, "toolResponse", "tool_response");
|
|
9652
|
-
const extractedLists = arrayField(toolExecutionResult, "extractedLists", "extracted_lists");
|
|
9653
|
-
const extractedValues = arrayField(toolExecutionResult, "extractedValues", "extracted_values");
|
|
9654
|
-
console.log(" Usage guidance:");
|
|
9655
|
-
if (execute) console.log(` ${execute}`);
|
|
9656
|
-
const raw = stringField(toolResponse, "raw");
|
|
9657
|
-
const meta = stringField(toolResponse, "meta");
|
|
9658
|
-
if (raw) console.log(` Raw tool response: ${raw}`);
|
|
9659
|
-
if (meta) console.log(` Tool response metadata: ${meta}`);
|
|
9660
|
-
printExtractions("Extracted lists", extractedLists);
|
|
9661
|
-
printExtractions("Extracted values", extractedValues);
|
|
9662
|
-
}
|
|
9663
|
-
function printExtractions(label, entries) {
|
|
9664
|
-
if (!entries.length) return;
|
|
9665
|
-
console.log(` ${label}:`);
|
|
9666
|
-
for (const entry of entries) {
|
|
9667
|
-
if (!isRecord4(entry)) continue;
|
|
9668
|
-
const name = stringField(entry, "name");
|
|
9669
|
-
const expression = stringField(entry, "expression");
|
|
9670
|
-
const details = recordField(entry, "details");
|
|
9671
|
-
const rawToolOutputPaths = arrayField(details, "rawToolOutputPaths", "raw_tool_output_paths").map((value) => typeof value === "string" ? value.trim() : "").filter(Boolean);
|
|
9672
|
-
const candidatePaths = arrayField(details, "candidatePaths", "candidate_paths").map((value) => typeof value === "string" ? value.trim() : "").filter(Boolean);
|
|
9673
|
-
if (!name || !expression) continue;
|
|
9674
|
-
const paths = candidatePaths.length ? candidatePaths : rawToolOutputPaths;
|
|
9675
|
-
const pathSuffix = paths.length ? ` from ${paths.join(", ")}` : "";
|
|
9676
|
-
console.log(` - ${name}: ${expression}${pathSuffix}`);
|
|
9677
|
-
}
|
|
9678
|
-
}
|
|
9679
10262
|
function singleLineText(value, maxLength = 260) {
|
|
9680
10263
|
if (typeof value !== "string") return "";
|
|
9681
10264
|
const text = value.replace(/\s+/g, " ").trim();
|
|
@@ -9692,42 +10275,6 @@ function formatListedToolCost(tool) {
|
|
|
9692
10275
|
const displayText = stringField(pricing, "displayText", "display_text");
|
|
9693
10276
|
return displayText ? `Cost: ${displayText}` : "";
|
|
9694
10277
|
}
|
|
9695
|
-
function printToolCost(input) {
|
|
9696
|
-
const { pricing, cost, billingSource, deeplineCredits, deeplineUsdPerPricingUnit } = input;
|
|
9697
|
-
if (billingSource === "own_provider_credentials") {
|
|
9698
|
-
console.log(" Cost: free through Deepline");
|
|
9699
|
-
return true;
|
|
9700
|
-
}
|
|
9701
|
-
const displayText = stringField(pricing, "displayText", "display_text");
|
|
9702
|
-
if (displayText) {
|
|
9703
|
-
console.log(` Cost: ${displayText}`);
|
|
9704
|
-
const details = arrayField(pricing, "details").map((item) => String(item).trim()).filter(Boolean);
|
|
9705
|
-
if (details.length) {
|
|
9706
|
-
console.log(" notes:");
|
|
9707
|
-
for (const detail of details) console.log(` - ${detail}`);
|
|
9708
|
-
}
|
|
9709
|
-
return true;
|
|
9710
|
-
}
|
|
9711
|
-
const pricingModel = cost ? typeof cost.pricingModel === "string" ? cost.pricingModel : typeof cost.pricing_model === "string" ? cost.pricing_model : "" : "";
|
|
9712
|
-
const billingMode = cost ? typeof cost.billingMode === "string" ? cost.billingMode : typeof cost.billing_mode === "string" ? cost.billing_mode : "" : "";
|
|
9713
|
-
if (deeplineCredits === 0) {
|
|
9714
|
-
console.log(" Cost: Free");
|
|
9715
|
-
return true;
|
|
9716
|
-
}
|
|
9717
|
-
if (pricingModel && deeplineCredits !== null) {
|
|
9718
|
-
const unit = pricingModel === "per_page" ? "page" : pricingModel === "per_result" ? "result" : "call";
|
|
9719
|
-
const usdText = deeplineUsdPerPricingUnit !== null ? ` / ${formatUsd(deeplineUsdPerPricingUnit)}` : "";
|
|
9720
|
-
const billingSuffix = billingMode ? ` (${billingMode})` : "";
|
|
9721
|
-
console.log(` Cost: ${formatDecimal(deeplineCredits)} Deepline credits${usdText} per ${unit}${billingSuffix}`);
|
|
9722
|
-
return true;
|
|
9723
|
-
}
|
|
9724
|
-
const summary = stringField(pricing, "summary");
|
|
9725
|
-
if (summary) {
|
|
9726
|
-
console.log(` Cost: ${summary}`);
|
|
9727
|
-
return true;
|
|
9728
|
-
}
|
|
9729
|
-
return false;
|
|
9730
|
-
}
|
|
9731
10278
|
function toolInputFieldsForDisplay(inputSchema) {
|
|
9732
10279
|
if (Array.isArray(inputSchema.fields)) return inputSchema.fields.filter(isRecord4);
|
|
9733
10280
|
const jsonSchema = isRecord4(inputSchema.jsonSchema) ? inputSchema.jsonSchema : inputSchema;
|
|
@@ -9778,17 +10325,6 @@ function listExtractorPathsFromUsageGuidance(tool) {
|
|
|
9778
10325
|
).filter(Boolean);
|
|
9779
10326
|
});
|
|
9780
10327
|
}
|
|
9781
|
-
function isPlayTool(tool) {
|
|
9782
|
-
const provider = typeof tool.provider === "string" ? tool.provider : "";
|
|
9783
|
-
return provider === "deepline_native" && Boolean(recordField(tool, "playExpansion", "play_expansion"));
|
|
9784
|
-
}
|
|
9785
|
-
function titleCase(value) {
|
|
9786
|
-
return value.replace(/[_-]+/g, " ").split(" ").filter(Boolean).map((part) => {
|
|
9787
|
-
const lower = part.toLowerCase();
|
|
9788
|
-
const special = { linkedin: "LinkedIn", crm: "CRM", api: "API" };
|
|
9789
|
-
return special[lower] ?? `${part[0]?.toUpperCase() ?? ""}${part.slice(1)}`;
|
|
9790
|
-
}).join(" ");
|
|
9791
|
-
}
|
|
9792
10328
|
function formatDecimal(value) {
|
|
9793
10329
|
const text = value.toFixed(12).replace(/0+$/, "").replace(/\.$/, "");
|
|
9794
10330
|
return text || "0";
|
|
@@ -10548,6 +11084,61 @@ function shouldDeferSkillsSyncForCommand() {
|
|
|
10548
11084
|
const subcommand = args[1];
|
|
10549
11085
|
return (command === "play" || command === "plays") && subcommand === "run" && args.includes("--json");
|
|
10550
11086
|
}
|
|
11087
|
+
async function runPlayRunnerHealthCheck() {
|
|
11088
|
+
const dir = await (0, import_promises5.mkdtemp)((0, import_node_path15.join)((0, import_node_os9.tmpdir)(), "deepline-health-play-"));
|
|
11089
|
+
const file = (0, import_node_path15.join)(dir, "health-check.play.ts");
|
|
11090
|
+
try {
|
|
11091
|
+
await (0, import_promises5.writeFile)(
|
|
11092
|
+
file,
|
|
11093
|
+
[
|
|
11094
|
+
"import { definePlay } from 'deepline';",
|
|
11095
|
+
"",
|
|
11096
|
+
"export default definePlay('health-check', async (ctx) => {",
|
|
11097
|
+
" const rows = await ctx",
|
|
11098
|
+
" .map('health_rows', [{ id: 'a' }, { id: 'b' }])",
|
|
11099
|
+
" .step('echo', (row) => ({ ok: true, id: row.id }))",
|
|
11100
|
+
" .run({ key: 'id' });",
|
|
11101
|
+
" return { ok: true, rows, source: 'deepline health --play-runner' };",
|
|
11102
|
+
"});",
|
|
11103
|
+
""
|
|
11104
|
+
].join("\n"),
|
|
11105
|
+
"utf8"
|
|
11106
|
+
);
|
|
11107
|
+
let capturedOutput = "";
|
|
11108
|
+
const originalWrite = process.stdout.write.bind(process.stdout);
|
|
11109
|
+
process.stdout.write = ((chunk, ...args) => {
|
|
11110
|
+
capturedOutput += typeof chunk === "string" ? chunk : String(chunk);
|
|
11111
|
+
return true;
|
|
11112
|
+
});
|
|
11113
|
+
let exitCode = 1;
|
|
11114
|
+
try {
|
|
11115
|
+
exitCode = await handlePlayRun([
|
|
11116
|
+
file,
|
|
11117
|
+
"--input",
|
|
11118
|
+
"{}",
|
|
11119
|
+
"--watch",
|
|
11120
|
+
"--no-open",
|
|
11121
|
+
"--json"
|
|
11122
|
+
]);
|
|
11123
|
+
} finally {
|
|
11124
|
+
process.stdout.write = originalWrite;
|
|
11125
|
+
}
|
|
11126
|
+
if (exitCode !== 0) {
|
|
11127
|
+
throw new Error(
|
|
11128
|
+
`play runner canary exited ${exitCode}: ${capturedOutput.slice(0, 1e3)}`
|
|
11129
|
+
);
|
|
11130
|
+
}
|
|
11131
|
+
return {
|
|
11132
|
+
status: "ok",
|
|
11133
|
+
playRunner: {
|
|
11134
|
+
status: "ok",
|
|
11135
|
+
check: "no-provider local play run completed"
|
|
11136
|
+
}
|
|
11137
|
+
};
|
|
11138
|
+
} finally {
|
|
11139
|
+
await (0, import_promises5.rm)(dir, { recursive: true, force: true });
|
|
11140
|
+
}
|
|
11141
|
+
}
|
|
10551
11142
|
async function main() {
|
|
10552
11143
|
const mainStartedAt = Date.now();
|
|
10553
11144
|
recordCliTrace({
|
|
@@ -10559,7 +11150,7 @@ async function main() {
|
|
|
10559
11150
|
if (printStartupPhase) {
|
|
10560
11151
|
progress?.phase("loading deepline cli");
|
|
10561
11152
|
}
|
|
10562
|
-
const program = new
|
|
11153
|
+
const program = new import_commander3.Command();
|
|
10563
11154
|
program.name("deepline").description("Deepline CLI (TypeScript SDK)").version(SDK_VERSION, "-v, --version", "Show version").showHelpAfterError().showSuggestionAfterError(true).addHelpText(
|
|
10564
11155
|
"after",
|
|
10565
11156
|
`
|
|
@@ -10568,7 +11159,7 @@ Common commands:
|
|
|
10568
11159
|
deepline auth status --json
|
|
10569
11160
|
deepline plays search email --json
|
|
10570
11161
|
deepline plays describe person-linkedin-to-email --json
|
|
10571
|
-
deepline plays run my.play.ts --input '{"domain":"stripe.com"}'
|
|
11162
|
+
deepline plays run my.play.ts --input '{"domain":"stripe.com"}'
|
|
10572
11163
|
deepline tools execute hunter_email_verifier --input '{"email":"a@b.com"}'
|
|
10573
11164
|
deepline update
|
|
10574
11165
|
|
|
@@ -10624,18 +11215,30 @@ Exit codes:
|
|
|
10624
11215
|
registerDbCommands(program);
|
|
10625
11216
|
registerFeedbackCommands(program);
|
|
10626
11217
|
registerUpdateCommand(program);
|
|
10627
|
-
program.command("health").description("Check server health.").option("--json", "Force JSON output.").
|
|
11218
|
+
program.command("health").description("Check server health.").option("--json", "Force JSON output.").option(
|
|
11219
|
+
"--play-runner",
|
|
11220
|
+
"Run a tiny no-provider play to verify the full play execution plane."
|
|
11221
|
+
).addHelpText(
|
|
10628
11222
|
"after",
|
|
10629
11223
|
`
|
|
10630
11224
|
Notes:
|
|
10631
11225
|
Read-only connectivity check for the configured Deepline host. Prints the raw
|
|
10632
11226
|
server health payload as JSON.
|
|
11227
|
+
Add --play-runner to verify bundling, coordinator dispatch, runtime callbacks,
|
|
11228
|
+
and run streaming with a tiny no-provider play.
|
|
10633
11229
|
|
|
10634
11230
|
Examples:
|
|
10635
11231
|
deepline health
|
|
11232
|
+
deepline health --play-runner
|
|
10636
11233
|
`
|
|
10637
|
-
).action(async () => {
|
|
11234
|
+
).action(async (options) => {
|
|
10638
11235
|
try {
|
|
11236
|
+
if (options.playRunner) {
|
|
11237
|
+
const data2 = await runPlayRunnerHealthCheck();
|
|
11238
|
+
process.stdout.write(`${JSON.stringify(data2, null, 2)}
|
|
11239
|
+
`);
|
|
11240
|
+
return;
|
|
11241
|
+
}
|
|
10639
11242
|
const client = new DeeplineClient();
|
|
10640
11243
|
const data = await client.health();
|
|
10641
11244
|
process.stdout.write(`${JSON.stringify(data, null, 2)}
|