deepline 0.1.48 → 0.1.50
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 +859 -258
- package/dist/cli/index.mjs +859 -258
- package/dist/index.d.mts +12 -4
- package/dist/index.d.ts +12 -4
- package/dist/index.js +53 -8
- package/dist/index.mjs +53 -8
- package/dist/repo/apps/play-runner-workers/src/coordinator-entry.ts +5 -2
- package/dist/repo/apps/play-runner-workers/src/entry.ts +3 -0
- package/dist/repo/sdk/src/client.ts +29 -4
- package/dist/repo/sdk/src/play.ts +1 -1
- package/dist/repo/sdk/src/version.ts +1 -1
- package/dist/repo/shared_libs/play-runtime/tool-result.ts +34 -3
- package/package.json +1 -1
package/dist/cli/index.mjs
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/cli/index.ts
|
|
4
|
-
import {
|
|
4
|
+
import { mkdtemp, rm, writeFile as writeFile4 } from "fs/promises";
|
|
5
|
+
import { join as join11 } from "path";
|
|
6
|
+
import { tmpdir as tmpdir4 } from "os";
|
|
7
|
+
import { Command as Command3 } from "commander";
|
|
5
8
|
|
|
6
9
|
// src/config.ts
|
|
7
10
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
@@ -193,7 +196,7 @@ function resolveConfig(options) {
|
|
|
193
196
|
}
|
|
194
197
|
|
|
195
198
|
// src/version.ts
|
|
196
|
-
var SDK_VERSION = "0.1.
|
|
199
|
+
var SDK_VERSION = "0.1.50";
|
|
197
200
|
var SDK_API_CONTRACT = "2026-05-stripe-promo-checkout";
|
|
198
201
|
|
|
199
202
|
// ../shared_libs/play-runtime/coordinator-headers.ts
|
|
@@ -713,9 +716,18 @@ var DeeplineClient = class {
|
|
|
713
716
|
* console.log(`Found ${searchTools.length} search tools`);
|
|
714
717
|
* ```
|
|
715
718
|
*/
|
|
716
|
-
async listTools() {
|
|
719
|
+
async listTools(options) {
|
|
720
|
+
const params = new URLSearchParams();
|
|
721
|
+
if (options?.categories?.trim()) {
|
|
722
|
+
params.set("categories", options.categories.trim());
|
|
723
|
+
}
|
|
724
|
+
if (options?.grep?.trim()) {
|
|
725
|
+
params.set("grep", options.grep.trim());
|
|
726
|
+
params.set("grep_mode", options.grepMode ?? "all");
|
|
727
|
+
}
|
|
728
|
+
const suffix = params.toString() ? `?${params.toString()}` : "";
|
|
717
729
|
const res = await this.http.get(
|
|
718
|
-
|
|
730
|
+
`/api/v2/tools${suffix}`
|
|
719
731
|
);
|
|
720
732
|
return res.tools;
|
|
721
733
|
}
|
|
@@ -1350,9 +1362,17 @@ var DeeplineClient = class {
|
|
|
1350
1362
|
options?.reason ? { reason: options.reason } : {}
|
|
1351
1363
|
);
|
|
1352
1364
|
}
|
|
1353
|
-
async listPlays() {
|
|
1365
|
+
async listPlays(options) {
|
|
1366
|
+
const params = new URLSearchParams();
|
|
1367
|
+
if (options?.origin) params.set("origin", options.origin);
|
|
1368
|
+
if (options?.grep?.trim()) {
|
|
1369
|
+
params.set("grep", options.grep.trim());
|
|
1370
|
+
params.set("grep_mode", options.grepMode ?? "all");
|
|
1371
|
+
params.set("limit", "60");
|
|
1372
|
+
}
|
|
1373
|
+
const suffix = params.toString() ? `?${params.toString()}` : "";
|
|
1354
1374
|
const response = await this.http.get(
|
|
1355
|
-
|
|
1375
|
+
`/api/v2/plays${suffix}`
|
|
1356
1376
|
);
|
|
1357
1377
|
return response.plays ?? [];
|
|
1358
1378
|
}
|
|
@@ -5670,6 +5690,16 @@ function extractPlayName(code, filePath) {
|
|
|
5670
5690
|
function isFileTarget(target) {
|
|
5671
5691
|
return existsSync6(resolve9(target));
|
|
5672
5692
|
}
|
|
5693
|
+
function looksLikeRunId(target) {
|
|
5694
|
+
return /^play\/[^/]+\/run\/[^/]+/.test(target.trim());
|
|
5695
|
+
}
|
|
5696
|
+
function formatPlayCommandReceivedRunIdError(input) {
|
|
5697
|
+
return `\`deepline plays ${input.command} <run-id>\` expects a play name, but this looks like a run id.
|
|
5698
|
+
Use:
|
|
5699
|
+
deepline runs get ${input.runId} --json
|
|
5700
|
+
deepline runs logs ${input.runId} --json
|
|
5701
|
+
deepline runs export ${input.runId} --out output.csv`;
|
|
5702
|
+
}
|
|
5673
5703
|
function looksLikeFilePath(target) {
|
|
5674
5704
|
if (target.trim().toLowerCase().startsWith("prebuilt/")) {
|
|
5675
5705
|
return false;
|
|
@@ -6096,6 +6126,69 @@ function describeLiveEventPhase(event) {
|
|
|
6096
6126
|
}
|
|
6097
6127
|
return null;
|
|
6098
6128
|
}
|
|
6129
|
+
function formatProgressLabel(raw) {
|
|
6130
|
+
const value = typeof raw === "string" && raw.trim() ? raw.trim() : "step";
|
|
6131
|
+
return value.replace(/^map:/, "").replace(/^tool:/, "");
|
|
6132
|
+
}
|
|
6133
|
+
function formatProgressCounts(input) {
|
|
6134
|
+
const completed = typeof input.completed === "number" && Number.isFinite(input.completed) ? input.completed : null;
|
|
6135
|
+
const total = typeof input.total === "number" && Number.isFinite(input.total) ? input.total : null;
|
|
6136
|
+
if (completed === null || total === null || total <= 0) {
|
|
6137
|
+
return null;
|
|
6138
|
+
}
|
|
6139
|
+
const percent = Math.max(0, Math.min(100, Math.round(completed / total * 100)));
|
|
6140
|
+
const failed = typeof input.failed === "number" && Number.isFinite(input.failed) && input.failed > 0 ? `, failed ${formatInteger(input.failed)}` : "";
|
|
6141
|
+
return `${formatInteger(completed)}/${formatInteger(total)} (${percent}%)${failed}`;
|
|
6142
|
+
}
|
|
6143
|
+
function getProgressLinesFromLiveEvent(event) {
|
|
6144
|
+
const payload = getEventPayload(event);
|
|
6145
|
+
if (event.type === "play.step.progress") {
|
|
6146
|
+
const counts = formatProgressCounts({
|
|
6147
|
+
completed: payload.completed,
|
|
6148
|
+
total: payload.total,
|
|
6149
|
+
failed: payload.failed
|
|
6150
|
+
});
|
|
6151
|
+
if (!counts) return [];
|
|
6152
|
+
return [`progress ${formatProgressLabel(payload.stepId)}: ${counts}`];
|
|
6153
|
+
}
|
|
6154
|
+
if (event.type !== "play.run.snapshot" && event.type !== "play.run.final_status") {
|
|
6155
|
+
return [];
|
|
6156
|
+
}
|
|
6157
|
+
const nodeStates = Array.isArray(payload.nodeStates) ? payload.nodeStates : Array.isArray(payload.steps) ? payload.steps : [];
|
|
6158
|
+
const lines = [];
|
|
6159
|
+
for (const state of nodeStates) {
|
|
6160
|
+
if (!state || typeof state !== "object" || Array.isArray(state)) {
|
|
6161
|
+
continue;
|
|
6162
|
+
}
|
|
6163
|
+
const record = state;
|
|
6164
|
+
const progress = record.progress && typeof record.progress === "object" && !Array.isArray(record.progress) ? record.progress : null;
|
|
6165
|
+
if (!progress) {
|
|
6166
|
+
continue;
|
|
6167
|
+
}
|
|
6168
|
+
const counts = formatProgressCounts({
|
|
6169
|
+
completed: progress.completed,
|
|
6170
|
+
total: progress.total,
|
|
6171
|
+
failed: progress.failed
|
|
6172
|
+
});
|
|
6173
|
+
if (!counts) {
|
|
6174
|
+
continue;
|
|
6175
|
+
}
|
|
6176
|
+
lines.push(
|
|
6177
|
+
`progress ${formatProgressLabel(record.nodeId ?? progress.artifactTableNamespace)}: ${counts}`
|
|
6178
|
+
);
|
|
6179
|
+
}
|
|
6180
|
+
return lines;
|
|
6181
|
+
}
|
|
6182
|
+
function printPlayProgressLines(input) {
|
|
6183
|
+
for (const line of input.lines) {
|
|
6184
|
+
const signature = line.trim();
|
|
6185
|
+
if (!signature || input.state.lastProgressSignature === signature) {
|
|
6186
|
+
continue;
|
|
6187
|
+
}
|
|
6188
|
+
input.state.lastProgressSignature = signature;
|
|
6189
|
+
input.progress.writeLine(line);
|
|
6190
|
+
}
|
|
6191
|
+
}
|
|
6099
6192
|
function buildPlayDashboardUrl(baseUrl, playName) {
|
|
6100
6193
|
const trimmedBase = baseUrl.replace(/\/$/, "");
|
|
6101
6194
|
const encodedPlayName = encodeURIComponent(playName);
|
|
@@ -6169,6 +6262,13 @@ async function waitForPlayCompletionByStream(input) {
|
|
|
6169
6262
|
state: input.state,
|
|
6170
6263
|
progress: input.progress
|
|
6171
6264
|
});
|
|
6265
|
+
if (!input.jsonOutput) {
|
|
6266
|
+
printPlayProgressLines({
|
|
6267
|
+
lines: getProgressLinesFromLiveEvent(event),
|
|
6268
|
+
state: input.state,
|
|
6269
|
+
progress: input.progress
|
|
6270
|
+
});
|
|
6271
|
+
}
|
|
6172
6272
|
const status = getStatusFromLiveEvent(event);
|
|
6173
6273
|
if (status && TERMINAL_PLAY_STATUSES2.has(status)) {
|
|
6174
6274
|
const finalStatus = await input.client.getPlayStatus(input.workflowId, {
|
|
@@ -6237,7 +6337,8 @@ async function startAndWaitForPlayCompletionByStreamOnce(input) {
|
|
|
6237
6337
|
);
|
|
6238
6338
|
const state = {
|
|
6239
6339
|
lastLogIndex: 0,
|
|
6240
|
-
emittedRunnerStarted: false
|
|
6340
|
+
emittedRunnerStarted: false,
|
|
6341
|
+
lastProgressSignature: null
|
|
6241
6342
|
};
|
|
6242
6343
|
const controller = new AbortController();
|
|
6243
6344
|
let timedOut = false;
|
|
@@ -6265,11 +6366,6 @@ async function startAndWaitForPlayCompletionByStreamOnce(input) {
|
|
|
6265
6366
|
}
|
|
6266
6367
|
const workflowId = lastKnownWorkflowId || "pending";
|
|
6267
6368
|
if (workflowId !== "pending" && !emittedDashboardUrl) {
|
|
6268
|
-
openPlayDashboard({
|
|
6269
|
-
dashboardUrl,
|
|
6270
|
-
jsonOutput: input.jsonOutput,
|
|
6271
|
-
noOpen: input.noOpen
|
|
6272
|
-
});
|
|
6273
6369
|
if (!input.jsonOutput) {
|
|
6274
6370
|
writeStartedPlayRun({
|
|
6275
6371
|
runId: workflowId,
|
|
@@ -6279,6 +6375,11 @@ async function startAndWaitForPlayCompletionByStreamOnce(input) {
|
|
|
6279
6375
|
progress: input.progress
|
|
6280
6376
|
});
|
|
6281
6377
|
}
|
|
6378
|
+
openPlayDashboard({
|
|
6379
|
+
dashboardUrl,
|
|
6380
|
+
jsonOutput: input.jsonOutput,
|
|
6381
|
+
noOpen: input.noOpen
|
|
6382
|
+
});
|
|
6282
6383
|
input.progress.phase(`loading play on ${dashboardUrl}`);
|
|
6283
6384
|
emittedDashboardUrl = true;
|
|
6284
6385
|
}
|
|
@@ -6301,6 +6402,13 @@ async function startAndWaitForPlayCompletionByStreamOnce(input) {
|
|
|
6301
6402
|
state,
|
|
6302
6403
|
progress: input.progress
|
|
6303
6404
|
});
|
|
6405
|
+
if (!input.jsonOutput) {
|
|
6406
|
+
printPlayProgressLines({
|
|
6407
|
+
lines: getProgressLinesFromLiveEvent(event),
|
|
6408
|
+
state,
|
|
6409
|
+
progress: input.progress
|
|
6410
|
+
});
|
|
6411
|
+
}
|
|
6304
6412
|
const finalStatus = getFinalStatusFromLiveEvent(event);
|
|
6305
6413
|
if (finalStatus) {
|
|
6306
6414
|
recordCliTrace({
|
|
@@ -6569,6 +6677,7 @@ function buildRunNextCommands(status) {
|
|
|
6569
6677
|
const commands = {
|
|
6570
6678
|
get: `deepline runs get ${runId} --json`,
|
|
6571
6679
|
full: `deepline runs get ${runId} --full --json`,
|
|
6680
|
+
export: `deepline runs export ${runId} --out output.csv`,
|
|
6572
6681
|
stop: `deepline runs stop ${runId} --reason "stale lock" --json`,
|
|
6573
6682
|
logs: `deepline runs logs ${runId} --out run.log --json`
|
|
6574
6683
|
};
|
|
@@ -6701,6 +6810,32 @@ function formatInsufficientCreditsMessage(input) {
|
|
|
6701
6810
|
const addSuffix = billingUrl && recommended !== "-" ? ` Add >=${recommended} at ${billingUrl}.` : billingUrl ? ` Add credits at ${billingUrl}.` : "";
|
|
6702
6811
|
return `Workspace balance ${balance} < required ${required} for ${operation}${workspaceSuffix}.${addSuffix}`;
|
|
6703
6812
|
}
|
|
6813
|
+
function buildInsufficientCreditsSummaryLines(input) {
|
|
6814
|
+
const progress = input.status.progress;
|
|
6815
|
+
const rowsInfo = extractCanonicalRowsInfo(input.status);
|
|
6816
|
+
const completed = getNumericField(progress, "completed") ?? getNumericField(progress, "completedRows") ?? rowsInfo?.rows.length ?? null;
|
|
6817
|
+
const total = getNumericField(progress, "total") ?? getNumericField(progress, "totalRows") ?? rowsInfo?.totalRows ?? null;
|
|
6818
|
+
const lines = [
|
|
6819
|
+
" status: stopped_insufficient_credits",
|
|
6820
|
+
completed === null ? " completed rows: unknown" : ` completed rows: ${formatInteger(completed)}${total !== null ? ` of ${formatInteger(total)}` : ""}`,
|
|
6821
|
+
" reusable receipts: yes; rerun after adding credits to continue from completed provider work"
|
|
6822
|
+
];
|
|
6823
|
+
const billingUrl = getStringField(input.billing, "billing_url");
|
|
6824
|
+
const recommended = formatCreditAmount(
|
|
6825
|
+
input.billing.recommended_add_credits ?? input.billing.needed_credits
|
|
6826
|
+
);
|
|
6827
|
+
if (billingUrl) {
|
|
6828
|
+
lines.push(
|
|
6829
|
+
recommended !== "-" ? ` add credits: add >=${recommended} at ${billingUrl}` : ` add credits: ${billingUrl}`
|
|
6830
|
+
);
|
|
6831
|
+
}
|
|
6832
|
+
const runId = input.status.runId?.trim();
|
|
6833
|
+
if (runId) {
|
|
6834
|
+
lines.push(` inspect: deepline runs get ${runId} --json`);
|
|
6835
|
+
lines.push(` export partial: deepline runs export ${runId} --out output.csv`);
|
|
6836
|
+
}
|
|
6837
|
+
return lines;
|
|
6838
|
+
}
|
|
6704
6839
|
function formatPlayErrorForDisplay(status, error) {
|
|
6705
6840
|
if (!error) {
|
|
6706
6841
|
return null;
|
|
@@ -6891,6 +7026,19 @@ function formatDatasetStatsLines(datasetStats) {
|
|
|
6891
7026
|
}
|
|
6892
7027
|
return lines;
|
|
6893
7028
|
}
|
|
7029
|
+
function buildJsonRunResultRenderLines(status) {
|
|
7030
|
+
const publicStatus = status.status ?? "running";
|
|
7031
|
+
const runId = status.runId ?? "unknown";
|
|
7032
|
+
const lines = [`${publicStatus} ${runId}`];
|
|
7033
|
+
const progressError = status.progress?.error;
|
|
7034
|
+
if (typeof progressError === "string") {
|
|
7035
|
+
const billing = extractBillingForStatus(status, progressError);
|
|
7036
|
+
if (isInsufficientCreditsBilling(billing)) {
|
|
7037
|
+
lines.push(...buildInsufficientCreditsSummaryLines({ status, billing }));
|
|
7038
|
+
}
|
|
7039
|
+
}
|
|
7040
|
+
return lines;
|
|
7041
|
+
}
|
|
6894
7042
|
function writePlayResult(status, jsonOutput, options) {
|
|
6895
7043
|
if (jsonOutput) {
|
|
6896
7044
|
const payload2 = options?.fullJson ? enrichPlayStatusWithDatasetStats(status) : compactPlayStatus(status);
|
|
@@ -6900,9 +7048,7 @@ function writePlayResult(status, jsonOutput, options) {
|
|
|
6900
7048
|
sections: [
|
|
6901
7049
|
{
|
|
6902
7050
|
title: "run result",
|
|
6903
|
-
lines:
|
|
6904
|
-
`${status.status ?? "running"} ${status.runId ?? "unknown"}`
|
|
6905
|
-
]
|
|
7051
|
+
lines: buildJsonRunResultRenderLines(status)
|
|
6906
7052
|
}
|
|
6907
7053
|
]
|
|
6908
7054
|
}
|
|
@@ -6929,6 +7075,10 @@ function writePlayResult(status, jsonOutput, options) {
|
|
|
6929
7075
|
lines.push(...formatDatasetStatsLines(datasetStats));
|
|
6930
7076
|
const progressError = status.progress?.error;
|
|
6931
7077
|
if (progressError && typeof progressError === "string") {
|
|
7078
|
+
const billing = extractBillingForStatus(status, progressError);
|
|
7079
|
+
if (isInsufficientCreditsBilling(billing)) {
|
|
7080
|
+
lines.push(...buildInsufficientCreditsSummaryLines({ status, billing }));
|
|
7081
|
+
}
|
|
6932
7082
|
const displayError = formatPlayErrorForDisplay(status, progressError) ?? progressError;
|
|
6933
7083
|
lines.push(` error: ${displayError.slice(0, 200)}`);
|
|
6934
7084
|
}
|
|
@@ -7308,24 +7458,31 @@ function writeStartedPlayRun(input) {
|
|
|
7308
7458
|
workflowId: input.runId,
|
|
7309
7459
|
name: input.playName,
|
|
7310
7460
|
status: input.status ?? "started",
|
|
7311
|
-
dashboardUrl: input.dashboardUrl
|
|
7461
|
+
dashboardUrl: input.dashboardUrl,
|
|
7462
|
+
next: {
|
|
7463
|
+
inspect: `deepline runs get ${input.runId} --json`,
|
|
7464
|
+
full: `deepline runs get ${input.runId} --full --json`,
|
|
7465
|
+
logs: `deepline runs logs ${input.runId} --json`,
|
|
7466
|
+
export: `deepline runs export ${input.runId} --out output.csv`,
|
|
7467
|
+
stop: `deepline runs stop ${input.runId} --reason "stale lock" --json`
|
|
7468
|
+
}
|
|
7312
7469
|
};
|
|
7470
|
+
const lines = [
|
|
7471
|
+
`Started ${input.playName}`,
|
|
7472
|
+
` run id: ${input.runId}`,
|
|
7473
|
+
` inspect: deepline runs get ${input.runId} --json`,
|
|
7474
|
+
` full debug: deepline runs get ${input.runId} --full --json`,
|
|
7475
|
+
` logs: deepline runs logs ${input.runId} --json`,
|
|
7476
|
+
` export after completion: deepline runs export ${input.runId} --out output.csv`,
|
|
7477
|
+
` stop run: deepline runs stop ${input.runId} --reason "stale lock" --json`
|
|
7478
|
+
];
|
|
7313
7479
|
if (input.jsonOutput) {
|
|
7314
7480
|
printCommandEnvelope({
|
|
7315
7481
|
...payload,
|
|
7316
|
-
render: { sections: [{ title: "play run", lines
|
|
7482
|
+
render: { sections: [{ title: "play run", lines }] }
|
|
7317
7483
|
}, { json: true });
|
|
7318
7484
|
return;
|
|
7319
7485
|
}
|
|
7320
|
-
const lines = [
|
|
7321
|
-
`Started ${input.playName}`,
|
|
7322
|
-
` run id: ${input.runId}`,
|
|
7323
|
-
` get status: deepline runs get ${input.runId} --json`,
|
|
7324
|
-
` logs: deepline runs logs ${input.runId} --json`,
|
|
7325
|
-
` stop run: deepline runs stop ${input.runId} --reason "stale lock" --json`,
|
|
7326
|
-
` result JSON: deepline runs get ${input.runId} --json`,
|
|
7327
|
-
` full debug JSON: deepline runs get ${input.runId} --full --json`
|
|
7328
|
-
];
|
|
7329
7486
|
if (input.dashboardUrl) {
|
|
7330
7487
|
lines.push(` play page: ${input.dashboardUrl}`);
|
|
7331
7488
|
}
|
|
@@ -7341,13 +7498,13 @@ function writeStartedPlayRun(input) {
|
|
|
7341
7498
|
` });
|
|
7342
7499
|
}
|
|
7343
7500
|
function parsePlayRunOptions(args) {
|
|
7344
|
-
const usage = "Usage: deepline plays run <play-name> [--input '{...}'] [--
|
|
7501
|
+
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.";
|
|
7345
7502
|
let filePath = null;
|
|
7346
7503
|
let playName = null;
|
|
7347
7504
|
let input = null;
|
|
7348
7505
|
let revisionId = null;
|
|
7349
7506
|
let revisionSelector = null;
|
|
7350
|
-
const watch = args.includes("--
|
|
7507
|
+
const watch = !args.includes("--no-wait");
|
|
7351
7508
|
let jsonOutput = watch ? args.includes("--json") : argsWantJson(args);
|
|
7352
7509
|
const emitLogs = !jsonOutput || args.includes("--logs");
|
|
7353
7510
|
const force = args.includes("--force");
|
|
@@ -7393,7 +7550,7 @@ function parsePlayRunOptions(args) {
|
|
|
7393
7550
|
waitTimeoutMs = parsePositiveInteger2(args[++index], arg);
|
|
7394
7551
|
continue;
|
|
7395
7552
|
}
|
|
7396
|
-
if (arg === "--json" || arg === "--wait" || arg === "--tail" || arg === "--watch" || arg === "--logs" || arg === "--force" || arg === "--no-open") {
|
|
7553
|
+
if (arg === "--json" || arg === "--wait" || arg === "--tail" || arg === "--watch" || arg === "--no-wait" || arg === "--logs" || arg === "--force" || arg === "--no-open") {
|
|
7397
7554
|
if (arg === "--watch") {
|
|
7398
7555
|
continue;
|
|
7399
7556
|
}
|
|
@@ -8249,6 +8406,12 @@ async function handlePlayGet(args) {
|
|
|
8249
8406
|
console.error("Usage: deepline play get <play-file.ts|play-name> [--json]");
|
|
8250
8407
|
return 1;
|
|
8251
8408
|
}
|
|
8409
|
+
if (looksLikeRunId(target)) {
|
|
8410
|
+
console.error(
|
|
8411
|
+
formatPlayCommandReceivedRunIdError({ command: "get", runId: target })
|
|
8412
|
+
);
|
|
8413
|
+
return 2;
|
|
8414
|
+
}
|
|
8252
8415
|
const client = new DeeplineClient();
|
|
8253
8416
|
const explicitJson = args.includes("--json");
|
|
8254
8417
|
const sourceOutput = args.includes("--source");
|
|
@@ -8363,8 +8526,20 @@ async function handlePlayVersions(args) {
|
|
|
8363
8526
|
}
|
|
8364
8527
|
async function handlePlayList(args) {
|
|
8365
8528
|
const jsonOutput = argsWantJson(args);
|
|
8529
|
+
const originArgIndex = args.findIndex((arg) => arg === "--origin");
|
|
8530
|
+
const rawOrigin = originArgIndex >= 0 ? args[originArgIndex + 1] : void 0;
|
|
8531
|
+
if (rawOrigin && rawOrigin !== "prebuilt" && rawOrigin !== "owned") {
|
|
8532
|
+
throw new Error(`Invalid value for --origin: ${rawOrigin}`);
|
|
8533
|
+
}
|
|
8534
|
+
const origin = rawOrigin;
|
|
8366
8535
|
const client = new DeeplineClient();
|
|
8367
|
-
const plays = await client.listPlays(
|
|
8536
|
+
const plays = (await client.listPlays({
|
|
8537
|
+
...origin ? { origin } : {}
|
|
8538
|
+
})).filter((play) => {
|
|
8539
|
+
if (!origin) return true;
|
|
8540
|
+
const isPrebuilt = play.origin === "prebuilt" || play.ownerType === "deepline";
|
|
8541
|
+
return origin === "prebuilt" ? isPrebuilt : !isPrebuilt;
|
|
8542
|
+
});
|
|
8368
8543
|
if (jsonOutput) {
|
|
8369
8544
|
process.stdout.write(`${JSON.stringify(plays)}
|
|
8370
8545
|
`);
|
|
@@ -8467,6 +8642,54 @@ function printPlayDescription(play) {
|
|
|
8467
8642
|
);
|
|
8468
8643
|
}
|
|
8469
8644
|
}
|
|
8645
|
+
function compactPlaySchema(schema) {
|
|
8646
|
+
if (!schema) return null;
|
|
8647
|
+
const fields = Array.isArray(schema.fields) ? schema.fields.map(
|
|
8648
|
+
(field) => field && typeof field === "object" ? {
|
|
8649
|
+
name: String(field.name ?? ""),
|
|
8650
|
+
type: field.type ?? void 0,
|
|
8651
|
+
required: field.required ?? void 0
|
|
8652
|
+
} : null
|
|
8653
|
+
).filter((field) => Boolean(field?.name)) : [];
|
|
8654
|
+
return fields.length > 0 ? { fields } : schema;
|
|
8655
|
+
}
|
|
8656
|
+
function playSchemaMetadata(schema, key) {
|
|
8657
|
+
if (!schema || typeof schema !== "object" || Array.isArray(schema)) return null;
|
|
8658
|
+
const value = schema[key];
|
|
8659
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
8660
|
+
}
|
|
8661
|
+
function playRunCommand(play, options) {
|
|
8662
|
+
const target = play.reference || play.name;
|
|
8663
|
+
if (options?.csvInput) {
|
|
8664
|
+
const inputField = typeof options.csvInput.inputField === "string" && options.csvInput.inputField.trim() ? options.csvInput.inputField.trim() : "csv";
|
|
8665
|
+
return `deepline plays run ${target} --input '${JSON.stringify({ [inputField]: "leads.csv" })}' --watch`;
|
|
8666
|
+
}
|
|
8667
|
+
return `deepline plays run ${target} --input '{...}' --watch`;
|
|
8668
|
+
}
|
|
8669
|
+
function summarizePlayListItemForCli(play, options) {
|
|
8670
|
+
const aliases = play.aliases?.length ? play.aliases : [play.name];
|
|
8671
|
+
const csvInput = playSchemaMetadata(play.inputSchema, "csvInput");
|
|
8672
|
+
const rowOutputSchema = playSchemaMetadata(play.outputSchema, "rowOutputSchema");
|
|
8673
|
+
const runCommand2 = playRunCommand(play, { csvInput });
|
|
8674
|
+
return {
|
|
8675
|
+
name: play.name,
|
|
8676
|
+
...play.reference ? { reference: play.reference } : {},
|
|
8677
|
+
...play.displayName ? { displayName: play.displayName } : {},
|
|
8678
|
+
origin: play.origin,
|
|
8679
|
+
ownerType: play.ownerType,
|
|
8680
|
+
canEdit: play.canEdit,
|
|
8681
|
+
canClone: play.canClone,
|
|
8682
|
+
aliases,
|
|
8683
|
+
inputSchema: options?.compact ? compactPlaySchema(play.inputSchema) : play.inputSchema ?? null,
|
|
8684
|
+
outputSchema: options?.compact ? compactPlaySchema(play.outputSchema) : play.outputSchema ?? null,
|
|
8685
|
+
...csvInput ? { csvInput } : {},
|
|
8686
|
+
...rowOutputSchema ? { rowOutputSchema } : {},
|
|
8687
|
+
runCommand: runCommand2,
|
|
8688
|
+
examples: [runCommand2],
|
|
8689
|
+
currentPublishedVersion: play.currentPublishedVersion ?? null,
|
|
8690
|
+
isDraftDirty: play.isDraftDirty
|
|
8691
|
+
};
|
|
8692
|
+
}
|
|
8470
8693
|
async function handlePlaySearch(args) {
|
|
8471
8694
|
let options;
|
|
8472
8695
|
try {
|
|
@@ -8488,6 +8711,100 @@ async function handlePlaySearch(args) {
|
|
|
8488
8711
|
}
|
|
8489
8712
|
process.stdout.write(`${plays.length} plays found:
|
|
8490
8713
|
|
|
8714
|
+
`);
|
|
8715
|
+
for (const play of plays) {
|
|
8716
|
+
printPlayDescription(play);
|
|
8717
|
+
console.log("");
|
|
8718
|
+
}
|
|
8719
|
+
return 0;
|
|
8720
|
+
}
|
|
8721
|
+
function normalizePlayGrepText(value) {
|
|
8722
|
+
if (value === null || value === void 0) return "";
|
|
8723
|
+
if (typeof value === "string") return value.toLowerCase();
|
|
8724
|
+
if (typeof value === "number" || typeof value === "boolean") {
|
|
8725
|
+
return String(value).toLowerCase();
|
|
8726
|
+
}
|
|
8727
|
+
if (Array.isArray(value)) return value.map(normalizePlayGrepText).join(" ");
|
|
8728
|
+
if (typeof value === "object") {
|
|
8729
|
+
return Object.values(value).map(normalizePlayGrepText).join(" ");
|
|
8730
|
+
}
|
|
8731
|
+
return "";
|
|
8732
|
+
}
|
|
8733
|
+
function parsePlayGrepTerms(query, mode) {
|
|
8734
|
+
const trimmed = query.trim().toLowerCase();
|
|
8735
|
+
if (!trimmed) return [];
|
|
8736
|
+
if (mode === "phrase") return [trimmed];
|
|
8737
|
+
const matches = trimmed.match(/"([^"]+)"|'([^']+)'|\S+/g) ?? [];
|
|
8738
|
+
return matches.map((term) => term.replace(/^["']|["']$/g, "").trim()).filter(Boolean);
|
|
8739
|
+
}
|
|
8740
|
+
function matchesPlayGrepQuery(value, query, mode) {
|
|
8741
|
+
const terms = parsePlayGrepTerms(query, mode);
|
|
8742
|
+
if (terms.length === 0) return true;
|
|
8743
|
+
const haystack = normalizePlayGrepText(value);
|
|
8744
|
+
if (mode === "any") return terms.some((term) => haystack.includes(term));
|
|
8745
|
+
return terms.every((term) => haystack.includes(term));
|
|
8746
|
+
}
|
|
8747
|
+
async function handlePlayGrep(args) {
|
|
8748
|
+
const query = args[0]?.trim();
|
|
8749
|
+
if (!query) {
|
|
8750
|
+
console.error("Usage: deepline plays grep <query> [--origin prebuilt|owned] [--compact] [--json]");
|
|
8751
|
+
return 1;
|
|
8752
|
+
}
|
|
8753
|
+
let origin;
|
|
8754
|
+
let mode = "all";
|
|
8755
|
+
for (let index = 1; index < args.length; index += 1) {
|
|
8756
|
+
const arg = args[index];
|
|
8757
|
+
if (arg === "--origin" && args[index + 1]) {
|
|
8758
|
+
const rawOrigin = args[++index].trim().toLowerCase();
|
|
8759
|
+
if (rawOrigin !== "prebuilt" && rawOrigin !== "owned") {
|
|
8760
|
+
throw new Error(`Invalid value for --origin: ${rawOrigin}`);
|
|
8761
|
+
}
|
|
8762
|
+
origin = rawOrigin;
|
|
8763
|
+
}
|
|
8764
|
+
if (arg === "--mode" && args[index + 1]) {
|
|
8765
|
+
const rawMode = args[++index].trim().toLowerCase();
|
|
8766
|
+
mode = rawMode === "any" || rawMode === "phrase" ? rawMode : "all";
|
|
8767
|
+
}
|
|
8768
|
+
}
|
|
8769
|
+
const compact = args.includes("--compact");
|
|
8770
|
+
const client = new DeeplineClient();
|
|
8771
|
+
const plays = (await client.listPlays({
|
|
8772
|
+
grep: query,
|
|
8773
|
+
grepMode: mode,
|
|
8774
|
+
...origin ? { origin } : {}
|
|
8775
|
+
})).filter((play) => {
|
|
8776
|
+
if (!origin) return true;
|
|
8777
|
+
const isPrebuilt = play.origin === "prebuilt" || play.ownerType === "deepline";
|
|
8778
|
+
return origin === "prebuilt" ? isPrebuilt : !isPrebuilt;
|
|
8779
|
+
}).filter(
|
|
8780
|
+
(play) => matchesPlayGrepQuery(
|
|
8781
|
+
{
|
|
8782
|
+
name: play.name,
|
|
8783
|
+
reference: play.reference,
|
|
8784
|
+
displayName: play.displayName,
|
|
8785
|
+
origin: play.origin,
|
|
8786
|
+
ownerType: play.ownerType,
|
|
8787
|
+
aliases: play.aliases,
|
|
8788
|
+
inputSchema: play.inputSchema,
|
|
8789
|
+
outputSchema: play.outputSchema
|
|
8790
|
+
},
|
|
8791
|
+
query,
|
|
8792
|
+
mode
|
|
8793
|
+
)
|
|
8794
|
+
).map((play) => summarizePlayListItemForCli(play, { compact }));
|
|
8795
|
+
if (argsWantJson(args)) {
|
|
8796
|
+
process.stdout.write(`${JSON.stringify({
|
|
8797
|
+
plays,
|
|
8798
|
+
count: plays.length,
|
|
8799
|
+
query,
|
|
8800
|
+
grep: { mode, terms: parsePlayGrepTerms(query, mode) },
|
|
8801
|
+
filters: { origin: origin ?? null }
|
|
8802
|
+
})}
|
|
8803
|
+
`);
|
|
8804
|
+
return 0;
|
|
8805
|
+
}
|
|
8806
|
+
process.stdout.write(`${plays.length} plays found:
|
|
8807
|
+
|
|
8491
8808
|
`);
|
|
8492
8809
|
for (const play of plays) {
|
|
8493
8810
|
printPlayDescription(play);
|
|
@@ -8503,6 +8820,15 @@ async function handlePlayDescribe(args) {
|
|
|
8503
8820
|
);
|
|
8504
8821
|
return 1;
|
|
8505
8822
|
}
|
|
8823
|
+
if (looksLikeRunId(playName)) {
|
|
8824
|
+
console.error(
|
|
8825
|
+
formatPlayCommandReceivedRunIdError({
|
|
8826
|
+
command: "describe",
|
|
8827
|
+
runId: playName
|
|
8828
|
+
})
|
|
8829
|
+
);
|
|
8830
|
+
return 2;
|
|
8831
|
+
}
|
|
8506
8832
|
const client = new DeeplineClient();
|
|
8507
8833
|
await assertCanonicalNamedPlayReference(client, playName);
|
|
8508
8834
|
const play = await client.describePlay(
|
|
@@ -8659,7 +8985,7 @@ Common commands:
|
|
|
8659
8985
|
deepline plays search email --json
|
|
8660
8986
|
deepline plays describe person-linkedin-to-email --json
|
|
8661
8987
|
deepline plays check my.play.ts
|
|
8662
|
-
deepline plays run my.play.ts --input '{"domain":"stripe.com"}'
|
|
8988
|
+
deepline plays run my.play.ts --input '{"domain":"stripe.com"}'
|
|
8663
8989
|
deepline plays set-live my.play.ts --json
|
|
8664
8990
|
deepline plays get person-linkedin-to-email --json
|
|
8665
8991
|
`
|
|
@@ -8690,8 +9016,10 @@ Notes:
|
|
|
8690
9016
|
Unknown --foo value and --foo.bar value flags are passed into play input.
|
|
8691
9017
|
Example: --limit 5 becomes input.limit = 5.
|
|
8692
9018
|
File args accept local paths; the CLI stages files before submit.
|
|
8693
|
-
|
|
8694
|
-
--wait
|
|
9019
|
+
By default, run waits for completion and prints logs, previews, stats, and
|
|
9020
|
+
next commands. --watch and --wait are accepted compatibility aliases for the
|
|
9021
|
+
default behavior. Use --no-wait only when you intentionally want
|
|
9022
|
+
a fire-and-forget run id.
|
|
8695
9023
|
The play page opens in your browser as soon as the run starts; use --no-open
|
|
8696
9024
|
to only print the URL.
|
|
8697
9025
|
--force supersedes active runs; it does not bypass completed reuse.
|
|
@@ -8719,17 +9047,18 @@ Idempotent execution:
|
|
|
8719
9047
|
.run({ key: 'domain', staleAfterSeconds: 86400 })
|
|
8720
9048
|
|
|
8721
9049
|
Examples:
|
|
8722
|
-
deepline plays run my.play.ts --input '{"domain":"stripe.com"}'
|
|
8723
|
-
deepline plays run my.play.ts --input @input.json --
|
|
8724
|
-
deepline plays run person-linkedin-to-email --input '{"linkedin_url":"..."}'
|
|
8725
|
-
deepline plays run cto-search.play.ts --limit 5
|
|
9050
|
+
deepline plays run my.play.ts --input '{"domain":"stripe.com"}'
|
|
9051
|
+
deepline plays run my.play.ts --input @input.json --json
|
|
9052
|
+
deepline plays run person-linkedin-to-email --input '{"linkedin_url":"..."}'
|
|
9053
|
+
deepline plays run cto-search.play.ts --limit 5
|
|
9054
|
+
deepline plays run long-background-play --no-wait
|
|
8726
9055
|
deepline runs export <run-id> --out output.csv
|
|
8727
9056
|
deepline runs get <run-id>
|
|
8728
9057
|
`
|
|
8729
9058
|
).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(
|
|
8730
9059
|
"--revision-id <id>",
|
|
8731
9060
|
"Run a specific saved revision instead of the live revision"
|
|
8732
|
-
).option("--watch", "
|
|
9061
|
+
).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(
|
|
8733
9062
|
"--logs",
|
|
8734
9063
|
"When output is non-interactive, stream play logs to stderr while waiting"
|
|
8735
9064
|
).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(
|
|
@@ -8762,6 +9091,7 @@ Pass-through input flags:
|
|
|
8762
9091
|
...options.live ? ["--live"] : [],
|
|
8763
9092
|
...options.latest ? ["--latest"] : [],
|
|
8764
9093
|
...options.revisionId ? ["--revision-id", options.revisionId] : [],
|
|
9094
|
+
...options.wait === false ? ["--no-wait"] : [],
|
|
8765
9095
|
...options.watch || options.wait ? ["--watch"] : [],
|
|
8766
9096
|
...options.logs ? ["--logs"] : [],
|
|
8767
9097
|
...options.tailTimeoutMs ? ["--tail-timeout-ms", options.tailTimeoutMs] : [],
|
|
@@ -8802,24 +9132,27 @@ Notes:
|
|
|
8802
9132
|
|
|
8803
9133
|
Examples:
|
|
8804
9134
|
deepline plays list
|
|
8805
|
-
deepline plays list --json
|
|
9135
|
+
deepline plays list --origin prebuilt --json
|
|
8806
9136
|
deepline plays search email --origin prebuilt --json
|
|
8807
9137
|
`
|
|
8808
|
-
).option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (options) => {
|
|
9138
|
+
).option("--origin <origin>", "Filter to prebuilt or owned plays").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (options) => {
|
|
8809
9139
|
process.exitCode = await handlePlayList([
|
|
9140
|
+
...options.origin ? ["--origin", options.origin] : [],
|
|
8810
9141
|
...options.json ? ["--json"] : []
|
|
8811
9142
|
]);
|
|
8812
9143
|
});
|
|
8813
|
-
|
|
9144
|
+
const addPlaySearchCommand = (command) => command.description("Search saved and prebuilt plays.").addHelpText(
|
|
8814
9145
|
"after",
|
|
8815
9146
|
`
|
|
8816
9147
|
Notes:
|
|
8817
9148
|
Ranked discovery for workflows. Use --origin prebuilt or --origin owned when
|
|
8818
9149
|
you need to narrow results. Use describe on a result before running it.
|
|
9150
|
+
The grep alias is the same ranked retrieval surface with a more literal name
|
|
9151
|
+
for agents that are filtering the play registry.
|
|
8819
9152
|
|
|
8820
9153
|
Examples:
|
|
8821
9154
|
deepline plays search email
|
|
8822
|
-
deepline plays
|
|
9155
|
+
deepline plays grep "linkedin to email" --origin prebuilt --compact --json
|
|
8823
9156
|
deepline plays describe person-linkedin-to-email --json
|
|
8824
9157
|
`
|
|
8825
9158
|
).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) => {
|
|
@@ -8830,6 +9163,30 @@ Examples:
|
|
|
8830
9163
|
...options.json ? ["--json"] : []
|
|
8831
9164
|
]);
|
|
8832
9165
|
});
|
|
9166
|
+
addPlaySearchCommand(play.command("search <query>"));
|
|
9167
|
+
play.command("grep <query>").description("Literal grep over play names, aliases, schemas, and descriptions.").addHelpText(
|
|
9168
|
+
"after",
|
|
9169
|
+
`
|
|
9170
|
+
Notes:
|
|
9171
|
+
Literal registry filtering. Terms are matched case-insensitively against play
|
|
9172
|
+
names, references, display names, aliases, ownership, and schemas. Use
|
|
9173
|
+
--mode phrase for exact phrase matching, --mode any for OR, and the default
|
|
9174
|
+
--mode all for AND.
|
|
9175
|
+
|
|
9176
|
+
Examples:
|
|
9177
|
+
deepline plays grep email --origin prebuilt --json
|
|
9178
|
+
deepline plays grep "company contact" --origin prebuilt --mode all --json
|
|
9179
|
+
deepline plays describe prebuilt/company-to-contact --json
|
|
9180
|
+
`
|
|
9181
|
+
).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) => {
|
|
9182
|
+
process.exitCode = await handlePlayGrep([
|
|
9183
|
+
query,
|
|
9184
|
+
...options.origin ? ["--origin", options.origin] : [],
|
|
9185
|
+
...options.compact ? ["--compact"] : [],
|
|
9186
|
+
...options.mode ? ["--mode", options.mode] : [],
|
|
9187
|
+
...options.json ? ["--json"] : []
|
|
9188
|
+
]);
|
|
9189
|
+
});
|
|
8833
9190
|
play.command("describe <target>").description("Describe a play contract and how to run it.").addHelpText(
|
|
8834
9191
|
"after",
|
|
8835
9192
|
`
|
|
@@ -8858,7 +9215,7 @@ Notes:
|
|
|
8858
9215
|
Examples:
|
|
8859
9216
|
deepline plays versions --name my-play
|
|
8860
9217
|
deepline plays versions --name my-play --json
|
|
8861
|
-
deepline plays run my-play --revision-id <revision-id>
|
|
9218
|
+
deepline plays run my-play --revision-id <revision-id>
|
|
8862
9219
|
`
|
|
8863
9220
|
).option("--name <name>", "Saved play name").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (options) => {
|
|
8864
9221
|
process.exitCode = await handlePlayVersions([
|
|
@@ -9060,6 +9417,7 @@ Examples:
|
|
|
9060
9417
|
}
|
|
9061
9418
|
|
|
9062
9419
|
// src/cli/commands/tools.ts
|
|
9420
|
+
import { Option } from "commander";
|
|
9063
9421
|
import { chmodSync, mkdtempSync, writeFileSync as writeFileSync8 } from "fs";
|
|
9064
9422
|
import { tmpdir as tmpdir3 } from "os";
|
|
9065
9423
|
import { join as join8 } from "path";
|
|
@@ -9244,9 +9602,42 @@ function toListedTool(tool) {
|
|
|
9244
9602
|
executeCommand: `deepline tools execute ${tool.toolId}`
|
|
9245
9603
|
};
|
|
9246
9604
|
}
|
|
9605
|
+
function normalizeGrepText(value) {
|
|
9606
|
+
if (value === null || value === void 0) return "";
|
|
9607
|
+
if (typeof value === "string") return value.toLowerCase();
|
|
9608
|
+
if (typeof value === "number" || typeof value === "boolean") {
|
|
9609
|
+
return String(value).toLowerCase();
|
|
9610
|
+
}
|
|
9611
|
+
if (Array.isArray(value)) return value.map(normalizeGrepText).join(" ");
|
|
9612
|
+
if (typeof value === "object") {
|
|
9613
|
+
return Object.values(value).map(normalizeGrepText).join(" ");
|
|
9614
|
+
}
|
|
9615
|
+
return "";
|
|
9616
|
+
}
|
|
9617
|
+
function parseGrepTerms(query, mode) {
|
|
9618
|
+
const trimmed = query.trim().toLowerCase();
|
|
9619
|
+
if (!trimmed) return [];
|
|
9620
|
+
if (mode === "phrase") return [trimmed];
|
|
9621
|
+
const matches = trimmed.match(/"([^"]+)"|'([^']+)'|\S+/g) ?? [];
|
|
9622
|
+
return matches.map((term) => term.replace(/^["']|["']$/g, "").trim()).filter(Boolean);
|
|
9623
|
+
}
|
|
9624
|
+
function matchesGrepQuery(value, query, mode) {
|
|
9625
|
+
const terms = parseGrepTerms(query, mode);
|
|
9626
|
+
if (terms.length === 0) return true;
|
|
9627
|
+
const haystack = normalizeGrepText(value);
|
|
9628
|
+
if (mode === "any") return terms.some((term) => haystack.includes(term));
|
|
9629
|
+
return terms.every((term) => haystack.includes(term));
|
|
9630
|
+
}
|
|
9247
9631
|
async function listTools(args) {
|
|
9248
9632
|
const client = new DeeplineClient();
|
|
9249
|
-
const
|
|
9633
|
+
const categoryArgIndex = args.findIndex((arg) => arg === "--categories");
|
|
9634
|
+
const categoryFilter = categoryArgIndex >= 0 ? args[categoryArgIndex + 1] : "";
|
|
9635
|
+
const requestedCategories = categoryFilter ? categoryFilter.split(",").map((item) => item.trim()).filter(Boolean) : [];
|
|
9636
|
+
const items = (await client.listTools({
|
|
9637
|
+
...categoryFilter ? { categories: categoryFilter } : {}
|
|
9638
|
+
})).map(toListedTool).filter(
|
|
9639
|
+
(item) => requestedCategories.length === 0 || requestedCategories.some((category) => item.categories.includes(category))
|
|
9640
|
+
);
|
|
9250
9641
|
const render = {
|
|
9251
9642
|
sections: [
|
|
9252
9643
|
{
|
|
@@ -9269,6 +9660,9 @@ async function listTools(args) {
|
|
|
9269
9660
|
{
|
|
9270
9661
|
tools: items,
|
|
9271
9662
|
count: items.length,
|
|
9663
|
+
filters: {
|
|
9664
|
+
categories: requestedCategories
|
|
9665
|
+
},
|
|
9272
9666
|
commandTemplates: TOOL_COMMAND_TEMPLATES,
|
|
9273
9667
|
render
|
|
9274
9668
|
},
|
|
@@ -9295,6 +9689,56 @@ async function searchTools(queryInput, options = {}) {
|
|
|
9295
9689
|
});
|
|
9296
9690
|
return 0;
|
|
9297
9691
|
}
|
|
9692
|
+
async function grepTools(queryInput, options = {}) {
|
|
9693
|
+
const query = queryInput.trim();
|
|
9694
|
+
if (!query) {
|
|
9695
|
+
console.error("Usage: deepline tools grep <query> [--json]");
|
|
9696
|
+
return 1;
|
|
9697
|
+
}
|
|
9698
|
+
const client = new DeeplineClient();
|
|
9699
|
+
const requestedCategories = options.categories ? options.categories.split(",").map((item) => item.trim()).filter(Boolean) : [];
|
|
9700
|
+
const mode = options.mode ?? "all";
|
|
9701
|
+
const tools = (await client.listTools({
|
|
9702
|
+
grep: query,
|
|
9703
|
+
grepMode: mode,
|
|
9704
|
+
...options.categories ? { categories: options.categories } : {}
|
|
9705
|
+
})).map(toListedTool).filter(
|
|
9706
|
+
(item) => requestedCategories.length === 0 || requestedCategories.some((category) => item.categories.includes(category))
|
|
9707
|
+
).filter(
|
|
9708
|
+
(item) => matchesGrepQuery(
|
|
9709
|
+
{
|
|
9710
|
+
id: item.toolId,
|
|
9711
|
+
toolId: item.toolId,
|
|
9712
|
+
provider: item.provider,
|
|
9713
|
+
displayName: item.displayName,
|
|
9714
|
+
description: item.description,
|
|
9715
|
+
categories: item.categories,
|
|
9716
|
+
operation: item.operation,
|
|
9717
|
+
operationAliases: item.operationAliases,
|
|
9718
|
+
inputFields: item.inputFields
|
|
9719
|
+
},
|
|
9720
|
+
query,
|
|
9721
|
+
mode
|
|
9722
|
+
)
|
|
9723
|
+
);
|
|
9724
|
+
printCommandEnvelope(
|
|
9725
|
+
{
|
|
9726
|
+
tools,
|
|
9727
|
+
count: tools.length,
|
|
9728
|
+
query,
|
|
9729
|
+
grep: {
|
|
9730
|
+
mode,
|
|
9731
|
+
terms: parseGrepTerms(query, mode)
|
|
9732
|
+
},
|
|
9733
|
+
filters: {
|
|
9734
|
+
categories: requestedCategories
|
|
9735
|
+
},
|
|
9736
|
+
commandTemplates: TOOL_COMMAND_TEMPLATES
|
|
9737
|
+
},
|
|
9738
|
+
{ json: options.json || shouldEmitJson() }
|
|
9739
|
+
);
|
|
9740
|
+
return 0;
|
|
9741
|
+
}
|
|
9298
9742
|
function playIdentifiers(play) {
|
|
9299
9743
|
return [play.name, play.reference, ...play.aliases ?? []].filter((value) => Boolean(value?.trim())).map((value) => value.trim());
|
|
9300
9744
|
}
|
|
@@ -9364,24 +9808,27 @@ Notes:
|
|
|
9364
9808
|
|
|
9365
9809
|
Examples:
|
|
9366
9810
|
deepline tools list
|
|
9367
|
-
deepline tools list --json
|
|
9811
|
+
deepline tools list --categories email_finder --json
|
|
9368
9812
|
deepline tools search email --json
|
|
9369
9813
|
`
|
|
9370
|
-
).option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (options) => {
|
|
9814
|
+
).option("--categories <categories>", "Comma-separated categories to filter inventory").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (options) => {
|
|
9371
9815
|
process.exitCode = await listTools([
|
|
9816
|
+
...options.categories ? ["--categories", options.categories] : [],
|
|
9372
9817
|
...options.json ? ["--json"] : []
|
|
9373
9818
|
]);
|
|
9374
9819
|
});
|
|
9375
|
-
|
|
9820
|
+
const addToolSearchCommand = (command) => command.description("Search available tools.").addHelpText(
|
|
9376
9821
|
"after",
|
|
9377
9822
|
`
|
|
9378
9823
|
Notes:
|
|
9379
9824
|
Ranked discovery for atomic provider/API operations. Results include tool ids
|
|
9380
9825
|
that can be passed to deepline tools describe or deepline tools execute.
|
|
9826
|
+
The grep alias is the same ranked retrieval surface with a more literal name
|
|
9827
|
+
for agents that are filtering a registry rather than choosing a workflow.
|
|
9381
9828
|
|
|
9382
9829
|
Examples:
|
|
9383
9830
|
deepline tools search email
|
|
9384
|
-
deepline tools
|
|
9831
|
+
deepline tools grep "company enrichment" --categories enrichment --json
|
|
9385
9832
|
deepline tools search verifier --search-mode v2 --json
|
|
9386
9833
|
`
|
|
9387
9834
|
).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) => {
|
|
@@ -9393,24 +9840,55 @@ Examples:
|
|
|
9393
9840
|
includeSearchDebug: Boolean(options.includeSearchDebug)
|
|
9394
9841
|
});
|
|
9395
9842
|
});
|
|
9843
|
+
addToolSearchCommand(tools.command("search <query>"));
|
|
9844
|
+
tools.command("grep <query>").description("Literal grep over tool ids, descriptions, categories, and input fields.").addHelpText(
|
|
9845
|
+
"after",
|
|
9846
|
+
`
|
|
9847
|
+
Notes:
|
|
9848
|
+
Literal registry filtering. Terms are matched case-insensitively against tool
|
|
9849
|
+
ids, provider, display name, description, categories, aliases, and input
|
|
9850
|
+
fields. Use --mode phrase for exact phrase matching, --mode any for OR, and
|
|
9851
|
+
the default --mode all for AND.
|
|
9852
|
+
|
|
9853
|
+
Examples:
|
|
9854
|
+
deepline tools grep email --categories email_finder --json
|
|
9855
|
+
deepline tools grep "phone validate" --mode all --json
|
|
9856
|
+
deepline tools grep hunter --mode phrase --json
|
|
9857
|
+
`
|
|
9858
|
+
).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) => {
|
|
9859
|
+
const mode = options.mode === "any" || options.mode === "phrase" ? options.mode : "all";
|
|
9860
|
+
process.exitCode = await grepTools(query, {
|
|
9861
|
+
json: options.json,
|
|
9862
|
+
categories: options.categories,
|
|
9863
|
+
mode
|
|
9864
|
+
});
|
|
9865
|
+
});
|
|
9396
9866
|
const addToolMetadataCommand = (command) => command.description("Show metadata for a tool.").addHelpText(
|
|
9397
9867
|
"after",
|
|
9398
9868
|
`
|
|
9399
9869
|
Notes:
|
|
9400
|
-
Shows the
|
|
9401
|
-
|
|
9402
|
-
|
|
9870
|
+
Shows the compact agent contract by default: what the tool does, cost,
|
|
9871
|
+
required inputs, play getters, and a runnable ctx.tools.execute snippet.
|
|
9872
|
+
Use --json for the full metadata/debug payload.
|
|
9403
9873
|
|
|
9404
9874
|
Examples:
|
|
9405
9875
|
deepline tools describe hunter_email_verifier
|
|
9406
|
-
deepline tools describe hunter_email_verifier --
|
|
9876
|
+
deepline tools describe hunter_email_verifier --pricing-only
|
|
9877
|
+
deepline tools describe hunter_email_verifier --schema-only
|
|
9878
|
+
deepline tools describe hunter_email_verifier --examples-only
|
|
9879
|
+
deepline tools describe hunter_email_verifier --json
|
|
9407
9880
|
deepline tools execute hunter_email_verifier --input '{"email":"a@b.com"}'
|
|
9408
9881
|
`
|
|
9409
|
-
).option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (toolId, options) => {
|
|
9410
|
-
process.exitCode = await getTool(
|
|
9411
|
-
|
|
9412
|
-
|
|
9413
|
-
|
|
9882
|
+
).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 Option("--compact", "Compatibility alias for the default compact view").hideHelp()).addOption(new Option("--contract-json", "Compatibility alias for compact contract JSON").hideHelp()).action(async (toolId, options) => {
|
|
9883
|
+
process.exitCode = await getTool(toolId, {
|
|
9884
|
+
json: Boolean(options.json),
|
|
9885
|
+
compact: Boolean(options.compact),
|
|
9886
|
+
contractJson: Boolean(options.contractJson),
|
|
9887
|
+
pricingOnly: Boolean(options.pricingOnly),
|
|
9888
|
+
schemaOnly: Boolean(options.schemaOnly),
|
|
9889
|
+
examplesOnly: Boolean(options.examplesOnly),
|
|
9890
|
+
gettersOnly: Boolean(options.gettersOnly)
|
|
9891
|
+
});
|
|
9414
9892
|
});
|
|
9415
9893
|
addToolMetadataCommand(tools.command("describe <toolId>"));
|
|
9416
9894
|
tools.command("get <toolId>").description("Deprecated. Use tools describe.").addHelpText(
|
|
@@ -9463,8 +9941,7 @@ Examples:
|
|
|
9463
9941
|
process.exitCode = await executeTool(args);
|
|
9464
9942
|
});
|
|
9465
9943
|
}
|
|
9466
|
-
async function getTool(
|
|
9467
|
-
const toolId = args[0];
|
|
9944
|
+
async function getTool(toolId, options = {}) {
|
|
9468
9945
|
if (!toolId) {
|
|
9469
9946
|
console.error("Usage: deepline tools get <toolId> [--json]");
|
|
9470
9947
|
return 1;
|
|
@@ -9481,14 +9958,264 @@ async function getTool(args) {
|
|
|
9481
9958
|
}
|
|
9482
9959
|
throw error;
|
|
9483
9960
|
}
|
|
9484
|
-
if (
|
|
9961
|
+
if (options.contractJson) {
|
|
9962
|
+
process.stdout.write(`${JSON.stringify(toolContractJsonForDescribe(tool, toolId))}
|
|
9963
|
+
`);
|
|
9964
|
+
return 0;
|
|
9965
|
+
}
|
|
9966
|
+
const emitJson = options.json === true;
|
|
9967
|
+
if (emitJson) {
|
|
9485
9968
|
process.stdout.write(`${JSON.stringify(toolMetadataJsonForDescribe(tool, toolId))}
|
|
9486
9969
|
`);
|
|
9487
9970
|
return 0;
|
|
9488
9971
|
}
|
|
9489
|
-
|
|
9972
|
+
const onlyModes = [
|
|
9973
|
+
options.pricingOnly,
|
|
9974
|
+
options.schemaOnly,
|
|
9975
|
+
options.examplesOnly,
|
|
9976
|
+
options.gettersOnly
|
|
9977
|
+
].filter(Boolean).length;
|
|
9978
|
+
if (onlyModes > 1) {
|
|
9979
|
+
console.error("Use only one of --pricing-only, --schema-only, --examples-only, or --getters-only.");
|
|
9980
|
+
return 2;
|
|
9981
|
+
}
|
|
9982
|
+
if (options.pricingOnly) {
|
|
9983
|
+
printToolPricingOnly(tool, toolId);
|
|
9984
|
+
return 0;
|
|
9985
|
+
}
|
|
9986
|
+
if (options.schemaOnly) {
|
|
9987
|
+
printToolSchemaOnly(tool, toolId);
|
|
9988
|
+
return 0;
|
|
9989
|
+
}
|
|
9990
|
+
if (options.examplesOnly) {
|
|
9991
|
+
printToolExamplesOnly(tool, toolId);
|
|
9992
|
+
return 0;
|
|
9993
|
+
}
|
|
9994
|
+
if (options.gettersOnly) {
|
|
9995
|
+
printToolGettersOnly(tool, toolId);
|
|
9996
|
+
return 0;
|
|
9997
|
+
}
|
|
9998
|
+
if (options.compact) {
|
|
9999
|
+
printCompactToolContract(tool, toolId);
|
|
10000
|
+
return 0;
|
|
10001
|
+
}
|
|
10002
|
+
if (shouldEmitJson()) {
|
|
10003
|
+
process.stdout.write(`${JSON.stringify(toolMetadataJsonForDescribe(tool, toolId))}
|
|
10004
|
+
`);
|
|
10005
|
+
return 0;
|
|
10006
|
+
}
|
|
10007
|
+
printCompactToolContract(tool, toolId);
|
|
9490
10008
|
return 0;
|
|
9491
10009
|
}
|
|
10010
|
+
function toolContractJsonForDescribe(tool, requestedToolId) {
|
|
10011
|
+
const toolId = String(tool.toolId || requestedToolId);
|
|
10012
|
+
const inputFields = toolInputFieldsForDisplay(recordField(tool, "inputSchema", "input_schema"));
|
|
10013
|
+
const usageGuidance = recordField(tool, "usageGuidance", "usage_guidance");
|
|
10014
|
+
const toolExecutionResult = recordField(usageGuidance, "toolExecutionResult", "tool_execution_result");
|
|
10015
|
+
const extractedLists = extractionContractEntries(
|
|
10016
|
+
arrayField(toolExecutionResult, "extractedLists", "extracted_lists")
|
|
10017
|
+
);
|
|
10018
|
+
const extractedValues = extractionContractEntries(
|
|
10019
|
+
arrayField(toolExecutionResult, "extractedValues", "extracted_values")
|
|
10020
|
+
);
|
|
10021
|
+
const cost = recordField(tool, "cost");
|
|
10022
|
+
const deeplineCredits = numberField(tool, "deeplineCreditsPerPricingUnit", "deepline_credits_per_pricing_unit");
|
|
10023
|
+
const deeplineUsdPerPricingUnit = numberField(tool, "deeplineUsdPerPricingUnit", "deepline_usd_per_pricing_unit");
|
|
10024
|
+
return {
|
|
10025
|
+
schemaVersion: 1,
|
|
10026
|
+
toolId,
|
|
10027
|
+
provider: tool.provider,
|
|
10028
|
+
displayName: tool.displayName,
|
|
10029
|
+
description: tool.description,
|
|
10030
|
+
categories: tool.categories,
|
|
10031
|
+
inputFields: inputFields.map((field) => ({
|
|
10032
|
+
name: field.name,
|
|
10033
|
+
type: field.type ?? "unknown",
|
|
10034
|
+
required: Boolean(field.required),
|
|
10035
|
+
...field.description ? { description: field.description } : {},
|
|
10036
|
+
...Object.prototype.hasOwnProperty.call(field, "default") ? { default: field.default } : {}
|
|
10037
|
+
})),
|
|
10038
|
+
cost: {
|
|
10039
|
+
pricingModel: stringField(cost, "pricingModel", "pricing_model") || null,
|
|
10040
|
+
billingMode: stringField(cost, "billingMode", "billing_mode") || null,
|
|
10041
|
+
deeplineCreditsPerPricingUnit: deeplineCredits,
|
|
10042
|
+
deeplineUsdPerPricingUnit
|
|
10043
|
+
},
|
|
10044
|
+
getters: {
|
|
10045
|
+
extractedLists,
|
|
10046
|
+
extractedValues
|
|
10047
|
+
},
|
|
10048
|
+
executeCommand: `deepline tools execute ${toolId} --input '{...}' --json`
|
|
10049
|
+
};
|
|
10050
|
+
}
|
|
10051
|
+
function extractionContractEntries(entries) {
|
|
10052
|
+
return entries.flatMap((entry) => {
|
|
10053
|
+
if (!isRecord4(entry)) return [];
|
|
10054
|
+
const name = stringField(entry, "name");
|
|
10055
|
+
const expression = stringField(entry, "expression");
|
|
10056
|
+
return name && expression ? [{ name, expression }] : [];
|
|
10057
|
+
});
|
|
10058
|
+
}
|
|
10059
|
+
function printCompactToolContract(tool, requestedToolId) {
|
|
10060
|
+
const contract = toolContractJsonForDescribe(tool, requestedToolId);
|
|
10061
|
+
const cost = isRecord4(contract.cost) ? contract.cost : {};
|
|
10062
|
+
const getters = isRecord4(contract.getters) ? contract.getters : {};
|
|
10063
|
+
const listGetters = Array.isArray(getters.extractedLists) ? getters.extractedLists : [];
|
|
10064
|
+
const valueGetters = Array.isArray(getters.extractedValues) ? getters.extractedValues : [];
|
|
10065
|
+
const inputFields = Array.isArray(contract.inputFields) ? contract.inputFields : [];
|
|
10066
|
+
console.log(String(contract.toolId));
|
|
10067
|
+
if (contract.displayName) console.log(`Best for: ${contract.displayName}`);
|
|
10068
|
+
if (typeof contract.description === "string" && contract.description.trim()) {
|
|
10069
|
+
console.log(`Description: ${contract.description.trim()}`);
|
|
10070
|
+
}
|
|
10071
|
+
if (Array.isArray(contract.categories) && contract.categories.length) {
|
|
10072
|
+
console.log(`Tags: ${contract.categories.join(", ")}`);
|
|
10073
|
+
}
|
|
10074
|
+
printToolPricingOnly(tool, requestedToolId, { heading: "Cost" });
|
|
10075
|
+
if (inputFields.length) {
|
|
10076
|
+
console.log("");
|
|
10077
|
+
console.log("Inputs:");
|
|
10078
|
+
for (const field of inputFields) {
|
|
10079
|
+
if (!isRecord4(field)) continue;
|
|
10080
|
+
const name = stringField(field, "name");
|
|
10081
|
+
if (!name) continue;
|
|
10082
|
+
const required = field.required ? "*" : "";
|
|
10083
|
+
const type = stringField(field, "type") || "unknown";
|
|
10084
|
+
const description = stringField(field, "description");
|
|
10085
|
+
console.log(`- ${name}${required}: ${type}${description ? ` - ${description}` : ""}`);
|
|
10086
|
+
}
|
|
10087
|
+
}
|
|
10088
|
+
console.log("");
|
|
10089
|
+
printToolExamplesOnly(tool, requestedToolId, { includeSamples: false });
|
|
10090
|
+
if (listGetters.length || valueGetters.length) {
|
|
10091
|
+
console.log("");
|
|
10092
|
+
console.log("Getters:");
|
|
10093
|
+
if (listGetters.length) console.log("Lists:");
|
|
10094
|
+
for (const entry of listGetters) {
|
|
10095
|
+
if (isRecord4(entry)) console.log(`- ${stringField(entry, "name")}: ${playResultExpression(entry)}`);
|
|
10096
|
+
}
|
|
10097
|
+
if (valueGetters.length) console.log("Values:");
|
|
10098
|
+
for (const entry of valueGetters) {
|
|
10099
|
+
if (isRecord4(entry)) console.log(`- ${stringField(entry, "name")}: ${playResultExpression(entry)}`);
|
|
10100
|
+
}
|
|
10101
|
+
}
|
|
10102
|
+
console.log("");
|
|
10103
|
+
console.log(`More: deepline tools describe ${contract.toolId} --pricing-only | --schema-only | --examples-only | --getters-only | --json`);
|
|
10104
|
+
}
|
|
10105
|
+
function printToolPricingOnly(tool, requestedToolId, options = {}) {
|
|
10106
|
+
const contract = toolContractJsonForDescribe(tool, requestedToolId);
|
|
10107
|
+
const cost = isRecord4(contract.cost) ? contract.cost : {};
|
|
10108
|
+
const pricingModel = stringField(cost, "pricingModel") || "unknown";
|
|
10109
|
+
const billingMode = stringField(cost, "billingMode") || "unknown";
|
|
10110
|
+
const unit = pricingModel === "per_page" ? "page" : pricingModel === "per_result" ? "result" : pricingModel === "fixed" ? "call" : pricingModel.replace(/^per_/, "") || "unit";
|
|
10111
|
+
const credits = numberField(cost, "deeplineCreditsPerPricingUnit");
|
|
10112
|
+
const usd = numberField(cost, "deeplineUsdPerPricingUnit");
|
|
10113
|
+
const price = credits !== null ? `${formatDecimal(credits)} Deepline credits${usd !== null ? ` / ${formatUsd(usd)}` : ""} per ${unit}` : "pricing unavailable";
|
|
10114
|
+
console.log(`${options.heading ?? `Pricing: ${contract.toolId}`}: ${price}`);
|
|
10115
|
+
console.log(`Billing: ${billingMode}`);
|
|
10116
|
+
}
|
|
10117
|
+
function printToolSchemaOnly(tool, requestedToolId) {
|
|
10118
|
+
const contract = toolContractJsonForDescribe(tool, requestedToolId);
|
|
10119
|
+
const inputFields = Array.isArray(contract.inputFields) ? contract.inputFields : [];
|
|
10120
|
+
console.log(`Schema: ${contract.toolId}`);
|
|
10121
|
+
if (!inputFields.length) {
|
|
10122
|
+
console.log("Inputs: none");
|
|
10123
|
+
return;
|
|
10124
|
+
}
|
|
10125
|
+
console.log("Inputs:");
|
|
10126
|
+
for (const field of inputFields) {
|
|
10127
|
+
if (!isRecord4(field)) continue;
|
|
10128
|
+
const name = stringField(field, "name");
|
|
10129
|
+
if (!name) continue;
|
|
10130
|
+
const required = field.required ? "*" : "";
|
|
10131
|
+
const type = stringField(field, "type") || "unknown";
|
|
10132
|
+
const description = stringField(field, "description");
|
|
10133
|
+
const defaultSuffix = Object.prototype.hasOwnProperty.call(field, "default") ? ` default=${JSON.stringify(field.default)}` : "";
|
|
10134
|
+
console.log(`- ${name}${required}: ${type}${defaultSuffix}${description ? ` - ${description}` : ""}`);
|
|
10135
|
+
}
|
|
10136
|
+
}
|
|
10137
|
+
function printToolExamplesOnly(tool, requestedToolId, options = {}) {
|
|
10138
|
+
const contract = toolContractJsonForDescribe(tool, requestedToolId);
|
|
10139
|
+
const toolId = String(contract.toolId);
|
|
10140
|
+
const inputFields = Array.isArray(contract.inputFields) ? contract.inputFields : [];
|
|
10141
|
+
const sampleInput = Object.fromEntries(
|
|
10142
|
+
inputFields.slice(0, 4).flatMap((field) => {
|
|
10143
|
+
if (!isRecord4(field)) return [];
|
|
10144
|
+
const name = stringField(field, "name");
|
|
10145
|
+
if (!name) return [];
|
|
10146
|
+
return [[name, sampleValueForField(field)]];
|
|
10147
|
+
})
|
|
10148
|
+
);
|
|
10149
|
+
console.log(`Use in a play:`);
|
|
10150
|
+
console.log("```ts");
|
|
10151
|
+
console.log("const result = await ctx.tools.execute({");
|
|
10152
|
+
console.log(` id: '${stableStepIdForTool(toolId)}',`);
|
|
10153
|
+
console.log(` tool: '${toolId}',`);
|
|
10154
|
+
console.log(` input: ${JSON.stringify(sampleInput || {}, null, 2).replace(/\n/g, "\n ")},`);
|
|
10155
|
+
console.log("});");
|
|
10156
|
+
const getters = isRecord4(contract.getters) ? contract.getters : {};
|
|
10157
|
+
const valueGetters = Array.isArray(getters.extractedValues) ? getters.extractedValues : [];
|
|
10158
|
+
const listGetters = Array.isArray(getters.extractedLists) ? getters.extractedLists : [];
|
|
10159
|
+
const firstGetter = [...valueGetters, ...listGetters].find(isRecord4);
|
|
10160
|
+
if (firstGetter) {
|
|
10161
|
+
const name = stringField(firstGetter, "name") || "value";
|
|
10162
|
+
const expression = stringField(firstGetter, "expression");
|
|
10163
|
+
if (expression) console.log(`const ${safeIdentifier(name)} = ${expression.replace(/^toolExecutionResult\./, "result.")};`);
|
|
10164
|
+
}
|
|
10165
|
+
console.log("```");
|
|
10166
|
+
if (options.includeSamples !== false) {
|
|
10167
|
+
const samples = recordField(tool, "samples");
|
|
10168
|
+
printSamples(samples);
|
|
10169
|
+
}
|
|
10170
|
+
}
|
|
10171
|
+
function printToolGettersOnly(tool, requestedToolId) {
|
|
10172
|
+
const contract = toolContractJsonForDescribe(tool, requestedToolId);
|
|
10173
|
+
const getters = isRecord4(contract.getters) ? contract.getters : {};
|
|
10174
|
+
const listGetters = Array.isArray(getters.extractedLists) ? getters.extractedLists : [];
|
|
10175
|
+
const valueGetters = Array.isArray(getters.extractedValues) ? getters.extractedValues : [];
|
|
10176
|
+
console.log(`Getters: ${contract.toolId}`);
|
|
10177
|
+
if (!listGetters.length && !valueGetters.length) {
|
|
10178
|
+
console.log("No generated getters declared. Use --json only if you need raw metadata.");
|
|
10179
|
+
return;
|
|
10180
|
+
}
|
|
10181
|
+
if (listGetters.length) {
|
|
10182
|
+
console.log("Lists:");
|
|
10183
|
+
for (const entry of listGetters) {
|
|
10184
|
+
if (isRecord4(entry)) console.log(`- ${stringField(entry, "name")}: ${playResultExpression(entry)}`);
|
|
10185
|
+
}
|
|
10186
|
+
}
|
|
10187
|
+
if (valueGetters.length) {
|
|
10188
|
+
console.log("Values:");
|
|
10189
|
+
for (const entry of valueGetters) {
|
|
10190
|
+
if (isRecord4(entry)) console.log(`- ${stringField(entry, "name")}: ${playResultExpression(entry)}`);
|
|
10191
|
+
}
|
|
10192
|
+
}
|
|
10193
|
+
}
|
|
10194
|
+
function sampleValueForField(field) {
|
|
10195
|
+
const name = stringField(field, "name").toLowerCase();
|
|
10196
|
+
const type = stringField(field, "type").toLowerCase();
|
|
10197
|
+
if (Object.prototype.hasOwnProperty.call(field, "default")) return field.default;
|
|
10198
|
+
if (name.includes("email")) return "ada@example.com";
|
|
10199
|
+
if (name.includes("domain") || name.includes("website")) return "example.com";
|
|
10200
|
+
if (name.includes("first")) return "Ada";
|
|
10201
|
+
if (name.includes("last")) return "Lovelace";
|
|
10202
|
+
if (name.includes("name")) return "Ada Lovelace";
|
|
10203
|
+
if (type === "integer" || type === "number") return 1;
|
|
10204
|
+
if (type === "boolean") return true;
|
|
10205
|
+
if (type === "array") return [];
|
|
10206
|
+
if (type === "object") return {};
|
|
10207
|
+
return "...";
|
|
10208
|
+
}
|
|
10209
|
+
function stableStepIdForTool(toolId) {
|
|
10210
|
+
return toolId.replace(/^[a-z0-9]+_/, "").replace(/[^a-z0-9_]+/gi, "_") || "tool_call";
|
|
10211
|
+
}
|
|
10212
|
+
function safeIdentifier(name) {
|
|
10213
|
+
const cleaned = name.replace(/[^a-zA-Z0-9_$]+/g, "_").replace(/^[^a-zA-Z_$]+/, "");
|
|
10214
|
+
return cleaned || "value";
|
|
10215
|
+
}
|
|
10216
|
+
function playResultExpression(entry) {
|
|
10217
|
+
return stringField(entry, "expression").replace(/^toolExecutionResult\./, "result.");
|
|
10218
|
+
}
|
|
9492
10219
|
function toolMetadataJsonForDescribe(tool, requestedToolId) {
|
|
9493
10220
|
const toolId = String(tool.toolId || requestedToolId);
|
|
9494
10221
|
const {
|
|
@@ -9519,152 +10246,6 @@ function toolMetadataJsonForDescribe(tool, requestedToolId) {
|
|
|
9519
10246
|
}
|
|
9520
10247
|
};
|
|
9521
10248
|
}
|
|
9522
|
-
function printToolDetails(tool, requestedToolId) {
|
|
9523
|
-
const toolId = String(tool.toolId || requestedToolId);
|
|
9524
|
-
const operation = typeof tool.operation === "string" ? tool.operation : "";
|
|
9525
|
-
const displayBase = operation && operation.startsWith(`${tool.provider}_`) ? operation.slice(String(tool.provider).length + 1) : operation ? `${tool.provider} ${operation}`.trim() : toolId;
|
|
9526
|
-
const displayName = titleCase(displayBase || String(tool.displayName || toolId));
|
|
9527
|
-
const cost = isRecord4(tool.cost) ? tool.cost : null;
|
|
9528
|
-
const pricing = recordField(tool, "pricing");
|
|
9529
|
-
const deeplineCredits = numberField(tool, "deeplineCreditsPerPricingUnit", "deepline_credits_per_pricing_unit");
|
|
9530
|
-
const deeplineUsdPerPricingUnit = numberField(tool, "deeplineUsdPerPricingUnit", "deepline_usd_per_pricing_unit");
|
|
9531
|
-
const billingSource = stringField(tool, "billingSource", "billing_source");
|
|
9532
|
-
const billingSourceLabel = stringField(tool, "billingSourceLabel", "billing_source_label");
|
|
9533
|
-
const estimatedCreditsRange = stringField(tool, "estimatedCreditsRange", "estimated_credits_range");
|
|
9534
|
-
const estimatedUsdRange = stringField(tool, "estimatedUsdRange", "estimated_usd_range");
|
|
9535
|
-
const estimateModelVersion = stringField(tool, "estimateModelVersion", "estimate_model_version");
|
|
9536
|
-
const estimateBasedOnTools = arrayField(tool, "estimateBasedOnTools", "estimate_based_on_tools").map((item) => String(item).trim()).filter(Boolean);
|
|
9537
|
-
const stepContributions = arrayField(tool, "stepContributions", "step_contributions");
|
|
9538
|
-
const playExpansion = recordField(tool, "playExpansion", "play_expansion");
|
|
9539
|
-
const samples = recordField(tool, "samples");
|
|
9540
|
-
const usageGuidance = recordField(tool, "usageGuidance", "usage_guidance");
|
|
9541
|
-
console.log(`Tool: ${toolId}`);
|
|
9542
|
-
console.log(" Runtime output help:");
|
|
9543
|
-
console.log(" describe shows declared schema/getters, not an observed provider response");
|
|
9544
|
-
console.log(` observe actual shape: deepline tools execute ${toolId} --input '{...}' --json`);
|
|
9545
|
-
console.log(" for play getter bugs: run the play, then use the db query commands printed by runs get");
|
|
9546
|
-
if (displayName) {
|
|
9547
|
-
console.log(" Display name:");
|
|
9548
|
-
console.log(` ${displayName}`);
|
|
9549
|
-
}
|
|
9550
|
-
if (tool.categories.length > 0) {
|
|
9551
|
-
console.log(" Categories:");
|
|
9552
|
-
console.log(` ${tool.categories.join(", ")}`);
|
|
9553
|
-
}
|
|
9554
|
-
const printedCost = printToolCost({
|
|
9555
|
-
pricing,
|
|
9556
|
-
cost,
|
|
9557
|
-
billingSource,
|
|
9558
|
-
deeplineCredits,
|
|
9559
|
-
deeplineUsdPerPricingUnit
|
|
9560
|
-
});
|
|
9561
|
-
if (!printedCost && ["run_javascript", "call_local_codex", "call_local_claude_code"].includes(toolId)) {
|
|
9562
|
-
console.log(" Cost: free");
|
|
9563
|
-
}
|
|
9564
|
-
if (billingSourceLabel) {
|
|
9565
|
-
console.log(` Billing source: ${billingSourceLabel}`);
|
|
9566
|
-
}
|
|
9567
|
-
if (estimatedCreditsRange) {
|
|
9568
|
-
const usdSuffix = estimatedUsdRange ? ` (~${estimatedUsdRange})` : "";
|
|
9569
|
-
console.log(` Estimated play spend: ${estimatedCreditsRange}${usdSuffix}`);
|
|
9570
|
-
if (estimateModelVersion) console.log(` model: ${estimateModelVersion}`);
|
|
9571
|
-
if (estimateBasedOnTools.length) console.log(` based on: ${estimateBasedOnTools.join(", ")}`);
|
|
9572
|
-
if (stepContributions.length) {
|
|
9573
|
-
console.log(" step contributions:");
|
|
9574
|
-
for (const item of stepContributions) {
|
|
9575
|
-
if (!isRecord4(item)) continue;
|
|
9576
|
-
const stepTool = typeof item.tool === "string" ? item.tool.trim() : "";
|
|
9577
|
-
const low = typeof item.lowCredits === "number" ? item.lowCredits : null;
|
|
9578
|
-
const high = typeof item.highCredits === "number" ? item.highCredits : null;
|
|
9579
|
-
const lowUsd = typeof item.lowUsd === "number" ? item.lowUsd : null;
|
|
9580
|
-
const highUsd = typeof item.highUsd === "number" ? item.highUsd : null;
|
|
9581
|
-
if (!stepTool || low === null || high === null) continue;
|
|
9582
|
-
const stepUsdSuffix = lowUsd !== null && highUsd !== null ? ` (~${formatUsd(lowUsd)}-${formatUsd(highUsd)})` : "";
|
|
9583
|
-
console.log(` - ${stepTool}: ${formatDecimal(low)}-${formatDecimal(high)} credits${stepUsdSuffix}`);
|
|
9584
|
-
}
|
|
9585
|
-
}
|
|
9586
|
-
}
|
|
9587
|
-
if (playExpansion && Object.keys(playExpansion).length > 0) {
|
|
9588
|
-
const group = typeof playExpansion.group === "string" ? playExpansion.group.trim() : "";
|
|
9589
|
-
console.log(" Play expansion:");
|
|
9590
|
-
if (group) console.log(` group: ${group}`);
|
|
9591
|
-
}
|
|
9592
|
-
const fields = toolInputFieldsForDisplay(recordField(tool, "inputSchema", "input_schema"));
|
|
9593
|
-
if (fields.length) {
|
|
9594
|
-
console.log(" Inputs (operation-specific):");
|
|
9595
|
-
for (const field of fields) {
|
|
9596
|
-
const name = String(field.name || "");
|
|
9597
|
-
const typeName = String(field.type || "unknown");
|
|
9598
|
-
const requiredLabel = field.required ? "required" : "optional";
|
|
9599
|
-
const defaultSuffix = Object.prototype.hasOwnProperty.call(field, "default") ? `, default: ${JSON.stringify(field.default)}` : "";
|
|
9600
|
-
const desc = typeof field.description === "string" && field.description.trim() ? ` - ${field.description.trim()}` : "";
|
|
9601
|
-
console.log(` - ${name} (${typeName}, ${requiredLabel}${defaultSuffix})${desc}`);
|
|
9602
|
-
}
|
|
9603
|
-
console.log(" Tip: pass --payload with a JSON object.");
|
|
9604
|
-
}
|
|
9605
|
-
printSamples(samples);
|
|
9606
|
-
printUsageGuidance(usageGuidance);
|
|
9607
|
-
if (isPlayTool(tool)) {
|
|
9608
|
-
console.log(" Play contract:");
|
|
9609
|
-
console.log(" - This is a deepline-native waterfall; the returned rows are extracted by target getters, not by hand-authored payload shape.");
|
|
9610
|
-
if (playExpansion && typeof playExpansion.group === "string" && playExpansion.group.trim()) {
|
|
9611
|
-
console.log(` - Output alias/runtime group is: ${playExpansion.group.trim()}`);
|
|
9612
|
-
}
|
|
9613
|
-
const toolExecutionResult = recordField(usageGuidance, "toolExecutionResult");
|
|
9614
|
-
const extractedValues = arrayField(toolExecutionResult, "extractedValues", "extracted_values");
|
|
9615
|
-
const targets = extractedValues.map((entry) => isRecord4(entry) && typeof entry.name === "string" ? entry.name : "").filter(Boolean).sort();
|
|
9616
|
-
if (targets.length) {
|
|
9617
|
-
console.log(` - Built-in extract targets: ${targets.join(", ")}`);
|
|
9618
|
-
}
|
|
9619
|
-
}
|
|
9620
|
-
console.log("");
|
|
9621
|
-
console.log("Usage:");
|
|
9622
|
-
const requestPayload = samplePayload(samples, "request");
|
|
9623
|
-
if (isPlayTool(tool)) {
|
|
9624
|
-
if (requestPayload !== void 0) {
|
|
9625
|
-
console.log(` deepline enrich --with '${JSON.stringify({ alias: "result", tool: toolId, payload: requestPayload })}'`);
|
|
9626
|
-
} else {
|
|
9627
|
-
console.log(` deepline enrich --with '{"alias":"result","tool":"${toolId}","payload":{...}}'`);
|
|
9628
|
-
}
|
|
9629
|
-
} else if (requestPayload !== void 0) {
|
|
9630
|
-
console.log(` deepline tools execute ${toolId} --payload '${JSON.stringify(requestPayload)}'`);
|
|
9631
|
-
} else {
|
|
9632
|
-
console.log(` deepline tools execute ${toolId} --payload '{...}'`);
|
|
9633
|
-
}
|
|
9634
|
-
console.log(" deepline tools describe <tool_id> --json");
|
|
9635
|
-
}
|
|
9636
|
-
function printUsageGuidance(usageGuidance) {
|
|
9637
|
-
if (Object.keys(usageGuidance).length === 0) return;
|
|
9638
|
-
const execute = stringField(usageGuidance, "execute");
|
|
9639
|
-
const toolExecutionResult = recordField(usageGuidance, "toolExecutionResult", "tool_execution_result");
|
|
9640
|
-
const toolResponse = recordField(toolExecutionResult, "toolResponse", "tool_response");
|
|
9641
|
-
const extractedLists = arrayField(toolExecutionResult, "extractedLists", "extracted_lists");
|
|
9642
|
-
const extractedValues = arrayField(toolExecutionResult, "extractedValues", "extracted_values");
|
|
9643
|
-
console.log(" Usage guidance:");
|
|
9644
|
-
if (execute) console.log(` ${execute}`);
|
|
9645
|
-
const raw = stringField(toolResponse, "raw");
|
|
9646
|
-
const meta = stringField(toolResponse, "meta");
|
|
9647
|
-
if (raw) console.log(` Raw tool response: ${raw}`);
|
|
9648
|
-
if (meta) console.log(` Tool response metadata: ${meta}`);
|
|
9649
|
-
printExtractions("Extracted lists", extractedLists);
|
|
9650
|
-
printExtractions("Extracted values", extractedValues);
|
|
9651
|
-
}
|
|
9652
|
-
function printExtractions(label, entries) {
|
|
9653
|
-
if (!entries.length) return;
|
|
9654
|
-
console.log(` ${label}:`);
|
|
9655
|
-
for (const entry of entries) {
|
|
9656
|
-
if (!isRecord4(entry)) continue;
|
|
9657
|
-
const name = stringField(entry, "name");
|
|
9658
|
-
const expression = stringField(entry, "expression");
|
|
9659
|
-
const details = recordField(entry, "details");
|
|
9660
|
-
const rawToolOutputPaths = arrayField(details, "rawToolOutputPaths", "raw_tool_output_paths").map((value) => typeof value === "string" ? value.trim() : "").filter(Boolean);
|
|
9661
|
-
const candidatePaths = arrayField(details, "candidatePaths", "candidate_paths").map((value) => typeof value === "string" ? value.trim() : "").filter(Boolean);
|
|
9662
|
-
if (!name || !expression) continue;
|
|
9663
|
-
const paths = candidatePaths.length ? candidatePaths : rawToolOutputPaths;
|
|
9664
|
-
const pathSuffix = paths.length ? ` from ${paths.join(", ")}` : "";
|
|
9665
|
-
console.log(` - ${name}: ${expression}${pathSuffix}`);
|
|
9666
|
-
}
|
|
9667
|
-
}
|
|
9668
10249
|
function singleLineText(value, maxLength = 260) {
|
|
9669
10250
|
if (typeof value !== "string") return "";
|
|
9670
10251
|
const text = value.replace(/\s+/g, " ").trim();
|
|
@@ -9681,42 +10262,6 @@ function formatListedToolCost(tool) {
|
|
|
9681
10262
|
const displayText = stringField(pricing, "displayText", "display_text");
|
|
9682
10263
|
return displayText ? `Cost: ${displayText}` : "";
|
|
9683
10264
|
}
|
|
9684
|
-
function printToolCost(input) {
|
|
9685
|
-
const { pricing, cost, billingSource, deeplineCredits, deeplineUsdPerPricingUnit } = input;
|
|
9686
|
-
if (billingSource === "own_provider_credentials") {
|
|
9687
|
-
console.log(" Cost: free through Deepline");
|
|
9688
|
-
return true;
|
|
9689
|
-
}
|
|
9690
|
-
const displayText = stringField(pricing, "displayText", "display_text");
|
|
9691
|
-
if (displayText) {
|
|
9692
|
-
console.log(` Cost: ${displayText}`);
|
|
9693
|
-
const details = arrayField(pricing, "details").map((item) => String(item).trim()).filter(Boolean);
|
|
9694
|
-
if (details.length) {
|
|
9695
|
-
console.log(" notes:");
|
|
9696
|
-
for (const detail of details) console.log(` - ${detail}`);
|
|
9697
|
-
}
|
|
9698
|
-
return true;
|
|
9699
|
-
}
|
|
9700
|
-
const pricingModel = cost ? typeof cost.pricingModel === "string" ? cost.pricingModel : typeof cost.pricing_model === "string" ? cost.pricing_model : "" : "";
|
|
9701
|
-
const billingMode = cost ? typeof cost.billingMode === "string" ? cost.billingMode : typeof cost.billing_mode === "string" ? cost.billing_mode : "" : "";
|
|
9702
|
-
if (deeplineCredits === 0) {
|
|
9703
|
-
console.log(" Cost: Free");
|
|
9704
|
-
return true;
|
|
9705
|
-
}
|
|
9706
|
-
if (pricingModel && deeplineCredits !== null) {
|
|
9707
|
-
const unit = pricingModel === "per_page" ? "page" : pricingModel === "per_result" ? "result" : "call";
|
|
9708
|
-
const usdText = deeplineUsdPerPricingUnit !== null ? ` / ${formatUsd(deeplineUsdPerPricingUnit)}` : "";
|
|
9709
|
-
const billingSuffix = billingMode ? ` (${billingMode})` : "";
|
|
9710
|
-
console.log(` Cost: ${formatDecimal(deeplineCredits)} Deepline credits${usdText} per ${unit}${billingSuffix}`);
|
|
9711
|
-
return true;
|
|
9712
|
-
}
|
|
9713
|
-
const summary = stringField(pricing, "summary");
|
|
9714
|
-
if (summary) {
|
|
9715
|
-
console.log(` Cost: ${summary}`);
|
|
9716
|
-
return true;
|
|
9717
|
-
}
|
|
9718
|
-
return false;
|
|
9719
|
-
}
|
|
9720
10265
|
function toolInputFieldsForDisplay(inputSchema) {
|
|
9721
10266
|
if (Array.isArray(inputSchema.fields)) return inputSchema.fields.filter(isRecord4);
|
|
9722
10267
|
const jsonSchema = isRecord4(inputSchema.jsonSchema) ? inputSchema.jsonSchema : inputSchema;
|
|
@@ -9767,17 +10312,6 @@ function listExtractorPathsFromUsageGuidance(tool) {
|
|
|
9767
10312
|
).filter(Boolean);
|
|
9768
10313
|
});
|
|
9769
10314
|
}
|
|
9770
|
-
function isPlayTool(tool) {
|
|
9771
|
-
const provider = typeof tool.provider === "string" ? tool.provider : "";
|
|
9772
|
-
return provider === "deepline_native" && Boolean(recordField(tool, "playExpansion", "play_expansion"));
|
|
9773
|
-
}
|
|
9774
|
-
function titleCase(value) {
|
|
9775
|
-
return value.replace(/[_-]+/g, " ").split(" ").filter(Boolean).map((part) => {
|
|
9776
|
-
const lower = part.toLowerCase();
|
|
9777
|
-
const special = { linkedin: "LinkedIn", crm: "CRM", api: "API" };
|
|
9778
|
-
return special[lower] ?? `${part[0]?.toUpperCase() ?? ""}${part.slice(1)}`;
|
|
9779
|
-
}).join(" ");
|
|
9780
|
-
}
|
|
9781
10315
|
function formatDecimal(value) {
|
|
9782
10316
|
const text = value.toFixed(12).replace(/0+$/, "").replace(/\.$/, "");
|
|
9783
10317
|
return text || "0";
|
|
@@ -10537,6 +11071,61 @@ function shouldDeferSkillsSyncForCommand() {
|
|
|
10537
11071
|
const subcommand = args[1];
|
|
10538
11072
|
return (command === "play" || command === "plays") && subcommand === "run" && args.includes("--json");
|
|
10539
11073
|
}
|
|
11074
|
+
async function runPlayRunnerHealthCheck() {
|
|
11075
|
+
const dir = await mkdtemp(join11(tmpdir4(), "deepline-health-play-"));
|
|
11076
|
+
const file = join11(dir, "health-check.play.ts");
|
|
11077
|
+
try {
|
|
11078
|
+
await writeFile4(
|
|
11079
|
+
file,
|
|
11080
|
+
[
|
|
11081
|
+
"import { definePlay } from 'deepline';",
|
|
11082
|
+
"",
|
|
11083
|
+
"export default definePlay('health-check', async (ctx) => {",
|
|
11084
|
+
" const rows = await ctx",
|
|
11085
|
+
" .map('health_rows', [{ id: 'a' }, { id: 'b' }])",
|
|
11086
|
+
" .step('echo', (row) => ({ ok: true, id: row.id }))",
|
|
11087
|
+
" .run({ key: 'id' });",
|
|
11088
|
+
" return { ok: true, rows, source: 'deepline health --play-runner' };",
|
|
11089
|
+
"});",
|
|
11090
|
+
""
|
|
11091
|
+
].join("\n"),
|
|
11092
|
+
"utf8"
|
|
11093
|
+
);
|
|
11094
|
+
let capturedOutput = "";
|
|
11095
|
+
const originalWrite = process.stdout.write.bind(process.stdout);
|
|
11096
|
+
process.stdout.write = ((chunk, ...args) => {
|
|
11097
|
+
capturedOutput += typeof chunk === "string" ? chunk : String(chunk);
|
|
11098
|
+
return true;
|
|
11099
|
+
});
|
|
11100
|
+
let exitCode = 1;
|
|
11101
|
+
try {
|
|
11102
|
+
exitCode = await handlePlayRun([
|
|
11103
|
+
file,
|
|
11104
|
+
"--input",
|
|
11105
|
+
"{}",
|
|
11106
|
+
"--watch",
|
|
11107
|
+
"--no-open",
|
|
11108
|
+
"--json"
|
|
11109
|
+
]);
|
|
11110
|
+
} finally {
|
|
11111
|
+
process.stdout.write = originalWrite;
|
|
11112
|
+
}
|
|
11113
|
+
if (exitCode !== 0) {
|
|
11114
|
+
throw new Error(
|
|
11115
|
+
`play runner canary exited ${exitCode}: ${capturedOutput.slice(0, 1e3)}`
|
|
11116
|
+
);
|
|
11117
|
+
}
|
|
11118
|
+
return {
|
|
11119
|
+
status: "ok",
|
|
11120
|
+
playRunner: {
|
|
11121
|
+
status: "ok",
|
|
11122
|
+
check: "no-provider local play run completed"
|
|
11123
|
+
}
|
|
11124
|
+
};
|
|
11125
|
+
} finally {
|
|
11126
|
+
await rm(dir, { recursive: true, force: true });
|
|
11127
|
+
}
|
|
11128
|
+
}
|
|
10540
11129
|
async function main() {
|
|
10541
11130
|
const mainStartedAt = Date.now();
|
|
10542
11131
|
recordCliTrace({
|
|
@@ -10548,7 +11137,7 @@ async function main() {
|
|
|
10548
11137
|
if (printStartupPhase) {
|
|
10549
11138
|
progress?.phase("loading deepline cli");
|
|
10550
11139
|
}
|
|
10551
|
-
const program = new
|
|
11140
|
+
const program = new Command3();
|
|
10552
11141
|
program.name("deepline").description("Deepline CLI (TypeScript SDK)").version(SDK_VERSION, "-v, --version", "Show version").showHelpAfterError().showSuggestionAfterError(true).addHelpText(
|
|
10553
11142
|
"after",
|
|
10554
11143
|
`
|
|
@@ -10557,7 +11146,7 @@ Common commands:
|
|
|
10557
11146
|
deepline auth status --json
|
|
10558
11147
|
deepline plays search email --json
|
|
10559
11148
|
deepline plays describe person-linkedin-to-email --json
|
|
10560
|
-
deepline plays run my.play.ts --input '{"domain":"stripe.com"}'
|
|
11149
|
+
deepline plays run my.play.ts --input '{"domain":"stripe.com"}'
|
|
10561
11150
|
deepline tools execute hunter_email_verifier --input '{"email":"a@b.com"}'
|
|
10562
11151
|
deepline update
|
|
10563
11152
|
|
|
@@ -10613,18 +11202,30 @@ Exit codes:
|
|
|
10613
11202
|
registerDbCommands(program);
|
|
10614
11203
|
registerFeedbackCommands(program);
|
|
10615
11204
|
registerUpdateCommand(program);
|
|
10616
|
-
program.command("health").description("Check server health.").option("--json", "Force JSON output.").
|
|
11205
|
+
program.command("health").description("Check server health.").option("--json", "Force JSON output.").option(
|
|
11206
|
+
"--play-runner",
|
|
11207
|
+
"Run a tiny no-provider play to verify the full play execution plane."
|
|
11208
|
+
).addHelpText(
|
|
10617
11209
|
"after",
|
|
10618
11210
|
`
|
|
10619
11211
|
Notes:
|
|
10620
11212
|
Read-only connectivity check for the configured Deepline host. Prints the raw
|
|
10621
11213
|
server health payload as JSON.
|
|
11214
|
+
Add --play-runner to verify bundling, coordinator dispatch, runtime callbacks,
|
|
11215
|
+
and run streaming with a tiny no-provider play.
|
|
10622
11216
|
|
|
10623
11217
|
Examples:
|
|
10624
11218
|
deepline health
|
|
11219
|
+
deepline health --play-runner
|
|
10625
11220
|
`
|
|
10626
|
-
).action(async () => {
|
|
11221
|
+
).action(async (options) => {
|
|
10627
11222
|
try {
|
|
11223
|
+
if (options.playRunner) {
|
|
11224
|
+
const data2 = await runPlayRunnerHealthCheck();
|
|
11225
|
+
process.stdout.write(`${JSON.stringify(data2, null, 2)}
|
|
11226
|
+
`);
|
|
11227
|
+
return;
|
|
11228
|
+
}
|
|
10628
11229
|
const client = new DeeplineClient();
|
|
10629
11230
|
const data = await client.health();
|
|
10630
11231
|
process.stdout.write(`${JSON.stringify(data, null, 2)}
|