deepline 0.1.23 → 0.1.25

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.
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/cli/index.ts
4
- import { Command } from "commander";
4
+ import { Command as Command2 } from "commander";
5
5
 
6
6
  // src/config.ts
7
7
  import { readFileSync, existsSync, mkdirSync, writeFileSync } from "fs";
@@ -243,7 +243,7 @@ function saveProjectDeeplineEnvValues(baseUrl, values, startDir = projectEnvStar
243
243
  }
244
244
 
245
245
  // src/version.ts
246
- var SDK_VERSION = "0.1.23";
246
+ var SDK_VERSION = "0.1.25";
247
247
  var SDK_API_CONTRACT = "2026-05-runs-v2";
248
248
 
249
249
  // ../shared_libs/play-runtime/coordinator-headers.ts
@@ -525,7 +525,7 @@ function decodeSseFrame(frame) {
525
525
  return parsed;
526
526
  }
527
527
  function sleep(ms) {
528
- return new Promise((resolve8) => setTimeout(resolve8, ms));
528
+ return new Promise((resolve9) => setTimeout(resolve9, ms));
529
529
  }
530
530
 
531
531
  // src/client.ts
@@ -533,7 +533,7 @@ var TERMINAL_PLAY_STATUSES = /* @__PURE__ */ new Set(["completed", "failed", "ca
533
533
  var INCLUDE_TOOL_METADATA_HEADER = "x-deepline-include-tool-metadata";
534
534
  var COMPILE_MANIFEST_RETRY_DELAYS_MS = [250, 1e3];
535
535
  function sleep2(ms) {
536
- return new Promise((resolve8) => setTimeout(resolve8, ms));
536
+ return new Promise((resolve9) => setTimeout(resolve9, ms));
537
537
  }
538
538
  function isTransientCompileManifestError(error) {
539
539
  if (error instanceof DeeplineError && typeof error.statusCode === "number") {
@@ -2023,7 +2023,7 @@ function buildCandidateUrls2(url) {
2023
2023
  }
2024
2024
  }
2025
2025
  function sleep3(ms) {
2026
- return new Promise((resolve8) => setTimeout(resolve8, ms));
2026
+ return new Promise((resolve9) => setTimeout(resolve9, ms));
2027
2027
  }
2028
2028
  function printDeeplineLogo() {
2029
2029
  if (process.stdout.isTTY && (process.stdout.columns ?? 80) >= 70) {
@@ -2330,18 +2330,48 @@ function registerAuthCommands(program) {
2330
2330
  `
2331
2331
  Common commands:
2332
2332
  deepline auth register
2333
+ deepline auth register --no-wait
2334
+ deepline auth wait --timeout 300
2333
2335
  deepline auth status
2334
2336
  deepline auth status --json
2337
+
2338
+ Notes:
2339
+ Registration opens a browser approval page by default. Use --no-wait in CI
2340
+ or agent runs, then finish with deepline auth wait.
2341
+ Auth status shows the target host and active workspace without printing secrets.
2335
2342
  `
2336
2343
  );
2337
- auth.command("register").description("Register this device and open the approval page in your browser.").option("--org-name <name>", "Workspace name to prefill").option("--agent-name <name>", "Agent name to register").option("--no-wait", "Return immediately after opening the approval page").action(async (options) => {
2344
+ auth.command("register").description("Register this device and open the approval page in your browser.").addHelpText(
2345
+ "after",
2346
+ `
2347
+ Notes:
2348
+ Opens a browser approval page and waits for approval unless --no-wait is set.
2349
+ The saved API key is scoped to the selected workspace and host.
2350
+
2351
+ Examples:
2352
+ deepline auth register
2353
+ deepline auth register --org-name Acme --agent-name local-cli
2354
+ deepline auth register --no-wait
2355
+ `
2356
+ ).option("--org-name <name>", "Workspace name to prefill").option("--agent-name <name>", "Agent name to register").option("--no-wait", "Return immediately after opening the approval page").action(async (options) => {
2338
2357
  process.exitCode = await handleRegister([
2339
2358
  ...options.orgName ? ["--org-name", options.orgName] : [],
2340
2359
  ...options.agentName ? ["--agent-name", options.agentName] : [],
2341
2360
  ...options.noWait || options.wait === false ? ["--no-wait"] : []
2342
2361
  ]);
2343
2362
  });
2344
- auth.command("wait").description("Wait for a pending browser approval and save the API key.").option("--timeout <seconds>", "Maximum seconds to wait", "300").action(async (options) => {
2363
+ auth.command("wait").description("Wait for a pending browser approval and save the API key.").addHelpText(
2364
+ "after",
2365
+ `
2366
+ Notes:
2367
+ Completes a previous deepline auth register --no-wait flow.
2368
+ Saves the approved API key into the host auth file.
2369
+
2370
+ Examples:
2371
+ deepline auth wait
2372
+ deepline auth wait --timeout 120
2373
+ `
2374
+ ).option("--timeout <seconds>", "Maximum seconds to wait", "300").action(async (options) => {
2345
2375
  process.exitCode = await handleWait([
2346
2376
  ...options.timeout ? ["--timeout", options.timeout] : []
2347
2377
  ]);
@@ -2367,6 +2397,10 @@ Examples:
2367
2397
  }
2368
2398
 
2369
2399
  // src/cli/commands/billing.ts
2400
+ import { Command } from "commander";
2401
+ import { appendFile, mkdir as mkdir2, writeFile as writeFile2 } from "fs/promises";
2402
+ import { dirname as dirname4, resolve as resolve3 } from "path";
2403
+ import { stringify as stringify2 } from "csv-stringify/sync";
2370
2404
  function humanize(value) {
2371
2405
  return String(value || "").split("_").filter(Boolean).map((token) => token[0]?.toUpperCase() + token.slice(1)).join(" ") || "Unknown";
2372
2406
  }
@@ -2384,6 +2418,54 @@ function printRecentUsage(entries) {
2384
2418
  `);
2385
2419
  }
2386
2420
  }
2421
+ function summarizeLedgerRows(summary, rows) {
2422
+ const netDelta = rows.reduce((sum, row) => {
2423
+ const value = Number.parseFloat(String(row.delta_credits ?? "").trim());
2424
+ return Number.isFinite(value) ? sum + value : sum;
2425
+ }, summary.net_delta_credits);
2426
+ return {
2427
+ row_count: summary.row_count + rows.length,
2428
+ net_delta_credits: Math.round((netDelta + Number.EPSILON) * 100) / 100
2429
+ };
2430
+ }
2431
+ function ledgerApiEntryToRow(entry) {
2432
+ const metadata = typeof entry.metadata === "object" && entry.metadata !== null ? entry.metadata : {};
2433
+ return {
2434
+ created_at: entry.created_at ?? "",
2435
+ delta_credits: entry.delta ?? "",
2436
+ reason: entry.reason ?? "",
2437
+ provider: metadata.provider ?? "",
2438
+ operation: metadata.operation ?? "",
2439
+ request_id: metadata.requestId ?? metadata.request_id ?? "",
2440
+ run_id: metadata.runId ?? metadata.run_id ?? "",
2441
+ api_key_id: entry.api_key_id ?? "",
2442
+ stripe_session_id: entry.stripe_session_id ?? ""
2443
+ };
2444
+ }
2445
+ function ledgerRowsToCsv(rows, header) {
2446
+ return stringify2(rows, {
2447
+ header,
2448
+ columns: [
2449
+ "created_at",
2450
+ "delta_credits",
2451
+ "reason",
2452
+ "provider",
2453
+ "operation",
2454
+ "request_id",
2455
+ "run_id",
2456
+ "api_key_id",
2457
+ "stripe_session_id"
2458
+ ]
2459
+ });
2460
+ }
2461
+ function defaultLedgerExportPath() {
2462
+ return resolve3(
2463
+ process.cwd(),
2464
+ "deepline",
2465
+ "data",
2466
+ `billing-ledger-all-${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-")}.csv`
2467
+ );
2468
+ }
2387
2469
  async function handleBalance(options) {
2388
2470
  const { http } = getAuthedHttpClient();
2389
2471
  const payload = await http.get("/api/v2/billing/balance");
@@ -2472,6 +2554,51 @@ async function handleHistory(options) {
2472
2554
  process.stdout.write(`${rows.length} row(s) exported.
2473
2555
  `);
2474
2556
  }
2557
+ async function handleLedgerExportAll(options) {
2558
+ const { http } = getAuthedHttpClient();
2559
+ const outputPath = options.output ? resolve3(String(options.output)) : defaultLedgerExportPath();
2560
+ let summary = { row_count: 0, net_delta_credits: 0 };
2561
+ let cursor = null;
2562
+ let initializedOutput = false;
2563
+ for (; ; ) {
2564
+ const params = new URLSearchParams({ limit: "5000" });
2565
+ if (cursor !== null) params.set("cursor", cursor);
2566
+ const payload = await http.get(
2567
+ `/api/v2/billing/ledger?${params.toString()}`
2568
+ );
2569
+ const entries = Array.isArray(payload.entries) ? payload.entries : [];
2570
+ const rows = entries.map(ledgerApiEntryToRow);
2571
+ if (!initializedOutput) {
2572
+ await mkdir2(dirname4(outputPath), { recursive: true });
2573
+ await writeFile2(outputPath, ledgerRowsToCsv([], true), "utf-8");
2574
+ initializedOutput = true;
2575
+ }
2576
+ if (rows.length > 0) {
2577
+ await appendFile(outputPath, ledgerRowsToCsv(rows, false), "utf-8");
2578
+ summary = summarizeLedgerRows(summary, rows);
2579
+ }
2580
+ const nextCursor = typeof payload.next_cursor === "string" && payload.next_cursor.length > 0 ? payload.next_cursor : null;
2581
+ if (rows.length === 0 || payload.has_more !== true || nextCursor === null) {
2582
+ break;
2583
+ }
2584
+ if (nextCursor === cursor) break;
2585
+ cursor = nextCursor;
2586
+ }
2587
+ if (shouldEmitJson(options.json)) {
2588
+ return printJson({
2589
+ output_path: outputPath,
2590
+ row_count: summary.row_count,
2591
+ net_delta_credits: summary.net_delta_credits,
2592
+ scope: "current_auth_context"
2593
+ });
2594
+ }
2595
+ process.stdout.write(`Billing ledger written to ${outputPath}
2596
+ `);
2597
+ process.stdout.write(`${summary.row_count} row(s) exported for the current auth context.
2598
+ `);
2599
+ process.stdout.write(`Net ledger delta: ${summary.net_delta_credits} Deepline Credits
2600
+ `);
2601
+ }
2475
2602
  async function handleCheckout(options) {
2476
2603
  const { http } = getAuthedHttpClient();
2477
2604
  const payload = await http.post("/api/v2/billing/checkout", {
@@ -2495,20 +2622,156 @@ async function handleRedeemCode(code, options) {
2495
2622
  `);
2496
2623
  }
2497
2624
  function registerBillingCommands(program) {
2498
- const billing = program.command("billing").description("Inspect balance, usage, limits, and checkout flows.");
2499
- billing.command("balance").description("Show current billing balance.").option("--json", "Emit JSON output").action(handleBalance);
2500
- billing.command("usage").description("Show current usage plus recent calls.").option("--limit <n>", "Recent-call page size").option("--offset <n>", "Recent-call offset").option("--json", "Emit JSON output").action(handleUsage);
2501
- billing.command("limit").description("Show configured monthly limit state.").option("--json", "Emit JSON output").action(handleLimit);
2502
- billing.command("set-limit").description("Set monthly credit cap.").argument("<credits>", "Monthly credits limit").option("--json", "Emit JSON output").action(handleSetLimit);
2503
- billing.command("off").description("Disable monthly credit cap.").option("--json", "Emit JSON output").action(handleLimitOff);
2504
- billing.command("history").description("Export billing ledger history to CSV.").requiredOption("--time <window>", "Rolling time window: 1d, 1w, 1m, or 1y").option("--json", "Emit JSON output").action(handleHistory);
2505
- billing.command("checkout").description("Create a checkout session and optionally open it in your browser.").option("--tier <tierId>", "Named pricing tier").option("--credits <credits>", "Custom credit amount").option("--discount-code <code>", "Apply a discount code").option("--no-open", "Print the checkout URL without opening a browser").option("--json", "Emit JSON output").action(handleCheckout);
2506
- billing.command("redeem-code").description("Redeem a billing code.").requiredOption("--code <code>", "Code to redeem").option("--no-open", "Do not open a browser").option("--json", "Emit JSON output").action(({ code, ...options }) => handleRedeemCode(code, options));
2625
+ const billing = program.command("billing").description("Inspect balance, usage, limits, and checkout flows.").addHelpText(
2626
+ "after",
2627
+ `
2628
+ Concepts:
2629
+ Billing commands show Deepline credits, not raw provider spend.
2630
+ set-limit/off mutate the monthly workspace cap. checkout/redeem-code can open
2631
+ a browser unless --no-open is set.
2632
+
2633
+ Examples:
2634
+ deepline billing balance --json
2635
+ deepline billing usage --limit 20 --json
2636
+ deepline billing set-limit 500 --json
2637
+ deepline billing checkout --credits 1000 --no-open --json
2638
+ `
2639
+ );
2640
+ billing.command("balance").description("Show current billing balance.").addHelpText(
2641
+ "after",
2642
+ `
2643
+ Notes:
2644
+ Read-only. Shows the current Deepline credit balance for the active workspace.
2645
+
2646
+ Examples:
2647
+ deepline billing balance
2648
+ deepline billing balance --json
2649
+ `
2650
+ ).option("--json", "Emit JSON output. Also automatic when stdout is piped").action(handleBalance);
2651
+ billing.command("usage").description("Show current usage plus recent calls.").addHelpText(
2652
+ "after",
2653
+ `
2654
+ Notes:
2655
+ Read-only. Shows last-30-day Deepline credit usage plus a bounded recent-call
2656
+ page. Use --limit/--offset to paginate the recent-call section.
2657
+
2658
+ Examples:
2659
+ deepline billing usage
2660
+ deepline billing usage --limit 50 --offset 50 --json
2661
+ `
2662
+ ).option("--limit <n>", "Recent-call page size").option("--offset <n>", "Recent-call offset").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(handleUsage);
2663
+ billing.command("limit").description("Show configured monthly limit state.").addHelpText(
2664
+ "after",
2665
+ `
2666
+ Notes:
2667
+ Read-only. Shows whether the monthly workspace cap is enabled and how many
2668
+ Deepline credits remain before the cap.
2669
+
2670
+ Examples:
2671
+ deepline billing limit
2672
+ deepline billing limit --json
2673
+ `
2674
+ ).option("--json", "Emit JSON output. Also automatic when stdout is piped").action(handleLimit);
2675
+ billing.command("set-limit").description("Set monthly credit cap.").addHelpText(
2676
+ "after",
2677
+ `
2678
+ Notes:
2679
+ Mutates workspace billing settings. The argument is a Deepline credit amount,
2680
+ not dollars and not provider credits.
2681
+
2682
+ Examples:
2683
+ deepline billing set-limit 500
2684
+ deepline billing set-limit 500 --json
2685
+ `
2686
+ ).argument("<credits>", "Monthly credits limit").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(handleSetLimit);
2687
+ billing.command("off").description("Disable monthly credit cap.").addHelpText(
2688
+ "after",
2689
+ `
2690
+ Notes:
2691
+ Mutates workspace billing settings by removing the monthly Deepline credit cap.
2692
+
2693
+ Examples:
2694
+ deepline billing off
2695
+ deepline billing off --json
2696
+ `
2697
+ ).option("--json", "Emit JSON output. Also automatic when stdout is piped").action(handleLimitOff);
2698
+ billing.command("ledger").description("Inspect and export billing ledger rows.").addHelpText(
2699
+ "after",
2700
+ `
2701
+ Notes:
2702
+ Read-only. Exports ledger rows for the current auth context. API-key auth is
2703
+ scoped by the server to that API key; session auth is scoped to the active
2704
+ workspace.
2705
+
2706
+ Examples:
2707
+ deepline billing ledger export all
2708
+ deepline billing ledger export all --output ./ledger.csv
2709
+ deepline billing ledger export all --json
2710
+ `
2711
+ ).addCommand(
2712
+ new Command("export").description("Export billing ledger rows.").addHelpText(
2713
+ "after",
2714
+ `
2715
+ Examples:
2716
+ deepline billing ledger export all
2717
+ `
2718
+ ).addCommand(
2719
+ new Command("all").description("Export all available billing ledger rows to CSV.").addHelpText(
2720
+ "after",
2721
+ `
2722
+ Notes:
2723
+ Pages through the ledger for the current auth context, writes CSV locally,
2724
+ then reports the row count and the net delta computed from delta_credits.
2725
+
2726
+ Examples:
2727
+ deepline billing ledger export all
2728
+ deepline billing ledger export all --json
2729
+ `
2730
+ ).option("--output <path>", "Write CSV to an explicit path").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(handleLedgerExportAll)
2731
+ )
2732
+ );
2733
+ billing.command("history").description("Export billing ledger history to CSV.").addHelpText(
2734
+ "after",
2735
+ `
2736
+ Notes:
2737
+ Read-only server query that writes a local CSV file. With --json, stdout is a
2738
+ summary containing the output path and row count.
2739
+
2740
+ Examples:
2741
+ deepline billing history --time 1m
2742
+ deepline billing history --time 1y --json
2743
+ `
2744
+ ).requiredOption("--time <window>", "Rolling time window: 1d, 1w, 1m, or 1y").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(handleHistory);
2745
+ billing.command("checkout").description("Create a checkout session and optionally open it in your browser.").addHelpText(
2746
+ "after",
2747
+ `
2748
+ Notes:
2749
+ Creates a payment checkout session. Opens the checkout URL in a browser unless
2750
+ --no-open is set. Use --json for automation.
2751
+
2752
+ Examples:
2753
+ deepline billing checkout --tier pro
2754
+ deepline billing checkout --credits 1000 --no-open --json
2755
+ deepline billing checkout --credits 1000 --discount-code LAUNCH --no-open
2756
+ `
2757
+ ).option("--tier <tierId>", "Named pricing tier").option("--credits <credits>", "Custom credit amount").option("--discount-code <code>", "Apply a discount code").option("--no-open", "Print the checkout URL without opening a browser").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(handleCheckout);
2758
+ billing.command("redeem-code").description("Redeem a billing code.").addHelpText(
2759
+ "after",
2760
+ `
2761
+ Notes:
2762
+ Redeems a workspace billing code and may open a browser for completion unless
2763
+ --no-open is set.
2764
+
2765
+ Examples:
2766
+ deepline billing redeem-code --code ABC123
2767
+ deepline billing redeem-code --code ABC123 --no-open --json
2768
+ `
2769
+ ).requiredOption("--code <code>", "Code to redeem").option("--no-open", "Do not open a browser").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(({ code, ...options }) => handleRedeemCode(code, options));
2507
2770
  }
2508
2771
 
2509
2772
  // src/cli/dataset-stats.ts
2510
2773
  import { writeFileSync as writeFileSync4 } from "fs";
2511
- import { resolve as resolve3 } from "path";
2774
+ import { resolve as resolve4 } from "path";
2512
2775
  var CSV_PROJECTED_FIELDS_KEY = "__deeplineCsvProjectedFields";
2513
2776
  function csvProjectedFields(row) {
2514
2777
  const serialized = row[CSV_PROJECTED_FIELDS_KEY];
@@ -2838,7 +3101,7 @@ function writeCanonicalRowsCsv(rowsInfo, outPath) {
2838
3101
  rows: rowsInfo.rows,
2839
3102
  columns: rowsInfo.columns
2840
3103
  });
2841
- const resolved = resolve3(outPath);
3104
+ const resolved = resolve4(outPath);
2842
3105
  writeFileSync4(
2843
3106
  resolved,
2844
3107
  csvStringFromRows(sanitized.rows, sanitized.columns),
@@ -2934,8 +3197,31 @@ async function handleCsvShow(options) {
2934
3197
  `);
2935
3198
  }
2936
3199
  function registerCsvCommands(program) {
2937
- const csv = program.command("csv").description("Inspect local CSV files.");
2938
- csv.command("show").description("Display rows from a CSV file in json, csv, or table form.").requiredOption("--csv <path>", "Input CSV path").option("--format <format>", "Output format: json, csv, or table", "json").option("--rows <range>", "Row range start:end", "0:19").option("--columns <names>", "Comma-separated column names to include").option("--summary", "Print a summary payload instead of row output").option("--verbose", "Do not truncate long values in table output").action(handleCsvShow);
3200
+ const csv = program.command("csv").description("Inspect local CSV files.").addHelpText(
3201
+ "after",
3202
+ `
3203
+ Notes:
3204
+ Local-only inspection helpers. These commands do not upload CSV files or call
3205
+ Deepline APIs.
3206
+
3207
+ Examples:
3208
+ deepline csv show --csv leads.csv --rows 0:10 --format table
3209
+ deepline csv show --csv leads.csv --summary
3210
+ `
3211
+ );
3212
+ csv.command("show").description("Display rows from a CSV file in json, csv, or table form.").addHelpText(
3213
+ "after",
3214
+ `
3215
+ Notes:
3216
+ Reads a local CSV path and prints a bounded row range. --rows uses inclusive
3217
+ start:end indexes, so 0:19 prints the first 20 rows. JSON is the default format.
3218
+
3219
+ Examples:
3220
+ deepline csv show --csv leads.csv
3221
+ deepline csv show --csv leads.csv --rows 20:39 --columns name,email --format table
3222
+ deepline csv show --csv leads.csv --summary
3223
+ `
3224
+ ).requiredOption("--csv <path>", "Input CSV path").option("--format <format>", "Output format: json, csv, or table", "json").option("--rows <range>", "Row range start:end", "0:19").option("--columns <names>", "Comma-separated column names to include").option("--summary", "Print a summary payload instead of row output").option("--verbose", "Do not truncate long values in table output").action(handleCsvShow);
2939
3225
  }
2940
3226
 
2941
3227
  // src/cli/commands/db.ts
@@ -3015,8 +3301,32 @@ async function handleDbQuery(args) {
3015
3301
  return 0;
3016
3302
  }
3017
3303
  function registerDbCommands(program) {
3018
- const db = program.command("db").alias("customer-db").description("Query the tenant customer database.");
3019
- db.command("query").alias("psql").description("Run SQL against the tenant customer database.").requiredOption("--sql <sql>", "SQL statement").option("--max-rows <n>", "Maximum returned rows").option("--json", "Emit raw JSON response").action(async (options) => {
3304
+ const db = program.command("db").alias("customer-db").description("Query the tenant customer database.").addHelpText(
3305
+ "after",
3306
+ `
3307
+ Notes:
3308
+ Runs SQL against the active workspace customer database through Deepline APIs.
3309
+ Results are bounded by the server and --max-rows. Use --json for stable output.
3310
+
3311
+ Examples:
3312
+ deepline db query --sql "select * from companies limit 20"
3313
+ deepline db query --sql "select domain, name from companies limit 20" --json
3314
+ deepline db query --sql "select * from contacts" --max-rows 100 --json
3315
+ `
3316
+ );
3317
+ db.command("query").alias("psql").description("Run SQL against the tenant customer database.").addHelpText(
3318
+ "after",
3319
+ `
3320
+ Notes:
3321
+ Requires --sql. Output is a compact table in a terminal and raw JSON with
3322
+ --json or when stdout is piped. The active auth workspace determines scope.
3323
+
3324
+ Examples:
3325
+ deepline db query --sql "select * from companies limit 20"
3326
+ deepline db query --sql "select domain, name from companies limit 20" --json
3327
+ deepline db psql --sql "select count(*) from contacts" --json
3328
+ `
3329
+ ).requiredOption("--sql <sql>", "SQL statement").option("--max-rows <n>", "Maximum returned rows").option("--json", "Emit raw JSON response. Also automatic when stdout is piped").action(async (options) => {
3020
3330
  process.exitCode = await handleDbQuery([
3021
3331
  "--sql",
3022
3332
  options.sql,
@@ -3042,9 +3352,29 @@ async function handleFeedback(text, options) {
3042
3352
  process.stdout.write("Feedback submitted. Thank you.\n");
3043
3353
  }
3044
3354
  function registerFeedbackCommands(program) {
3045
- const feedback = program.command("feedback").description("Submit CLI feedback to Deepline.");
3355
+ const feedback = program.command("feedback").description("Submit CLI feedback to Deepline.").addHelpText(
3356
+ "after",
3357
+ `
3358
+ Notes:
3359
+ Sends the feedback text plus local CLI environment info to Deepline support.
3360
+ Use --command and --payload to attach a reproducible command shape.
3361
+
3362
+ Examples:
3363
+ deepline feedback "plays run failed after upload" --command "deepline plays run my.play.ts --watch"
3364
+ deepline feedback "unexpected billing output" --payload '{"command":"billing usage"}' --json
3365
+ `
3366
+ );
3046
3367
  feedback.argument("<text>", "Feedback text").option("--command <command>", "Command that reproduced the issue").option("--payload <payload>", "JSON or plain-text payload for the repro").option("--json", "Emit JSON output").action(handleFeedback);
3047
- program.command("provide-feedback").description("Legacy alias for `deepline feedback`.").argument("<text>", "Feedback text").option("--command <command>", "Command that reproduced the issue").option("--payload <payload>", "JSON or plain-text payload for the repro").option("--json", "Emit JSON output").action(handleFeedback);
3368
+ program.command("provide-feedback").description("Legacy alias for `deepline feedback`.").addHelpText(
3369
+ "after",
3370
+ `
3371
+ Notes:
3372
+ Compatibility alias. Prefer deepline feedback in new scripts and docs.
3373
+
3374
+ Examples:
3375
+ deepline feedback "tools search returned stale results" --json
3376
+ `
3377
+ ).argument("<text>", "Feedback text").option("--command <command>", "Command that reproduced the issue").option("--payload <payload>", "JSON or plain-text payload for the repro").option("--json", "Emit JSON output").action(handleFeedback);
3048
3378
  }
3049
3379
 
3050
3380
  // src/cli/commands/org.ts
@@ -3124,9 +3454,43 @@ async function handleOrgSwitch(selection, options) {
3124
3454
  `);
3125
3455
  }
3126
3456
  function registerOrgCommands(program) {
3127
- const org = program.command("org").description("List and switch organizations.");
3128
- org.command("list").description("List your organizations.").option("--json", "Emit JSON output").action(handleOrgList);
3129
- org.command("switch [selection]").description("Switch to another organization and save the new API key in the host auth file.").option("--org-id <id>", "Switch using an explicit organization id").option("--json", "Emit JSON output").action(handleOrgSwitch);
3457
+ const org = program.command("org").description("List and switch organizations.").addHelpText(
3458
+ "after",
3459
+ `
3460
+ Notes:
3461
+ Organizations are workspaces. Switching organizations mutates the saved host
3462
+ auth file so later CLI commands target the selected workspace.
3463
+
3464
+ Examples:
3465
+ deepline org list --json
3466
+ deepline org switch 2
3467
+ deepline org switch --org-id org_123 --json
3468
+ `
3469
+ );
3470
+ org.command("list").description("List your organizations.").addHelpText(
3471
+ "after",
3472
+ `
3473
+ Notes:
3474
+ Read-only. Marks the active organization when the server returns that metadata.
3475
+
3476
+ Examples:
3477
+ deepline org list
3478
+ deepline org list --json
3479
+ `
3480
+ ).option("--json", "Emit JSON output. Also automatic when stdout is piped").action(handleOrgList);
3481
+ org.command("switch [selection]").description("Switch to another organization and save the new API key in the host auth file.").addHelpText(
3482
+ "after",
3483
+ `
3484
+ Notes:
3485
+ Mutates the saved host auth file. Selection can be a list number, exact
3486
+ organization name, or organization id. Without a selection, prints choices.
3487
+
3488
+ Examples:
3489
+ deepline org switch
3490
+ deepline org switch 2
3491
+ deepline org switch --org-id org_123 --json
3492
+ `
3493
+ ).option("--org-id <id>", "Switch using an explicit organization id").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(handleOrgSwitch);
3130
3494
  }
3131
3495
 
3132
3496
  // src/cli/commands/play.ts
@@ -3138,19 +3502,19 @@ import {
3138
3502
  realpathSync,
3139
3503
  writeFileSync as writeFileSync5
3140
3504
  } from "fs";
3141
- import { basename as basename3, dirname as dirname7, join as join6, resolve as resolve7 } from "path";
3505
+ import { basename as basename3, dirname as dirname8, join as join6, resolve as resolve8 } from "path";
3142
3506
 
3143
3507
  // src/plays/bundle-play-file.ts
3144
3508
  import { tmpdir as tmpdir2 } from "os";
3145
- import { dirname as dirname6, join as join5, resolve as resolve6 } from "path";
3509
+ import { dirname as dirname7, join as join5, resolve as resolve7 } from "path";
3146
3510
  import { fileURLToPath } from "url";
3147
3511
  import { existsSync as existsSync4 } from "fs";
3148
3512
 
3149
3513
  // ../shared_libs/plays/bundling/index.ts
3150
3514
  import { createHash } from "crypto";
3151
- import { mkdir as mkdir2, readFile, realpath, stat, writeFile as writeFile2 } from "fs/promises";
3515
+ import { mkdir as mkdir3, readFile, realpath, stat, writeFile as writeFile3 } from "fs/promises";
3152
3516
  import { tmpdir } from "os";
3153
- import { basename, dirname as dirname4, extname, isAbsolute, join as join3, resolve as resolve4 } from "path";
3517
+ import { basename, dirname as dirname5, extname, isAbsolute, join as join3, resolve as resolve5 } from "path";
3154
3518
  import { builtinModules, createRequire } from "module";
3155
3519
  import { build } from "esbuild";
3156
3520
 
@@ -3243,13 +3607,13 @@ async function normalizeLocalPath(filePath) {
3243
3607
  try {
3244
3608
  return await realpath(filePath);
3245
3609
  } catch {
3246
- return resolve4(filePath);
3610
+ return resolve5(filePath);
3247
3611
  }
3248
3612
  }
3249
3613
  function createPlayWorkspace(entryFile) {
3250
3614
  return {
3251
3615
  entryFile,
3252
- rootDir: dirname4(entryFile)
3616
+ rootDir: dirname5(entryFile)
3253
3617
  };
3254
3618
  }
3255
3619
  function isPathInsideDirectory(filePath, directory) {
@@ -3450,7 +3814,7 @@ function workersNamedPlayEntryAliasPlugin(playFilePath, exportName) {
3450
3814
  contents: `export { ${exportName} as default } from ${JSON.stringify(playFilePath)};
3451
3815
  `,
3452
3816
  loader: "ts",
3453
- resolveDir: dirname4(playFilePath)
3817
+ resolveDir: dirname5(playFilePath)
3454
3818
  })
3455
3819
  );
3456
3820
  }
@@ -3614,7 +3978,7 @@ function importedPlayProxyPlugin(importedPlayDependencies) {
3614
3978
  return {
3615
3979
  contents: buildImportedPlayProxyModule(dependency.playName),
3616
3980
  loader: "ts",
3617
- resolveDir: dirname4(args.path)
3981
+ resolveDir: dirname5(args.path)
3618
3982
  };
3619
3983
  });
3620
3984
  }
@@ -3632,7 +3996,7 @@ async function resolveLocalImport(fromFile, specifier) {
3632
3996
  if (specifier.startsWith("file:")) {
3633
3997
  return normalizeLocalPath(new URL(specifier).pathname);
3634
3998
  }
3635
- const base = isAbsolute(specifier) ? resolve4(specifier) : resolve4(dirname4(fromFile), specifier);
3999
+ const base = isAbsolute(specifier) ? resolve5(specifier) : resolve5(dirname5(fromFile), specifier);
3636
4000
  const candidates = [base];
3637
4001
  const explicitExtension = extname(base).toLowerCase();
3638
4002
  if (!explicitExtension) {
@@ -3833,8 +4197,8 @@ async function readArtifactCache(graphHash, artifactKind, adapter) {
3833
4197
  }
3834
4198
  async function writeArtifactCache(artifact, adapter) {
3835
4199
  const cacheDir = adapter.cacheDir ?? PLAY_ARTIFACT_CACHE_DIR;
3836
- await mkdir2(cacheDir, { recursive: true });
3837
- await writeFile2(
4200
+ await mkdir3(cacheDir, { recursive: true });
4201
+ await writeFile3(
3838
4202
  artifactCachePath(
3839
4203
  artifact.graphHash,
3840
4204
  artifact.artifactKind ?? PLAY_ARTIFACT_KINDS.cjsNode20,
@@ -3850,7 +4214,7 @@ function normalizeSourceMapForRuntime(sourceMapText) {
3850
4214
  if (sourcePath.startsWith("data:") || sourcePath.startsWith("node:") || sourcePath.startsWith("/") || /^[a-zA-Z]+:\/\//.test(sourcePath)) {
3851
4215
  return sourcePath;
3852
4216
  }
3853
- return resolve4(process.cwd(), sourcePath);
4217
+ return resolve5(process.cwd(), sourcePath);
3854
4218
  });
3855
4219
  parsed.sourceRoot = void 0;
3856
4220
  return JSON.stringify(parsed);
@@ -3882,7 +4246,7 @@ async function runEsbuildForCjsNode(entryFile, importedPlayDependencies, adapter
3882
4246
  ...namedExportShim ? {
3883
4247
  stdin: {
3884
4248
  contents: namedExportShim,
3885
- resolveDir: dirname4(entryFile),
4249
+ resolveDir: dirname5(entryFile),
3886
4250
  sourcefile: `${basename(entryFile)}.${exportName}.entry.ts`,
3887
4251
  loader: "ts"
3888
4252
  }
@@ -4172,7 +4536,7 @@ function resolveExecutionProfile(override) {
4172
4536
  // src/plays/local-file-discovery.ts
4173
4537
  import { createHash as createHash2 } from "crypto";
4174
4538
  import { readFile as readFile2, stat as stat2 } from "fs/promises";
4175
- import { basename as basename2, dirname as dirname5, extname as extname2, isAbsolute as isAbsolute2, join as join4, relative, resolve as resolve5 } from "path";
4539
+ import { basename as basename2, dirname as dirname6, extname as extname2, isAbsolute as isAbsolute2, join as join4, relative, resolve as resolve6 } from "path";
4176
4540
  var SOURCE_EXTENSIONS2 = [".ts", ".tsx", ".mts", ".cts", ".js", ".jsx", ".mjs", ".cjs", ".json"];
4177
4541
  function sha2562(buffer) {
4178
4542
  return createHash2("sha256").update(buffer).digest("hex");
@@ -4373,7 +4737,7 @@ function isPathInsideDirectory2(filePath, directory) {
4373
4737
  return relativePath === "" || !relativePath.startsWith("..") && !isAbsolute2(relativePath);
4374
4738
  }
4375
4739
  async function resolveLocalImport2(fromFile, specifier) {
4376
- const base = isAbsolute2(specifier) ? resolve5(specifier) : resolve5(dirname5(fromFile), specifier);
4740
+ const base = isAbsolute2(specifier) ? resolve6(specifier) : resolve6(dirname6(fromFile), specifier);
4377
4741
  const candidates = [base];
4378
4742
  const explicitExtension = extname2(base).toLowerCase();
4379
4743
  if (!explicitExtension) {
@@ -4391,13 +4755,13 @@ async function resolveLocalImport2(fromFile, specifier) {
4391
4755
  throw new Error(`Could not resolve local import "${specifier}" from ${fromFile}`);
4392
4756
  }
4393
4757
  async function discoverPackagedLocalFiles(entryFile) {
4394
- const absoluteEntryFile = resolve5(entryFile);
4395
- const packagingRoot = dirname5(absoluteEntryFile);
4758
+ const absoluteEntryFile = resolve6(entryFile);
4759
+ const packagingRoot = dirname6(absoluteEntryFile);
4396
4760
  const files = /* @__PURE__ */ new Map();
4397
4761
  const unresolved = [];
4398
4762
  const visitedFiles = /* @__PURE__ */ new Set();
4399
4763
  const visitSourceFile = async (filePath) => {
4400
- const absolutePath = resolve5(filePath);
4764
+ const absolutePath = resolve6(filePath);
4401
4765
  if (visitedFiles.has(absolutePath)) {
4402
4766
  return;
4403
4767
  }
@@ -4429,7 +4793,7 @@ async function discoverPackagedLocalFiles(entryFile) {
4429
4793
  message: "Could not resolve this ctx.csv(...) path at submit time. Use a string literal, a top-level const string, or pass a runtime input like input.file."
4430
4794
  });
4431
4795
  } else {
4432
- const absoluteCsvPath = resolve5(dirname5(absolutePath), resolvedPath);
4796
+ const absoluteCsvPath = resolve6(dirname6(absolutePath), resolvedPath);
4433
4797
  if (isAbsolute2(resolvedPath) || !isPathInsideDirectory2(absoluteCsvPath, packagingRoot)) {
4434
4798
  unresolved.push({
4435
4799
  sourceFragment: sourceCode.slice(argument.start, argument.end).trim(),
@@ -4468,24 +4832,24 @@ async function discoverPackagedLocalFiles(entryFile) {
4468
4832
 
4469
4833
  // src/plays/bundle-play-file.ts
4470
4834
  var PLAY_BUNDLE_CACHE_VERSION2 = 26;
4471
- var MODULE_DIR = dirname6(fileURLToPath(import.meta.url));
4472
- var SDK_PACKAGE_ROOT = resolve6(MODULE_DIR, "..", "..");
4473
- var SOURCE_REPO_ROOT = resolve6(SDK_PACKAGE_ROOT, "..");
4835
+ var MODULE_DIR = dirname7(fileURLToPath(import.meta.url));
4836
+ var SDK_PACKAGE_ROOT = resolve7(MODULE_DIR, "..", "..");
4837
+ var SOURCE_REPO_ROOT = resolve7(SDK_PACKAGE_ROOT, "..");
4474
4838
  var HAS_SOURCE_BUNDLING_SOURCES = existsSync4(
4475
- resolve6(SOURCE_REPO_ROOT, "apps", "play-runner-workers", "src", "entry.ts")
4839
+ resolve7(SOURCE_REPO_ROOT, "apps", "play-runner-workers", "src", "entry.ts")
4476
4840
  );
4477
- var PACKAGED_REPO_ROOT = resolve6(SDK_PACKAGE_ROOT, "dist", "repo");
4841
+ var PACKAGED_REPO_ROOT = resolve7(SDK_PACKAGE_ROOT, "dist", "repo");
4478
4842
  var HAS_PACKAGED_BUNDLING_SOURCES = existsSync4(
4479
- resolve6(PACKAGED_REPO_ROOT, "apps", "play-runner-workers", "src", "entry.ts")
4843
+ resolve7(PACKAGED_REPO_ROOT, "apps", "play-runner-workers", "src", "entry.ts")
4480
4844
  );
4481
- var PROJECT_ROOT = HAS_SOURCE_BUNDLING_SOURCES ? SOURCE_REPO_ROOT : HAS_PACKAGED_BUNDLING_SOURCES ? PACKAGED_REPO_ROOT : resolve6(SDK_PACKAGE_ROOT, "..");
4482
- var SDK_SOURCE_ROOT = HAS_SOURCE_BUNDLING_SOURCES ? resolve6(SOURCE_REPO_ROOT, "sdk", "src") : HAS_PACKAGED_BUNDLING_SOURCES ? resolve6(PACKAGED_REPO_ROOT, "sdk", "src") : resolve6(SDK_PACKAGE_ROOT, "src");
4483
- var SDK_PACKAGE_JSON = resolve6(SDK_PACKAGE_ROOT, "package.json");
4484
- var SDK_ENTRY_FILE = resolve6(SDK_SOURCE_ROOT, "index.ts");
4485
- var SDK_TYPES_ENTRY_FILE = HAS_SOURCE_BUNDLING_SOURCES ? SDK_ENTRY_FILE : resolve6(SDK_PACKAGE_ROOT, "dist", "index.d.ts");
4486
- var SDK_WORKERS_ENTRY_FILE = resolve6(SDK_SOURCE_ROOT, "worker-play-entry.ts");
4487
- var WORKERS_HARNESS_ENTRY_FILE = resolve6(PROJECT_ROOT, "apps", "play-runner-workers", "src", "entry.ts");
4488
- var WORKERS_HARNESS_FILES_DIR = resolve6(PROJECT_ROOT, "apps", "play-runner-workers", "src");
4845
+ var PROJECT_ROOT = HAS_SOURCE_BUNDLING_SOURCES ? SOURCE_REPO_ROOT : HAS_PACKAGED_BUNDLING_SOURCES ? PACKAGED_REPO_ROOT : resolve7(SDK_PACKAGE_ROOT, "..");
4846
+ var SDK_SOURCE_ROOT = HAS_SOURCE_BUNDLING_SOURCES ? resolve7(SOURCE_REPO_ROOT, "sdk", "src") : HAS_PACKAGED_BUNDLING_SOURCES ? resolve7(PACKAGED_REPO_ROOT, "sdk", "src") : resolve7(SDK_PACKAGE_ROOT, "src");
4847
+ var SDK_PACKAGE_JSON = resolve7(SDK_PACKAGE_ROOT, "package.json");
4848
+ var SDK_ENTRY_FILE = resolve7(SDK_SOURCE_ROOT, "index.ts");
4849
+ var SDK_TYPES_ENTRY_FILE = HAS_SOURCE_BUNDLING_SOURCES ? SDK_ENTRY_FILE : resolve7(SDK_PACKAGE_ROOT, "dist", "index.d.ts");
4850
+ var SDK_WORKERS_ENTRY_FILE = resolve7(SDK_SOURCE_ROOT, "worker-play-entry.ts");
4851
+ var WORKERS_HARNESS_ENTRY_FILE = resolve7(PROJECT_ROOT, "apps", "play-runner-workers", "src", "entry.ts");
4852
+ var WORKERS_HARNESS_FILES_DIR = resolve7(PROJECT_ROOT, "apps", "play-runner-workers", "src");
4489
4853
  var hasWarnedAboutNonDevelopmentBundling = false;
4490
4854
  function warnAboutNonDevelopmentBundling(filePath) {
4491
4855
  if (hasWarnedAboutNonDevelopmentBundling) {
@@ -4509,7 +4873,7 @@ function defaultPlayBundleTarget() {
4509
4873
  function createSdkPlayBundlingAdapter() {
4510
4874
  return {
4511
4875
  projectRoot: PROJECT_ROOT,
4512
- nodeModulesDir: resolve6(PROJECT_ROOT, "node_modules"),
4876
+ nodeModulesDir: resolve7(PROJECT_ROOT, "node_modules"),
4513
4877
  cacheDir: join5(tmpdir2(), `deepline-play-artifacts-v${PLAY_BUNDLE_CACHE_VERSION2}`),
4514
4878
  sdkSourceRoot: SDK_SOURCE_ROOT,
4515
4879
  sdkPackageJson: SDK_PACKAGE_JSON,
@@ -4790,7 +5154,7 @@ function formatPlayListReference(play) {
4790
5154
  function defaultMaterializedPlayPath(reference) {
4791
5155
  const playName = parseReferencedPlayTarget(reference).unqualifiedPlayName;
4792
5156
  const safeName = playName.trim().toLowerCase().replace(/[^a-z0-9-]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
4793
- return resolve7(`${safeName || "play"}.play.ts`);
5157
+ return resolve8(`${safeName || "play"}.play.ts`);
4794
5158
  }
4795
5159
  function materializeRemotePlaySource(input) {
4796
5160
  if (isFileTarget(input.target)) {
@@ -4853,7 +5217,7 @@ function extractPlayName(code, filePath) {
4853
5217
  throw buildMissingDefinePlayError(filePath);
4854
5218
  }
4855
5219
  function isFileTarget(target) {
4856
- return existsSync5(resolve7(target));
5220
+ return existsSync5(resolve8(target));
4857
5221
  }
4858
5222
  function looksLikeFilePath(target) {
4859
5223
  if (target.trim().toLowerCase().startsWith("prebuilt/")) {
@@ -4872,7 +5236,7 @@ function parsePositiveInteger2(value, flagName) {
4872
5236
  return parsed;
4873
5237
  }
4874
5238
  function parseJsonInput(raw) {
4875
- const source = raw.startsWith("@") ? readFileSync3(resolve7(raw.slice(1)), "utf-8") : raw;
5239
+ const source = raw.startsWith("@") ? readFileSync3(resolve8(raw.slice(1)), "utf-8") : raw;
4876
5240
  const parsed = JSON.parse(source);
4877
5241
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
4878
5242
  throw new Error("--input must be a JSON object.");
@@ -4982,7 +5346,7 @@ function applyCsvShortcutInput(input) {
4982
5346
  function isLocalFilePathValue(value) {
4983
5347
  if (typeof value !== "string" || !value.trim()) return false;
4984
5348
  if (/^[a-z][a-z0-9+.-]*:\/\//i.test(value.trim())) return false;
4985
- return existsSync5(resolve7(value));
5349
+ return existsSync5(resolve8(value));
4986
5350
  }
4987
5351
  function inputContainsLocalFilePath(value) {
4988
5352
  if (isLocalFilePathValue(value)) {
@@ -5008,7 +5372,7 @@ async function stageFileInputArgs(input) {
5008
5372
  const localFiles = uniqueBindings.flatMap((binding) => {
5009
5373
  const value = getDottedInputValue(input.runtimeInput, binding.inputPath);
5010
5374
  if (!isLocalFilePathValue(value)) return [];
5011
- const absolutePath = resolve7(value);
5375
+ const absolutePath = resolve8(value);
5012
5376
  return [{ binding, absolutePath, logicalPath: basename3(absolutePath) }];
5013
5377
  });
5014
5378
  if (localFiles.length === 0) {
@@ -5044,9 +5408,9 @@ function stageFile(logicalPath, absolutePath) {
5044
5408
  }
5045
5409
  function normalizePlayPath(filePath) {
5046
5410
  try {
5047
- return realpathSync.native(resolve7(filePath));
5411
+ return realpathSync.native(resolve8(filePath));
5048
5412
  } catch {
5049
- return resolve7(filePath);
5413
+ return resolve8(filePath);
5050
5414
  }
5051
5415
  }
5052
5416
  function formatBundlingErrors(filePath, errors) {
@@ -6072,7 +6436,7 @@ function parsePlayRunOptions(args) {
6072
6436
  let input = null;
6073
6437
  let revisionId = null;
6074
6438
  let revisionSelector = null;
6075
- const watch = args.includes("--watch");
6439
+ const watch = args.includes("--watch") || args.includes("--wait");
6076
6440
  let jsonOutput = watch ? args.includes("--json") : argsWantJson(args);
6077
6441
  const emitLogs = !jsonOutput || args.includes("--logs");
6078
6442
  const force = args.includes("--force");
@@ -6106,7 +6470,7 @@ function parsePlayRunOptions(args) {
6106
6470
  continue;
6107
6471
  }
6108
6472
  if (arg === "--out" && args[index + 1]) {
6109
- outPath = resolve7(args[++index]);
6473
+ outPath = resolve8(args[++index]);
6110
6474
  continue;
6111
6475
  }
6112
6476
  if (arg === "--poll-interval-ms" || arg === "--interval-ms") {
@@ -6122,15 +6486,13 @@ function parsePlayRunOptions(args) {
6122
6486
  if (arg === "--watch") {
6123
6487
  continue;
6124
6488
  }
6489
+ if (arg === "--wait") {
6490
+ continue;
6491
+ }
6125
6492
  if (arg === "--json") {
6126
6493
  jsonOutput = true;
6127
6494
  continue;
6128
6495
  }
6129
- if (arg === "--wait") {
6130
- throw new Error(
6131
- "--wait is removed for `plays run`; use `--watch` to stream completion output."
6132
- );
6133
- }
6134
6496
  if (arg === "--tail") {
6135
6497
  throw new Error(
6136
6498
  "--tail is removed for `plays run`; use `--watch` to stream completion output."
@@ -6208,11 +6570,11 @@ function shouldUseLocalOnlyPlayCheck() {
6208
6570
  async function handlePlayCheck(args) {
6209
6571
  const options = parsePlayCheckOptions(args);
6210
6572
  if (!isFileTarget(options.target)) {
6211
- const resolved = resolve7(options.target);
6573
+ const resolved = resolve8(options.target);
6212
6574
  console.error(`File not found: ${resolved}`);
6213
6575
  return 1;
6214
6576
  }
6215
- const absolutePlayPath = resolve7(options.target);
6577
+ const absolutePlayPath = resolve8(options.target);
6216
6578
  const sourceCode = readFileSync3(absolutePlayPath, "utf-8");
6217
6579
  let graph;
6218
6580
  try {
@@ -6276,7 +6638,7 @@ async function handleFileBackedRun(options) {
6276
6638
  }
6277
6639
  const client = new DeeplineClient();
6278
6640
  const progress = getActiveCliProgress() ?? createCliProgress(!options.jsonOutput);
6279
- const absolutePlayPath = resolve7(options.target.path);
6641
+ const absolutePlayPath = resolve8(options.target.path);
6280
6642
  progress.phase("compiling play");
6281
6643
  const sourceCode = traceCliSync(
6282
6644
  "cli.play_file_read_source",
@@ -6565,9 +6927,9 @@ async function handlePlayRun(args) {
6565
6927
  if (isFileTarget(options.target.path)) {
6566
6928
  return handleFileBackedRun(options);
6567
6929
  }
6568
- const resolved = resolve7(options.target.path);
6930
+ const resolved = resolve8(options.target.path);
6569
6931
  console.error(`File not found: ${resolved}`);
6570
- const dir = dirname7(resolved);
6932
+ const dir = dirname8(resolved);
6571
6933
  if (existsSync5(dir)) {
6572
6934
  const base = basename3(resolved);
6573
6935
  try {
@@ -6723,7 +7085,7 @@ async function handleRunLogs(args) {
6723
7085
  continue;
6724
7086
  }
6725
7087
  if (arg === "--out" && args[index + 1]) {
6726
- outPath = resolve7(args[++index]);
7088
+ outPath = resolve8(args[++index]);
6727
7089
  }
6728
7090
  }
6729
7091
  const client = new DeeplineClient();
@@ -6810,7 +7172,7 @@ async function handleRunExport(args) {
6810
7172
  for (let index = 0; index < args.length; index += 1) {
6811
7173
  const arg = args[index];
6812
7174
  if (arg === "--out" && args[index + 1]) {
6813
- outPath = resolve7(args[++index]);
7175
+ outPath = resolve8(args[++index]);
6814
7176
  }
6815
7177
  }
6816
7178
  if (!outPath) {
@@ -6850,10 +7212,10 @@ async function handlePlayGet(args) {
6850
7212
  for (let index = 1; index < args.length; index += 1) {
6851
7213
  const arg = args[index];
6852
7214
  if (arg === "--out" && args[index + 1]) {
6853
- outPath = resolve7(args[++index]);
7215
+ outPath = resolve8(args[++index]);
6854
7216
  }
6855
7217
  }
6856
- const playName = isFileTarget(target) ? extractPlayName(readFileSync3(resolve7(target), "utf-8"), resolve7(target)) : parseReferencedPlayTarget(target).playName;
7218
+ const playName = isFileTarget(target) ? extractPlayName(readFileSync3(resolve8(target), "utf-8"), resolve8(target)) : parseReferencedPlayTarget(target).playName;
6857
7219
  const detail = isFileTarget(target) ? await client.getPlay(playName) : await assertCanonicalNamedPlayReference(client, target);
6858
7220
  const resolvedSource = detail.play.workingRevision?.sourceCode ?? detail.play.liveRevision?.sourceCode ?? detail.play.currentRevision?.sourceCode ?? detail.play.sourceCode ?? "";
6859
7221
  const materializedFile = outPath ? materializeRemotePlaySource({
@@ -7145,7 +7507,7 @@ async function handlePlayPublish(args) {
7145
7507
  }
7146
7508
  let graph;
7147
7509
  try {
7148
- graph = await collectBundledPlayGraph(resolve7(playName));
7510
+ graph = await collectBundledPlayGraph(resolve8(playName));
7149
7511
  await compileBundledPlayGraphManifests(client, graph);
7150
7512
  await publishImportedPlayDependencies(client, graph);
7151
7513
  } catch (error) {
@@ -7245,12 +7607,15 @@ Concepts:
7245
7607
  Plays are durable cloud workflows.
7246
7608
  Stable ctx.tools.execute({ id, tool, input }) calls are replay-safe.
7247
7609
  ctx.map adds row keys and row progress.
7610
+ Named play runs use the live revision unless --latest or --revision-id is set.
7611
+ Running a local file does not make it live; use set-live/publish explicitly.
7248
7612
 
7249
7613
  Common commands:
7250
7614
  deepline plays search email --json
7251
7615
  deepline plays describe person-linkedin-to-email --json
7252
7616
  deepline plays check my.play.ts
7253
7617
  deepline plays run my.play.ts --input '{"domain":"stripe.com"}' --watch
7618
+ deepline plays set-live my.play.ts --json
7254
7619
  deepline plays get person-linkedin-to-email --json
7255
7620
  `
7256
7621
  );
@@ -7280,9 +7645,11 @@ Notes:
7280
7645
  Unknown --foo and --foo.bar flags are treated as play input args.
7281
7646
  File args accept local paths; the CLI stages files before submit.
7282
7647
  --watch prints logs, previews, stats, and next commands.
7648
+ --wait is accepted as a compatibility alias for --watch.
7283
7649
  The play page opens in your browser as soon as the run starts; use --no-open
7284
7650
  to only print the URL.
7285
7651
  --force supersedes active runs; it does not bypass completed reuse.
7652
+ This command starts cloud work and may spend Deepline credits through tool calls.
7286
7653
 
7287
7654
  Idempotent execution:
7288
7655
  Stable tool call ids are the reuse key:
@@ -7307,6 +7674,7 @@ Idempotent execution:
7307
7674
 
7308
7675
  Examples:
7309
7676
  deepline plays run my.play.ts --input '{"domain":"stripe.com"}' --watch
7677
+ deepline plays run my.play.ts --input @input.json --wait --json
7310
7678
  deepline plays run person-linkedin-to-email --input '{"linkedin_url":"..."}' --watch
7311
7679
  deepline plays run enrich.play.ts --csv leads.csv --watch --out leads-enriched.csv
7312
7680
  deepline plays run cto-search.play.ts --limit 5 --watch
@@ -7318,7 +7686,7 @@ Examples:
7318
7686
  ).option(
7319
7687
  "--out <path>",
7320
7688
  "Write the completed row output to CSV; requires --watch"
7321
- ).option("--watch", "Stream logs until completion").option(
7689
+ ).option("--watch", "Stream logs until completion").option("--wait", "Alias for --watch; stream logs until completion").option(
7322
7690
  "--logs",
7323
7691
  "When output is non-interactive, stream play logs to stderr while waiting"
7324
7692
  ).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").action(async (target, options, command) => {
@@ -7341,7 +7709,7 @@ Examples:
7341
7709
  ...options.latest ? ["--latest"] : [],
7342
7710
  ...options.revisionId ? ["--revision-id", options.revisionId] : [],
7343
7711
  ...options.out ? ["--out", options.out] : [],
7344
- ...options.watch ? ["--watch"] : [],
7712
+ ...options.watch || options.wait ? ["--watch"] : [],
7345
7713
  ...options.logs ? ["--logs"] : [],
7346
7714
  ...options.tailTimeoutMs ? ["--tail-timeout-ms", options.tailTimeoutMs] : [],
7347
7715
  ...options.force ? ["--force"] : [],
@@ -7372,12 +7740,36 @@ Examples:
7372
7740
  ...options.out ? ["--out", options.out] : []
7373
7741
  ]);
7374
7742
  });
7375
- play.command("list").description("List saved and prebuilt plays.").option("--json", "Emit JSON output").action(async (options) => {
7743
+ play.command("list").description("List saved and prebuilt plays.").addHelpText(
7744
+ "after",
7745
+ `
7746
+ Notes:
7747
+ Inventory command for saved org plays and prebuilt plays. Use search for
7748
+ ranked discovery by task or schema.
7749
+
7750
+ Examples:
7751
+ deepline plays list
7752
+ deepline plays list --json
7753
+ deepline plays search email --origin prebuilt --json
7754
+ `
7755
+ ).option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (options) => {
7376
7756
  process.exitCode = await handlePlayList([
7377
7757
  ...options.json ? ["--json"] : []
7378
7758
  ]);
7379
7759
  });
7380
- play.command("search <query>").description("Search saved and prebuilt plays.").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) => {
7760
+ play.command("search <query>").description("Search saved and prebuilt plays.").addHelpText(
7761
+ "after",
7762
+ `
7763
+ Notes:
7764
+ Ranked discovery for workflows. Use --origin prebuilt or --origin owned when
7765
+ you need to narrow results. Use describe on a result before running it.
7766
+
7767
+ Examples:
7768
+ deepline plays search email
7769
+ deepline plays search "linkedin to email" --origin prebuilt --compact --json
7770
+ deepline plays describe person-linkedin-to-email --json
7771
+ `
7772
+ ).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) => {
7381
7773
  process.exitCode = await handlePlaySearch([
7382
7774
  query,
7383
7775
  ...options.origin ? ["--origin", options.origin] : [],
@@ -7403,13 +7795,53 @@ Examples:
7403
7795
  ...options.json ? ["--json"] : []
7404
7796
  ]);
7405
7797
  });
7406
- play.command("versions").description("List revisions for a named play.").option("--name <name>", "Saved play name").option("--json", "Emit JSON output").action(async (options) => {
7798
+ play.command("versions").description("List revisions for a named play.").addHelpText(
7799
+ "after",
7800
+ `
7801
+ Notes:
7802
+ Shows saved revisions for an org-owned play, including which revision is live
7803
+ when that metadata is available. Named runs use the live revision by default.
7804
+
7805
+ Examples:
7806
+ deepline plays versions --name my-play
7807
+ deepline plays versions --name my-play --json
7808
+ deepline plays run my-play --revision-id <revision-id> --watch
7809
+ `
7810
+ ).option("--name <name>", "Saved play name").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (options) => {
7407
7811
  process.exitCode = await handlePlayVersions([
7408
7812
  ...options.name ? ["--name", options.name] : [],
7409
7813
  ...options.json ? ["--json"] : []
7410
7814
  ]);
7411
7815
  });
7412
- play.command("publish <target>").description("Bundle, validate, save, and publish a play.").option("--latest", "Promote the newest saved revision").option("--revision-id <id>", "Revision to promote").option("--json", "Emit JSON output").action(async (target, options) => {
7816
+ const addPublishHelp = (command) => command.addHelpText(
7817
+ "after",
7818
+ `
7819
+ Notes:
7820
+ Mutates cloud state. For a local file, this bundles, validates, saves a new
7821
+ revision, and promotes that revision live. For a saved play, --latest or
7822
+ --revision-id promotes an existing saved revision live.
7823
+ Running a local file with plays run does not publish it.
7824
+
7825
+ Examples:
7826
+ deepline plays set-live my.play.ts --json
7827
+ deepline plays set-live my-play --latest --json
7828
+ deepline plays set-live my-play --revision-id <revision-id> --json
7829
+ deepline plays publish my.play.ts --json
7830
+ `
7831
+ );
7832
+ addPublishHelp(
7833
+ play.command("publish <target>").description("Bundle, validate, save, and promote a play revision live.")
7834
+ ).option("--latest", "Promote the newest saved revision").option("--revision-id <id>", "Revision to promote").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (target, options) => {
7835
+ process.exitCode = await handlePlayPublish([
7836
+ target,
7837
+ ...options.latest ? ["--latest"] : [],
7838
+ ...options.revisionId ? ["--revision-id", options.revisionId] : [],
7839
+ ...options.json ? ["--json"] : []
7840
+ ]);
7841
+ });
7842
+ addPublishHelp(
7843
+ play.command("set-live <target>").description("Promote a local file or saved revision as the live play revision.")
7844
+ ).option("--latest", "Promote the newest saved revision").option("--revision-id <id>", "Revision to promote").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (target, options) => {
7413
7845
  process.exitCode = await handlePlayPublish([
7414
7846
  target,
7415
7847
  ...options.latest ? ["--latest"] : [],
@@ -7417,7 +7849,18 @@ Examples:
7417
7849
  ...options.json ? ["--json"] : []
7418
7850
  ]);
7419
7851
  });
7420
- play.command("delete <target>").description("Delete an org-owned play and its saved revisions/runs.").option("-y, --yes", "Confirm deletion").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (target, options) => {
7852
+ play.command("delete <target>").description("Delete an org-owned play and its saved revisions/runs.").addHelpText(
7853
+ "after",
7854
+ `
7855
+ Notes:
7856
+ Destructive mutation. Deletes an org-owned play plus saved revisions and run
7857
+ records. Prebuilt/read-only plays are refused. Use --yes for noninteractive runs.
7858
+
7859
+ Examples:
7860
+ deepline plays delete my-play
7861
+ deepline plays delete my-play --yes --json
7862
+ `
7863
+ ).option("-y, --yes", "Confirm deletion").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (target, options) => {
7421
7864
  process.exitCode = await handlePlayDelete([
7422
7865
  target,
7423
7866
  ...options.yes ? ["--yes"] : [],
@@ -7427,6 +7870,12 @@ Examples:
7427
7870
  const runs = program.command("runs").description("Inspect, tail, stop, and export play runs.").addHelpText(
7428
7871
  "after",
7429
7872
  `
7873
+ Concepts:
7874
+ A run is one execution instance of a play. It has status, progress, logs,
7875
+ preview output, recovery metadata, and optional full row export.
7876
+ tail reads the live stream. logs fetches persisted logs after the fact.
7877
+ stop mutates cloud state by requesting cancellation.
7878
+
7430
7879
  Examples:
7431
7880
  deepline runs get play/my-play/run/20260501t000000-000 --json
7432
7881
  deepline runs tail play/my-play/run/20260501t000000-000
@@ -7436,14 +7885,36 @@ Examples:
7436
7885
  deepline runs export play/my-play/run/20260501t000000-000 --out output.csv
7437
7886
  `
7438
7887
  );
7439
- runs.command("get <runId>").description("Get status, progress, outputs, errors, and recovery metadata for a play run.").option("--json", "Emit JSON output. Also automatic when stdout is piped").option("--full", "Debug only: with --json, emit the raw status payload").action(async (runId, options) => {
7888
+ runs.command("get <runId>").description("Get status, progress, outputs, errors, and recovery metadata for a play run.").addHelpText(
7889
+ "after",
7890
+ `
7891
+ Notes:
7892
+ Full run status read. Use --full --json when debugging raw stream/status fields.
7893
+
7894
+ Examples:
7895
+ deepline runs get play/my-play/run/20260501t000000-000
7896
+ deepline runs get play/my-play/run/20260501t000000-000 --json
7897
+ deepline runs get play/my-play/run/20260501t000000-000 --full --json
7898
+ `
7899
+ ).option("--json", "Emit JSON output. Also automatic when stdout is piped").option("--full", "Debug only: with --json, emit the raw status payload").action(async (runId, options) => {
7440
7900
  process.exitCode = await handleRunGet([
7441
7901
  runId,
7442
7902
  ...options.json ? ["--json"] : [],
7443
7903
  ...options.full ? ["--full"] : []
7444
7904
  ]);
7445
7905
  });
7446
- runs.command("list").description("List play runs.").requiredOption("--play <name>", "Play name to filter runs").option("--status <status>", "Filter by run status").option("--compact", "Drop verbose fields from JSON output").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (options) => {
7906
+ runs.command("list").description("List play runs.").addHelpText(
7907
+ "after",
7908
+ `
7909
+ Notes:
7910
+ Bounded inventory for a play's recent runs. Use --compact for agent loops.
7911
+ Common statuses include running, completed, failed, and stopped.
7912
+
7913
+ Examples:
7914
+ deepline runs list --play my-play
7915
+ deepline runs list --play my-play --status failed --compact --json
7916
+ `
7917
+ ).requiredOption("--play <name>", "Play name to filter runs").option("--status <status>", "Filter by run status").option("--compact", "Drop verbose fields from JSON output").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (options) => {
7447
7918
  process.exitCode = await handleRunsList([
7448
7919
  "--play",
7449
7920
  options.play,
@@ -7452,14 +7923,37 @@ Examples:
7452
7923
  ...options.json ? ["--json"] : []
7453
7924
  ]);
7454
7925
  });
7455
- runs.command("tail <runId>").description("Read the canonical live stream for a play run.").option("--json", "Emit JSON output. Also automatic when stdout is piped").option("--compact", "Drop verbose fields from JSON output").action(async (runId, options) => {
7926
+ runs.command("tail <runId>").description("Read the canonical live stream for a play run.").addHelpText(
7927
+ "after",
7928
+ `
7929
+ Notes:
7930
+ Streams live run events until the stream ends. Use get for current status and
7931
+ logs for persisted log history.
7932
+
7933
+ Examples:
7934
+ deepline runs tail play/my-play/run/20260501t000000-000
7935
+ deepline runs tail play/my-play/run/20260501t000000-000 --compact --json
7936
+ `
7937
+ ).option("--json", "Emit JSON output. Also automatic when stdout is piped").option("--compact", "Drop verbose fields from JSON output").action(async (runId, options) => {
7456
7938
  process.exitCode = await handleRunTail([
7457
7939
  runId,
7458
7940
  ...options.json ? ["--json"] : [],
7459
7941
  ...options.compact ? ["--compact"] : []
7460
7942
  ]);
7461
7943
  });
7462
- runs.command("logs <runId>").description("Fetch persisted logs for a play run.").option("--limit <count>", "Maximum recent log lines to print without --out", "200").option("--out <path>", "Write the full persisted log stream to a file").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (runId, options) => {
7944
+ runs.command("logs <runId>").description("Fetch persisted logs for a play run.").addHelpText(
7945
+ "after",
7946
+ `
7947
+ Notes:
7948
+ Prints a bounded recent log preview by default. Use --out to write the full
7949
+ persisted log stream to a local file.
7950
+
7951
+ Examples:
7952
+ deepline runs logs play/my-play/run/20260501t000000-000
7953
+ deepline runs logs play/my-play/run/20260501t000000-000 --limit 500
7954
+ deepline runs logs play/my-play/run/20260501t000000-000 --out run.log --json
7955
+ `
7956
+ ).option("--limit <count>", "Maximum recent log lines to print without --out", "200").option("--out <path>", "Write the full persisted log stream to a file").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (runId, options) => {
7463
7957
  process.exitCode = await handleRunLogs([
7464
7958
  runId,
7465
7959
  ...options.limit ? ["--limit", options.limit] : [],
@@ -7467,14 +7961,36 @@ Examples:
7467
7961
  ...options.json ? ["--json"] : []
7468
7962
  ]);
7469
7963
  });
7470
- runs.command("stop <runId>").description("Stop a play run.").option("--reason <text>", "Reason to include with the stop request").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (runId, options) => {
7964
+ runs.command("stop <runId>").description("Stop a play run.").addHelpText(
7965
+ "after",
7966
+ `
7967
+ Notes:
7968
+ Mutates cloud state by requesting cancellation for an active run. Already
7969
+ terminal runs are returned as no-ops by the server when applicable.
7970
+
7971
+ Examples:
7972
+ deepline runs stop play/my-play/run/20260501t000000-000 --reason "stale lock"
7973
+ deepline runs stop play/my-play/run/20260501t000000-000 --json
7974
+ `
7975
+ ).option("--reason <text>", "Reason to include with the stop request").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (runId, options) => {
7471
7976
  process.exitCode = await handleRunStop([
7472
7977
  runId,
7473
7978
  ...options.reason ? ["--reason", options.reason] : [],
7474
7979
  ...options.json ? ["--json"] : []
7475
7980
  ]);
7476
7981
  });
7477
- runs.command("export <runId>").description("Export the completed row output for a play run to CSV.").requiredOption("--out <path>", "Output CSV path").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (runId, options) => {
7982
+ runs.command("export <runId>").description("Export the completed row output for a play run to CSV.").addHelpText(
7983
+ "after",
7984
+ `
7985
+ Notes:
7986
+ Writes the completed row output to the requested local CSV path. Use runs get
7987
+ first when you need to confirm the run is complete or inspect preview output.
7988
+
7989
+ Examples:
7990
+ deepline runs export play/my-play/run/20260501t000000-000 --out output.csv
7991
+ deepline runs export play/my-play/run/20260501t000000-000 --out output.csv --json
7992
+ `
7993
+ ).requiredOption("--out <path>", "Output CSV path").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (runId, options) => {
7478
7994
  process.exitCode = await handleRunExport([
7479
7995
  runId,
7480
7996
  "--out",
@@ -7718,16 +8234,44 @@ Concepts:
7718
8234
 
7719
8235
  Common commands:
7720
8236
  deepline tools search email --json
7721
- deepline tools get hunter_email_verifier --json
8237
+ deepline tools describe hunter_email_verifier --json
7722
8238
  deepline tools call hunter_email_verifier --input '{"email":"a@b.com"}'
8239
+
8240
+ Output:
8241
+ Search/list output is bounded. Use describe for a compact contract and get for
8242
+ the full machine-readable metadata available for the tool.
7723
8243
  `
7724
8244
  );
7725
- tools.command("list").description("List available tools.").option("--json", "Emit JSON output").action(async (options) => {
8245
+ tools.command("list").description("List available tools.").addHelpText(
8246
+ "after",
8247
+ `
8248
+ Notes:
8249
+ Inventory command for known tool ids. Use search for ranked discovery by
8250
+ intent, aliases, descriptions, and schema fields.
8251
+
8252
+ Examples:
8253
+ deepline tools list
8254
+ deepline tools list --json
8255
+ deepline tools search email --json
8256
+ `
8257
+ ).option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (options) => {
7726
8258
  process.exitCode = await listTools([
7727
8259
  ...options.json ? ["--json"] : []
7728
8260
  ]);
7729
8261
  });
7730
- tools.command("search <query>").description("Search available tools.").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) => {
8262
+ tools.command("search <query>").description("Search available tools.").addHelpText(
8263
+ "after",
8264
+ `
8265
+ Notes:
8266
+ Ranked discovery for atomic provider/API operations. Results include tool ids
8267
+ that can be passed to deepline tools describe or deepline tools call.
8268
+
8269
+ Examples:
8270
+ deepline tools search email
8271
+ deepline tools search "company enrichment" --categories enrichment --json
8272
+ deepline tools search verifier --search-mode v2 --json
8273
+ `
8274
+ ).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) => {
7731
8275
  process.exitCode = await searchTools(query, {
7732
8276
  json: options.json,
7733
8277
  categories: options.categories,
@@ -7736,15 +8280,18 @@ Common commands:
7736
8280
  includeSearchDebug: Boolean(options.includeSearchDebug)
7737
8281
  });
7738
8282
  });
7739
- tools.command("get <toolId>").alias("describe").description("Show metadata for a tool.").addHelpText(
8283
+ const addToolMetadataCommand = (command, preferredExample) => command.description("Show metadata for a tool.").addHelpText(
7740
8284
  "after",
7741
8285
  `
7742
8286
  Notes:
7743
- Shows the tool contract, input schema, output schema, costs, aliases, and metadata.
8287
+ Shows the tool contract, input schema, output schema, Deepline cost, aliases,
8288
+ and metadata. describe is the preferred discovery verb; get is kept as a
8289
+ compatibility command for the same metadata surface.
7744
8290
 
7745
8291
  Examples:
7746
- deepline tools get hunter_email_verifier
7747
- deepline tools get hunter_email_verifier --json | jq '.inputSchema'
8292
+ deepline tools ${preferredExample} hunter_email_verifier
8293
+ deepline tools ${preferredExample} hunter_email_verifier --json | jq '.inputSchema'
8294
+ deepline tools call hunter_email_verifier --input '{"email":"a@b.com"}'
7748
8295
  `
7749
8296
  ).option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (toolId, options) => {
7750
8297
  process.exitCode = await getTool([
@@ -7752,12 +8299,16 @@ Examples:
7752
8299
  ...options.json ? ["--json"] : []
7753
8300
  ]);
7754
8301
  });
8302
+ addToolMetadataCommand(tools.command("describe <toolId>"), "describe");
8303
+ addToolMetadataCommand(tools.command("get <toolId>"), "get");
7755
8304
  tools.command("call <toolId>").alias("execute").alias("run").description("Execute a tool by id.").addHelpText(
7756
8305
  "after",
7757
8306
  `
7758
8307
  Notes:
7759
8308
  Use tools for one atomic provider/API operation. Use plays for composed workflows,
7760
8309
  waterfalls, row maps, checkpoints, and retries.
8310
+ Calling a provider-backed tool can spend Deepline credits. Use --json for the
8311
+ stable result payload and --full-output when debugging response metadata.
7761
8312
 
7762
8313
  Examples:
7763
8314
  deepline tools call hunter_email_verifier --input '{"email":"a@b.com"}'
@@ -8249,7 +8800,7 @@ async function executeTool(args) {
8249
8800
  import { spawn, spawnSync as spawnSync2 } from "child_process";
8250
8801
  import { existsSync as existsSync6, mkdirSync as mkdirSync5, readFileSync as readFileSync4, writeFileSync as writeFileSync8 } from "fs";
8251
8802
  import { homedir as homedir4 } from "os";
8252
- import { dirname as dirname8, join as join9 } from "path";
8803
+ import { dirname as dirname9, join as join9 } from "path";
8253
8804
  var CHECK_TIMEOUT_MS2 = 3e3;
8254
8805
  var SDK_SKILL_NAME = "deepline-sdk";
8255
8806
  var SKILL_AGENTS = ["codex", "claude-code", "cursor"];
@@ -8273,7 +8824,7 @@ function readLocalSkillsVersion(baseUrl) {
8273
8824
  }
8274
8825
  function writeLocalSkillsVersion(baseUrl, version) {
8275
8826
  const path = sdkSkillsVersionPath(baseUrl);
8276
- mkdirSync5(dirname8(path), { recursive: true });
8827
+ mkdirSync5(dirname9(path), { recursive: true });
8277
8828
  writeFileSync8(path, `${version}
8278
8829
  `, "utf-8");
8279
8830
  }
@@ -8368,7 +8919,7 @@ function resolveSkillsInstallCommands(baseUrl) {
8368
8919
  return [npxInstall];
8369
8920
  }
8370
8921
  function runOneSkillsInstall(install) {
8371
- return new Promise((resolve8) => {
8922
+ return new Promise((resolve9) => {
8372
8923
  const child = spawn(install.command, install.args, {
8373
8924
  stdio: ["ignore", "ignore", "pipe"],
8374
8925
  env: process.env
@@ -8378,7 +8929,7 @@ function runOneSkillsInstall(install) {
8378
8929
  stderr += chunk.toString("utf-8");
8379
8930
  });
8380
8931
  child.on("error", (error) => {
8381
- resolve8({
8932
+ resolve9({
8382
8933
  ok: false,
8383
8934
  detail: `failed to start ${install.command}: ${error.message}`,
8384
8935
  manualCommand: install.manualCommand
@@ -8386,11 +8937,11 @@ function runOneSkillsInstall(install) {
8386
8937
  });
8387
8938
  child.on("close", (code) => {
8388
8939
  if (code === 0) {
8389
- resolve8({ ok: true, detail: "", manualCommand: install.manualCommand });
8940
+ resolve9({ ok: true, detail: "", manualCommand: install.manualCommand });
8390
8941
  return;
8391
8942
  }
8392
8943
  const detail = stderr.trim();
8393
- resolve8({
8944
+ resolve9({
8394
8945
  ok: false,
8395
8946
  detail: detail ? `${install.command}: ${detail}` : `${install.command} exited ${code}`,
8396
8947
  manualCommand: install.manualCommand
@@ -8443,6 +8994,9 @@ function shouldPrintStartupPhase() {
8443
8994
  return false;
8444
8995
  }
8445
8996
  const args = process.argv.slice(2);
8997
+ if (args.includes("-h") || args.includes("--help")) {
8998
+ return false;
8999
+ }
8446
9000
  const command = args[0];
8447
9001
  const subcommand = args[1];
8448
9002
  return (command === "play" || command === "plays") && subcommand === "run";
@@ -8464,7 +9018,7 @@ async function main() {
8464
9018
  if (printStartupPhase) {
8465
9019
  progress?.phase("loading deepline cli");
8466
9020
  }
8467
- const program = new Command();
9021
+ const program = new Command2();
8468
9022
  program.name("deepline").description("Deepline CLI (TypeScript SDK)").version(SDK_VERSION, "-v, --version", "Show version").showHelpAfterError().showSuggestionAfterError(true).addHelpText(
8469
9023
  "after",
8470
9024
  `
@@ -8476,9 +9030,23 @@ Common commands:
8476
9030
  deepline plays run my.play.ts --input '{"domain":"stripe.com"}' --watch
8477
9031
  deepline tools call hunter_email_verifier --input '{"email":"a@b.com"}'
8478
9032
 
9033
+ Product model:
9034
+ Tools are atomic provider/API operations that may spend credits.
9035
+ Plays are durable workflows backed by source code or saved cloud revisions.
9036
+ Runs are execution instances with logs, status, outputs, and cancellation.
9037
+ Live plays are promoted revisions used by named play runs.
9038
+
8479
9039
  Output:
8480
9040
  Structured commands print human-readable output in a terminal and JSON when stdout is piped.
8481
9041
  Use --json to force JSON in an interactive terminal.
9042
+
9043
+ Safety:
9044
+ Commands that mutate state, open a browser, write files, stop work, or spend credits say so in their help.
9045
+ Use --no-open where available for CI and agent runs.
9046
+
9047
+ Exit codes:
9048
+ 0 success; 2 usage/local input error; 3 auth/permission error; 4 not found;
9049
+ 5 server/runtime/provider failure; 7 validation/check failed.
8482
9050
  `
8483
9051
  );
8484
9052
  program.hook("preAction", async (_thisCommand, actionCommand) => {
@@ -8513,7 +9081,17 @@ Output:
8513
9081
  registerCsvCommands(program);
8514
9082
  registerDbCommands(program);
8515
9083
  registerFeedbackCommands(program);
8516
- program.command("health").description("Check server health.").action(async () => {
9084
+ program.command("health").description("Check server health.").addHelpText(
9085
+ "after",
9086
+ `
9087
+ Notes:
9088
+ Read-only connectivity check for the configured Deepline host. Prints the raw
9089
+ server health payload as JSON.
9090
+
9091
+ Examples:
9092
+ deepline health
9093
+ `
9094
+ ).action(async () => {
8517
9095
  try {
8518
9096
  const client = new DeeplineClient();
8519
9097
  const data = await client.health();
@@ -8525,7 +9103,18 @@ Output:
8525
9103
  );
8526
9104
  }
8527
9105
  });
8528
- program.command("version").description("Show version.").action(() => {
9106
+ program.command("version").description("Show version.").addHelpText(
9107
+ "after",
9108
+ `
9109
+ Notes:
9110
+ Prints the SDK CLI package version. The top-level -v/--version flag returns
9111
+ the same version.
9112
+
9113
+ Examples:
9114
+ deepline version
9115
+ deepline --version
9116
+ `
9117
+ ).action(() => {
8529
9118
  process.stdout.write(`deepline ${SDK_VERSION}
8530
9119
  `);
8531
9120
  });